Android微信支付V3版

由于公司需求做微信APP支付,在集成过程中也遇到各种问题,比如说签名错误,body编码必须为UTF-8、APP端无法调用支付页面直接到支付结果页面、结果为null,code=-1等等;

1、签名错误问题,首先得确保APPID、商户ID、api密钥正确,其次就是编码问题了,Java文件得是UTF-8的,再有就是接下来代码里注释的。

2、body编码必须为UTF-8的问题,改body编码后报签名错误,唉!各种无奈,于是想到是不是跟开发环境编码有关,换了台电脑,居然成了。(这是我的办法,不一定适用大家)

3、APP端无法调用支付页面直接到支付结果页面,支付结果:null,code=-1,这个问题官方(http://kf.qq.com/faq/140225MveaUz150413eimyiQ.html)给的解决方法是:

开放平台配置的报名和应用签名是否一致:(android);确认是否使用正式的keystore打包apk并安装调试;(android);提交订单部分需要在服务器端完成。

所以,调试微信支付要么申请一个debug.keystore版的,要么使用正式的keystore打包apk并安装调试。

接下来给大家分享我的结果,我是从服务段获取的prepay_id:

服务端:WXPaynewBiz.java

 1 import java.io.UnsupportedEncodingException;
 2 import java.util.ArrayList;
 3 import java.util.List;
 4 import java.util.UUID;
 5 
 6 import org.apache.commons.httpclient.NameValuePair;
 7 
 8 import com.jing.lang.MD5Util;
 9 public class WXPaynewBiz {
10     /** APP_ID 应用从官方网站申请到的合法appId */
11     public static final String WX_APP_ID = "APP_ID";
12     /** 商户号 */
13     public static final String WX_PARTNER_ID = "商户号";
14     /** 接口链接 */
15     public static final String url="https://api.mch.weixin.qq.com/pay/unifiedorder";
16     /** 商户平台和开发平台约定的API密钥,在商户平台设置  */
17     public static final String key="API密钥";
18     
19     public void submitOrder(double realPayPrice, int tradeType, String ip) {
20         int realpayPrice=(int)(realPayPrice*100);
21         List<NameValuePair> nvps = new ArrayList <NameValuePair>();
22         nvps.add(new NameValuePair("appid", WX_APP_ID));
23         nvps.add(new NameValuePair("body", "商品描述"));
24         nvps.add(new NameValuePair("mch_id", WX_PARTNER_ID));
25         nvps.add(new NameValuePair("nonce_str", UUID.randomUUID().toString().replace("-", "")));
26         nvps.add(new NameValuePair("notify_url", "回调通知地址"));
27         nvps.add(new NameValuePair("out_trade_no", "86"));
28         nvps.add(new NameValuePair("spbill_create_ip", ip));
29         nvps.add(new NameValuePair("total_fee",realpayPrice+"" ));
30         nvps.add(new NameValuePair("trade_type", "APP"));
31         StringBuffer sb=new StringBuffer();
32         
33         for (NameValuePair nvp : nvps) {
34             sb.append(nvp.getName()+"="+nvp.getValue()+"&");
35         }
36         String signA=sb.toString();
37         String stringSignTemp=signA+"key="+key ;
38         System.out.println(signA);
39         System.out.println(stringSignTemp);
40         String sign=MD5Util.getMD5String(stringSignTemp).toUpperCase();
41         System.out.println(sign);
42         nvps.add(new NameValuePair("sign", sign));
43         try {
44             // 最关键的一步,我们要把最终发送的数据字符转为字节后,再使用“ISO8859-1”进行编码,得到“ISO8859-1”的字符串,否则有可能有“签名错误”的问题
45             byte[] buf = Util.httpPost(url, new String(toXml(nvps).getBytes(),"ISO8859-1"));
46             String content = new String(buf);
47             System.out.println(content);
48         } catch (UnsupportedEncodingException e) {
49             e.printStackTrace();
50         }
51     }
52     
53     private String toXml(List<NameValuePair> params) {
54         StringBuilder sb = new StringBuilder();
55         sb.append("<?xml version='1.0' encoding='UTF-8'?><xml>");
56         for (int i = 0; i < params.size(); i++) {
57             sb.append("<"+params.get(i).getName()+">");
58 
59 
60             sb.append(params.get(i).getValue());
61             sb.append("</"+params.get(i).getName()+">");
62         }
63         sb.append("</xml>");
64         System.out.println(sb.toString());
65         return sb.toString();
66     }
67     public static void main(String[] args) {
68         WXPaynewBiz wx=new WXPaynewBiz();
69         wx.submitOrder(10.00, 1, "127.0.0.1");
70     }
71 }

 Android端,android端是根据官方给的Demo做的:

一、在自己的项目的包路径中实现WXPayEntryActivity类,即添加 .wxapi.WXPayEntryActivity,在WXPayEntryActivity类中实现onResp函数,支付完成后,微信APP会返回到商户APP并回调onResp函数,开发者需要在该函数中接收通知,判断返回错误码,如果支付成功则去后台查询支付结果再展示用户实际支付结果。注意一定不能以客户端返回作为用户支付的结果,应以服务器端的接收的支付通知或查询API返回的结果为准。代码示例如下:

 1 import android.app.Activity;
 2 import android.app.AlertDialog;
 3 import android.content.DialogInterface;
 4 import android.content.DialogInterface.OnClickListener;
 5 import android.content.Intent;
 6 import android.os.Bundle;
 7 
 8 import com.tencent.mm.sdk.constants.ConstantsAPI;
 9 import com.tencent.mm.sdk.modelbase.BaseReq;
10 import com.tencent.mm.sdk.modelbase.BaseResp;
11 import com.tencent.mm.sdk.openapi.IWXAPI;
12 import com.tencent.mm.sdk.openapi.IWXAPIEventHandler;
13 import com.tencent.mm.sdk.openapi.WXAPIFactory;
14 
15 public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
16     
17     private IWXAPI api;
18     
19     @Override
20     public void onCreate(Bundle savedInstanceState) {
21         super.onCreate(savedInstanceState);
22         setContentView(R.layout.pay_result);
23         api = WXAPIFactory.createWXAPI(this, Constants.WX_APP_ID);
24         api.handleIntent(getIntent(), this);
25     }
26 
27     @Override
28     protected void onNewIntent(Intent intent) {
29         super.onNewIntent(intent);
30         setIntent(intent);
31         api.handleIntent(intent, this);
32     }
33 
34     @Override
35     public void onReq(BaseReq req) {
36     }
37 
38     @Override
39     public void onResp(BaseResp resp) {
40         if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
41             int code = resp.errCode;
42             String msg = "";
43             switch (code) {
44             case 0:
45                 msg = "支付成功!";
46                 break;
47             case -1:
48                 msg = "支付失败!";
49                 break;
50             case -2:
51                 msg = "您取消了支付!";
52                 break;
53 
54             default:
55                 msg = "支付失败!";
56                 break;
57             }
58             AlertDialog.Builder builder = new AlertDialog.Builder(this);
59             builder.setTitle(R.string.app_tip);
60             builder.setMessage(msg);
61             builder.setNegativeButton("确定", new OnClickListener() {
62                 @Override
63                 public void onClick(DialogInterface dialog, int which) {
64                     dialog.dismiss();
65                     WXPayEntryActivity.this.finish();
66                 }
67             });
68             builder.show();
69         }
70     }
71 }

二、在APP项目配置文件AndroidManifest.xml中配置WXPayEntryActivity,代码如下:

<activity
  android:name=".wxapi.WXPayEntryActivity"
  android:exported="true"
  android:launchMode="singleTop"/>

三、看官方demo还有一个AppRegister.java文件,具体不知道什么作用,我也给配置了,代码如下:

import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.WXAPIFactory;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class AppRegister extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null);

        // 将该app注册到微信
        msgApi.registerApp(Constants.WX_APP_ID);
    }
}
1 <receiver
2     android:name=".wxpay.AppRegister">
3     <intent-filter>
4     <action android:name="com.tencent.mm.plugin.openapi.Intent.ACTION_REFRESH_WXAPP" />
5     </intent-filter>
6 </receiver>

四、在项目包名下添加微信客户端回调函数类 .wxapi.WXEntryActivity,并添加AndroidManifest.xml配置:代码如下:

 1 import android.content.Intent;
 2 import android.widget.Toast;
 3 import cn.sharesdk.wechat.utils.WXAppExtendObject;
 4 import cn.sharesdk.wechat.utils.WXMediaMessage;
 5 import cn.sharesdk.wechat.utils.WechatHandlerActivity;
 6 
 7 /** 微信客户端回调activity示例 */
 8 public class WXEntryActivity extends WechatHandlerActivity {
 9 
10     /**
11      * 处理微信发出的向第三方应用请求app message
12      * <p>
13      * 在微信客户端中的聊天页面有“添加工具”,可以将本应用的图标添加到其中
14      * 此后点击图标,下面的代码会被执行。Demo仅仅只是打开自己而已,但你可
15      * 做点其他的事情,包括根本不打开任何页面
16      */
17     public void onGetMessageFromWXReq(WXMediaMessage msg) {
18         Intent iLaunchMyself = getPackageManager().getLaunchIntentForPackage(getPackageName());
19         startActivity(iLaunchMyself);
20     }
21 
22     /**
23      * 处理微信向第三方应用发起的消息
24      * <p>
25      * 此处用来接收从微信发送过来的消息,比方说本demo在wechatpage里面分享
26      * 应用时可以不分享应用文件,而分享一段应用的自定义信息。接受方的微信
27      * 客户端会通过这个方法,将这个信息发送回接收方手机上的本demo中,当作
28      * 回调。
29      * <p>
30      * 本Demo只是将信息展示出来,但你可做点其他的事情,而不仅仅只是Toast
31      */
32     public void onShowMessageFromWXReq(WXMediaMessage msg) {
33         if (msg != null && msg.mediaObject != null
34                 && (msg.mediaObject instanceof WXAppExtendObject)) {
35             WXAppExtendObject obj = (WXAppExtendObject) msg.mediaObject;
36             Toast.makeText(this, obj.extInfo, Toast.LENGTH_SHORT).show();
37         }
38     }
39 
40 }
<activity
    android:name=".wxapi.WXEntryActivity"
    android:theme="@android:style/Theme.Translucent.NoTitleBar"
    android:configChanges="keyboardHidden|orientation|screenSize"
    android:exported="true"
    android:screenOrientation="portrait" />

五、最后做我们的发起微信支付的页面,主要代码如下(主要还是官方Demo里的),另外还要在发起微信支付的Activity标签中添加属性<data android:scheme="appid"/>:

 1 private PayReq req;
 2 private StringBuffer sb;
 3 
 4 /**
 5  * 微信支付临时订单的prepay_id
 6  */
 7 private void getWXPrepayId(){
 8     //从服务器获取,代码略……
 9     //获取成功后
10     sendPayReq(prepayId);
11 }
12 
13 /**
14  * 调用微信支付页面
15  */
16 private void sendPayReq(String prepayId){
17     genPayReq(prepayId);
18     WXapi.registerApp(Constants.WX_APP_ID);
19     WXapi.sendReq(req);
20     try {
21         Thread.sleep(1000*3);
22     } catch (InterruptedException e) {
23         e.printStackTrace();
24     }
25     closeProDialog();
26     this.finish();
27 }
28 
29 /**
30  * 生成签名参数
31  */
32 private void genPayReq(String prepayId) {
33     req.appId = Constants.WX_APP_ID;
34     req.partnerId = Constants.WX_PARTNER_ID;
35     req.prepayId = prepayId;
36     req.packageValue = "Sign=WXPay";
37     req.nonceStr = genNonceStr();
38     req.timeStamp = String.valueOf(genTimeStamp());
39 
40 
41     List<NameValuePair> signParams = new LinkedList<NameValuePair>();
42     signParams.add(new BasicNameValuePair("appid", req.appId));
43     signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
44     signParams.add(new BasicNameValuePair("package", req.packageValue));
45     signParams.add(new BasicNameValuePair("partnerid", req.partnerId));
46     signParams.add(new BasicNameValuePair("prepayid", req.prepayId));
47     signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));
48     req.sign = genAppSign(signParams);
49     sb.append("sign\n"+req.sign+"\n\n");
50 }
51 
52 /**
53  * 随机数
54  * @return
55  */
56 private String genNonceStr() {
57     Random random = new Random();
58     return MD5Util.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
59 }
60 
61 /**
62  * 时间戳
63  * @return
64  */
65 private long genTimeStamp() {
66     return System.currentTimeMillis() / 1000;
67 }
68 
69 /**
70  * 获取签名
71  * @param params
72  * @return
73  */
74 private String genAppSign(List<NameValuePair> params) {
75     StringBuilder sb = new StringBuilder();
76 
77     for (int i = 0; i < params.size(); i++) {
78         sb.append(params.get(i).getName());
79         sb.append('=');
80         sb.append(params.get(i).getValue());
81         sb.append('&');
82     }
83     sb.append("key=");
84     sb.append(Constants.WX_API_SECRET);
85     this.sb.append("sign str\n"+sb.toString()+"\n\n");
86     String appSign = MD5Util.getMessageDigest(sb.toString().getBytes()).toUpperCase(Locale.CHINA);
87     return appSign;
88 }
1 <activity android:name=".OrderFormPayActivity" >
2     <data android:scheme="自己的appid"/>
3 </activity>

 

到此就差不多了,主要还是的注意下编码格式,希望对各位有帮助,谢谢!

附官方demo:wechat_sdk_sample_android_v3_pay.zip

 

posted @ 2015-05-19 20:21  Leevey·L  阅读(1292)  评论(2编辑  收藏  举报