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,包名,签名。应该就可以用了。

 
 
Ionic 修改Android sdk版本
Android 支付宝支付详解与demo

发表评论

发表评论  
HTML/XMLobjective-cDelphiRubyPHPC#C++JavaScriptVisual BasicPythonJavaCSSSQL其它
weixin_36631046

海边的卡夫卡Fu

你好,我现在是模块化开发,在这其中集成微信支付,到时候以library的形式倒进宿主app.请问我在开放平台创建应用的时候留的包名,是我该模块的包名,还是宿主app的包名
昨天 14:45
Simon_Crystin

Simon_Crystin

回复weixin_36631046:不好意思,我也没做过,不清楚
昨天 19:35
qq_32013205

hgyq

如果是 AS 导入项目项目的话,把 AS 中的debug.keystore 替换成 demo 里的,可多次运行,不过还是会有异常
5天前 21:51
Simon_Crystin

Simon_Crystin

回复qq_32013205:具体什么异常呢?
前天 22:58
suprememjie

suprememjie

你好,请问一下我装了微信但是点击确认支付后还是不能唤起客户端,这是怎么回事?也没有报错
2017-04-19 18:30
gj333

gj333

你好 我其他参数也对 但是点击确认支付之后 程序就退出了
2017-04-17 18:27
Simon_Crystin

Simon_Crystin

回复gj333:程序退出了,看看error,是什么引起的报错呢,空指针吗
2017-04-17 21:14
qq_33871687

qq_33871687

特地注册账号来感谢。官网案例看得晕。这个简单
2017-04-17 11:13
Simon_Crystin

Simon_Crystin

回复qq_33871687:能帮到你很开心哦
2017-04-17 21:13
gcsky5211

gcsky5211

回复gcsky5211:就是不想展示什么,直接略过这个界面,因为微信有支付成功展示的界面了,所以想直接返回原画面,但现在返回会回到WXPayEntryActivity里,在回到原画面,会闪烁下...
2017-04-10 09:23
Simon_Crystin

Simon_Crystin

回复gcsky5211:你这边回调的页面你是想展示什么呢?你可以把你想展示的页面放在这个回调方法中处理啊
2017-04-07 19:37
frank7023

凭轩望月

太给力啦,非常感谢,好人好报,事事顺心。官方demo里感觉没有关于支付这一块的代码
2017-03-13 17:07
Simon_Crystin

Simon_Crystin

回复frank7023:能够帮到你很高兴
2017-03-13 20:07
qq_36546669

qq_36546669

博主能说下keystore具体怎么用么,我是菜鸟,看了txt文档还是不懂keystore该怎么弄,也出现了测试一次成功后面不成功的情况,我用的是Android Studio我能找到debug.keystore文件但后面不知道怎么做了。
2017-03-10 18:54
Simon_Crystin

Simon_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

qq_33166870

用demo只能跑一次,换成自己的总是prepay_id为null,可不可指导一下?
2017-03-10 10:15
Simon_Crystin

Simon_Crystin

回复qq_33166870:出现了只能支付一次 ,可能是你的签名存在了问题,你看下你用微信官方app生成的签名是不是和你在微信后台设置的签名一样呢?还有你的包名是不是和微信后台设置的一样呢
2017-03-11 08:58
u012115406

敬楠

终端IP spbill_create_ip 是 String(16) 123.12.12.123 用户端实际ip

这个参数提示是必传啊
2017-02-23 18:04
Simon_Crystin

Simon_Crystin

回复u012115406:不好意思,我开发的时候没有遇到这个问题哦
2017-02-27 11:43
a123191047

a123191047

解决了,大家遇到同样的问题可以参考这篇http://www.oschina.net/question/1018597_238672
2017-02-16 18:20
a123191047

a123191047

packageParams.add(new BasicNameValuePair("body", "APP pay test"));请问我把这里面“APP pay test”,换成中文,报签名错误呢
2017-02-16 17:28
yangjingfang5

yangjingfang5

后来我发现。是不是这个没涉及到支付成功或者不成功的回调接口?还是那个回调是在微信里调起的?WXPayEntryActivity这个类。因为我需要在里面做跳转网页
2016-12-29 15:41
Simon_Crystin

Simon_Crystin

回复yangjingfang5:页面跳转在这个WXPayEntryActivity类里面的一个方法里面跳转。
2016-12-30 12:08
kaiaya000

阿丫000

还有怎么在服务端完成获取prepayid和加签呢?
2016-12-28 16:56
kaiaya000

阿丫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

yangjingfang5

666666666666666666666666666666666666666666666
一次就成功了。
太爱你了。。
2016-12-23 09:51
Simon_Crystin

Simon_Crystin

回复yangjingfang5:客气了,我也很开心。
2016-12-23 12:59
gcsky5211

gcsky5211

不好意思~您的demo我下载下来,直接运行,可以调起支付界面的“客商惠”,但就只有第一次可以,以后就没有调起来了?
2016-12-16 13:56
Simon_Crystin

Simon_Crystin

回复gcsky5211:您好 客商惠是我们公司做的项目名,你有看text文档吗?下载自带的那个? 你需要设置keystore。
2016-12-16 20:40
baidu_36989885

baidu_36989885

写的挺好的,我有个问题想请教一下 ,如果确认付款不跳转到微信里面直接进行付款 ,这样可行吗
2016-12-11 09:40
Simon_Crystin

Simon_Crystin

回复baidu_36989885:你的意思不调起客户端吗 像支付宝那样直接弹出一个类似dialog吗?个人感觉是不可以的,因为微信支付网上都是说要调起微信客户端的,没有调起就是你代码有问题或者签名配置有误,具体不太清楚,你感兴趣可以看下源代码,研究一下。本来小白一个,非常感谢你的评论。
2016-12-14 10:20