本文章将介绍如何将微信支付App支付功能,接入到React Native应用中,包含Android、iOS,还有JS的调用示例三大模块。

Android

一、目录结构

文章所述将需要改动以下文件:

app/
└──  build.gradle
app/src/main/
└── AndroidManifest.xml
app/src/main/java/com/xxx/mobile
└── App.kt
app/src/main/java/com/xxx/mobile/wxapi
├── WXPayEntryActivity.kt
├── WxpayModule.kt
└── WxpayPackage.kt

二、获取AppID

在微信开放平台上管理中心 / 应用详情获取得到AppID

三、获取应用签名(MD5)

具体获取步骤(示范):

1
2
3
4
5
$ keytool -list -v -keystore ~/.android/demo.keystore | awk '/MD5/{print $2}'
输入密钥库口令:  123456
8B:8A:62:7E:EC:16:00:E4:00:89:13:81:B0:84:C5:D2
$ python -c 'print("8B:8A:62:7E:EC:16:00:E4:00:89:13:81:B0:84:C5:D2".replace(":", "").lower())'
8b8a627eec1600e400891381b084c5d2

PS:需要的是MD5值,小写,而不是别的,之前因为其他同事把这个填写错了,导致每个用户只有微信支付一次,排查了半天…

在微信开放平台上管理中心 / 修改应用 / 修改开发信息填入信息:

三、集成微信支付SDK

1
2
3
4
dependencies {
    implementation "com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+"
    // ... more ...
}

PS: 这样子的集成方式,感觉要比直接导入.jar.aar都舒服不少呀。

四、创建wxapi包名

com.xx.mobile创建包名wxapi,注意此处包名一定要为wxapi,否则后续将无法处理回调

五、WxpayModule.kt

 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
package com.xxx.mobile.wxapi

import android.util.Log
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableMap
import com.tencent.mm.opensdk.modelpay.PayReq
import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.WXAPIFactory

internal class WxpayModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
    companion object {
        val TAG = "WxpayModule"
        var APP_ID = ""
        var promise: Promise? = null
    }

    private val api: IWXAPI = WXAPIFactory.createWXAPI(reactContext, null)

    override fun getName(): String {
        return "Wxpay"
    }

    @ReactMethod
    fun registerApp(APP_ID: String) { // 向微信注册
        WxpayModule.APP_ID = APP_ID
        api.registerApp(APP_ID)
    }

    @ReactMethod
    fun isSupported(promise: Promise) { // 判断是否支持调用微信SDK
        val isSupported = api.isWXAppInstalled
        promise.resolve(isSupported)
    }

    @ReactMethod
    fun pay(order: ReadableMap, promise: Promise) {
        Log.d(TAG, "wxpay pay start")
        WxpayModule.promise = promise
        val request = PayReq()
        request.appId = order.getString("appid") // 应用ID
        request.partnerId = order.getString("partnerid") // 商户号
        request.prepayId = order.getString("prepayid") // 预支付交易会话ID
        request.packageValue = order.getString("package") // 扩展字段(暂定固定值Sign=WXPay)
        request.nonceStr = order.getString("noncestr") // 随机字符串
        request.timeStamp = order.getInt("timestamp").toString() // 时间戳 epoch
        request.sign = order.getString("sign") // 签名,签名方式一定要与统一下单接口使用的一致
        api.sendReq(request)
    }
}

六、WxpayPackage.kt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package com.xxx.mobile.wxapi

import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager

class WxpayPackage : ReactPackage {

    override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
        return emptyList()
    }

    override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
        return listOf(WxpayModule(reactContext))
    }
}

七、WXPayEntryActivity.kt

 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
package com.xxx.mobile.wxapi

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import com.facebook.react.bridge.Arguments
import com.tencent.mm.opensdk.constants.ConstantsAPI
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

class WXPayEntryActivity : Activity(), IWXAPIEventHandler {
    companion object {
        val TAG = "WXPayEntryActivity"
    }

    private var api: IWXAPI? = null

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        api = WXAPIFactory.createWXAPI(this, WxpayModule.APP_ID)
        api?.handleIntent(intent, this)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        setIntent(intent)
        api?.handleIntent(intent, this)
    }

    override fun onReq(req: BaseReq) {}

    override fun onResp(resp: BaseResp) {
        Log.d(TAG, "wxpay onPayFinish, errCode = " + resp.errCode)
        if (resp.type == ConstantsAPI.COMMAND_PAY_BY_WX) {
            val map = Arguments.createMap()
            map.putInt("errCode", resp.errCode)
            WxpayModule.promise!!.resolve(map)
            finish()
        }
    }
}

八、App.kt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import com.xxx.mobile.wxapi.WxpayPackage // ← here
class App : Application(), ReactApplication {

    private val mReactNativeHost = object : ReactNativeHost(this) {
        override fun getUseDeveloperSupport(): Boolean {
            return BuildConfig.DEBUG
        }
        override fun getPackages(): List<ReactPackage> {
            return listOf(
                    MainReactPackage(),
                    // ...
                    WxpayPackage() // ← here
            )
        }
        override fun getJSMainModuleName(): String {
            return "index"
        }
    }
    // ...
}

PS: 此App.kt实际是由MainApplication.java转为Kotlin语言的文件

九、AndroidManifest.xml

在AndroidManifest.xml中添加微信支付的activity:

1
2
    <!--微信支付-->
    <activity android:name=".wxapi.WXPayEntryActivity" android:exported="true"/>

iOS

一、目录结构

文章所述将涉及以下文件的改动:

├── AppDelegate.m
└── Info.plist
Wxapi
├── WXApi.h
├── WXApiObject.h
├── WechatAuthSDK.h
├── WxpayModule.h
└── WxpayModule.m
thirdparty/wechat
└── libWeChatSDK.a

二、集成微信SDK

SDK下载链接:WeChatSDK1.8.4.zip

WeChatSDK1.8.4.zip解压到thirdparty/wechat,目录结构如下:

thirdparty/wechat
└── libWeChatSDK.a

XcodeProjectTargetGeneralLinked Frameworks and Libraries,添加以下项:

三、创建Wxapi的Group

XcodeProjectNew GroupWxapi,并将SDK的头文件拷贝过去,拷贝完成后,目录结构如下:

Wxapi/
├── WXApi.h
├── WXApiObject.h
└── WechatAuthSDK.h

四、WxpayModule.h

1
2
3
4
5
6
7
#import <React/RCTBridgeModule.h>
#import <React/RCTLog.h>
#import "WXApiObject.h"
#import "WXApi.h"

@interface WxpayModule : NSObject <RCTBridgeModule, WXApiDelegate>
@end

五、WxpayModule.m

 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

#import <Foundation/Foundation.h>
#import "WxpayModule.h"

@implementation WxpayModule
{
  RCTPromiseResolveBlock resolveBlock;
}

- (instancetype)init
{
  self = [super init];
  if (self) {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleWXPay:) name:@"WXPay" object:nil];
  }
  return self;
}

- (void)dealloc
{
  [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)handleWXPay:(NSNotification *)aNotification
{
  NSString *errCode =  [aNotification userInfo][@"errCode"];
  NSLog(@"wxpay finished, errCode = %@", errCode);
  resolveBlock(@{ @"errCode": errCode });
}

RCT_EXPORT_METHOD(registerApp:(NSString *)APP_ID) {
  NSLog(@"wxpay registerApp, appID %@", APP_ID);
  [WXApi registerApp:APP_ID];   //向微信注册
}

RCT_EXPORT_METHOD(pay:(NSDictionary *)order
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
  NSLog(@"wxpay pay start");
  resolveBlock = resolve;
  //调起微信支付
  PayReq *req = [[PayReq alloc] init];
  req.partnerId = [order objectForKey:@"partnerid"];
  req.prepayId = [order objectForKey:@"prepayid"];
  req.nonceStr = [order objectForKey:@"noncestr"];
  req.timeStamp = [[order objectForKey:@"timestamp"] intValue];
  req.package = [order objectForKey:@"package"];
  req.sign = [order objectForKey:@"sign"];
  [WXApi sendReq:req];
}

RCT_REMAP_METHOD(isSupported,   // 判断是否支持调用微信SDK
                 resolver:(RCTPromiseResolveBlock)resolve
                 rejecter:(RCTPromiseRejectBlock)reject) {
  if (![WXApi isWXAppInstalled]) resolve(@NO);
  else resolve(@YES);
}

RCT_EXPORT_MODULE(Wxpay);
@end

六、AppDelegate.m

 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
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
  return [WXApi handleOpenURL:url delegate:self];
}

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options
{
  // 微信支付
  if ([url.scheme isEqualToString:@"<YOUR_APPID>"]) {
    return [WXApi handleOpenURL:url delegate:self];
  }
  return NO;
}

//ios9以后的方法
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
  NSLog(@"%s url: %@, sourceApplication: %@", __PRETTY_FUNCTION__, url, sourceApplication);
  // 微信支付 com.tencent.xin
  if ([sourceApplication isEqualToString:@"com.tencent.xin"]) {
    return [WXApi handleOpenURL:url delegate:self];
  }
  return NO;
}

#pragma mark - wx callback
- (void)onReq:(BaseReq *)req
{
  // TODO Something
}

- (void)onResp:(BaseResp *)resp
{
  //判断是否是微信支付回调 (注意是PayResp 而不是PayReq)
  if ([resp isKindOfClass:[PayResp class]]) {
    //发出通知 从微信回调回来之后,发一个通知,让请求支付的页面接收消息,并且展示出来,或者进行一些自定义的展示或者跳转
    NSNotification *notification = [NSNotification notificationWithName:@"WXPay" object:nil userInfo:@{ @"errCode": @(resp.errCode) }];
    [[NSNotificationCenter defaultCenter] postNotification:notification];
  }
}

七、Info.plist

  1. XcodeProjectTargetInfoURL Types,填入信息:
  • Identifier:weixin
  • URL Schemes: YOUR_APPID

  1. XcodeProjectTargetInfoLSApplicationQueriesSchemes,添加两个item:

JavaScript

1)在React Native的App.js入口处,向微信注册:

1
2
3
  componentWillMount() {
    wxpay.registerApp('<YOUR_APPID>');
  }

2)在需要发起微信支付的pay.js

1
2
3
4
5
6
7
wxpay.pay(params)
  .then(v => {
    __DEV__ && console.log('_wechatPay: result:', v);
  })
  .catch(e => {
    console.warn('_wechatPay: error:', e);
  });

参考链接:

  1. 一步一步将微信支付集成到 react-native 应用
  2. 官网:SDK与DEMO下载
  3. 官网: 业务流程
  4. 官网: 统一下单
  5. 官网: 调起支付接口
  6. 微信开放平台apk应用签名获取