最近在忙着做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内,最后展示支付结果。
目前微信支付支持手机系统有:IOS(苹果)、Android(安卓)和WP(Windows Phone)。
第二步 集成微信支付SDK
android的导入方法
后台设置
商户在微信开放平台申请开发应用后,微信开放平台会生成APP的唯一标识APPID。由于需要保证支付安全,需要在开放平台绑定商户应用包名和应用签名,设置好后才能正常发起支付。设置界面在【开放平台】中的栏目【管理中心 / 修改应用 / 修改开发信息】里面,如下图红框内所示。
注意了前方高能,此处有坑:android 应用的签名有调试签名和上线签名两个,调试阶段,先运行程序,然后根据签名工具GenSignature获取签名,这个签名是调试的签名,配好之后,需要3个小时左右才能生效(微信同步数据需要时间),反正不是立马生效的,所以配好后马上调用微信支付,肯定是失败的(跳不到微信支付的页面),需要等2-3个小时,再调用,就会跳到微信支付的页面。同时上线也是一样的,别忘了改正式版的签名,用GenSignature获取打包后的apk签名,然后在配上去,2-3个小时,才能生效。同一个程序调试和发布的签名是不一样的。
- 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(); } } }
@Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(),// ...other packages new WxpayPackage() // <-- 注册模块 ); }
ios的导入方法
1)项目设置APPID,在Xcode中打开项目,设置项目属性中的URL Schemes为你的APPID。如图标红位置所示:
这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
#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
//支付回调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]; } }
第三步 react-native 端
react-native run-android # 运行Android端 react-native run-ios # 运行iOS端
2)编写
Wxpay.js
工具类
import { NativeModules } from 'react-native'; export default NativeModules.Wxpay;
import Wxpay from './your/path/to/Wxpay'; Wxpay.registerApp(APPID); //向微信注册
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" }