网上有大部分很多微信sdk集成的文档和爬坑经过,但很少是react native,大部分都是原生的接入,我用我的血汗教训踩坑之路,希望能帮助大家快速定位解决问题。 我们rn是需要接安卓+ios,按照我自己的尿性我肯定先讲一下较为简单的ios接入。
给大家个tips,官方接入是有demo的!一定要配合着demo看 demo地址
ios接入
- 相信大部分公司都会选择使用CocoaPods安装对应的ios包(CocoaPods是专门为iOS工程提供第三方依赖库的管理工具,有需要了解点击=》pod官网。
我们根据文档在podfile中加入代码
pod 'WechatOpenSDK'
然后cd到ios目录下执行pod install就oj8k
- Xcode设置URL
scheme(路径左边目录选中项目根文件,右边顶部选项栏选中info,正中选项中下拉选中URL Type,identifier输入包名,URL scheme输入注册的id。如果多个id可以用逗号隔开(如下图
解释:接下来这一步是为了让实现跳转微信app并带去注册的id。众所周知iOS是一个自闭的系统,应用之间是不能互相存储,读取文件。为了满足应用的通讯,URL Scheme来实现了这个功能。通过各个APP设计的符合苹果的统一规范的URL Scheme,Url Scheme 是可以用来在各种应用之间传递信息。浅析URLScheme在iOS中存在的意义
- 借鉴demo,复制==WXApiManager==到目录中,我们需要其进行发送wx请求成功后回调的处理。其本身头文件已然import WXApi.h 头文件,并增加 WXApiDelegate 协议。这里因为注册方法多次调用,我们可以抽象一个方法放在WXApiManager中,AppDelegate中的注册调用WXApiManager的方法
+ (BOOL) registerApp {
NSString* appId = xxx;
return [WXApi registerApp:appId];
}
- 第三步到AppDelegate的didFinishLaunchingWithOptions注册id.
//头部引入
#import "WXApiManager.h"
//didFinishLaunchingWithOptions中加入
//向微信注册
[WXApiManager registerApp];
return YES;
//并且最后实现代理WXApiDelegate
//重写handleOpenURL和openURL方法
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
return [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]];
}
配置完成我们开始开发
这里先理一理我们的调用过程
- 用户点击js处理事件对原生发起请求
- 原生响应调用wx sdk 的sendReq跳转到微信,弹出对应模版的微信信息接受提示
- 用户点击确认则跳回app,触发回调onResp返回openid等信息,这个openid就是我们需要的用户唯一标示
- js调用后台提供的接口,后台根据openid发送订阅信息到对应微信用户。
好我们来看看到底每个步骤怎么达成,存在什么坑:
第一步:js发送事件到原生,毫无疑问我们用官方推荐的方式RCT_EXPORT_METHOD()就ok(原生模块)[reactnative.cn/docs/native…]。
但这里我有一个坑,我这边是js发送的scene和temleteId给原生事件,但这个过程中我js发送的scene本来为1,却不知道为啥变成一串不认得的数字,这个是我oc在处理sence值时不经意进行了值转换,我是在抓包中才发现scene变化,解决方案是在原生中写死这个scene。
这里我们还可以用RCTPromiseResolveBlock设置promise,当发送wxapi sendReq的时候我们可以捕捉到返回值,异常可以进行抛出,await事件进行loading或其余操作。 贴上代码
RCT_EXPORT_METHOD(sendSubscribeRequest:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
dispatch_sync(dispatch_get_main_queue(), ^{
WXSubscribeMsgReq *req = [[WXSubscribeMsgReq alloc] init];
req.scene = 1;
req.reserved = @"xxx";
req.templateId = @"xxx";
BOOL result = [WXApi sendReq:req];
result ? resolve(@{@"code": @0}) : reject(@"1", @"error", nil);
});
}
//解释
dispatch_sync 和 dispatch_async 区别:
dispatch_async(queue,block) async 异步队列,dispatch_async 函数会立即返回, block会在后台异步执行。
dispatch_sync(queue,block) sync 同步队列,dispatch_sync 函数不会立即返回,即阻塞当前线程,等待 block同步执行完成。
GCD Queue 分为三种:
1,The main queue :主队列,主线程就是在个队列中。
2,Global queues : 全局并发队列。
3,用户队列:是用函数 dispatch_queue_create 创建的自定义队列
第二步:第二部只要保证好scene写死,URL scheme配置等前置条件设置妥当基本可以跳转成功
第三步:在WXApiDelegate实现的,onResp模仿demo写法就ok,拿到了回调我们需要将数据传回到js进行请求,这里官方推荐用的方式是RCTEventEmitter,实现suppportEvents方法并调用self sendEventWithName,我跟着官网做完之后发现,无法让WXApiManager的回调执行我所定义的,返回到js的方法,这里我换了一种方法,用了之前我们公司自己封装好的RCTDeviceEventEmitter公共方法。
第四步:就是js获取微信回调的参数发送请求,贴上代码:
import { DeviceEventEmitter } from 'react-native';
//...
componentDidMount() {
this.listener = DeviceEventEmitter.addListener('getWxCallback', data => {
// handle event.
console.log(data, '==========DeviceEventEmitter back data');
this.sendWxReq(data);
});
}
安卓
安卓对比ios着实要麻烦,从一开始接触rn,进入原生的坑之后一直对安卓开发敬而远之,总会出现莫名其妙的bug,无论是运行环境和开发体验都。。。 让我们先进入安卓的环境配置,照旧先按照官网的配
相关文档
首先我们先解决发送的问题,我们按rn官网的发送方案=》RCTDeviceEventEmitter
照旧也是引入promise方便监测微信接口调用情况和方便报错,这一步应该相对简单。
// 发送wx订阅方法
@ReactMethod
public void sendSubscribeRequest(final Promise promise){
SubscribeMessage.Req req = new SubscribeMessage.Req();
req.scene = 1;
req.templateID = Constant.WX_SUBSCRIBE_TEMPLATE_ID;
req.reserved = "xxx";
IWXAPI api = WXHelper.getInstance();
Boolean result = api.sendReq(req);
if (result) {
WritableMap info = Arguments.createMap();
info.putString("code", "0");
promise.resolve(info);
return;
}
promise.reject("1", "error");
}
我们按照demo引入WXEntryActivity文件,文件一定要放在名叫wxapi的文件夹下
注意文件存放的路径,必须在打包的包名applicationId对应的文件目录下(这个applicationId可以在项目build.gradle中的defaultConfig下的applicationId看到。
// 这里是根据demo和官方工作人员对于存在的bug修复的方案
// 这一步设置比较关键,不然调不起WXEntryActivity的回调
// activity的android:name这一个我看很多设置是不写的包名,但我发现不写无法回调成功,一定要写上
//因为我们这边打包不止一个包名,所以用${applicationId}指代,而且对应的wxapi文件夹需要存放到对应的路径上,不然返回无法回调成功!
<activity
android:name="${applicationId}.wxapi.WXEntryActivity"
android:exported="true"
android:taskAffinity="${applicationId}"
android:launchMode="singleTask"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
来看一下整理后的WXEntryActivity文件:
package com.xxx;
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.modelbiz.SubscribeMessage;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
import static com.xxx.xxxmodule.wechatModule.sendEvent; // 获取微信订阅回调的处理事件
// 实现IWXAPIEventHandler接口,微信发送的请求将回调到onReq方法,发送到微信请求的响应结果将回调到onResp方法
public class WXEntryBaseActivity extends Activity implements IWXAPIEventHandler{
private static final String TAG = "WXEntryBaseActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IWXAPI api = WXAPIFactory.createWXAPI(this, Constants.APP_ID, false);
//优化后,注册api提取成一个公共方法
//IWXAPI api = WXHelper.getInstance();
api.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
IWXAPI api = WXHelper.getInstance();
setIntent(intent);
api.handleIntent(intent, this);
Log.d(TAG, "onNewIntent: ");
}
//不写会报错。
@Override
public void onReq(BaseReq req) {
Log.d(TAG, "onReq: ");
finish();
}
// 回调成功回到这里来
@Override
public void onResp(BaseResp resp) {
Log.d(TAG, "onResp: ");
if (resp.getType() == ConstantsAPI.COMMAND_SUBSCRIBE_MESSAGE) {
SubscribeMessage.Resp subscribeMsgResp = (SubscribeMessage.Resp) resp;
String openId = subscribeMsgResp.openId;
if (openId != null) {
// 包装一个存储参数对象
WritableMap params = Arguments.createMap();
params.putString("openId", openId);
params.putString("templateId", subscribeMsgResp.templateID);
params.putInt("scene", subscribeMsgResp.scene);
// 调用我们的发送方法,这里我是将数据发送到js,再进行调用后台接口发送微信消息到对应微信用户
sendEvent(params);
}
}
finish();
}
}
发送的事件
public static void sendEvent(WritableMap params) {
mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("getWxCallback",params );
}
js调用跟ios的保持一致即可。
第一次在掘金上发文,小陈也是react native的新手,学习过程中略感社区文档和高质量指导文章的稀少,希望能跟大家一起讨论学习,向高级前端架构进阶