文章目录
- 一 、前言
- 二、RN与安卓通信
- 2.1 RN 调用安卓原生组件
- 2.2 RN 应用消息机制方式与安卓原生代码切换
- 2.3 RN 应用 Promise 机制与安卓原生代码通信
- 2.4 RN 应用 callback 回调方式与安卓原生代码通信
- 三、RN与IOS通信
- 3.1 定义导出的方法名
- 3.2 promise 实现回调函数
- 3.3 继承 RCTEventEmitter 类
- 四、拓展阅读
一 、前言
RN项目开发阶段,需要实现RN与原生应用间进行数据通讯。
(图片来源网络,侵删)二、RN与安卓通信
2.1 RN 调用安卓原生组件
- 用Android Studio打开一个已经创建好的RN项目,选择android/build.gradle文件。
- 创建一个类MyNativeModule继承ReactContextBaseJavaModule,暴露出一些让RN调用的方法,封装成一个原生模块。
public class MyNativeModule extends ReactContextBaseJavaModule{ }
实现getName方法,用于返回RN代码需要寻找的类的名称。
//RN代码要通过名字来调用该类的方法 @Override public String getName() { return "ToastModule"; }
实现类的构造方法,将传入的上下文赋值给类内部私有的上下文。
(图片来源网络,侵删)// 创建一个上下文,放到构造函数中,得到reactContext private ReactApplicationContext mContext; public MyNativeModule(ReactApplicationContext reactContext){ super(reactContext); mContext = reactContext; }
创建暴露给RN调用的方法,需要用注释符号@ReactMethod修饰。
//方法不能返回值。因为被调用的原生代码是异步的。原生代码执行结束之后只能通过回调函数或者发送消息给RN。 @ReactMethod public void rnCallNative(String msg){ //这个方法是说弹出一个弹窗到界面Toast.makeText(mContext,msg,Toast.LENGTH_LONG).show(); }
- 在原生代码中创建一个类实现接口ReactPackage包管理器,并且把第二步已经创建好的类加入到原生模块列表里。
public class MyReactPackage implements ReactPackage { @Override public List createNativeModules(ReactApplicationContext reactContext) { List modules = new ArrayList(); modules.add(new MyNativeModule(reactContext)); return modules; } @Override public List createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); } }
- 将创建好的包管理器添加到ReactPackage列表里,也就是MainApplication代码中,在类里找到方法getPackages方法,将包管理器添加进去。
@Override protected List getPackages() { return Arrays.asList( new MainReactPackage(), new MyReactPackage() ); }
- 在RN代码中用NativeModules组件去调用原生模块。
导入组件
import { AppRegistry, StyleSheet, Text, View, NativeModules, } from 'react-native';
设置方法调用原生代码
call_button(){ NativeModules.ToastModule.rnCallNative('RN与安卓开发'); }
布置UI 在render方法里面设置当用户点击文字时,调用自定义的方法call_button。并且以这种形式创建的方法需要进行绑定。
render() { return( styles.container} this.call_button.bind(this)}测试原生通讯 ); } .... const styles = StyleSheet.create({ container: { flex:1, backgroundColor:'deeppink', flexDirection:'row', justifyContent:'center', alignItems:'center' }, });
RN调用原生的方法,此时安卓的application就会启动,完成之后它会去找Package列表,进而找到自己创建的列表。而在组件的列表里面有一个原生模块列表,到自己的模块列表里面调用模块里的方法就完成了调用。
2.2 RN 应用消息机制方式与安卓原生代码切换
在原生代码中添加一个按钮,当用户从RN界面调用原生代码就会进入到原生代码开发的界面中,而点击原生代码中的按钮就会返回到RN界面。
实施步骤如下:
- 在与MainApplication同级的目录下创建一个MyActivity,会自动生成一个自动布局文件activity_my做布局的工作。
- 打开布局文件,将左下角的Design切换成Text文件,为原生界面创建一个按钮并且布局。
- 回到新创建的MyActivity代码,实现onBack方法。
//点击按钮,直接完成 public void onBack(View v){ finish(); }
- 在MyNativeModule原生模块中去实现Activity。
//方法不能返回值 因为被调用的原生代码是异步的 原生代码执行结束之后只能通过回调函数或者发送消息给RN @ReactMethod public void rnCallNative(String msg){ Toast.makeText(mContext,msg,Toast.LENGTH_LONG).show(); Intent intent = new Intent(mContext,MyActivity.class); //创建一个意图,意图是android进程之间、线程之间、交换数据的载体 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //一定要加上这句 mContext.startActivity(intent); }
2.3 RN 应用 Promise 机制与安卓原生代码通信
使用Promise机制也是RN与原生通信的一种方式。在原生代码的MyNativeModule文件中创建桥接方法,当桥接的原生方法的最后一个参数是一个Promise对象,那么该方法会返回一个JS的Promise对象给与之对应的js方法。与上文类似,需要暴露给RN的方法不能有返回值,并且要以注释@ReactMethod标识。
@ReactMethod public void rnCallNative_promise(String msg,Promise promise){ Toast.makeText(mContext,msg,Toast.LENGTH_SHORT).show(); //得到组件名称 String componentName = getCurrentActivity().getComponentName().toString(); promise.resolve(componentName); }
在RN中创建一个方法,这个方法内部使用NativeModules组件来调用原生模块提供的名称,进而找到要调用的原生方法。原生方法最后一个参数是一个promise,所以在js中用.then的方法实现即可。
callAndroid_promise(){ NativeModules.ToastModule.rnCallNative_promise('promise调用原生').then( (msg) => { console.log('promise收到消息:'+msg); } ).catch( (err)=>{ console.log(err); } ) }
渲染方法中,调用方法。
styles.welcome} onPress={this.callAndroid_promise.bind(this)}Promise通信 .... welcome: { fontSize: 16, textAlign: 'left', margin: 10 }
2.4 RN 应用 callback 回调方式与安卓原生代码通信
在原生模块中暴露一个桥接方法给RN调用,参数传入一个成功的回调和一个失败的回调。
@ReactMethod public void measureLayout(Callback errorCallback,Callback successCallback){ try { successCallback.invoke(100,100,200,200); //调用回调函数,返回结果 }catch (IllegalViewOperationException e){ errorCallback.invoke(e.getMessage()); } }
在js中实现回调方法。同样是通过NativeModules组件寻找到桥接名称ToastModule,进而找到想要调用的方法。拿到返回的参数,做功能处理。
callAndroid_callback(){ NativeModules.ToastModule.measureLayout( (msg)=>{ console.log(msg); }, (x,y,width,height)=>{ console.log('x坐标:'+x+'y坐标:'+y+'高:'+height+'宽'+width); } ) }
在使用回调函数时会呈现出某些缺点,比如说每次调用只应当调用一次,多次调用可能会出现意想不到的结果,并且用这种方法安卓原生代码是无法主动发送信息给RN侧的。
三、RN与IOS通信
首先 RN 与 IOS 通信,在原生端需创建一个bridge ,并遵守协议。
#import @interface PushModule : NSObject
其次,在@implementation中导出 Module。
@implementation PushModule RCT_EXPORT_MODULE()
有以下3种通信方式。
3.1 定义导出的方法名
RCT_EXPORT_METHOD(pushEvent:(NSString *)event callback:(RCTResponseSenderBlock)callback){ NSLog(@"----对React Native提供调用方法,Callback---%@",event); NSString *callbackData = @"原生数据被RN调用"; //准备回调回去的数据 callback(@[[NSNull null],callbackData]); }
定义一个方法后,RN 就可通过NativeModules获取到对于 Module后调用相应方法,event是 RN 传给 IOS 的值,IOS 这边可通过 callback 这个 block 回调给 RN 数据。
callBackEvent (){ NativeModules.PushModule.pushEvent(('RN->原生的数据'),(error, events) => { if (error) { console.log(error); }else { alert(events) } }) }
3.2 promise 实现回调函数
static RCTPromiseResolveBlock _resolve;//成功回调 static RCTPromiseRejectBlock _reject;//失败回调 RCT_REMAP_METHOD(pushPromisesEvent, resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject){ _resolve = resolve; _reject = reject; } //异步回调函数 +(void) handleResult:(id)result{ //原生Promises数据被RN调用 if ([result isEqualToString:@"获取数据成功"]) { _resolve(@[result]); }else{ //返回错误信息 NSError *error=[NSError errorWithDomain:result code:101 userInfo:nil]; _reject(@"no_events", @"There were no events", error); } }
RN 侧方法调用。
NativeModules.PushModule.pushPromisesEvent().then((events)=>{ alert(events+1111) }).catch((e)=>{ // alert(e) console.log("错误信息------"+e); }) }
3.3 继承 RCTEventEmitter 类
#import #import @interface PushModule : RCTEventEmitter
在 .m 的实现中有几个继承方法需要实现。
//IOS 回传给 RN 的通知方法 - (NSArray*)supportedEvents{ return @[@"Notice_name"] } - (void)startObserving { [PushTool sharedPushTool].isReady = YES; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notice:) name:@"event-notice" object:nil]; } -(void)notice:(NSNotification*)notification { NSDictionary*obj = notification.object; [self sendEventWithName:@"Notice_name" body:obj]; }
在 RN 侧实施监听。
var module = new NativeEventEmitter(NativeModules.PushModule); module.addListener('Notice_name',(data)=>this.message(data));
四、拓展阅读
- 《iOS开发进阶(八):ipa应用唤起并跳转至指定页面》
- 《Android进阶(二十九) 走近 IntentFilter》
还没有评论,来说两句吧...