Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android_app開發微信支付集成

android_app開發微信支付集成

編輯:關於Android編程

最近項目裡面需要支付功能,boss一致決定用微信支付,所以在網上查了很多資料,說的不全,完了就找以前的同事指教。算是成功集成上去了。在這裡做個總結記錄。

1、在APP上集成微信支付,首先當然是當官網上去注冊並獲取到支付功能。這些不涉及到開發,官網上說的很詳細,這裡就不多做文章。獲取到這些能力了就為開發提供了條件了。開發中會用到的就是平台給的APPID、APPsercet、以及商戶平台上設置的APP_key。

2、具備了支付能力等前提條件之後,就是開發過程了。代碼裡面怎麼才能吊起支付了,參照官網上的DEMO自己也做了一些總結和各方大神的指教。分為了下面幾個步奏。

(1)、首先當然是將sdk配置進工程環境中,官網中下載Android端SDK,解壓後將libmmsdk.jar導入工程,然後將DEMO中Constant.java(這裡是參照官方demo的樣式寫的,當然也可以采用其他方式)、MD5.java、Util.java放入工程(我這裡用到了這些),這些先決條件有了之後就可以下一步寫代碼操作了。

(2)、生成訂單信息

生成訂單信息采用了如下方法生成,生成訂單信息需要簽名文件,所以裡面包含了生成簽名。微信要求所有請求采用XML參數形式,所有生產訂單信息之後又需要轉換成xml。訂單信息需要的請求參數可以到官網上去對照,這裡只加入了一些必要的參數。

生成訂單信息方法:

 

[java]view plaincopy   在CODE上查看代碼片派生到我的代碼片
  1. //獲取產品訂單信息
  2. privateStringgenProductArgs(){
  3. StringBufferxml=newStringBuffer();
  4. try{
  5. StringnonceStr=genNonceStr();
  6.  
  7. xml.append("");
  8. ListpackageParams=newLinkedList();
  9.  
  10. packageParams.add(newBasicNameValuePair("appid",Constants.APP_ID));//APPID
  11.  
  12. packageParams.add(newBasicNameValuePair("body","單價:"+singlePrice+"x"+payment_num.getText().toString()+"份"));//簡單描述
  13.  
  14. packageParams.add(newBasicNameValuePair("mch_id",Constants.MCH_ID));//商戶ID
  15.  
  16. packageParams.add(newBasicNameValuePair("nonce_str",nonceStr));//隨機字符串
  17.  
  18. packageParams.add(newBasicNameValuePair("notify_url","http://www.weixin.qq.com/wxpay/pay.php"));//通知地址
  19.  
  20. packageParams.add(newBasicNameValuePair("out_trade_no",getTrade()));//商戶訂單號
  21.  
  22. packageParams.add(newBasicNameValuePair("spbill_create_ip",getLocalHostIp()));//終端IP
  23.  
  24. //doubleprice=Double.parseDouble(payment_num.getText().toString())*(Integer.parseInt(singlePrice)*100);
  25. doubleprice=Double.parseDouble(singlePrice)*100*n;
  26. intpriceInt=(int)price;
  27. packageParams.add(newBasicNameValuePair("total_fee",priceInt+""));//微信接收int型價格
  28.  
  29. packageParams.add(newBasicNameValuePair("trade_type","APP"));//支付類型
  30.  
  31. Stringsign=genAppSign(packageParams);
  32. packageParams.add(newBasicNameValuePair("sign",sign));//簽名
  33.  
  34. Stringxmlstring=parseNodeToXML(packageParams);//轉化成xml
  35.  
  36. returnxmlstring;
  37. }catch(Exceptione){
  38. e.printStackTrace();
  39. returnnull;
  40. }
  41. }

構造這個xml請求參數采用的是httpclient生成的,所以引入了某些包。也可以采用其他方式生成支付訂單,只要最後的形式與官網中的形式相同即可。

 

裡面涉及到某些參數的生成,這裡列出的是我們項目裡面的業務邏輯,當然不同項目可定是不同的。

 

[java]view plaincopy   在CODE上查看代碼片派生到我的代碼片
  1. //獲取訂單號
  2. privateStringgetTrade(){
  3. longnowTime=System.currentTimeMillis();
  4. SimpleDateFormatformat=newSimpleDateFormat("yyMMddHHmmss");
  5. returnformat.format(newDate(nowTime));
  6. }
  7.  
  8.  
  9.  
  10. //獲取支付簽名Sign
  11. StringBuildersb=newStringBuilder();
  12. privateStringgenAppSign(Listparams){
  13. StringBuildersb=newStringBuilder();
  14. for(inti=0;i sb.append(params.get(i).getName());
  15. sb.append('=');
  16. sb.append(params.get(i).getValue());
  17. sb.append('&');
  18. }
  19. sb.append("key=");
  20. sb.append(Constants.API_KEY);
  21. this.sb.append("signstr\n"+sb.toString()+"\n\n");
  22. StringappSign=MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
  23. returnappSign;
  24. }
  25.  
  26. //獲取隨機字符串
  27. privateStringgenNonceStr(){
  28. Randomrandom=newRandom();
  29. returnMD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
  30. }
  31.  
  32. /**
  33. *解析為xml格式
  34. *@paramtreeNodes
  35. *@return
  36. */
  37. publicStringparseNodeToXML(ListtreeNodes){
  38. StringBufferxmlnodes=newStringBuffer();
  39. if(treeNodes!=null&&treeNodes.size()>0){
  40. xmlnodes.append("");
  41. for(inti=0;i NameValuePairnode=treeNodes.get(i);
  42. xmlnodes.append("<"+node.getName()+">").append(node.getValue()).append("");
  43. }
  44. xmlnodes.append("");
  45. }
  46. //returnxmlnodes.toString();
  47. Stringxml=xmlnodes.toString();
  48. try{
  49. xml=newString(xml.toString().getBytes(),"ISO8859-1");//商品詳情為中文,將其轉化為統一編碼,不然獲取perpred_id失敗
  50. returnxml;
  51. }catch(UnsupportedEncodingExceptione){
  52. e.printStackTrace();
  53. returnnull;
  54. }
  55. }
  56.  
  57.  
  58. //獲取手機IP
  59. publicStringgetLocalHostIp(){
  60. Stringipaddress="";
  61. try{
  62. Enumerationen=NetworkInterface.getNetworkInterfaces();
  63. //遍歷所用的網絡接口
  64. while(en.hasMoreElements()){
  65. NetworkInterfacenif=en.nextElement();//得到每一個網絡接口綁定的所有ip
  66. Enumerationinet=nif.getInetAddresses();
  67. //遍歷每一個接口綁定的所有ip
  68. while(inet.hasMoreElements()){
  69. InetAddressip=inet.nextElement();
  70. if(!ip.isLoopbackAddress()&&InetAddressUtils.isIPv4Address(ip.getHostAddress())){
  71. returnip.getHostAddress();
  72. }
  73. }
  74. }
  75. }
  76. catch(SocketExceptione){
  77. Log.e("feige","獲取本地ip地址失敗");
  78. e.printStackTrace();
  79. }
  80. returnipaddress;
  81. }

(3)、訪問微信後台指定接口,獲取perpay_id。

可以說前面的都是為了獲取這個perpay_id做准備的,官網上給出的指定接口是“https://api.mch.weixin.qq.com/pay/unifiedorder” 請求采用官網demo中util提供的請求方式

這裡采用異步處理方式,當請求指定接口得到perapy_id之後直接吊起支付的方式。

 

 

[html]view plaincopy   在CODE上查看代碼片派生到我的代碼片
  1. //調用支付獲取id
  2. publicvoidgotoWechat(){
  3. newAsyncTask(){
  4. @Override
  5. protectedObjectdoInBackground(Object[]objects){//獲取Prepay_id
  6. Stringurl=String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
  7. Stringentity=genProductArgs();//獲取訂單信息
  8. byte[]buf=Util.httpPost(url,entity);
  9. Stringcontent=newString(buf);//請求成功返回的信息
  10. //Log.e("orion",content);
  11. try{
  12. xmlParseTest(content);//解析返回的信息
  13. }catch(IOExceptione){
  14. e.printStackTrace();
  15. }catch(XmlPullParserExceptione){
  16. e.printStackTrace();
  17. }
  18. returnnull;
  19. }
  20.  
  21. @Override
  22. protectedvoidonPostExecute(Objecto){
  23. super.onPostExecute(o);
  24. wechatPay();
  25. }
  26. }.execute();
  27. }

請求成功返回的數據當然也是xml格式的,需要解析並從中取到perpay_id(返回的結果不止perpay_id,包括其他信息,個人感覺吊起支付只需要perpay_id就行了)。這裡也是參考demo中的方式將獲取到的信息通過xml解析到

WeixinParentId對象當中。

[java] view plain copy
  在CODE上查看代碼片派生到我的代碼片
  1. /**
  2. *解析xml
  3. *返回prepay_id
  4. *通過對象Books獲取數據
  5. */
  6. WeixinParentIdbook=null;//通過對象Books獲取數據
  7. publicvoidxmlParseTest(Stringstr)throwsIOException,XmlPullParserException{
  8. XmlPullParserpullParser=Xml.newPullParser();//獲取XmlPullParser對象
  9. //InputStreamis=getContext().getAssets().open("parse.xml");//解析文本
  10. ByteArrayInputStreamis=newByteArrayInputStream(str.getBytes("UTF-8"));
  11. ArrayListbooks=null;
  12.  
  13. pullParser.setInput(is,"UTF-8");
  14. inttype=pullParser.getEventType();//獲取事件類型
  15. while(type!=pullParser.END_DOCUMENT){//結束文本
  16. switch(type){
  17. caseXmlPullParser.START_DOCUMENT://開始文本
  18. books=newArrayList();
  19. break;
  20. caseXmlPullParser.START_TAG://開始標記
  21. if(pullParser.getName().equals("xml")){
  22. book=newWeixinParentId();
  23. }elseif(pullParser.getName().equals("return_msg")){
  24. type=pullParser.next();//指向下一個位置,不然無法獲取數據
  25. book.setReturn_msg(pullParser.getText());
  26. }elseif(pullParser.getName().equals("appid")){
  27. type=pullParser.next();
  28. book.setAppid(pullParser.getText());
  29. }elseif(pullParser.getName().equals("prepay_id")){
  30. type=pullParser.next();
  31. book.setPrepay_id(pullParser.getText());
  32. }
  33.  
  34. break;
  35. caseXmlPullParser.END_TAG://結束標記
  36. if(pullParser.getName().equals("book")){
  37. books.add(book);
  38. book=null;//置為空釋放資源
  39. }
  40. break;
  41. }
  42. type=pullParser.next();//指向下一個標記
  43.  
  44. }
  45. //Log.e("test","book------id----"+book.getPrepay_id());
  46. } 成功執行這不之後,book對象中perpay_id已經被賦值。只需在異步中取出使用即可。

[java] view plain copy
  在CODE上查看代碼片派生到我的代碼片
  1. //獲取到perpay_id之後吊起微信支付
  2. protectedvoidwechatPay(){
  3. PayReqreq=newPayReq();
  4. req.appId=Constants.APP_ID;
  5. req.partnerId=Constants.MCH_ID;
  6. req.prepayId=book.getPrepay_id();
  7. req.packageValue="Sign=WXPay";
  8. req.nonceStr=genNonceStr();
  9. req.timeStamp=String.valueOf(genTimeStamp());
  10.  
  11. ListsignParams=newLinkedList();
  12. signParams.add(newBasicNameValuePair("appid",req.appId));
  13. signParams.add(newBasicNameValuePair("noncestr",req.nonceStr));
  14. signParams.add(newBasicNameValuePair("package",req.packageValue));
  15. signParams.add(newBasicNameValuePair("partnerid",req.partnerId));
  16. signParams.add(newBasicNameValuePair("prepayid",req.prepayId));
  17. signParams.add(newBasicNameValuePair("timestamp",req.timeStamp));
  18. req.sign=genAppSign(signParams);
  19. sb.append("sign\n"+req.sign+"\n\n");
  20. //在支付之前,如果應用沒有注冊到微信,應該先調用IWXMsg.registerApp將應用注冊到微信
  21. //Log.e("test","book.getPrepay_id()----------"+book.getPrepay_id()+"-------genNonceStr()-------"+genNonceStr()+"--------genTimeStamp()-------"+genTimeStamp()+"---genAppSign(signParams)--"+genAppSign(signParams));
  22. api.sendReq(req);
  23. //dialog.dismiss();
  24.  
  25. }
  26.  
  27. //獲取時間搓
  28. privatelonggenTimeStamp(){
  29. returnSystem.currentTimeMillis()/1000;
  30. }
把前面的異步操作方法賦給一個按鈕點擊事件,如果所有步奏正確,就可以進入支付界面了,如下圖:

\

點擊確支付當然就是輸入密碼什麼的操作了,支付成功後有一個反饋信息如下圖:


\

點擊完成,當然是回到APP咯,這裡就是微信提供的一個回調了。也就是官網上強調的wxapi包下的
WXPayEntryActivity裡的Onresp()方法中做回調處理,該包必須在項目工程包目錄下才能回調成功。下面貼出的是示例工程結構


\

 

 

在回調中彈出了對話框提示用戶支付成功並處理其他邏輯。

 

 

[java]view plaincopy   在CODE上查看代碼片派生到我的代碼片
  1. publicclassWXPayEntryActivityextendsActivityimplementsIWXAPIEventHandler{
  2.  
  3. privatestaticfinalStringTAG="MicroMsg.SDKSample.WXPayEntryActivity";
  4.  
  5. privateIWXAPIapi;
  6.  
  7.  
  8. @OverridepublicvoidonCreate(BundlesavedInstanceState){
  9. super.onCreate(savedInstanceState);
  10.  
  11. //setContentView(R.layout.activity_main2);
  12. api=WXAPIFactory.createWXAPI(this,Constants.APP_ID);
  13. api.handleIntent(getIntent(),this);
  14. api.registerApp(Constants.APP_ID);
  15. }
  16.  
  17.  
  18. @Override
  19. protectedvoidonNewIntent(Intentintent){
  20. super.onNewIntent(intent);
  21. setIntent(intent);
  22. api.handleIntent(intent,this);
  23. }
  24.  
  25.  
  26. @Override
  27. publicvoidonReq(BaseReqreq){
  28.  
  29. }
  30.  
  31.  
  32. @Override
  33. publicvoidonResp(BaseRespresp){
  34. interrCode=resp.errCode;
  35.  
  36. if(errCode==0){
  37.  
  38. //0成功展示成功頁面
  39. //Intentintent=newIntent("name");
  40. //sendBroadcast(intent);
  41. //Log.e("test","支付成功的回調方法--onResp--");
  42. //Toast.makeText(this,"支付完成",Toast.LENGTH_SHORT).show();
  43.  
  44. newAlertDialog.Builder(this).setMessage("支付成功").setPositiveButton("確定",newDialogInterface.OnClickListener(){
  45. @Override
  46. publicvoidonClick(DialogInterfacedialog,intwhich){
  47. dialog.dismiss();
  48. finish();
  49. PaymentActivity.instance.finish();
  50.  
  51. Intentintent=newIntent(WXPayEntryActivity.this,PuzzGameActivity.class);
  52. intent.putExtra("ISPLAY",true);
  53. startActivity(intent);
  54.  
  55. }
  56. }).setTitle("提示").create().show();
  57.  
  58. Toast.makeText(this,"點擊確定按鈕開始參與拼圖游戲活動",Toast.LENGTH_LONG).show();
  59.  
  60. }
  61. elseif(errCode==-1){
  62. //-1錯誤可能的原因:簽名錯誤、未注冊APPID、項目設置APPID不正確、注冊的APPID與設置的不匹配、其他異常等。
  63. newAlertDialog.Builder(this).setMessage("支付出錯").setPositiveButton("確定",newDialogInterface.OnClickListener(){
  64. @Override
  65. publicvoidonClick(DialogInterfacedialog,intwhich){
  66. dialog.dismiss();
  67. finish();
  68. }
  69. }).setTitle("提示").create().show();
  70. finish();
  71. }
  72. elseif(errCode==-2){
  73. //-2用戶取消無需處理。發生場景:用戶不支付了,點擊取消,返回APP。
  74. finish();
  75. }
  76. }
  77.  
  78.  
  79. }

這樣所有步驟就幾乎完全了,結合官方示例和文檔,應該可以快速的在項目中加入支付功能了。

 

當然,這裡所涉及到的步驟全是在app客戶端進行的,官網上建議將獲取簽名等操作放在服務後台進行,應該是為了安全吧,也就是客服端將訂單信息傳給服務端。服務端返回吊起支付必要的信息

(包括perpay_id、商戶id 、簽名等),然後由客戶端吊起微信支付的。


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved