unity集成安卓微信支付的坑点

今天花了一整天在unity上集成安卓的微信支付,把微信的相关文档反复看了很多遍,网上相关文章和资料也看了挺多。。但目标,还是无限趟坑…… 最后终于调好,在此分享一下各个坑点,以及支付集成的要点吧。

微信没有提供unity集成方法,所以我们需要使用安卓原生方法调用。


可以在C#中使用AndroidJavaClass、AndroidJavaObject来实现直接调用com.tencent.mm.sdk.openapi.WXAPIFactory的createWXAPI方法。
具体方法就不赘述了,网上很多,请自行搜索。

核心参考代码

static AndroidJavaObject WXApi {
    get{
        if (_wxApi == null) {

            AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
            AndroidJavaClass apiFactory = new AndroidJavaClass ("com.tencent.mm.sdk.openapi.WXAPIFactory");

            _wxApi = apiFactory.CallStatic<AndroidJavaObject> ("createWXAPI",
                activity,
                CommonSettings.WXAppID,
                false
            );
        }
        return _wxApi;
    }
}
static AndroidJavaObject _wxApi;


Dictionary<string,string> paras = new Dictionary<string, string>();
//BY CG:由于wechat android sdk中的变量与签名标志不一致,所以分开写,#前面是签名属性,后面对应的SDK中变量名
paras.Add ("appid#appId", CommonSettings.WXAppID);
paras.Add ("partnerid#partnerId", CommonSettings.WXShopId); //商户号
paras.Add ("prepayid#prepayId", prepayid);
paras.Add ("package#packageValue", "Sign=WXPay"); //暂填写固定值Sign=WXPay
paras.Add ("noncestr#nonceStr", transactionId + "#" + Tools.GetRandomInt(0,100).ToString ()); //随机字符串

Int32 timestamp = (Int32)(HSTimeHelper.Now.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
paras.Add ("timestamp#timeStamp", timestamp.ToString ());
paras.Add ("sign#sign", GenerateSignString(paras)); //应用签名

var request = new AndroidJavaObject ("com.tencent.mm.sdk.modelpay.PayReq");
foreach(var kv in paras){
    request.Set (kv.Key.Split('#')[1], kv.Value);
}
bool ret = WXApi.Call<bool>("sendReq", request);

签名算法

//生成微信支付签名
private static string GenerateSignString(Dictionary<string,string> paras)
{
    SortedDictionary<string, string> dict = new SortedDictionary<string, string>();
    foreach(var kv in paras)
    {
        dict.Add(kv.Key.Split('#')[0], kv.Value);
    }
    List<string> tmp = new List<string>();
    foreach (var kv in dict)
    {
        tmp.Add(string.Format("{0}={1}", kv.Key, kv.Value));
    }
    tmp.Add("key=" + CommonSettings.WXPaySecret);
    var signTmp = string.Join("&", tmp.ToArray());
    var result = MD5Utils.Encrypt(signTmp).ToUpper();
    return result;
}

微信的客户端签名算法变量名与赋值变量名不一致


微信APP端SDK类com.tencent.mm.sdk.modelpay.PayReq提供的变量参数名,与最后参与签名算法的参数名是不一样的,这里要特别注意。

比如变量packageValue参与签名算法是package。
以下是必选参数的映射关系(注意大小写,左边是签名算法的参数名,右边是API中的类成员名)

appid = appId
partnerid = partnerId
prepayid = prepayId
package = packageValue
noncestr = nonceStr
timestamp = timeStamp

上面的示例代码中已经有了,请大家参考。

使用JDK1.8编译的JAR包导致unity生成APK出错


在unity打包APK的时候总是报错生成java dex的时候出错。我排查了半天,发现应该是使用的几个JAR包编译环境不一致,我在写支付回调包的时候,使用的jdk1.8版本编译的,而环境中的支付宝SDK的JAR包用的是jdk1.7

将编译环境改为jdk1.7即解决本问题。

sendReq方法并非阻塞Unity线程的,需要使用回调机制


不同于支付宝,微信支付必须写回调。并且严格要求了回调的包名和类名。
API中提供的客户端支付接口(sendReq方法)没有阻塞unity 的UI线程,在启动微信支付的activity页的同时就返回了。

所以需要我们实现WXPayEntryActivity类,我们使用UnityPlayer.UnitySendMessage来实现JAVA回调unity,以下是参考代码。

package com.hanjiasongshu.jianghux.wxapi;

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 com.unity3d.player.UnityPlayer;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;

public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler   {

    private IWXAPI api;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //这里填你的微信APP ID
        api = WXAPIFactory.createWXAPI(this, "");
        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 retCode = resp.errCode;
            UnityPlayer.UnitySendMessage("Payment","WXPayCallback", String.valueOf(retCode));
            finish();
        }
    }
}

如何编写“健壮”不丢充值的支付程序?


支付对接最怕的就是丢单(用户付了费但是我们没发商品),什么情况下会导致丢单呢?我们要从一般的支付流程说起。

微信APP支付流程

注意几个常见的丢单点:

  • 不能使用客户端微信到APP的回调来确认是否已支付成功。(原因:微信端支付成功却可能闪退、或由于各种原因回调失败)
  • 服务端期望微信的http回调是可能失败的(原因:我方服务器断网、微信端出问题)
  • 不能将支付凭证只保存在客户端(原因:用户换设备不能丢单)

那么我们保证不丢单的方式如下:

  1. 用户点击商品,发起支付
  2. 该用户生成transactionId(交易凭证)并保存到服务端
  3. 服务端根据transactionId调用统一下单接口生成prepayId
  4. 客户端获得prepayId,调用微信支付接口付费
  5. 若客户端支付失败或取消,则通知服务端删除transacionId
  6. 若支付成功,则服务端开启轮询(调用查询实际支付结果),询问微信支付状态
  7. 查到已付费或付费取消等有定论的结果后,发放商品,并通知客户端进行展现

猜你喜欢

转载自blog.csdn.net/rcfalcon/article/details/52518700
今日推荐