Android支付开发(微信)

微信接入支付流程跟支付宝差不多,这里介绍一下接入流程以及注意事项。

接入流程:

1.1、到微信开放平台添加移动应用,申请权限

到微信开放平台注册开发者账号,并添加应用,申请支付权限,等待审核,需要提前做,审核需要时间,一般在7个工作日内。

获取的参数配置:

Android支付开发(微信)

1.2、后台设置

Android支付开发(微信)

这里应用跟应用签名和包名挂钩,也就是说一个移动应用对应一个APPID,表明了配置参数的不可公用性。另外要注意调试的时候签名问题,可以先设置为debug签名,等调试成功换成正式签名。一般调试问题就是签名问题。

签名工具下载地址:
https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk

1.3、注册吊起支付

 // 通过WXAPIFactory工厂,获取IWXAPI的实例
 IWXAPI  api = WXAPIFactory.createWXAPI(this, Constants.APP_ID, false);
 // 将该app注册到微信
 api.registerApp(Constants.APP_ID);   

商户服务器生成支付订单,先调用统一下单API(详见第7节)生成预付单,获取到prepay_id后将参数再次签名传输给APP发起支付,由服务器端进行操作,简化了客户端的复杂度跟安全性。

订单参数:

Android支付开发(微信)

这里是服务器端生成预支付订单并加签名返回。

调用方式:

api = WXAPIFactory.createWXAPI(this, "wxb4ba3c02aa476ea1");

        Button appayBtn = (Button) findViewById(R.id.appay_btn);
        appayBtn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                //订单接口
                String url = "http://wxpay.weixin.qq.com/pub_v2/app/app_pay.php?plat=android";
                Button payBtn = (Button) findViewById(R.id.appay_btn);
                payBtn.setEnabled(false);
                Toast.makeText(PayActivity.this, "获取订单中...", Toast.LENGTH_SHORT).show();
                try{
                    byte[] buf = Util.httpGet(url);
                    if (buf != null && buf.length > 0) {
                        String content = new String(buf);
                        Log.e("get server pay params:",content);
                        JSONObject json = new JSONObject(content); 
                        if(null != json && !json.has("retcode") ){
                            PayReq req = new PayReq();
                            //req.appId = "wxf8b4f85f3a794e77";  
                            // 测试用appId
                            //订单参数
                            req.appId           = json.getString("appid");
                            req.partnerId       = json.getString("partnerid");
                            req.prepayId        = json.getString("prepayid");
                            req.nonceStr        = json.getString("noncestr");
                            req.timeStamp       = json.getString("timestamp");
                            req.packageValue    = json.getString("package");
                            req.sign            = json.getString("sign");
                            req.extData         = "app data"; // optional
                            Toast.makeText(PayActivity.this, "正常调起支付", Toast.LENGTH_SHORT).show();
                            // 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
                            api.sendReq(req);
                        }else{
                            Log.d("PAY_GET", "返回错误"+json.getString("retmsg"));
                            Toast.makeText(PayActivity.this, "返回错误"+json.getString("retmsg"), Toast.LENGTH_SHORT).show();
                        }
                    }else{
                        Log.d("PAY_GET", "服务器请求错误");
                        Toast.makeText(PayActivity.this, "服务器请求错误", Toast.LENGTH_SHORT).show();
                    }
                }catch(Exception e){
                    Log.e("PAY_GET", "异常:"+e.getMessage());
                    Toast.makeText(PayActivity.this, "异常:"+e.getMessage(), Toast.LENGTH_SHORT).show();
                }
                payBtn.setEnabled(true);
            }
        }); 

1.4、支付结果回调

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

清单文件:

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

Activity设置:

package net.sourceforge.simcpux.wxapi;
import net.sourceforge.simcpux.Constants;
import net.sourceforge.simcpux.R;
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;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler{

    private static final String TAG = "MicroMsg.SDKSample.WXPayEntryActivity";

    private IWXAPI api;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.pay_result);
        api = WXAPIFactory.createWXAPI(this, Constants.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) {
        Log.d(TAG, "errCode = " + resp.errCode);
        if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle(R.string.app_tip);
            builder.setMessage(getString(R.string.pay_result_callback_msg,            String.valueOf(resp.errCode)));
            builder.show();
        }
    }
}

errCode:

0 支付成功
-1 支付出错,可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。
-2 用户取消支付

这样一个完整的流程就走完了,下面来说一下老版本关于在客户端加签的流程。因为现在要求加签过程都扔到服务器端进行操作。

旧版本的操作总结:

商户系统和微信支付系统主要交互说明:
步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。
步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。
步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式为Sign=WXPay
步骤4:商户APP调起微信支付。
步骤5:商户后台接收支付通知。
步骤6:商户后台查询支付结果。

这里主要讲一下步骤2,步骤3,这两步现在是放在服务器端进行的操作,以前旧版本很多都是放在客户端进行的。

步骤2:

需要调用微信的下单接口,那么需要了解微信的接口规则。

Android支付开发(微信)

标注红都是应该注意的地方。

签名算法:

private String genProductArgs(BaseOrder order) {
        StringBuffer xml = new StringBuffer();

        try {
            //生成随机数算法
            String nonceStr = genNonceStr();
            //第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:
            xml.append("</xml>");
            List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
            packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID));
            packageParams.add(new BasicNameValuePair("body", order.getTitle()));
            packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));
            packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
            packageParams.add(new BasicNameValuePair("notify_url", order.getNotifyUrl()));
            packageParams.add(new BasicNameValuePair("out_trade_no", order.getOrderNo()));
            packageParams.add(new BasicNameValuePair("spbill_create_ip", "127.0.0.1"));
            packageParams.add(new BasicNameValuePair("total_fee", order.getWXTotalFee() + ""));
            packageParams.add(new BasicNameValuePair("trade_type", "APP"));

             //第二步:拼接API密钥:
            String sign = genPackageSign(packageParams);
            packageParams.add(new BasicNameValuePair("sign", sign));
             //转为成xml格式
            String xmlstring = toXml(packageParams);
             //有汉字时需要用ISO8859-1编码,没有时用utf-8
            return new String(xmlstring.toString().getBytes(), "ISO8859-1");

        } catch (Exception e) {
            Log.e(TAG, "genProductArgs fail, ex = " + e.getMessage());
            return null;
        }
    }
    //转为成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(TAG, sb.toString());
        return sb.toString();
    }
     //生成随机数算法
 private String genNonceStr() {
        Random random = new Random();
        return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
    }

具体参考:
https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1

步骤三:

private void genPayReq() {
        req = new PayReq();
        req.appId = Constants.APP_ID;
        req.partnerId = Constants.MCH_ID;
        req.prepayId = resultunifiedorder.get("prepay_id");
        req.packageValue = "prepay_id=" + resultunifiedorder.get("prepay_id");
        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");
    }

    private long genTimeStamp() {
        return System.currentTimeMillis() / 1000;
    }

    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(TAG, appSign);
        return appSign;
    }

签名比较麻烦啊,建议还是按照新版的来吧,省事,安全!

Android支付开发(微信)

上一篇:iOS-微信-分享


下一篇:tp根据数据库动态创建微信菜单