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

 import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import org.apache.commons.httpclient.NameValuePair; import com.jing.lang.MD5Util;
public class WXPaynewBiz {
/** APP_ID 应用从官方网站申请到的合法appId */
public static final String WX_APP_ID = "APP_ID";
/** 商户号 */
public static final String WX_PARTNER_ID = "商户号";
/** 接口链接 */
public static final String url="https://api.mch.weixin.qq.com/pay/unifiedorder";
/** 商户平台和开发平台约定的API密钥,在商户平台设置 */
public static final String key="API密钥"; public void submitOrder(double realPayPrice, int tradeType, String ip) {
int realpayPrice=(int)(realPayPrice*100);
List<NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new NameValuePair("appid", WX_APP_ID));
nvps.add(new NameValuePair("body", "商品描述"));
nvps.add(new NameValuePair("mch_id", WX_PARTNER_ID));
nvps.add(new NameValuePair("nonce_str", UUID.randomUUID().toString().replace("-", "")));
nvps.add(new NameValuePair("notify_url", "回调通知地址"));
nvps.add(new NameValuePair("out_trade_no", "86"));
nvps.add(new NameValuePair("spbill_create_ip", ip));
nvps.add(new NameValuePair("total_fee",realpayPrice+"" ));
nvps.add(new NameValuePair("trade_type", "APP"));
StringBuffer sb=new StringBuffer(); for (NameValuePair nvp : nvps) {
sb.append(nvp.getName()+"="+nvp.getValue()+"&");
}
String signA=sb.toString();
String stringSignTemp=signA+"key="+key ;
System.out.println(signA);
System.out.println(stringSignTemp);
String sign=MD5Util.getMD5String(stringSignTemp).toUpperCase();
System.out.println(sign);
nvps.add(new NameValuePair("sign", sign));
try {
// 最关键的一步,我们要把最终发送的数据字符转为字节后,再使用“ISO8859-1”进行编码,得到“ISO8859-1”的字符串,否则有可能有“签名错误”的问题
byte[] buf = Util.httpPost(url, new String(toXml(nvps).getBytes(),"ISO8859-1"));
String content = new String(buf);
System.out.println(content);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} private String toXml(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
sb.append("<?xml version='1.0' encoding='UTF-8'?><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>");
System.out.println(sb.toString());
return sb.toString();
}
public static void main(String[] args) {
WXPaynewBiz wx=new WXPaynewBiz();
wx.submitOrder(10.00, 1, "127.0.0.1");
}
}

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

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

 import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Bundle; import com.tencent.mm.sdk.constants.ConstantsAPI;
import com.tencent.mm.sdk.modelbase.BaseReq;
import com.tencent.mm.sdk.modelbase.BaseResp;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.sdk.openapi.WXAPIFactory; public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler { private IWXAPI api; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pay_result);
api = WXAPIFactory.createWXAPI(this, Constants.WX_APP_ID);
api.handleIntent(getIntent(), this);
} @Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
api.handleIntent(intent, this);
} @Override
public void onReq(BaseReq req) {
} @Override
public void onResp(BaseResp resp) {
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
int code = resp.errCode;
String msg = "";
switch (code) {
case 0:
msg = "支付成功!";
break;
case -1:
msg = "支付失败!";
break;
case -2:
msg = "您取消了支付!";
break; default:
msg = "支付失败!";
break;
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.app_tip);
builder.setMessage(msg);
builder.setNegativeButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
WXPayEntryActivity.this.finish();
}
});
builder.show();
}
}
}

二、在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);
}
}
 <receiver
android:name=".wxpay.AppRegister">
<intent-filter>
<action android:name="com.tencent.mm.plugin.openapi.Intent.ACTION_REFRESH_WXAPP" />
</intent-filter>
</receiver>

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

 import android.content.Intent;
import android.widget.Toast;
import cn.sharesdk.wechat.utils.WXAppExtendObject;
import cn.sharesdk.wechat.utils.WXMediaMessage;
import cn.sharesdk.wechat.utils.WechatHandlerActivity; /** 微信客户端回调activity示例 */
public class WXEntryActivity extends WechatHandlerActivity { /**
* 处理微信发出的向第三方应用请求app message
* <p>
* 在微信客户端中的聊天页面有“添加工具”,可以将本应用的图标添加到其中
* 此后点击图标,下面的代码会被执行。Demo仅仅只是打开自己而已,但你可
* 做点其他的事情,包括根本不打开任何页面
*/
public void onGetMessageFromWXReq(WXMediaMessage msg) {
Intent iLaunchMyself = getPackageManager().getLaunchIntentForPackage(getPackageName());
startActivity(iLaunchMyself);
} /**
* 处理微信向第三方应用发起的消息
* <p>
* 此处用来接收从微信发送过来的消息,比方说本demo在wechatpage里面分享
* 应用时可以不分享应用文件,而分享一段应用的自定义信息。接受方的微信
* 客户端会通过这个方法,将这个信息发送回接收方手机上的本demo中,当作
* 回调。
* <p>
* 本Demo只是将信息展示出来,但你可做点其他的事情,而不仅仅只是Toast
*/
public void onShowMessageFromWXReq(WXMediaMessage msg) {
if (msg != null && msg.mediaObject != null
&& (msg.mediaObject instanceof WXAppExtendObject)) {
WXAppExtendObject obj = (WXAppExtendObject) msg.mediaObject;
Toast.makeText(this, obj.extInfo, Toast.LENGTH_SHORT).show();
}
} }
<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"/>:

 private PayReq req;
private StringBuffer sb; /**
* 微信支付临时订单的prepay_id
*/
private void getWXPrepayId(){
//从服务器获取,代码略……
//获取成功后
sendPayReq(prepayId);
} /**
* 调用微信支付页面
*/
private void sendPayReq(String prepayId){
genPayReq(prepayId);
WXapi.registerApp(Constants.WX_APP_ID);
WXapi.sendReq(req);
try {
Thread.sleep(1000*3);
} catch (InterruptedException e) {
e.printStackTrace();
}
closeProDialog();
this.finish();
} /**
* 生成签名参数
*/
private void genPayReq(String prepayId) {
req.appId = Constants.WX_APP_ID;
req.partnerId = Constants.WX_PARTNER_ID;
req.prepayId = prepayId;
req.packageValue = "Sign=WXPay";
req.nonceStr = genNonceStr();
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");
} /**
* 随机数
* @return
*/
private String genNonceStr() {
Random random = new Random();
return MD5Util.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
} /**
* 时间戳
* @return
*/
private long genTimeStamp() {
return System.currentTimeMillis() / 1000;
} /**
* 获取签名
* @param params
* @return
*/
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.WX_API_SECRET);
this.sb.append("sign str\n"+sb.toString()+"\n\n");
String appSign = MD5Util.getMessageDigest(sb.toString().getBytes()).toUpperCase(Locale.CHINA);
return appSign;
}
 <activity android:name=".OrderFormPayActivity" >
<data android:scheme="自己的appid"/>
</activity>

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

附官方demo:wechat_sdk_sample_android_v3_pay.zip

上一篇:python bytes和bytearray、编码和解码


下一篇:CentOS “/lib64/libc.so.6: version `GLIBC_2.14′ not found”系统glibc版本太低