## 第三方支付
app中支付功能集成了微信支付和支付寶支付兩大主流支付模式。
[TOC=3,3]
### 微信支付接入流程
   注1:微信SDK改成通過Gradle的方式發布到jcenter,包名做了相應修改,從原來的com.tencent.mm.sdk修改為com.tencent.mm.opensdk,需要開發者修改對應的import語句。
* 申請你的AppID
   應用包名:是在APP項目配置文件AndroidManifest.xml中聲明的package值,項目中的 package="com.yuanfengbbc.shop"。

* 下載SDK及API文檔
在build.gradle文件中,添加如下依賴即可:
~~~
dependencies {
compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
}
~~~
或
~~~
dependencies {
compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'
}
~~~
(其中,前者包含統計功能)
3. 注冊APPID
商戶APP工程中引入微信JAR包,調用API前,需要先向微信注冊您的APPID,代碼如下:
~~~
IWXAPI api = WXAPIFactory.createWXAPI(this, null);
~~~
將該app注冊到微信
WX_APP_ID在com.yuanfeng.ecdemo.yf.util的包下的Contants.java文件下。
~~~
api.registerApp(Contants.WX_APP_ID);
~~~
* 調起支付
  商戶服務器生成支付訂單,先調用統一下單API生成預付單,獲取到prepay_id后將參數再次簽名傳輸給APP發起支付。以下是調起微信支付的關鍵代碼:
~~~
IWXAPI api;
PayReq request = new PayReq();
request.appId = "wxd930ea5d5a258f4f";
request.partnerId = "1900000109";
request.prepayId= "1101000000140415649af9fc314aa427",;
request.packageValue = "Sign=WXPay";
request.nonceStr= "1101000000140429eb40476f8896f4c9";
request.timeStamp= "1398746574";
request.sign= "7FFECB600D7157C5AA49810D2D8F28BC2811827B";
api.sendReq(request);
~~~
注:如果遇到支付不成功,可能是后臺返回的簽名的問題,需要自己手動簽名
~~~
StringBuilder sb = new StringBuilder();
sb.append("appid=");
sb.append(Constans.WX_APP_ID);
sb.append('&');
sb.append("noncestr=");
sb.append(beanWx.getNonce_str());
sb.append('&');
sb.append("package=");
sb.append(req.packageValue);
sb.append('&');
sb.append("partnerid=");
sb.append(beanWx.getMch_id());
sb.append('&');
sb.append("prepayid=");
sb.append(beanWx.getPrepay_id());
sb.append('&');
sb.append("timestamp=");
sb.append(String.valueOf(System.currentTimeMillis()/ 1000 ));
sb.append('&');
sb.append("key=");
sb.append("fa45be83eaeb9e4da1661ba9c9e7cad9");
String appSign = MD5Util.encrypt(sb.toString());
req.sign = appSign;//簽名
~~~
* 支付結果回調
  在com.yuanfengbbc.shop.wxapi包路徑中實現WXPayEntryActivity類(包名或類名不一致會造成無法回調),在WXPayEntryActivity類中實現onResp函數,支付完成后,微信APP會返回到商戶APP并回調onResp函數,開發者需要在該函數中接收通知,判斷返回錯誤碼,如果支付成功則去后臺查詢支付結果再展示用戶實際支付結果。注意一定不能以客戶端返回作為用戶支付的結果,應以服務器端的接收的支付通知或查詢API返回的結果為準。代碼示例如下:
~~~
@Override
public void onResp(BaseResp resp) {
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {//微信支付
PAY_CALLBACK_FLAG = resp.errCode;
LogUtil.i("resp.errStr====" + resp.errStr);
if (PAY_CALLBACK_FLAG == WXPayEntryActivity.SUCESS) {
currentStatus.setText("支付成功");
Constans.NUM_WAIT_PAY_ORDER = true;
Constans.NUM_WAIT_SEND = true;
} else {
ORDER_NUMBER = null;
currentStatus.setText("支付失敗");
}
}
}
~~~
回調中errCode值列表:
| 名稱 | 描述 | 解決方案 |
| --- | --- | --- |
|    0  | 成功 | 展示成功頁面 |
| -1 | 錯誤 | 可能的原因:簽名錯誤、未注冊APPID、項目設置APPID不正確、注冊的APPID與設置的不匹配、其他異常等。 |
| -2 | 用戶取消 | 發生場景:用戶不支付了,點擊取消,返回APP。|
詳細文檔參考微信開放平臺 [https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5)
### 支付寶支付接入流程
* 導入開發資源
將alipaySdk-xxxxxxxx.jar包放入商戶應用工程的libs目錄下,如下圖。

在app module下的build.gradle下手動添加依賴,如下代碼所示:
~~~
dependencies {
......
compile files('libs/alipaySdk-20170725.jar')
......
}
~~~
* 修改Manifest
在應用工程的AndroidManifest.xml文件里面添加聲明:
~~~
<activity
android:name="com.alipay.sdk.app.H5PayActivity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false"
android:screenOrientation="behind"
android:windowSoftInputMode="adjustResize|stateHidden" >
</activity>
<activity
android:name="com.alipay.sdk.app.H5AuthActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind"
android:windowSoftInputMode="adjustResize|stateHidden" >
</activity>
~~~
和權限聲明:
~~~
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
~~~
* 添加混淆規則
在應用工程的proguard-project.txt里添加以下相關規則:
~~~
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IAlixPay$Stub{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{ public *;}
-keep class com.alipay.sdk.app.AuthTask{ public *;}
-keep class com.alipay.sdk.app.H5PayCallback {
<fields>;
<methods>;
}
-keep class com.alipay.android.phone.mrpc.core.** { *; }
-keep class com.alipay.apmobilesecuritysdk.** { *; }
-keep class com.alipay.mobile.framework.service.annotation.** { *; }
-keep class com.alipay.mobilesecuritysdk.face.** { *; }
-keep class com.alipay.tscenter.biz.rpc.** { *; }
-keep class org.json.alipay.** { *; }
-keep class com.alipay.tscenter.** { *; }
-keep class com.ta.utdid2.** { *;}
-keep class com.ut.device.** { *;}
~~~
至此,開發包開發資源導入完成。
* 支付接口調用
需要在新線程中調用支付接口。(可參考alipay_demo實現)
PayTask對象主要為商戶提供訂單支付、查詢功能,及獲取當前開發包版本號。
獲取PayTask支付對象調用支付(支付行為需要在獨立的非ui線程中執行),代碼示例:
~~~
//訂單信息
final String payInfo = object.getJSONObject("data").getString("orderString");
Runnable payRun = new Runnable() {
@Override
public void run() {
// 構造PayTask 對象
PayTask alipay = new PayTask(ActivityOrderPayMethod.this);
// 調用支付接口,獲取支付結果
String result = alipay.pay(payInfo, true);
Message msg = new Message();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
aliPayResultHandler.sendMessage(msg);
}
};
// 必須異步調用
Thread payThread = new Thread(payRun);
payThread.start();
~~~
| 參數名稱 | 參數說明 |
| --- | --- |
| String orderInfo | app支付請求參數字符串,主要包含商戶的訂單信息,key=value形式,以&連接。 |
| boolean isShowPayLoading | 用戶在商戶app內部點擊付款,是否需要一個loading做為在錢包喚起之前的過渡,這個值設置為true,將會在調用pay接口的時候直接喚起一個loading,直到喚起H5支付頁面或者喚起外部的錢包付款頁面loading才消失。(建議將該值設置為true,優化點擊付款到支付喚起支付頁面的過渡過程。) |
orderStr示例如下,參數說明見"請求參數說明",orderStr的獲取必須來源于服務端:
~~~
app_id=2015052600090779&biz_content=%7B%22timeout_express%22%3A%2230m%22%2C%22seller_id%22%3A%22%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22total_amount%22%3A%220.02%22%2C%22subject%22%3A%221%22%2C%22body%22%3A%22%E6%88%91%E6%98%AF%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%22%2C%22out_trade_no%22%3A%22314VYGIAGG7ZOYY%22%7D&charset=utf-8&method=alipay.trade.app.pay&sign_type=RSA2×tamp=2016-08-15%2012%3A12%3A15&version=1.0&sign=MsbylYkCzlfYLy9PeRwUUIg9nZPeN9SfXPNavUCroGKR5Kqvx0nEnd3eRmKxJuthNUx4ERCXe552EV9PfwexqW%2B1wbKOdYtDIb4%2B7PL3Pc94RZL0zKaWcaY3tSL89%2FuAVUsQuFqEJdhIukuKygrXucvejOUgTCfoUdwTi7z%2BZzQ%3D
~~~
* 支付結果獲取和處理
調用pay方法支付后,將通過2種途徑獲得支付結果:
同步返回
  商戶應用客戶端通過當前調用支付的Activity的Handler對象,通過它的回調函數獲取支付結果。(可參考alipay_demo實現)代碼示例:
~~~
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
PayResult payResult = new PayResult((String) msg.obj);
String resultStatus = payResult.getResultStatus();
};
};
~~~
異步通知
  商戶需要提供一個http協議的接口,包含在請求支付的入參中,其key對應notify_url。支付寶服務器在支付完成后,會以POST方式調用notify_url傳輸數據。
詳細文檔參考支付寶開發平臺[https://docs.open.alipay.com/204/105296/](https://docs.open.alipay.com/204/105296/)