Android編程實(shí)現(xiàn)的微信支付功能詳解【附Demo源碼下載】
本文實(shí)例講述了Android編程實(shí)現(xiàn)的微信支付功能。分享給大家供大家參考,具體如下:
最近公司弄Ionic框架,項(xiàng)目中需要微信支付,無(wú)奈,把我調(diào)過(guò)去弄,期間也是幾近崩潰,好在皇天不負(fù)有心人,在看別人的文檔,終于是在項(xiàng)目中集成了微信支付,下面作為一個(gè)小白的我,想要把我的經(jīng)驗(yàn)分享給大家,希望對(duì)大家有所幫助。
先給一個(gè)可用的demo吧(運(yùn)行前先看txt文件)
demo代碼點(diǎn)擊此處本站下載。
這個(gè)demo是基于eclipse開(kāi)發(fā)的,博主也在Android Studio開(kāi)發(fā)過(guò)微信支付,原理都是一樣的,大家把這個(gè)demo弄懂了,在AS上面也是一樣的。
(溫馨提示:大家下載下來(lái)可能會(huì)出錯(cuò),也有可能不會(huì)。下面給出出錯(cuò)的解決方法:1.進(jìn)入項(xiàng)目中的WeIXinPay->Build Path->configure build path,移除那個(gè)報(bào)錯(cuò)的jar包。 2.會(huì)出現(xiàn)資源找不到的情況,這是因?yàn)槟銢](méi)有v7包,下載一個(gè)v7包,或者把出錯(cuò)的地方都刪除,只是一個(gè)主題,刪除了看起來(lái)不好看而已,當(dāng)然,你也可以用你有的主題。 還有一個(gè)問(wèn)題需要提出來(lái),就是你可能按照里面的text操作的仍然調(diào)不起客戶(hù)端,有可能是你沒(méi)有安裝微信客戶(hù)端,因?yàn)槲覜](méi)有做判斷。這個(gè)demo不會(huì)出現(xiàn)只能成功支付一次的情況,博主親測(cè)有效。出現(xiàn)只能支付一次只能說(shuō)明你的簽名沒(méi)有對(duì)應(yīng))
1. 去微信開(kāi)放平臺(tái)申請(qǐng)微信支付服務(wù),綁定自己的應(yīng)用這里具體不多講,但是一定要申請(qǐng)完成,將會(huì)得到是三個(gè)參數(shù)
//appid 微信分配的公眾賬號(hào)ID public static final String APP_ID = ""; //商戶(hù)號(hào) 微信分配的公眾賬號(hào)ID public static final String MCH_ID = ""; // API密鑰,在商戶(hù)平臺(tái)設(shè)置 public static final String API_KEY= "";
**坑點(diǎn)提示:在微信開(kāi)發(fā)平臺(tái)設(shè)置包名和簽名。這里的包名一定要和你自己的包名一樣,就是manifest中的package,簽名一定要和你用官方app生成的一樣(https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk)。
微信會(huì)根據(jù)你的填寫(xiě)的包名,然后對(duì)你的keystore進(jìn)行一種算法,生成你的簽名。包名和簽名一定要和微信開(kāi)放平臺(tái)的相同。不過(guò)這里需要注意的是,如果你發(fā)布的正式版本,需要用官方app重新生成簽名,然后在開(kāi)放平臺(tái)重新設(shè)置sign,因?yàn)闇y(cè)試版本的keystore與正式版的keystore不一樣??傊?,就是你用的keystore生成的sign要和微信開(kāi)放平臺(tái)的時(shí)刻保持一致。**
2. 準(zhǔn)備工作做好了,接下來(lái)就是開(kāi)發(fā)了,先下載微信的jar包,導(dǎo)入。
微信支付分為三個(gè)步驟
① .生成prepayId
@Override protected Map<String, String> doInBackground(String... params) { // TODO Auto-generated method stub String url=String.format(params[0]); String entity=getProductArgs(); Log.e("Simon",">>>>"+entity); byte[] buf=Util.httpPost(url, entity); String content = new String(buf); Log.e("orion", "----"+content); Map<String,String> xml=decodeXml(content); return xml; }
② .生成簽名參數(shù)
private void genPayReq() { req.appId = Constants.APP_ID; req.partnerId = Constants.MCH_ID; if (resultunifiedorder!=null) { req.prepayId = resultunifiedorder.get("prepay_id"); req.packageValue = "prepay_id="+resultunifiedorder.get("prepay_id"); } else { Toast.makeText(MainActivity.this, "prepayid為空", Toast.LENGTH_SHORT).show(); } req.nonceStr = getNonceStr(); 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"); textView.setText(sb.toString()); Log.e("Simon", "----"+signParams.toString()); }
③ .調(diào)起支付
/* * 調(diào)起微信支付 */ private void sendPayReq() { msgApi.registerApp(Constants.APP_ID); msgApi.sendReq(req); Log.i(">>>>>", req.partnerId); }
下面給出完整代碼
package com.alpha.live; import java.io.StringReader; 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.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.AlertDialog; import android.app.ProgressDialog; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.util.Xml; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; /** * Created by Simon on 2016/12/2. */ public class MainActivity extends Activity implements OnClickListener { private Button submitButton; private Button confirmButton; private TextView textView; private StringBuffer sb; private Map<String,String> resultunifiedorder; private PayReq req; private final IWXAPI msgApi = WXAPIFactory.createWXAPI(this, null); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); submitButton=(Button) findViewById(R.id.bt_submit_order); confirmButton=(Button) findViewById(R.id.bt_corfirm); textView=(TextView) findViewById(R.id.tv_prepay_id); submitButton.setOnClickListener(this); confirmButton.setOnClickListener(this); sb=new StringBuffer(); req=new PayReq(); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.bt_submit_order: String urlString="https://api.mch.weixin.qq.com/pay/unifiedorder"; PrePayIdAsyncTask prePayIdAsyncTask=new PrePayIdAsyncTask(); prePayIdAsyncTask.execute(urlString); //生成prepayId break; case R.id.bt_corfirm: genPayReq();//生成簽名參數(shù) sendPayReq();//調(diào)起支付 break; default: break; } } /* * 調(diào)起微信支付 */ private void sendPayReq() { msgApi.registerApp(Constants.APP_ID); msgApi.sendReq(req); Log.i(">>>>>", req.partnerId); } private long genTimeStamp() { return System.currentTimeMillis() / 1000; } private void genPayReq() { req.appId = Constants.APP_ID; req.partnerId = Constants.MCH_ID; if (resultunifiedorder!=null) { req.prepayId = resultunifiedorder.get("prepay_id"); req.packageValue = "prepay_id="+resultunifiedorder.get("prepay_id"); } else { Toast.makeText(MainActivity.this, "prepayid為空", Toast.LENGTH_SHORT).show(); } req.nonceStr = getNonceStr(); 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"); textView.setText(sb.toString()); Log.e("Simon", "----"+signParams.toString()); } 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("Simon","----"+appSign); return appSign; } private class PrePayIdAsyncTask extends AsyncTask<String,Void, Map<String, String>> { private ProgressDialog dialog; @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); dialog = ProgressDialog.show(MainActivity.this, "提示", "正在提交訂單"); } @Override protected Map<String, String> doInBackground(String... params) { // TODO Auto-generated method stub String url=String.format(params[0]); String entity=getProductArgs(); Log.e("Simon",">>>>"+entity); byte[] buf=Util.httpPost(url, entity); String content = new String(buf); Log.e("orion", "----"+content); Map<String,String> xml=decodeXml(content); return xml; } @Override protected void onPostExecute(Map<String, String> result) { // TODO Auto-generated method stub super.onPostExecute(result); if (dialog != null) { dialog.dismiss(); } sb.append("prepay_id\n"+result.get("prepay_id")+"\n\n"); textView.setText(sb.toString()); resultunifiedorder=result; } } 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){ //實(shí)例化student對(duì)象 xml.put(nodeName,parser.nextText()); } break; case XmlPullParser.END_TAG: break; } event = parser.next(); } return xml; } catch (Exception e) { Log.e("Simon","----"+e.toString()); } return null; } private String getProductArgs() { // TODO Auto-generated method stub StringBuffer xml=new StringBuffer(); try { String nonceStr=getNonceStr(); xml.append("<xml>"); List<NameValuePair> packageParams=new LinkedList<NameValuePair>(); packageParams.add(new BasicNameValuePair("appid",Constants.APP_ID)); packageParams.add(new BasicNameValuePair("body", "APP pay test")); packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID)); packageParams.add(new BasicNameValuePair("nonce_str", nonceStr)); packageParams.add(new BasicNameValuePair("notify_url", "https://www.baidu.com"));//寫(xiě)你們的回調(diào)地址 packageParams.add(new BasicNameValuePair("out_trade_no",genOutTradNo())); packageParams.add(new BasicNameValuePair("total_fee", "1")); packageParams.add(new BasicNameValuePair("trade_type", "APP")); String sign=getPackageSign(packageParams); packageParams.add(new BasicNameValuePair("sign", sign)); String xmlString=toXml(packageParams); return xmlString; } catch (Exception e) { // TODO: handle exception return null; } } //生成訂單號(hào),測(cè)試用,在客戶(hù)端生成 private String genOutTradNo() { Random random = new Random(); // return "dasgfsdg1234"; //訂單號(hào)寫(xiě)死的話(huà)只能支付一次,第二次不能生成訂單 return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); } //生成隨機(jī)號(hào),防重發(fā) private String getNonceStr() { // TODO Auto-generated method stub Random random=new Random(); return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); } /** 生成簽名 */ private String getPackageSign(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); String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase(); Log.e("Simon",">>>>"+packageSign); return packageSign; } /* * 轉(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("Simon",">>>>"+sb.toString()); return sb.toString(); } }
接下來(lái)就是有個(gè)支付結(jié)果的頁(yè)面代碼。是微信官方提供的一個(gè)類(lèi)。你要在manifest注冊(cè)這個(gè)類(lèi)。這里需要注意的是,這個(gè)類(lèi)必須放在wxapi包下,你自己新建一個(gè)包即可。
為了大家可以直接運(yùn)行這個(gè)demo,我的微信加簽都是在本地執(zhí)行的,獲取prepayid和加簽都應(yīng)該在服務(wù)端完成,還有最終的支付返回結(jié)果也是以服務(wù)端的為準(zhǔn)。
*下面給出運(yùn)行結(jié)果圖*
大家下載demo然后把參數(shù)換了,弄下keystore,包名,簽名。應(yīng)該就可以用了。
更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專(zhuān)題:《Android開(kāi)發(fā)入門(mén)與進(jìn)階教程》、《Android數(shù)據(jù)庫(kù)操作技巧總結(jié)》、《Android編程之a(chǎn)ctivity操作技巧總結(jié)》、《Android文件操作技巧匯總》、《Android編程開(kāi)發(fā)之SD卡操作方法匯總》、《Android資源操作技巧匯總》、《Android視圖View技巧總結(jié)》及《Android控件用法總結(jié)》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
相關(guān)文章
Android12四大組件之Activity生命周期變化詳解
雖然說(shuō)我們天天都在使用Activity,但是你真的對(duì)Activity的生命機(jī)制完全了解了嗎?Activity的生命周期方法只有七個(gè),但是其實(shí)那只是默認(rèn)的情況。也就是說(shuō)在其他情況下,Activity的生命周期可能不會(huì)是按照我們以前所知道的流程,本章著重講解Activity的生命周期變化2022-07-07PowerManagerService之自動(dòng)滅屏流程解析
這篇文章主要為大家介紹了PowerManagerService之自動(dòng)滅屏流程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Android實(shí)現(xiàn)常見(jiàn)的驗(yàn)證碼輸入框?qū)嵗a
我們?cè)陂_(kāi)發(fā)APP的時(shí)候經(jīng)常要遇到輸入框,下面這篇文章主要給大家介紹了關(guān)于利用Android如何實(shí)現(xiàn)常見(jiàn)的驗(yàn)證碼輸入框的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)下吧。2017-09-09Android TextView字體顏色設(shè)置方法小結(jié)
這篇文章主要介紹了Android TextView字體顏色設(shè)置方法,結(jié)合實(shí)例形式總結(jié)分析了Android開(kāi)發(fā)中TextView設(shè)置字體顏色的常用技巧,需要的朋友可以參考下2016-02-02Android開(kāi)發(fā)之毛玻璃效果實(shí)例代碼
這篇文章主要給大家分享android開(kāi)發(fā)之毛玻璃效果的實(shí)例代碼,非常具有參考借鑒價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-05-05Android開(kāi)發(fā)中避免應(yīng)用無(wú)響應(yīng)的方法(Application Not Responding、ANR)
這篇文章主要介紹了Android開(kāi)發(fā)中避免應(yīng)用無(wú)響應(yīng)的方法,即避免彈出Application Not Responding(ANR)對(duì)話(huà)框,需要的朋友可以參考下2014-06-06