第三方支付指的是第三方平臺與各銀行簽約,在買方與賣方之間實現中介擔保,從而增強了支付交易的安全性。國內常用的支付平臺主要是支付寶和微信支付,其中支付寶的市場份額為71.5%,微信支付的市場份額為15.99%,也就是說這兩家壟斷了八分之七的支付市場(2015年數據)。除此之外,還有幾個app開發會用到的支付平臺,包括:銀聯支付,主要用于公共事業繳費,如水電煤、有線電視、移動電信等等的充值;易寶支付,主要用于各種報名考試的繳費,特別是公務員與事業單位招考;快錢,被萬達收購,主要用于航空旅行、教育培訓、游戲娛樂等網站的支付;京東支付,主要用于京東商城的支付;百度錢包,主要用于百度系的電商平臺。
因為第三方支付只是個中介,交易流程要多次確認,所以app若要集成支付sdk,得進行以下處理:
1、除了作為買方的用戶自己擁有支付賬號,開發者還得申請作為賣方的商戶賬號。
2、支付過程中,雖然允許app直接與第三方支付平臺通信,但是最好app要有自己的后臺服務器,由自己的后臺與第三方平臺進行通信。這樣做的好處是,一方面自己后臺掌握了用戶交易記錄,做賬有依據,管理也方便;另一方面,關鍵交易在自己后臺處理,也減少了惡意篡改的風險。
3、為保證信息安全,需對關鍵數據進行加密處理,如支付寶采用RSA+BASE64算法,微信支付采用MD5算法,銀聯支付采用RSA算法。
支付寶支付
交易流程
支付寶支付的交易流程大致如下:
1、按照指定格式封裝好交易信息;
2、對交易信息進行RSA加密與URL編碼;
3、調用支付接口,傳入加密好的信息串;(這步要另開線程處理,不能放在UI線程中)
4、支付寶sdk在界面下方彈出支付窗口,用戶輸入支付帳號信息,提交支付;
5、收到支付完成的結果,判斷支付狀態是成功還是失敗;
集成步驟
支付寶sdk的集成比較簡單,除了必要的權限外,無需再修改AndroidManifest.xml,jar包也只要導入alipaySdk-20160516.jar。
代碼方面,支付寶官方給的demo采用了Thread+Handler的異步處理模式,不過該模式要把代碼寫在Activity中,不便管理和維護,而本文的測試代碼將它改為Android自帶的異步任務處理即AsyncTask方式
測試帳號
支付寶官方demo沒有給出測試的商戶賬號,下面是我在網上找到的測試帳號:
[java]view plaincopy
1.//?商戶PID
2.publicstaticfinalString?PARTNER?="2088811977704990";
3.//?商戶收款賬號
4.publicstaticfinalString?SELLER?="dev@ifensi.com";
5.//?商戶私鑰,pkcs8格式
6.publicstaticfinalString?RSA_PRIVATE?=
7."MIICXQIBAAKBgQDlQ468L1A7Q+GG80/Z8f3IsSiiFIluSxfTTSuJ/XSPzvYS+bMZ"
8.+"AQLMqq/nGhkp+1Q5pHF9LAQtQS3gL2pqzbKdtvZSsy/tNFFQcGCsgK2ygMl+MW/F"
9.+"g/ufx7c1jy1kZAeDyl1m302dnRrtSgDalkgH7FKRcmDxbXPTnFGHbg9zMQIDAQAB"
10.+"AoGAa28wGQF28H7L1Yh5V+FtkrlqGCHVkQjBfnRAPea205kheRzoD4SIwk4OJhb1"
11.+"ydWLz4M+53BT+Lz9eXveu3PvCdQe9zMIVC5dKUNVYCvvcHZ+Ot8HriiuwGPb3Quu"
12.+"twbnLGM5gxxPDo0yUyWrfaVn/qR35mS6TDfmgowVG8CmBpECQQDzuhodR/Jgxrtn"
13.+"tka+88alyy+BfjUZqNloPuE7JfXrpOxH5lodk7Y4lTki/dlo5BrK+hrismLFr9Du"
14.+"ueAJ7G9dAkEA8M8C6VnpUMAK5+rYcjKnQssDqcMfurKYEil1BD/TUdSbLI6v8p02"
15.+"mv1ApuTVtQQypZJKIFfurGk0g0QlvzLZ5QJAGfY38+iHDAH/UnPbI1oKTfzPyaZs"
16.+"95fB2NXh3hAUGw7NUHdcIAxs+6gBlxWdRAwQQpDTrlQ8KzyoL9XC5Ku3zQJBALO8"
17.+"j5vEtFTFQl6f9zYlgJpmFTHcpg4fx0mnD+RAD2aAneHADquzlFJSvLLVEn2tyG+0"
18.+"pQdHGqotTDi94L65IdECQQDb1h+5kugCu47IxsDkrLRsKVcr8dSDMORyeT1L0HWR"
19.+"ctramBu+2PBz2UKC6+9dQ+ZQH4XTKpBSvkyZH4mYi1de";
20.//??//?支付寶公鑰
21.//??public?static?final?String?RSA_PUBLIC?=?"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnxj/9qwVfgoUh/y2W89L6BkRAFljhNhgPdyPuBV64bfQNN1PjbCzkIM6qRdKBoLPXmKKMiFYnkd6rAoprih3/PrQEB/VsW8OoM8fxn67UDYuyBTqA23MML9q1+ilIZwBC2AQ2UBVOrFXfFl75p6/B5KsiNG9zpgmLCUYuLkxpLQIDAQAB";
下面是支付寶支付的示例代碼:
[java]view plaincopy
1.importjava.io.UnsupportedEncodingException;
2.importjava.net.URLEncoder;
3.importjava.text.SimpleDateFormat;
4.importjava.util.Date;
5.importjava.util.Locale;
6.importjava.util.Random;
7.
8.importcom.alipay.sdk.app.PayTask;
9.importcom.example.exmpay.alipay.bean.AlipayConstants;
10.importcom.example.exmpay.alipay.bean.PayResult;
11.importcom.example.exmpay.alipay.util.SignUtils;
12.
13.importandroid.app.Activity;
14.importandroid.app.AlertDialog;
15.importandroid.app.ProgressDialog;
16.importandroid.content.Context;
17.importandroid.content.DialogInterface;
18.importandroid.os.AsyncTask;
19.importandroid.text.TextUtils;
20.importandroid.widget.Toast;
21.
22.publicclassAlipayTaskextendsAsyncTask?{
23.
24.privatestaticfinalString?TAG?="AlipayTask";
25.privateContext?context;
26.privateProgressDialog?dialog;
27.
28.publicAlipayTask(Context?context)?{
29.this.context?=?context;
30.}
31.
32.@Override
33.protectedvoidonPreExecute()?{
34.if(TextUtils.isEmpty(AlipayConstants.PARTNER)
35.||?TextUtils.isEmpty(AlipayConstants.RSA_PRIVATE)
36.||?TextUtils.isEmpty(AlipayConstants.SELLER))?{
37.newAlertDialog.Builder(context).setTitle("警告").setMessage("需要配置PARTNER?|?RSA_PRIVATE|?SELLER")
38..setPositiveButton("確定",newDialogInterface.OnClickListener()?{
39.publicvoidonClick(DialogInterface?dialoginterface,inti)?{
40.}
41.}).show();
42.cancel(true);
43.}else{
44.dialog?=?ProgressDialog.show(context,"提示","正在啟動支付寶...");
45.}
46.}
47.
48.@Override
49.protectedString?doInBackground(Void...?params)?{
50.String?orderInfo?=?getOrderInfo("測試的商品","該測試商品的詳細描述","0.01");
51.
52.//特別注意,這里的簽名邏輯需要放在服務端,切勿將私鑰泄露在代碼中!
53.String?sign?=?sign(orderInfo);
54.try{
55.//僅需對sign?做URL編碼
56.sign?=?URLEncoder.encode(sign,"UTF-8");
57.}catch(UnsupportedEncodingException?e)?{
58.e.printStackTrace();
59.}
60.
61.//完整的符合支付寶參數規范的訂單信息
62.finalString?payInfo?=?orderInfo?+"&sign=\""+?sign?+"\"&"+?getSignType();
63.//?構造PayTask?對象
64.PayTask?alipay?=newPayTask((Activity)?context);
65.//?調用支付接口,獲取支付結果
66.String?result?=?alipay.pay(payInfo,false);
67.returnresult;
68.}
69.
70.@Override
71.protectedvoidonPostExecute(String?result)?{
72.if(dialog?!=null)?{
73.dialog.dismiss();
74.}
75.
76.PayResult?payResult?=newPayResult(result);
77.
78.//?支付寶返回此次支付結果及加簽,建議對支付寶簽名信息拿簽約時支付寶提供的公鑰做驗簽
79.String?resultInfo?=?payResult.getResult();
80.Toast.makeText(context,"resultInfo="+resultInfo,?Toast.LENGTH_SHORT).show();
81.
82.String?resultStatus?=?payResult.getResultStatus();
83.//?判斷resultStatus?為“9000”則代表支付成功,具體狀態碼代表含義可參考接口文檔
84.if(TextUtils.equals(resultStatus,"9000"))?{
85.Toast.makeText(context,"支付寶繳費成功",?Toast.LENGTH_SHORT).show();
86.}else{
87.//?判斷resultStatus?為非“9000”則代表可能支付失敗
88.//?“8000”代表支付結果因為支付渠道原因或者系統原因還在等待支付結果確認,最終交易是否成功以服務端異步通知為準(小概率狀態)
89.if(TextUtils.equals(resultStatus,"8000"))?{
90.Toast.makeText(context,"支付寶繳費結果確認中",?Toast.LENGTH_SHORT).show();
91.}else{
92.//?其他值就可以判斷為支付失敗,包括用戶主動取消支付,或者系統返回的錯誤
93.Toast.makeText(context,"支付寶繳費失敗"+payResult.getResult(),?Toast.LENGTH_SHORT).show();
94.}
95.}
96.}
97.privateString?getOrderInfo(String?subject,?String?body,?String?price)?{
98.//?簽約合作者身份ID
99.String?orderInfo?="partner="+"\""+?AlipayConstants.PARTNER?+"\"";
100.//?簽約賣家支付寶賬號
101.orderInfo?+="&seller_id="+"\""+?AlipayConstants.SELLER?+"\"";
102.//?商戶網站唯一訂單號
103.orderInfo?+="&out_trade_no="+"\""+?getOutTradeNo()?+"\"";
104.//?商品名稱
105.orderInfo?+="&subject="+"\""+?subject?+"\"";
106.//?商品詳情
107.orderInfo?+="&body="+"\""+?body?+"\"";
108.//?商品金額
109.orderInfo?+="&total_fee="+"\""+?price?+"\"";
110.//?服務器異步通知頁面路徑
111.orderInfo?+="?ify_url="+"\""+"http://notify.msp.hk/notify.htm"+"\"";
112.//?服務接口名稱,?固定值
113.orderInfo?+="&service=\"mobile.securitypay.pay\"";
114.//?支付類型,?固定值
115.orderInfo?+="&payment_type=\"1\"";
116.//?參數編碼,?固定值
117.orderInfo?+="&_input_charset=\"utf-8\"";
118.
119.//?設置未付款交易的超時時間,默認30分鐘,一旦超時,該筆交易就會自動被關閉。
120.//?取值范圍:1m~15d。m-分鐘,h-小時,d-天,1c-當天(無論交易何時創建,都在0點關閉)。
121.//?該參數數值不接受小數點,如1.5h,可轉換為90m。
122.orderInfo?+="&it_b_pay=\"30m\"";
123.
124.//?extern_token為經過快登授權獲取到的alipay_open_id,帶上此參數用戶將使用授權的賬戶進行支付
125.//?orderInfo?+=?"&extern_token="?+?"\""?+?extern_token?+?"\"";
126.
127.//?支付寶處理完請求后,當前頁面跳轉到商戶指定頁面的路徑,可空
128.orderInfo?+="&return_url=\"m.alipay.com\"";
129.
130.//?調用銀行卡支付,需配置此參數,參與簽名,?固定值?(需要簽約《無線銀行卡快捷支付》才能使用)
131.//?orderInfo?+=?"&paymethod=\"expressGateway\"";
132.
133.returnorderInfo;
134.}
135.
136.privateString?getOutTradeNo()?{
137.SimpleDateFormat?format?=newSimpleDateFormat("MMddHHmmss",?Locale.getDefault());
138.Date?date?=newDate();
139.String?key?=?format.format(date);
140.
141.Random?r?=newRandom();
142.key?=?key?+?r.nextInt();
143.key?=?key.substring(0,15);
144.returnkey;
145.}
146.
147.privateString?sign(String?content)?{
148.returnSignUtils.sign(content,?AlipayConstants.RSA_PRIVATE);
149.}
150.
151.privateString?getSignType()?{
152.return"sign_type=\"RSA\"";
153.}
154.
155.}