Android微信支付的坑

和上个文章一样也是接的单子开发文档也是很花里胡哨让人蛋疼折腾了一个下午终于搞定了
第一个坑:
回调不了
这里和上文章的登录回调有一点不同
也是要在wxapi包下名字必须是WXPayEntryActivity
配置清单的时候记得加上android:exported=”true”否则会导致无法启动回调的activity

第二个坑订单会话id
获取订单会话id的时候需要传入很多花里胡哨的参数甚至支付的客户端IP都要提交其实没必要这么麻烦的
只要提交这几个参数即可
appid,mch_id,nonce_str,body,out_trade_no,total_fee,notify_url,trade_type,sign
分别是申请的微信开放平台的id,商户号,随机字符串32位,名称,订单号随机生成32位同一个订单号只能支付一次,金额单位不是元是分注意了,支付回调接口php写好可以防止app被本地破解,类型默认APP,签名使用算法进行签名

第三个坑算法签名
官网把集合也扯出来了虽然我也会,但有想过一些人吗?我还是直接百度了发现那么简单的又被复杂化了

private static String generateSign(SortedMap<String, String> parameters, String key) {
    Set<Map.Entry<String, String>> iterator = parameters.entrySet();
    StringBuilder stringA = new StringBuilder();
    for (Map.Entry<String, String> map : iterator) {
        stringA.append(map.getKey() + "=" + map.getValue());
        stringA.append("&");
    }
    stringA.append("key=" + key);
    return md5(stringA.toString().getBytes());
}

上面写好了传入的参数是一个sortmap为什么不是hashmap因为需要对参数的key进行ascii码排序所以用的SortMap,第二个是自己后台设置的key32位

搞好了签名还没完他需要传入的是xml内容不是http的表单内容
转xml我也帮你们写好了

private String toXml(SortedMap<String, String> params) {
    StringBuilder sb = new StringBuilder();
    sb.append("<xml>");
    Set<Map.Entry<String, String>> entrySet = params.entrySet();
    for (Map.Entry<String, String> map :
            entrySet) {
        sb.append("<" + map.getKey() + ">");
        sb.append(map.getValue());
        sb.append("</" + map.getKey() + ">");
    }
    sb.append("</xml>");
    return sb.toString();
}

传入一个SortMap
到这里还没结束需要发包https://api.mch.weixin.qq.com/pay/unifiedorder提交刚刚生成的xml内容
返回来一个xml还需要解析

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) {
                        xml.put(nodeName, parser.nextText());
                    }
                    break;
                case XmlPullParser.END_TAG:
                    break;
            }
            event = parser.next();
        }
        return xml;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

获取prepay_id把多余的内容<![CDATA[,]]>替换成空才是最终的prepay_id
你以为获取到prepay_id就完美了吗不,发送支付请求的时候需要传
appid,noncestr,package,partnerid,prepayid,timestamp
分别是分别是申请的微信开放平台的id,随机字符串这里注意了这里的随机字符串要和第一次订单会话id生成的随机字符串一样,Sign=WXPay固定,商户号,会话id,10位时间戳

然后基本上就这些坑了把完整代码贴在下面

Payment

package com.yarluong.tb.xm;

import android.app.Activity;
import android.os.Bundle;
import android.util.Xml;
import android.widget.Button;

import com.tencent.mm.opensdk.modelpay.PayReq;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import com.yarluong.tb.R;
import com.yarluong.tb.wxapi.utils.Http;

import org.xmlpull.v1.XmlPullParser;

import java.io.StringReader;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

public class Payment extends Activity {

private Button btn_pay;
private IWXAPI iwxapi;
private final String APP_ID = "自己的id";
private final String MCH_ID = "自己的商户id";
private final String KEY = "自己设置的key用于获取签名";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.xm_payment);
    this.iwxapi = WXAPIFactory.createWXAPI(this, APP_ID);
    this.iwxapi.registerApp(this.APP_ID);
    this.btn_pay = findViewById(R.id.btn_pay);

    this.btn_pay.setOnClickListener((e) -> {
        pay(0.01);
    });
}

private void pay(double rmb) {
    new Thread(() -> {
        String randomString = generateRandomString(32);
        String respone = Http.httpPost("https://api.mch.weixin.qq.com/pay/unifiedorder", getData(rmb,randomString));
        String prepayid = decodeXml(respone).get("prepay_id").replace("<![CDATA[", "").replace("]]>", "");
        String timeStamp = ((int) (System.currentTimeMillis() / 1000)) + "";
        PayReq request = new PayReq();
        request.appId = this.APP_ID;
        request.partnerId = this.MCH_ID;
        request.prepayId = prepayid;
        request.packageValue = "Sign=WXPay";
        request.nonceStr = randomString;
        request.timeStamp = timeStamp;

        SortedMap<String, String> stringSortedMap = new TreeMap<>();
        stringSortedMap.put("appid", this.APP_ID);
        stringSortedMap.put("noncestr", randomString);
        stringSortedMap.put("package", "Sign=WXPay");
        stringSortedMap.put("partnerid", this.MCH_ID);
        stringSortedMap.put("prepayid", prepayid);
        stringSortedMap.put("timestamp", timeStamp);
        request.sign = generateSign(stringSortedMap, this.KEY);
        iwxapi.sendReq(request);

    }).start();
}
private String toXml(SortedMap<String, String> params) {
    StringBuilder sb = new StringBuilder();
    sb.append("<xml>");
    Set<Map.Entry<String, String>> entrySet = params.entrySet();
    for (Map.Entry<String, String> map :
            entrySet) {
        sb.append("<" + map.getKey() + ">");
        sb.append(map.getValue());
        sb.append("</" + map.getKey() + ">");
    }
    sb.append("</xml>");
    return sb.toString();
}
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) {
                        xml.put(nodeName, parser.nextText());
                    }
                    break;
                case XmlPullParser.END_TAG:
                    break;
            }
            event = parser.next();
        }
        return xml;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
private String getData(double rmb,String nonce) {
    SortedMap<String, String> stringSortedMap = new TreeMap<>();
    stringSortedMap.put("appid", this.APP_ID);
    stringSortedMap.put("mch_id", this.MCH_ID);
    stringSortedMap.put("nonce_str", nonce);
    stringSortedMap.put("sign_type", "MD5");
    stringSortedMap.put("body", "xxx-会员购买");
    stringSortedMap.put("out_trade_no", md5(generateRandomString(32).getBytes()).toLowerCase());
    stringSortedMap.put("total_fee", changeY2F(rmb) + "");
    stringSortedMap.put("notify_url", "http://www.weixin.qq.com/wxpay/pay.php");
    stringSortedMap.put("trade_type", "APP");
    stringSortedMap.put("sign", generateSign(stringSortedMap, this.KEY));
    return toXml(stringSortedMap);
}
public static int changeY2F(double price) {
    DecimalFormat df = new DecimalFormat("#.00");
    price = Double.valueOf(df.format(price));
    int money = (int) (price * 100);
    return money;
}

private String generateRandomString(int len) {
    String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    Random random = new Random();
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < len; i++) {
        int number = random.nextInt(str.length());
        sb.append(str.charAt(number));
    }
    return sb.toString();
}

private static String generateSign(SortedMap<String, String> parameters, String key) {
    Set<Map.Entry<String, String>> iterator = parameters.entrySet();
    StringBuilder stringA = new StringBuilder();
    for (Map.Entry<String, String> map : iterator) {
        stringA.append(map.getKey() + "=" + map.getValue());
        stringA.append("&");
    }
    stringA.append("key=" + key);
    return md5(stringA.toString().getBytes());
}
private static String md5(byte[] src) {
    try {
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        messageDigest.update(src);
        byte[] byt = messageDigest.digest();
        return bytesToHex(byt).toUpperCase();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return null;
}

public static String bytesToHex(byte[] src) {
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < src.length; i++) {
        stringBuilder.append(String.format("%02x", src[i] & 0xff));
    }
    return stringBuilder.toString();
}

}

WXPayEntryActivity

package com.yarluong.tb.wxapi;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelbase.BaseResp;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;

public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {

private IWXAPI iwxapi;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    iwxapi = WXAPIFactory.createWXAPI(this, "自己的id");
    iwxapi.registerApp("自己的id");
    iwxapi.handleIntent(getIntent(), this);
}
@Override
public void onReq(BaseReq baseReq) {

}

@Override
public void onResp(BaseResp baseResp) {
    Log.d("WXPayEntryActivity", "onPayFinish, errCode = " + baseResp.errCode);
    switch (baseResp.errCode) {
        case BaseResp.ErrCode.ERR_OK:
            Toast.makeText(this,"支付成功",Toast.LENGTH_LONG).show();
            this.finish();
            break;
        //用户取消支付
        case BaseResp.ErrCode.ERR_USER_CANCEL:
            Toast.makeText(this,"支付失败",Toast.LENGTH_LONG).show();
            this.finish();
            break;

    }
}

}

androidmanifest

<activity
        android:name=".wxapi.WXPayEntryActivity"
        android:exported="true"
        android:theme="@android:style/Theme.Translucent.NoTitleBar" />

发表评论

邮箱地址不会被公开。 必填项已用*标注