Android微信支付V3版

时间:2022-10-25 11:39:22

由于公司需求做微信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