一、引入微信支付
微信支付需要以下三個參數(shù),具體獲取過程參考官方說明。
- App ID:在微信開放平臺創(chuàng)建應(yīng)用,配置應(yīng)用包名和簽名
- API KEY: 微信商戶平臺設(shè)置
- 商戶號: 微信商戶平臺商戶號
添加依賴包:
compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+
二、后臺統(tǒng)一下單
App 端通過接口將訂單參數(shù)傳給后臺,后臺調(diào)用微信統(tǒng)一下單接口,獲得預(yù)支付訂單id(prepayid), 簽名后將參數(shù)返回給App端。
組裝統(tǒng)一下單參數(shù):
private Map<String, String> getParams() {
HashMap<String, String> params = new HashMap<>();
params.put("appid", Const.APP_ID);//App ID
params.put("body", "Test Goods");//商品名稱
params.put("mch_id", Const.MCH_ID);//商戶號
params.put("nonce_str", WXPayUtil.generateNonceStr());//隨機(jī)字符串
params.put("notify_url", Const.NOTIFY_URL);//支付結(jié)果回調(diào)地址
params.put("out_trade_no", WXPayUtil.generateUUID());//訂單號
params.put("spbill_create_ip", "127.0.0.1");// 用戶端實際ip
params.put("total_fee", "1");//金額
params.put("trade_type", "APP");//支付類型
params.put("sign", sign(params));//簽名
return params;
}
向微信后臺發(fā)送統(tǒng)一下單請求,參數(shù)是xml格式的:
public void getOrder() {
Map<String, String> params = getParams();
String xml = null;
try {
xml = WXPayUtil.mapToXml(params);
} catch (Exception e) {
e.printStackTrace();
}
if (TextUtils.isEmpty(xml)) {
Log.i(TAG, "getOrder: 組裝參數(shù)出錯");
return;
}
Log.i("統(tǒng)一下單參數(shù):", xml);
MediaType XML = MediaType.parse("application/xml; charset=utf-8");
RequestBody requestBody = RequestBody.create(XML, xml);
final Request request = new Request.Builder().url(Const.UNIFIED_ORDER).post(requestBody).build();
new OkHttpClient().newCall(request).enqueue(this);
}
微信后臺返回的數(shù)據(jù)也是xml格式,將參數(shù)簽名后(注意字段名),返回給App端:
private JSONObjecttoClient(String xml) throws Exception {
Map<String, String> map = WXPayUtil.xmlToMap(xml);
HashMap<String, String> params = new HashMap<>();
params.put("appid", map.get("appid"));
params.put("noncestr", map.get("nonce_str"));
params.put("prepayid", map.get("prepay_id"));
params.put("partnerid", map.get("mch_id"));
params.put("package", Const.PKG_VALUE);//固定值 Sign=WXPay
params.put("timestamp", String.valueOf(WXPayUtil.getCurrentTimestamp()));
params.put("sign", sign(params));//簽名
return new JSONObject(params);
}
三、App端調(diào)起支付
從后臺拿到返回數(shù)據(jù)后,發(fā)起支付:
private void invokeClient(JSONObject object) {
try {
IWXAPI api = WXAPIFactory.createWXAPI(this, object.getString("appid"));
PayReq request = new PayReq();
request.appId = object.getString("appid");
request.nonceStr = object.getString("noncestr");
request.partnerId = object.getString("partnerid");
request.prepayId = object.getString("prepayid");
request.packageValue = object.getString("package");
request.timeStamp = object.getString("timestamp");
request.sign = object.getString("sign");
api.sendReq(request);
} catch (JSONException e) {
e.printStackTrace();
}
}
處理支付結(jié)果:
在包名目錄下新建wxapi包,將官方Demo中的WXPayEntryActivity 放進(jìn)去,并在manifest 中注冊:
<activity
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
WXPayEntryActivity 界面也可以自定義,但包名和類名不可更改。重寫onResp(BaseResp resp) 方法,進(jìn)行結(jié)果處理:
@Override
public void onResp(BaseResp resp) {
Log.i(TAG, "返回碼:" + resp.errCode + ",返回信息:" + resp.errStr);
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
switch (resp.errCode) {
case BaseResp.ErrCode.ERR_OK://成功
Toast.makeText(this, "支付成功", Toast.LENGTH_SHORT).show();
break;
case BaseResp.ErrCode.ERR_USER_CANCEL://用戶取消
Toast.makeText(this, "支付取消", Toast.LENGTH_SHORT).show();
break;
case BaseResp.ErrCode.ERR_COMM://錯誤
Toast.makeText(this, "支付出錯", Toast.LENGTH_SHORT).show();
break;
}
}
finish();
}
四、其他
配置debug key: 在微信開放平臺創(chuàng)建應(yīng)用時,填入的簽名要與你運(yùn)行的App 簽名一致,否則無法調(diào)起支付,調(diào)試時可以將debug key 設(shè)置為正式的簽名key.
關(guān)于簽名方法:簽名參數(shù)需要排序,最后加上API Key,進(jìn)行MD5加密,方法可以自己寫,但建議直接復(fù)制官方Demo 中的 WXPayUtil 類,里面有所有你需要的方法,這樣出錯時只需要檢查參數(shù).
客戶端調(diào)起失敗,返回-1:檢查App Id,Api Key,商戶號,一般來講這幾個不可能出錯,那就要仔細(xì)檢查參與簽名的各項參數(shù)了,包括參數(shù)的字段名稱.
以上代碼全部是在Android 端完成的,理論上來說整個支付過程都可以在App 端完成(實際上也可以,親測),但官方建議簽名加密過程由后臺完成,安全性考慮。