Android—基于微信開放平臺v3SDK開發(fā)(微信支付填坑)
接觸微信支付之前聽說過這是一個坑,,,心里已經(jīng)有了準備。。。我以為我沒準跳坑出不來了,沒有想到我填上了,調(diào)用成功之后我感覺公司所有的同事都是漂亮的,隔著北京的大霧霾我仿佛看見了太陽~~~好了,裝逼結束。。。進入正題
開發(fā)準備:
1.在微信開放平臺申請賬號
2.成功后創(chuàng)建應用,就是填一些看似很官方很正經(jīng)的資料了。。。(說審核7天左右,沒有意外的情況下你的app第二天就審核成功了是不是很開心,有了appid,是不是就可以調(diào)用微 信支付了????-------想多了,真的)
3.微信支付是需要額外申請的:需要資料審核,賬戶驗證,協(xié)議簽署等步驟,(我記得,,資料審核要填寫的東西好多,,,好多,,,賬戶驗證就是你審核成功后微信會發(fā)送郵件到你 注冊時登記的郵箱賬號,其中含有隨機金額用于賬戶驗證,協(xié)議簽署,略,太簡單)一定要好好閱讀你郵件的任何信息,因為有的細節(jié)錯了,,,你可能填坑很久。。。。。。
正式開發(fā)階段:
問題1:
調(diào)用官方的SDK發(fā)現(xiàn)只能成功的調(diào)起一次微信,再次支付的時候怎么也調(diào)用不起來了
解決:
似乎不是什么正經(jīng)方法:在手機設置中管理應用程序,清除微信數(shù)據(jù),緩存,,再來一遍,絕對可以調(diào)起來(當然還是只是一次。。。。)
繼續(xù):
我認為要用微信支付嘛,,就只看了調(diào)用支付接口的文檔:
后來發(fā)現(xiàn)需要的參數(shù)prepayid是怎么也找不到啊,,后來才發(fā)現(xiàn)這個prepayid是先調(diào)用”統(tǒng)一下單“這個接口時候溫馨反過來的東西,但是官方的SDK中并沒有統(tǒng)一下單的代碼。坑嗎???
所以要先看統(tǒng)一下單文檔了
1.使用自己的APP調(diào)用的時候把官網(wǎng)down下來的SDK中WXPayEntryActivity拷貝到自己的項目,所在包的名字最后一定是.wxapi(我連包一起拷了。。。。)
2.在項目清單文件中填寫:
3.SDK中的AppRegister拷貝下來,,,里面換成你自己的appid,然后在項目清單中也注冊一下。
4.重點來了,,就是你APP要調(diào)微信支付的activity,我這還叫PayActivity
要調(diào)起微信支付頁面,要在這個activity中,將你的app注冊到微信
接下來先調(diào)用統(tǒng)一下單獲取prepayid,參數(shù),微信人家要xml格式的!我們就得發(fā)送xml格式的!
好了調(diào)用的時候把這個方法的返回值當參數(shù)傳,,等待微信返回success吧!。。
我遇見的錯誤:簽名錯誤
我的原因是大意了 ConfigUtil.NOTIFY_URL這個參數(shù)寫的空字符串
還有是因為debug版運行的,沒有打包運行
返回成功之后,可以調(diào)用支付接口了
不要忘了這一步去跳轉(zhuǎn)界面,,,,,
沒有跳轉(zhuǎn)到微信支付可能是你由運行的debug版本,,,,沒有打包。。。。。
下面是我的PayActivity完整代碼:
package com.example.taijiapp.ui; import java.io.StringReader; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.xmlpull.v1.XmlPullParser; import com.example.taijiapp.R; import com.example.taijiapp.util.Constants; import com.example.taijiapp.util.MD5; import com.example.taijiapp.util.T; import com.example.taijiapp.util.Util; import com.example.taijiapp.utils.ConfigUtil; import com.tencent.mm.sdk.modelpay.PayReq; import com.tencent.mm.sdk.openapi.IWXAPI; import com.tencent.mm.sdk.openapi.WXAPIFactory; import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.util.Xml; import android.view.View; import android.widget.Button; public class PayActivity extends Activity { PayReq req; private IWXAPI msgApi; Map<string, string=""> resultunifiedorder; StringBuffer sb; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.pay); req = new PayReq(); sb = new StringBuffer(); msgApi = WXAPIFactory.createWXAPI(this, Constants.APP_ID); /** * 將app注冊到微信 */ boolean registerApp = msgApi.registerApp(Constants.APP_ID); T.show(this, "注冊========"+registerApp+""); Button appayBtn = (Button) findViewById(R.id.appay_btn); Button check_pay_btn = (Button) findViewById(R.id.check_pay_btn); appayBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { GetPrepayIdTask getPrepayId = new GetPrepayIdTask(); getPrepayId.execute(); } }); /** * 將該app注冊到微信 */ check_pay_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { genPayReq(); sendPayReq(); } }); // // 生成簽名參數(shù) // Button appay_pre_btn = (Button) findViewById(R.id.appay_pre_btn); // appay_pre_btn.setOnClickListener(new View.OnClickListener() { // // @Override // public void onClick(View v) { // genPayReq(); // } // }); } /** * 生成簽名 */ private String genPackageSign(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.KEY); Log.e("拼接=====", sb.toString()); String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase(); Log.e("orion生成簽名===", packageSign); return packageSign; } /** * 簽名工具 不含商戶密鑰 -暫時不用 = * 編碼格式 UTF-8 = * @return */ public static String createSignNoKey(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('&'); } String signStr = sb.toString(); String subStr = signStr.substring(0, signStr.length() - 1); // 注意sign轉(zhuǎn)為大寫 return MD5.getMessageDigest(subStr.getBytes()).toUpperCase(); } 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.KEY); this.sb.append("sign str\n" + sb.toString() + "\n\n"); String appSign = MD5.getMessageDigest(sb.toString().getBytes()); Log.e("orion", appSign); return appSign; } 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("orion", sb.toString()); return sb.toString(); } private class GetPrepayIdTask extends AsyncTask<void, void,="" map<string,="" string="">> { private ProgressDialog dialog; @Override protected void onPreExecute() { dialog = ProgressDialog.show(PayActivity.this, getString(R.string.app_tip), getString(R.string.getting_prepayid)); } @Override protected void onPostExecute(Map<string, string=""> result) { if (dialog != null) { dialog.dismiss(); } sb.append("prepay_id\n" + result.get("prepay_id") + "\n\n"); resultunifiedorder = result; } @Override protected void onCancelled() { super.onCancelled(); } @Override protected Map<string, string=""> doInBackground(Void... params) { String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder"); String entity = genProductArgs(); Log.e("orion===發(fā)送過去", entity); byte[] buf = Util.httpPost(url, entity); String content = new String(buf); Log.e("orion", content); Map<string, string=""> xml = decodeXml(content); return xml; } } public Map<string, string=""> decodeXml(String content) { try { Map<string, string=""> xml = new HashMap<string, string="">(); XmlPullParser parser = Xml.newPullParser(); parser.setInput(new StringReader(content)); int event = parser.getEventType(); while (event != XmlPullParser.END_DOCUMENT) { String nodeName = parser.getName(); switch (event) { case XmlPullParser.START_DOCUMENT: break; case XmlPullParser.START_TAG: if ("xml".equals(nodeName) == false) { // 實例化student對象 xml.put(nodeName, parser.nextText()); } break; case XmlPullParser.END_TAG: break; } event = parser.next(); } return xml; } catch (Exception e) { Log.e("orion", e.toString()); } return null; } /** * 生成隨機數(shù) * @return */ private String genNonceStr() { Random random = new Random(); return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); } /** * 時間戳 * @return */ private long genTimeStamp() { return System.currentTimeMillis() / 1000; } /** * 隨機數(shù) * @return */ private String genOutTradNo() { Random random = new Random(); return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); } /** * 獲取設備的ip地址 * @return */ public String getLocalIpAddress() { try { for (Enumeration<networkinterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { NetworkInterface intf = en.nextElement(); for (Enumeration<inetaddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { InetAddress inetAddress = enumIpAddr.nextElement(); if (!inetAddress.isLoopbackAddress()) { return inetAddress.getHostAddress().toString(); } } } } catch (SocketException ex) { } return null; } private String getWifiIp() { // 獲取wifi服務 WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); // 判斷wifi是否開啟 if (!wifiManager.isWifiEnabled()) { wifiManager.setWifiEnabled(true); } WifiInfo wifiInfo = wifiManager.getConnectionInfo(); int ipAddress = wifiInfo.getIpAddress(); String ip = intToIp(ipAddress); return ip; } /** * 轉(zhuǎn)化成Ip地址的格式 * @param i * @return */ private String intToIp(int i) { return (i & 0xFF) + "." + ((i >> 8) & 0xFF) + "." + ((i >> 16) & 0xFF) + "." + (i >> 24 & 0xFF); } private String genProductArgs() { StringBuffer xml = new StringBuffer(); String ip = getWifiIp(); if (ip == "" && ip == "") { ip = getLocalIpAddress(); } try { String nonceStr = genNonceStr(); xml.append(""); List<namevaluepair> packageParams = new LinkedList<namevaluepair>(); packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID)); packageParams.add(new BasicNameValuePair("body", "APPtest")); packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID)); packageParams.add(new BasicNameValuePair("nonce_str", nonceStr)); packageParams.add(new BasicNameValuePair("notify_url", ConfigUtil.NOTIFY_URL)); packageParams.add(new BasicNameValuePair("out_trade_no", genOutTradNo())); packageParams.add(new BasicNameValuePair("spbill_create_ip", ip)); packageParams.add(new BasicNameValuePair("total_fee", "100")); packageParams.add(new BasicNameValuePair("trade_type", "APP")); String sign = genPackageSign(packageParams); packageParams.add(new BasicNameValuePair("sign", sign)); String xmlstring = toXml(packageParams); return xmlstring; } catch (Exception e) { Log.e("TAG", "fail, ex = " + e.getMessage()); return null; } } private void genPayReq() { 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"); Log.e("orion==genPayReq===============", signParams.toString()); } private void sendPayReq() { boolean sendReq = msgApi.sendReq(req); T.show(this, "微信跳轉(zhuǎn)====="+sendReq+""); } } </namevaluepair></namevaluepair></namevaluepair></namevaluepair></inetaddress></networkinterface></string,></string,></string,></string,></string,></string,></void,></namevaluepair></namevaluepair></namevaluepair></namevaluepair></string,>
里面沒有的類,,,,吶:源碼下載。自己下載一下拷貝一下。。。
參考文章:http://www.dbjr.com.cn/article/97712.htm
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- Android開發(fā)騰訊驗證碼遇到的坑
- Android開發(fā)中那些需要注意的坑
- Android開發(fā)手機無線調(diào)試的方法
- Android開發(fā)教程之獲取系統(tǒng)輸入法高度的正確姿勢
- Android開發(fā)解決popupWindow重疊報錯問題
- 使用Win10+Android+夜神安卓模擬器,搭建ReactNative開發(fā)環(huán)境
- Android快速開發(fā)系列 10個常用工具類實例代碼詳解
- Android開發(fā)筆記之如何正確獲取WebView的網(wǎng)頁Title
- Android開發(fā)圖片水平旋轉(zhuǎn)180度方法
- Android Studio中使用jni進行opencv開發(fā)的環(huán)境配置方法
- Android UI開發(fā)中所遇到的各種坑
相關文章
Android切換至SurfaceView時閃屏(黑屏閃一下)以及黑屏移動問題的解決方法
本文主要介紹了Android切換至SurfaceView時閃屏(黑屏閃一下)以及黑屏移動問題的解決方法。具有一定的參考作用,下面跟著小編一起來看下吧2017-01-01Android程序報錯程序包org.apache.http不存在問題的解決方法
這篇文章主要介紹了Android程序報錯"程序包org.apache.http不存在——Android 6.0已經(jīng)不支持HttpClient" 問題的解決方法,感興趣的小伙伴們可以參考一下2016-06-06淺談Android studio 生成apk文件時的 key store path 的問題
這篇文章主要介紹了淺談Android studio 生成apk文件時的 key store path 的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03viewpager+photoview實現(xiàn)圖片查看器
這篇文章主要為大家詳細介紹了viewpager+photoview實現(xiàn)圖片查看器,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12Android入門之使用SharedPreference存取信息詳解
這篇文章主要為大家詳細介紹了Android如何使用SharedPreference實現(xiàn)存取信息,文中的示例代碼講解詳細,對我們學習Android有一定的幫助,需要的可以參考一下2022-12-12Android根據(jù)電話號碼獲得聯(lián)系人頭像實例代碼
這篇文章主要介紹了Android根據(jù)電話號碼獲得聯(lián)系人頭像實例代碼,是Android程序開發(fā)中非常重要的技巧,需要的朋友可以參考下2014-09-09Android中SurfaceView和view畫出觸摸軌跡
這篇文章主要介紹了Android中SurfaceView和view畫出觸摸軌跡的相關資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-03-03