最近在忙着做rn移动端的开发,碰到不少问题,其中把微信支付的问题分享给大家,希望对大家有所帮助
react-native 集成微信支付主要有两种方法(目前来说,不排除以后还有别的npm第三方包)第一种是使用npm包(react-native-wechat),这个包是别人封装好的,优点:使用过程中方便,不写原生的代码,但是我在用这个包时碰到一个最奇葩的问题,就是在ios上面真机调试没有任何错误,打包之后,运行ipa安装包时,微信支付报错( <Notice>: Exception '-[__NSCFString unsignedIntValue]: unrecognized selector sent to instance 0x1c4233ae0'
),同样的代码,在android是好的,ios调试是好的,唯独ipa包是报错的,后来果断的放弃这个包改用rn调用原生支付的模式,也就是今天我讲的第二种方法。期间参考了这篇博客:
http://fangzf.me/2017/12/11/react-native-集成微信支付/
但是这篇博客有些坑,且看以下简述:
第一步 场景介绍
适用于商户在移动端APP中集成微信支付功能。
商户APP调用微信提供的SDK调用微信支付模块,商户APP会跳转到微信中完成支付。
支付完后跳回到商户APP内,最后展示支付结果。
目前微信支付支持手机系统有:IOS(苹果)、Android(安卓)和WP(Windows Phone)。
第二步 集成微信支付SDK
android的导入方法
后台设置
商户在微信开放平台申请开发应用后,微信开放平台会生成APP的唯一标识APPID。由于需要保证支付安全,需要在开放平台绑定商户应用包名和应用签名,设置好后才能正常发起支付。设置界面在【开放平台】中的栏目【管理中心 / 修改应用 / 修改开发信息】里面,如下图红框内所示。
注意了前方高能,此处有坑:android 应用的签名有调试签名和上线签名两个,调试阶段,先运行程序,然后根据签名工具GenSignature获取签名,这个签名是调试的签名,配好之后,需要3个小时左右才能生效(微信同步数据需要时间),反正不是立马生效的,所以配好后马上调用微信支付,肯定是失败的(跳不到微信支付的页面),需要等2-3个小时,再调用,就会跳到微信支付的页面。同时上线也是一样的,别忘了改正式版的签名,用GenSignature获取打包后的apk签名,然后在配上去,2-3个小时,才能生效。同一个程序调试和发布的签名是不一样的。
2) 导入微信SDK,修改android/app/build.gradle添加如下代码:
- dependencies { ...... compile "com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+" ......}
3)在com.xx.xx创建包名wxapi,注意此处包名一定要为wxapi,否则后续将无法处理回调
针对没有原生开发经验的可能并不太明白这句话意思。
注意了,此处有坑:假如你创建了一个应用:react-native init test
那么android程序的目录一定是这样的:
创建的wxapi包一定要在test里面,这样才能处理微信支付后的回调结果,如图
4)编写 Module,在wxapi包下创建WxpayModule.java,代码如下:
package com.test.wxapi;
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;
class WxpayModule extends ReactContextBaseJavaModule {
private IWXAPI api;
static String APP_ID = "";
static Promise promise = null;
WxpayModule(ReactApplicationContext reactContext) {
super(reactContext);
api = WXAPIFactory.createWXAPI(reactContext, null);
}
@Override
public String getName() {
return "Wxpay";
}
@ReactMethod
public void registerApp(String APP_ID) { // 向微信注册
WxpayModule.APP_ID = APP_ID;
api.registerApp(APP_ID);
}
@ReactMethod
public void pay(final ReadableMap order, Promise promise) {
WxpayModule.promise = promise;
PayReq request = new PayReq();
request.appId = order.getString("appId");
request.partnerId = order.getString("partnerId");
request.prepayId= order.getString("prepayId");
request.packageValue = order.getString("package");
request.nonceStr= order.getString("nonceStr");
request.timeStamp= order.getString("timeStamp");
request.sign= order.getString("sign");
api.sendReq(request);
}
@ReactMethod
public void isSupported(Promise promise) { // 判断是否支持调用微信SDK
boolean isSupported = api.isWXAppInstalled();
promise.resolve(isSupported);
}
}
此处也有个小坑:第一行的报名一定要写对,同时
request
.
appId
=
order
.
getString
(
"appId"
);这个appid是根据你服务器生成预支付订单返回的数据决定的,你服务器返回APPID,这个地方就而写APPID。写一篇我会写一个基于nodejs服务端微信支付生成预支付订单的接口实现。
5)编写 Package,在wxapi包下创建WxpayPackage.java,代码如下:
package com.test.wxapi;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class WxpayPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new WxpayModule(reactContext));
return modules;
}
}
6)编写 WXPayEntryActivity 处理微信支付回调,在wxapi包下创建WXPayEntryActivity.java,注意包名或类名不一致会造成无法回调,代码如下:
package com.test.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.facebook.react.bridge.WritableMap;
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;
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
private static final String TAG = "WXPayEntryActivity";
private IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
api = WXAPIFactory.createWXAPI(this, WxpayModule.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, "onPayFinish, errCode = " + resp.errCode);
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
WritableMap map = Arguments.createMap();
map.putInt("errCode", resp.errCode);
WxpayModule.promise.resolve(map);
finish();
}
}
}
7)最后在 Android 这边要做的最后一件事就是注册这个模块,在com.xx.xx.MainApplication中注册模块:
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
// ...other packages
new WxpayPackage() // <-- 注册模块
);
}
ios的导入方法
1)项目设置APPID,在Xcode中打开项目,设置项目属性中的URL Schemes为你的APPID。如图标红位置所示:
2)添加微信白名单和修改http访问权限,默认的xcode是https的访问
3)添加必要的类库 这个pay相当于test,就是工程名字,不影响支付功能
这3个文件去微信开放平台下载
4)导入必要的库文件
5)在项目目录下创建Group Wxapi,并创建WxpayMoudle模块
6)编写WxpayModule.h代码如下:
#import <React/RCTBridgeModule.h>
#import <React/RCTLog.h>
#import "WXApiObject.h"
#import "WXApi.h"
@interface WxpayMoudle : NSObject <RCTBridgeModule, WXApiDelegate>
@end
7)
编写
WxpayModule.m
代码如下:
#import "WxpayMoudle.h"
@implementation WxpayMoudle
RCTPromiseResolveBlock resolveBlock = nil;
- (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"];
resolveBlock(@{@"errCode": errCode});
}
RCT_EXPORT_METHOD(registerApp:(NSString *)APP_ID){
[WXApi registerApp: APP_ID];//向微信注册
}
RCT_EXPORT_METHOD(pay:(NSDictionary *)order
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject){
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
8)处理微信支付回调,在AppDelegate.m中添加如下代码:
//支付回调9以后
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary*)options {
return [WXApi handleOpenURL:url delegate:self];
}
//支付回调9以前
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
return [WXApi handleOpenURL:url delegate:self];
}
//ios9以后的方法
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [WXApi handleOpenURL:url delegate:self];
}
#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];
}
}
致此微信支付的相关原生功能模块都写好了,android和ios的。接下来要react-native去调用这些原生的功能方法。react-native怎么和原生交互请看官方文档:
第三步 react-native 端
1)修改原生代码后,需要重新打包运行程序:
react-native run-android # 运行Android端
react-native run-ios # 运行iOS端
2)编写
Wxpay.js
工具类
import { NativeModules } from 'react-native';
export default NativeModules.Wxpay;
3)在入口文件
index.js
向微信注册应用
import Wxpay from './your/path/to/Wxpay';
Wxpay.registerApp(APPID); //向微信注册
4)调用
Wxpay
模块发起微信支付:
import Wxpay from './your/path/to/Wxpay';
async pay(params) { // params 为后端提供的参数
let isSupported = await Wxpay.isSupported();
if (!isSupported) { // 判断是否支持微信支付
alertModel('找不到微信应用,请安装最新版微信');
return;
}
let ret = await Wxpay.pay(params); // 调起微信客户端,发起支付
if (ret.errCode === 0) {
// 支付成功回调
alertModel('支付成功');
} else {
// 支付失败回调
alertModel('支付失败');
}
}
服务端返回的params数据结构如
{
"appId": "wx28f86efd23cc3dse",
"partnerId": "1494562862",
"prepayId": "wx24153040008020562a5d00291301203432",
"nonceStr": "d7c18718502a444a1a88227b0915de84",
"timeStamp": "1524555040",
"package": "Sign=WXPay",
"sign": "44718752BAC35C8C29896F7707A96A77"
}