游戏中微信支付的接入

android接入,参考文献

  • 流程:
    1. 客户端向自己的服务端申请订单,服务端同步到微信服务端
    2. 客户端收到订单后,调起微信进行支付
    3. 等微信返回后,会通知客户端,然后根据结果向自己的服务端请求相关信息
    4. 同时服务端会接受微信服务端的支付成功失败通知,也可以向微信服务端查询支付情况
  • android的sdk已经升级过,从sdk变成了opensdk,下载wechat-sdk-android-without-mta-x.x.xjar或者wechat-sdk-android-with-mta-x.x.xjar
  • 引入微信支付依赖,android studio的build.gradle文件中,添加如下依赖即可:

    1
    2
    3
    dependencies {
    compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
    }
  • 配置WXPayEntryActivity,从官网demo中copy一个来即可,必须放到app包下新建一个wxapi包里面

  • AndroidManifest.xml中注册

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!--wx pay所需权限-->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <!--wx pay-->
    <activity
    android:name=".wxapi.WXPayEntryActivity"
    android:exported="true"
    android:launchMode="singleTop">
    <activity/>
  • 发送支付信息给服务端,自定义处理

  • 跳转微信进行支付,java代码大致如下,需要注意的是需要运行到UI主线程,不然Toast.makeText等操作会崩溃

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public static void wxPay(final String orderJson)
    {
    mAppActivity.runOnUiThread(new Runnable(){
    @Override
    public void run() {
    try{
    JSONObject json = new JSONObject(orderJson);
    if(null != json){
    PayReq req = new PayReq();
    req.appId = APP_ID; //json.getString("appid");
    req.partnerId = json.optString("partnerid");
    req.prepayId = json.optString("prepayid");
    req.nonceStr = json.optString("noncestr");
    req.timeStamp = json.optString("timestamp");
    req.packageValue = json.optString("package");
    req.sign = json.optString("sign");
    //req.extData = json.optString("extdata"); // optional
    Toast.makeText(mAppActivity, "正在打开微信", Toast.LENGTH_SHORT).show();

    mWXAPI.sendReq(req);
    }else{
    Toast.makeText(mAppActivity, "生成订单失败", Toast.LENGTH_SHORT).show();
    }
    }catch(Exception e){
    Toast.makeText(mAppActivity, "支付失败"+e.getMessage(), Toast.LENGTH_SHORT).show();
    }
    }
    });
    }
  • 微信客户端回调支付结果处理,微信会自动回调到继续IWXAPIEventHandler的WXPayEntryActivity::public void onResp(BaseResp resp),如果在cocos上调用,同样要注意让回调运行在GLThread中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    public static void onWXResp(BaseResp resp) {
    if (resp instanceof SendAuth.Resp) {
    //
    }
    else if (resp instanceof SendMessageToWX.Resp) {
    //
    }
    // com.tencent.mm.opensdk.constants.ConstantsAPI;
    // resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX
    else if (resp instanceof PayResp) {
    final PayResp payResp = (PayResp)resp;
    if (payResp.errCode == 0) {
    mAppActivity.runOnGLThread(new Runnable(){
    @Override
    public void run() {
    onWXpaySuccess("支付成功");
    }
    });
    } else {
    final String resultStatus;
    if (payResp.errCode == -2) {
    resultStatus = "您取消了支付";
    } else {
    resultStatus = "支付失败";
    }
    mAppActivity.runOnGLThread(new Runnable(){
    @Override
    public void run() {
    onWXpayFail(resultStatus);
    }
    });
    }
    }
    }

ios接入,参考文献

  • 接入流程跟android是一样的,区别的是,一般ios游戏为了上AppStore,一般不接带支付功能的sdk,所以用微信去除支付功能的sdk
  • 将解压的微信OpenSDK文件夹拷贝到项目文件夹下,并导入开发环境中。

    1
    2
    3
    4
    libWeChatSDK.a
    WechatAuthSDK.h
    WXApi.h
    WXApiObject.h
  • 并根据官方文档导入依赖库

  • 添加URL Schemes, 点击项目名称,点击“Info”选项卡,在“URL Types”选项中,点击“+”, 在“URL Schemes”中输入微信的注册码
  • 使用URLScheme调起weixin

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    void wxPay(const std::string& orderJson, const std::function<void(bool, const std::string&)>& callback)
    {
    std::string output = "";
    // 隐藏微信地址
    Base64Decode("d2VpeGluOi8vYXBwL3d4NWI5YmZkZGFiNGZiZjQyNi9wYXkvPw==", &output);

    rapidjson::Document document;
    document.Parse(orderJson.c_str());
    std::string partnerid, prepayid, noncestr, timestamp, package, sign, extdata;
    bool bfirst = true;

    if ( document.HasMember("extdata") ) {
    rapidjson::Value& v = document["extdata"];
    if (v.IsString()) {
    extdata = v.GetString();
    if (!extdata.empty()) {
    output += "extData=" + extdata;
    bfirst = false;
    }
    }
    }
    if ( document.HasMember("noncestr") ) {
    rapidjson::Value& v = document["noncestr"];
    if (v.IsString()) {
    noncestr = v.GetString();
    if (noncestr.empty()) { callback(false, "支付失败"); return;}
    if ( bfirst ) {
    bfirst = false;
    output += "nonceStr=" + noncestr;
    } else {
    output += "&nonceStr=" + noncestr;
    }
    }
    }
    if ( document.HasMember("package") ) {
    rapidjson::Value& v = document["package"];
    if (v.IsString()) {
    package = v.GetString();
    package = package.replace(package.find("="), 1, "\%\%3D");
    if (package.empty()) { callback(false, "支付失败"); return;}
    output += "&package=" + package;
    }
    }
    if ( document.HasMember("partnerid") ) {
    rapidjson::Value& v = document["partnerid"];
    if (v.IsString()) {
    partnerid = v.GetString();
    if (partnerid.empty()) { callback(false, "支付失败"); return;}
    output += "&partnerId=" + partnerid;
    }
    }
    if ( document.HasMember("prepayid") ) {
    rapidjson::Value& v = document["prepayid"];
    if (v.IsString()) {
    prepayid = v.GetString();
    if (prepayid.empty()) { callback(false, "支付失败"); return;}
    output += "&prepayId=" + prepayid;
    }
    }
    if ( document.HasMember("timestamp") ) {
    rapidjson::Value& v = document["timestamp"];
    if (v.IsString()) {
    timestamp = v.GetString();
    if (timestamp.empty()) { callback(false, "支付失败"); return;}
    output += "&timeStamp=" + timestamp;
    }
    }
    if ( document.HasMember("sign") ) {
    rapidjson::Value& v = document["sign"];
    if (v.IsString()) {
    sign = v.GetString();
    if (sign.empty()) { callback(false, "支付失败"); return;}
    output += "&sign=" + sign;
    }
    }
    output += "&signType=SHA1";

    setWXpayCallback(callback);
    NSString * pUrl = [NSString stringWithUTF8String:output.c_str()];
    NSURL* url = [NSURL URLWithString:pUrl];
    [[UIApplication sharedApplication] openURL:url];
    }
  • 等待微信回调,头文件中App继承WXApiDelegate,sdk会回调到openURL,但并不会回调到onResp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
    {
    return [WXApi handleOpenURL:url delegate:self];
    }

    // NOTE: 9.0以后使用新API接口
    - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
    {
    if ([url.absoluteString rangeOfString:APP_ID].length) {
    auto callback = getWXpayCallback();
    if ( callback ) {
    // 微信支付,微信回调的时候回回传ret参数,这样来区分支付知否成功
    NSArray *array = [url.absoluteString componentsSeparatedByString:@"ret="];
    NSInteger ret = [array.lastObject integerValue];
    // 调起微信结果返回
    // ret: 0成功支付 -2取消支付 -1其他原因
    if ( ret == 0 ) {
    callback(true, "支付成功");
    } else if ( ret==-2 ) {
    callback(false, "您取消了支付");
    } else {
    callback(false, "支付失败");
    }
    setWXpayCallback(nullptr);
    }
    }
    else {
    return [WXApi handleOpenURL:url delegate:self];
    }
    return YES;
    }