안드로이드 위챗페이: errCode -1 문제 해결

WindSekirun (wind.seo)·2022년 4월 26일
0

이 글은 기존 운영했던 WordPress 블로그인 PyxisPub: Development Life (pyxispub.uzuki.live) 에서 가져온 글 입니다. 모든 글을 가져오지는 않으며, 작성 시점과 현재 시점에는 차이가 많이 존재합니다.

작성 시점: 2018-03-06

요약

위챗 개방 플랫폼에 잘 등록되었다면 errCode가 -1로 내려올 경우에는 대부분 서명 생성에서 에러가 난 것이다.

도입

이번에 고객사가 일본에 납품하는 솔루션에 중국의 Wechat 페이가 들어가는데, 계속 returnCode가 -1로 돌아오는 문제가 있었다.

개방 플랫폼에는 앱의 패키지와 MD5 Signature가 잘 등록되어있는 것을 확인해서 아무리 생각해도 클라이언트 단에서 위챗으로 데이터를 잘못 보내줘서 생긴 일이라고 판단했다.

문제

현재 이 앱은 고객사 솔루션 서버에서 웨이신 통합주문 API  을 통해 가져온 preorder 값들을 위챗으로 보내서 위챗에서 결제 후에, 다시 고객사 솔루션 서버에 보내는 방식으로 되어있다.

고객사 솔루션 서버와의 통신이 제대로 됨을 확인하고, WXAPI의 결제 요청 모듈 클래스인 PayReq 클래스에 값을 집어넣었다.

PayReq request = new PayReq();
request.appId = mAppId;
request.nonceStr = nonceStr;
request.packageValue = packageValue;
request.partnerId = partnerId;
request.prepayId = prepayId;
request.timeStamp = String.valueOf(timestamp);

nonceStr에 대해서는 클라이언트에서 생성하기로 규악을 했기 때문에, 아래와 같은 코드를 사용한다.

/**
 * create nonceStr using url-safe base64 string with 16-length and no-padding
 *
 * @return created nonceStr
 */
private String createNonceStr() {
    SecureRandom random = new SecureRandom();
    byte[] bytes = new byte[16];
    random.nextBytes(bytes);
    return Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
}

그리고 파라미터 맵과 키를 넘기면 Sign키를 생성해주는 메서드를 만들었다.

private String createSign(SortedMap<String, String> parameters, String key) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : parameters.entrySet()) {
            String k = entry.getKey();
            String v = entry.getValue();
            if (!TextUtils.isEmpty(v) && !k.equals("sign") && !k.equals("key")) {
                sb.append(k).append("=").append(v).append("&");
            }
        }
        sb.append("key=").append(key);
        return new String(Hex.encodeHex(DigestUtils.md5(sb.toString()))).toUpperCase();
}

SortedMap<String, String> data = new TreeMap<>();
data.put("appid", request.appId);
data.put("mch_id", request.partnerId);
data.put("nonce_str", request.nonceStr);
data.put("package", request.packageValue);
data.put("prepay_id", request.prepayId);
data.put("timestamp", request.timeStamp);
request.sign = createSign(data, request.appId);

이렇게 하면, 위챗 앱이 잠깐 떴다가 errCode가 -1로 내려오게 된다.

-1에 대한 위챗쪽 설명은 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等(Possible reasons: wrong signatures, unregistered APPID, incorrect project settings APPID, registered APPIDs do not match the settings, and other exceptions.) 라는 문구이나 이거만으로는 파악하기가 부족하다.

해결 방법

일단 해당 파라미터들에 대한 키 값이 문제였다.

어느 글에서 나와있는대로 하면 오류난다고 하는 글을 본 뒤로 저 키를 사용하고 있었는데, 결국엔 아닌 것으로 판단되었다.

정확한 파라미터는 다음과 같다.

data.put("appid", request.appId);
data.put("noncestr", request.nonceStr);
data.put("package", request.packageValue);
data.put("partnerid", request.partnerId);
data.put("prepayid", request.prepayId);
data.put("timestamp", request.timeStamp);

그리고 생성하는 메서드에서 key 값을 정렬한 다음에 그대로 이어붙여주니, 제대로 작동이 된다.

/**
 * create Sign value follow by Sign random number algorithm document by
 * Wechat(https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3)
 *
 * @param json   {@link JSONObject} object which contains all value of PayReq except sign itself.
 * @param appKey Key which setting in WeChat SDK Business Platform
 * @return created Sign
 */
private String getWXSign(JSONObject json, String appKey) {
    List<String> signList = new ArrayList<>();
    Iterator<String> keys = json.keys();
    while (keys.hasNext()) {
    String key = keys.next();
        signList.add(key);
    }

    Collections.sort(signList);
    StringBuilder sign = new StringBuilder();
    for (int i = 0; i < signList.size(); i++) {
        String key = signList.get(i);
        String value = json.optString(key);
        sign.append(key).append("=").append(value).append("&");
    }

    sign.append("key=").append(appKey);

    sign = new StringBuilder(new String(DigestUtils.md5(sign.toString())).toUpperCase());
    return sign.toString();
}

결론

결론적으로는 완전히 연동이 끝난건 아니지만,  적어도 결제는 되니 나머지는 수월하게 넘어갈 수 있을 것 같다.

profile
Android Developer @kakaobank

0개의 댓글