Android支付开发(微信)
微信接入支付流程跟支付寶差不多,這里介紹一下接入流程以及注意事項。
接入流程:
1.1、到微信開放平臺添加移動應(yīng)用,申請權(quán)限
到微信開放平臺注冊開發(fā)者賬號,并添加應(yīng)用,申請支付權(quán)限,等待審核,需要提前做,審核需要時間,一般在7個工作日內(nèi)。
獲取的參數(shù)配置:
1.2、后臺設(shè)置
這里應(yīng)用跟應(yīng)用簽名和包名掛鉤,也就是說一個移動應(yīng)用對應(yīng)一個APPID,表明了配置參數(shù)的不可公用性。另外要注意調(diào)試的時候簽名問題,可以先設(shè)置為debug簽名,等調(diào)試成功換成正式簽名。一般調(diào)試問題就是簽名問題。
簽名工具下載地址:
https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk
支付流程
由流程圖可知,客戶端只需要調(diào)用下單接口,拿到后臺簽名后的預(yù)支付訂單即可,客戶端根據(jù)預(yù)支付訂單去吊起微信支付
1.3、注冊吊起支付
// 通過WXAPIFactory工廠,獲取IWXAPI的實例IWXAPI api = WXAPIFactory.createWXAPI(this, Constants.APP_ID, false);// 將該app注冊到微信api.registerApp(Constants.APP_ID);商戶服務(wù)器生成支付訂單,先調(diào)用統(tǒng)一下單API(詳見第7節(jié))生成預(yù)付單,獲取到prepay_id后將參數(shù)再次簽名傳輸給APP發(fā)起支付,由服務(wù)器端進(jìn)行操作,簡化了客戶端的復(fù)雜度跟安全性。
訂單參數(shù):
這里是服務(wù)器端生成預(yù)支付訂單并加簽名返回。
調(diào)用方式:
0) {String content = new String(buf);Log.e("get server pay params:",content);JSONObject json = new JSONObject(content); if(null != json && !json.has("retcode") ){PayReq req = new PayReq();//req.appId = "wxf8b4f85f3a794e77"; // 測試用appId//訂單參數(shù)req.appId = json.getString("appid");req.partnerId = json.getString("partnerid");req.prepayId = json.getString("prepayid");req.nonceStr = json.getString("noncestr");req.timeStamp = json.getString("timestamp");req.packageValue = json.getString("package");req.sign = json.getString("sign");req.extData = "app data"; // optionalToast.makeText(PayActivity.this, "正常調(diào)起支付", Toast.LENGTH_SHORT).show();// 在支付之前,如果應(yīng)用沒有注冊到微信,應(yīng)該先調(diào)用IWXMsg.registerApp將應(yīng)用注冊到微信api.sendReq(req);}else{Log.d("PAY_GET", "返回錯誤"+json.getString("retmsg"));Toast.makeText(PayActivity.this, "返回錯誤"+json.getString("retmsg"), Toast.LENGTH_SHORT).show();}}else{Log.d("PAY_GET", "服務(wù)器請求錯誤");Toast.makeText(PayActivity.this, "服務(wù)器請求錯誤", Toast.LENGTH_SHORT).show();}}catch(Exception e){Log.e("PAY_GET", "異常:"+e.getMessage());Toast.makeText(PayActivity.this, "異常:"+e.getMessage(), Toast.LENGTH_SHORT).show();}payBtn.setEnabled(true);}}); " data-snippet-id="ext.e81c40480e05a2f627716c229015f412" data-snippet-saved="false" data-codota-status="done">api = WXAPIFactory.createWXAPI(this, "wxb4ba3c02aa476ea1");Button appayBtn = (Button) findViewById(R.id.appay_btn);appayBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//訂單接口String url = "http://wxpay.weixin.qq.com/pub_v2/app/app_pay.php?plat=android";Button payBtn = (Button) findViewById(R.id.appay_btn);payBtn.setEnabled(false);Toast.makeText(PayActivity.this, "獲取訂單中...", Toast.LENGTH_SHORT).show();try{byte[] buf = Util.httpGet(url);if (buf != null && buf.length > 0) {String content = new String(buf);Log.e("get server pay params:",content);JSONObject json = new JSONObject(content); if(null != json && !json.has("retcode") ){PayReq req = new PayReq();//req.appId = "wxf8b4f85f3a794e77"; // 測試用appId//訂單參數(shù)req.appId = json.getString("appid");req.partnerId = json.getString("partnerid");req.prepayId = json.getString("prepayid");req.nonceStr = json.getString("noncestr");req.timeStamp = json.getString("timestamp");req.packageValue = json.getString("package");req.sign = json.getString("sign");req.extData = "app data"; // optionalToast.makeText(PayActivity.this, "正常調(diào)起支付", Toast.LENGTH_SHORT).show();// 在支付之前,如果應(yīng)用沒有注冊到微信,應(yīng)該先調(diào)用IWXMsg.registerApp將應(yīng)用注冊到微信api.sendReq(req);}else{Log.d("PAY_GET", "返回錯誤"+json.getString("retmsg"));Toast.makeText(PayActivity.this, "返回錯誤"+json.getString("retmsg"), Toast.LENGTH_SHORT).show();}}else{Log.d("PAY_GET", "服務(wù)器請求錯誤");Toast.makeText(PayActivity.this, "服務(wù)器請求錯誤", Toast.LENGTH_SHORT).show();}}catch(Exception e){Log.e("PAY_GET", "異常:"+e.getMessage());Toast.makeText(PayActivity.this, "異常:"+e.getMessage(), Toast.LENGTH_SHORT).show();}payBtn.setEnabled(true);}});1.4、支付結(jié)果回調(diào)
在包名.wxapi包路徑中實現(xiàn)WXPayEntryActivity類(包名或類名不一致會造成無法回調(diào)),在WXPayEntryActivity類中實現(xiàn)onResp函數(shù),支付完成后,微信APP會返回到商戶APP并回調(diào)onResp函數(shù),開發(fā)者需要在該函數(shù)中接收通知,判斷返回錯誤碼,如果支付成功則去后臺查詢支付結(jié)果再展示用戶實際支付結(jié)果。注意一定不能以客戶端返回作為用戶支付的結(jié)果,應(yīng)以服務(wù)器端的接收的支付通知或查詢API返回的結(jié)果為準(zhǔn)。
清單文件:
<activity android:name=".wxapi.WXPayEntryActivity"android:exported="true"android:launchMode="singleTop" />Activity設(shè)置:
package net.sourceforge.simcpux.wxapi; import net.sourceforge.simcpux.Constants; import net.sourceforge.simcpux.R; import com.tencent.mm.sdk.constants.ConstantsAPI; import com.tencent.mm.sdk.modelbase.BaseReq; import com.tencent.mm.sdk.modelbase.BaseResp; import com.tencent.mm.sdk.openapi.IWXAPI; import com.tencent.mm.sdk.openapi.IWXAPIEventHandler; import com.tencent.mm.sdk.openapi.WXAPIFactory; import android.app.Activity; import android.app.AlertDialog; import android.content.Intent; import android.os.Bundle; import android.util.Log;public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler{private static final String TAG = "MicroMsg.SDKSample.WXPayEntryActivity";private IWXAPI api;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.pay_result);api = WXAPIFactory.createWXAPI(this, Constants.APP_ID);api.handleIntent(getIntent(), this);}@Overrideprotected void onNewIntent(Intent intent) {super.onNewIntent(intent);setIntent(intent);api.handleIntent(intent, this);}@Overridepublic void onReq(BaseReq req) {}@Overridepublic void onResp(BaseResp resp) {Log.d(TAG, "errCode = " + resp.errCode);if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle(R.string.app_tip);builder.setMessage(getString(R.string.pay_result_callback_msg, String.valueOf(resp.errCode)));builder.show();}} }errCode:
0 支付成功
-1 支付出錯,可能的原因:簽名錯誤、未注冊APPID、項目設(shè)置APPID不正確、注冊的APPID與設(shè)置的不匹配、其他異常等。
-2 用戶取消支付
這樣一個完整的流程就走完了,下面來說一下老版本關(guān)于在客戶端加簽的流程。因為現(xiàn)在要求加簽過程都扔到服務(wù)器端進(jìn)行操作。
舊版本的操作總結(jié):
商戶系統(tǒng)和微信支付系統(tǒng)主要交互說明:
步驟1:用戶在商戶APP中選擇商品,提交訂單,選擇微信支付。
步驟2:商戶后臺收到用戶支付單,調(diào)用微信支付統(tǒng)一下單接口。
步驟3:統(tǒng)一下單接口返回正常的prepay_id,再按簽名規(guī)范重新生成簽名后,將數(shù)據(jù)傳輸給APP。參與簽名的字段名為appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式為Sign=WXPay
步驟4:商戶APP調(diào)起微信支付。
步驟5:商戶后臺接收支付通知。
步驟6:商戶后臺查詢支付結(jié)果。
這里主要講一下步驟2,步驟3,這兩步現(xiàn)在是放在服務(wù)器端進(jìn)行的操作,以前舊版本很多都是放在客戶端進(jìn)行的。
步驟2:
需要調(diào)用微信的下單接口,那么需要了解微信的接口規(guī)則。
標(biāo)注紅都是應(yīng)該注意的地方。
簽名算法:
private String genProductArgs(BaseOrder order) {StringBuffer xml = new StringBuffer();try {//生成隨機(jī)數(shù)算法String nonceStr = genNonceStr();//第一步:對參數(shù)按照key=value的格式,并按照參數(shù)名ASCII字典序排序如下:xml.append("</xml>");List<NameValuePair> packageParams = new LinkedList<NameValuePair>();packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID));packageParams.add(new BasicNameValuePair("body", order.getTitle()));packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));packageParams.add(new BasicNameValuePair("notify_url", order.getNotifyUrl()));packageParams.add(new BasicNameValuePair("out_trade_no", order.getOrderNo()));packageParams.add(new BasicNameValuePair("spbill_create_ip", "127.0.0.1"));packageParams.add(new BasicNameValuePair("total_fee", order.getWXTotalFee() + ""));packageParams.add(new BasicNameValuePair("trade_type", "APP"));//第二步:拼接API密鑰:String sign = genPackageSign(packageParams);packageParams.add(new BasicNameValuePair("sign", sign));//轉(zhuǎn)為成xml格式String xmlstring = toXml(packageParams);//有漢字時需要用ISO8859-1編碼,沒有時用utf-8return new String(xmlstring.toString().getBytes(), "ISO8859-1");} catch (Exception e) {Log.e(TAG, "genProductArgs fail, ex = " + e.getMessage());return null;}}//轉(zhuǎn)為成xml格式private String toXml(List<NameValuePair> params) {StringBuilder sb = new StringBuilder();sb.append("<xml>");for (int i = 0; i < params.size(); i++) {sb.append("<" + params.get(i).getName() + ">");sb.append(params.get(i).getValue());sb.append("</" + params.get(i).getName() + ">");}sb.append("</xml>");Log.e(TAG, sb.toString());return sb.toString();}//生成隨機(jī)數(shù)算法private String genNonceStr() {Random random = new Random();return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());}具體參考:
https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
步驟三:
private void genPayReq() {req = new PayReq();req.appId = Constants.APP_ID;req.partnerId = Constants.MCH_ID;req.prepayId = resultunifiedorder.get("prepay_id");req.packageValue = "prepay_id=" + resultunifiedorder.get("prepay_id");req.nonceStr = genNonceStr();req.timeStamp = String.valueOf(genTimeStamp());List<NameValuePair> signParams = new LinkedList<NameValuePair>();signParams.add(new BasicNameValuePair("appid", req.appId));signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));signParams.add(new BasicNameValuePair("package", req.packageValue));signParams.add(new BasicNameValuePair("partnerid", req.partnerId));signParams.add(new BasicNameValuePair("prepayid", req.prepayId));signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));req.sign = genAppSign(signParams);sb.append("sign\n" + req.sign + "\n\n");}private long genTimeStamp() {return System.currentTimeMillis() / 1000;}private String genAppSign(List<NameValuePair> params) {StringBuilder sb = new StringBuilder();for (int i = 0; i < params.size(); i++) {sb.append(params.get(i).getName());sb.append('=');sb.append(params.get(i).getValue());sb.append('&');}sb.append("key=");sb.append(Constants.API_KEY);this.sb.append("sign str\n" + sb.toString() + "\n\n");String appSign = MD5.getMessageDigest(sb.toString().getBytes());Log.e(TAG, appSign);return appSign;}簽名比較麻煩啊,建議還是按照新版的來吧,省事,安全!
總結(jié)
以上是生活随笔為你收集整理的Android支付开发(微信)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ansys Zemax | 使用Opti
- 下一篇: L-Lactate用途和性质,以及分析测