Android 微信支付详解与Demo
来源:互联网 发布:async await python 编辑:程序博客网 时间:2024/06/05 05:53
- 2016十二月02
- 原
Android 微信支付详解与Demo
最近公司弄Ionic框架,项目中需要微信支付,无奈,把我调过去弄,期间也是几近崩溃,好在皇天不负有心人,在看别人的文档,终于是在项目中集成了微信支付,下面作为一个小白的我,想要把我的经验分享给大家,希望对大家有所帮助。
先给一个可用的demo吧(运行前先看txt文件)
http://download.csdn.net/detail/simon_crystin/9699743;这个demo是基于eclipse开发的,博主也在Android Studio开发过微信支付,原理都是一样的,大家把这个demo弄懂了,在AS上面也是一样的。
(温馨提示:大家下载下来可能会出错,也有可能不会。下面给出出错的解决方法:1.进入项目中的WeIXinPay->Build Path->configure build path,移除那个报错的jar包。 2.会出现资源找不到的情况,这是因为你没有v7包,下载一个v7包,或者把出错的地方都删除,只是一个主题,删除了看起来不好看而已,当然,你也可以用你有的主题。 还有一个问题需要提出来,就是你可能按照里面的text操作的仍然调不起客户端,有可能是你没有安装微信客户端,因为我没有做判断。这个demo不会出现只能成功支付一次的情况,博主亲测有效。出现只能支付一次只能说明你的签名没有对应)
1.去微信开放平台申请微信支付服务,绑定自己的应用这里具体不多讲,但是一定要申请完成,将会得到是三个参数
//appid 微信分配的公众账号ID public static final String APP_ID = ""; //商户号 微信分配的公众账号ID public static final String MCH_ID = "";// API密钥,在商户平台设置 public static final String API_KEY= "";
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
**坑点提示:在微信开发平台设置包名和签名。这里的包名一定要和你自己的包名一样,就是manifest中的package,签名一定要和你用官方app生成的一样(https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk)。
微信会根据你的填写的包名,然后对你的keystore进行一种算法,生成你的签名。包名和签名一定要和微信开放平台的相同。不过这里需要注意的是,如果你发布的正式版本,需要用官方app重新生成签名,然后在开放平台重新设置sign,因为测试版本的keystore与正式版的keystore不一样。总之,就是你用的keystore生成的sign要和微信开放平台的时刻保持一致。**2.准备工作做好了,接下来就是开发了,先下载微信的jar包,导入。
微信支付分为三个步骤
1.生成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; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
2.生成签名参数
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()); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
3.调起支付。
/* * 调起微信支付 */ private void sendPayReq() { msgApi.registerApp(Constants.APP_ID); msgApi.sendReq(req); Log.i(">>>>>", req.partnerId); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
下面给出完整代码
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();//生成签名参数 sendPayReq();//调起支付 break; default: break; } } /* * 调起微信支付 */ 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){ //实例化student对象 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"));//写你们的回调地址 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; } } //生成订单号,测试用,在客户端生成 private String genOutTradNo() { Random random = new Random();// return "dasgfsdg1234"; //订单号写死的话只能支付一次,第二次不能生成订单 return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); } //生成随机号,防重发 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; } /* * 转换成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(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
接下来就是有个支付结果的页面代码。是微信官方提供的一个类。你要在manifest注册这个类。这里需要注意的是,这个类必须放在wxapi包下,你自己新建一个包即可。
为了大家可以直接运行这个demo,我的微信加签都是在本地执行的,获取prepayid和加签都应该在服务端完成,还有最终的支付返回结果也是以服务端的为准。
*下面给出运行结果图*
大家下载demo然后把参数换了,弄下keystore,包名,签名。应该就可以用了。
版权声明:本文为博主原创文章,未经博主允许不得转载。
海边的卡夫卡Fu
你好,我现在是模块化开发,在这其中集成微信支付,到时候以library的形式倒进宿主app.请问我在开放平台创建应用的时候留的包名,是我该模块的包名,还是宿主app的包名昨天 14:45Simon_Crystin
回复weixin_36631046:不好意思,我也没做过,不清楚昨天 19:35
hgyq
如果是 AS 导入项目项目的话,把 AS 中的debug.keystore 替换成 demo 里的,可多次运行,不过还是会有异常5天前 21:51Simon_Crystin
回复qq_32013205:具体什么异常呢?前天 22:58
suprememjie
你好,请问一下我装了微信但是点击确认支付后还是不能唤起客户端,这是怎么回事?也没有报错2017-04-19 18:30
gj333
你好 我其他参数也对 但是点击确认支付之后 程序就退出了2017-04-17 18:27Simon_Crystin
回复gj333:程序退出了,看看error,是什么引起的报错呢,空指针吗2017-04-17 21:14
qq_33871687
特地注册账号来感谢。官网案例看得晕。这个简单2017-04-17 11:13Simon_Crystin
回复qq_33871687:能帮到你很开心哦2017-04-17 21:13
gcsky5211
回复gcsky5211:就是不想展示什么,直接略过这个界面,因为微信有支付成功展示的界面了,所以想直接返回原画面,但现在返回会回到WXPayEntryActivity里,在回到原画面,会闪烁下...2017-04-10 09:23
Simon_Crystin
回复gcsky5211:你这边回调的页面你是想展示什么呢?你可以把你想展示的页面放在这个回调方法中处理啊2017-04-07 19:37
凭轩望月
太给力啦,非常感谢,好人好报,事事顺心。官方demo里感觉没有关于支付这一块的代码2017-03-13 17:07Simon_Crystin
回复frank7023:能够帮到你很高兴2017-03-13 20:07
qq_36546669
博主能说下keystore具体怎么用么,我是菜鸟,看了txt文档还是不懂keystore该怎么弄,也出现了测试一次成功后面不成功的情况,我用的是Android Studio我能找到debug.keystore文件但后面不知道怎么做了。2017-03-10 18:54Simon_Crystin
回复qq_36546669:你好 ,keystore不需要会用的,Android Studio会自动生成一个keystore的,具体路径你可以百度下,或者你们公司有专门的keystore,你就用公司的keystore。http://blog.csdn.net/nimasike/article/details/51457229,你可以看下这个blog,我当时好像看的是这篇。然后在运行下,生成新的签名,最后在微信后台设置下签名,我想应该就可以了。我后面也用过Android Studio开发过微信支付,通过这种方法是不会有问题的。2017-03-11 09:03
qq_33166870
用demo只能跑一次,换成自己的总是prepay_id为null,可不可指导一下?2017-03-10 10:15Simon_Crystin
回复qq_33166870:出现了只能支付一次 ,可能是你的签名存在了问题,你看下你用微信官方app生成的签名是不是和你在微信后台设置的签名一样呢?还有你的包名是不是和微信后台设置的一样呢2017-03-11 08:58
敬楠
终端IP spbill_create_ip 是 String(16) 123.12.12.123 用户端实际ip
这个参数提示是必传啊2017-02-23 18:04Simon_Crystin
回复u012115406:不好意思,我开发的时候没有遇到这个问题哦2017-02-27 11:43
a123191047
解决了,大家遇到同样的问题可以参考这篇http://www.oschina.net/question/1018597_2386722017-02-16 18:20
a123191047
packageParams.add(new BasicNameValuePair("body", "APP pay test"));请问我把这里面“APP pay test”,换成中文,报签名错误呢2017-02-16 17:28
yangjingfang5
后来我发现。是不是这个没涉及到支付成功或者不成功的回调接口?还是那个回调是在微信里调起的?WXPayEntryActivity这个类。因为我需要在里面做跳转网页2016-12-29 15:41Simon_Crystin
回复yangjingfang5:页面跳转在这个WXPayEntryActivity类里面的一个方法里面跳转。2016-12-30 12:08
阿丫000
还有怎么在服务端完成获取prepayid和加签呢?2016-12-28 16:56
阿丫000
你好,你的demo是可以运行的。但是我运行官方给的demo为什么一直运行不起来呢?官方给个demo中有一个PahActivity,大概在第30几的行有这样一个地址“http://wxpay.weixin.qq.com/pub_v2/app/app_pay.php?plat=android” ,我运行官方demo的时候总是报这个地址拒绝呢2016-12-28 16:54
yangjingfang5
666666666666666666666666666666666666666666666
一次就成功了。
太爱你了。。2016-12-23 09:51Simon_Crystin
回复yangjingfang5:客气了,我也很开心。2016-12-23 12:59
gcsky5211
不好意思~您的demo我下载下来,直接运行,可以调起支付界面的“客商惠”,但就只有第一次可以,以后就没有调起来了?2016-12-16 13:56Simon_Crystin
回复gcsky5211:您好 客商惠是我们公司做的项目名,你有看text文档吗?下载自带的那个? 你需要设置keystore。2016-12-16 20:40
baidu_36989885
写的挺好的,我有个问题想请教一下 ,如果确认付款不跳转到微信里面直接进行付款 ,这样可行吗2016-12-11 09:40Simon_Crystin
回复baidu_36989885:你的意思不调起客户端吗 像支付宝那样直接弹出一个类似dialog吗?个人感觉是不可以的,因为微信支付网上都是说要调起微信客户端的,没有调起就是你代码有问题或者签名配置有误,具体不太清楚,你感兴趣可以看下源代码,研究一下。本来小白一个,非常感谢你的评论。2016-12-14 10:20
- Android 微信支付详解与Demo
- Android 微信支付详解与Demo
- Android 微信支付详解与Demo
- Android支付实践(二)之微信支付详解与Demo
- Android 微信支付demo
- android微信支付详解与坑
- Android 支付宝支付详解与demo
- 微信支付demo
- 微信支付demo
- 微信支付demo
- Android微信支付:如何跑通微信支付官方Demo
- 微信支付DEMO完整版
- 微信支付类 demo
- 微信支付,回调demo
- 微信支付Demo踩坑记
- ANDROID微信支付开发源代码_微信支付V3接口DEMO下载
- Android studio微信支付官网demo
- android studio 导入微信支付demo的一些问题
- 借助LVS+Keepalived实现负载均衡
- 关于Java DecimalFormat 用法(数字格式化)
- EOJ 3261分词(静态字典树)@
- python处理时序模型之StatsModels
- 欢迎使用CSDN-markdown编辑器
- Android 微信支付详解与Demo
- Eclipse如何导入Gradle创建的web项目
- 读取一条记录数据里边所有字段 MySQLi语句
- 腾讯笔试题 求a^b<<2的计算结果 运算符优先级问题
- [BZOJ4260][字典树]Codechef REBXOR
- 个人--对重写equals与hashcode理解
- Jquery datatable中文排序问题
- QRCode插件生成二维码
- 将GrADS数据转化为netCDF文件
发表评论