React Native iOS混合开发实战教程
栏目: JavaScript · 发布时间: 6年前
内容简介:在做RN开发的时候通常离不了JS 和Native之间的通信,比如:初始化RN时Native向JS传递数据,JS调用Native的相册选择图片,JS调用Native的模块进行一些复杂的计算,Native将一些数据(GPS信息,陀螺仪,传感器等)主动传递给JS等。在这篇文章中我将向大家介绍在RN中JS和Native之间通信的几种方式以及其原理和使用技巧;接下来我将分场景来介绍JS 和Native之间的通信。
在做RN开发的时候通常离不了JS 和Native之间的通信,比如:初始化RN时Native向JS传递数据,JS调用Native的相册选择图片,JS调用Native的模块进行一些复杂的计算,Native将一些数据(GPS信息,陀螺仪,传感器等)主动传递给JS等。
在这篇文章中我将向大家介绍在RN中JS和Native之间通信的几种方式以及其原理和使用技巧;
接下来我将分场景来介绍JS 和Native之间的通信。
几种通信场景:
- 初始化RN时Native向JS传递数据;
- Native发送数据给JS;
- JS发送数据给Native;
- JS发送数据给Native,然后Native回传数据给JS;
1. 初始化RN时Native向JS传递数据
在RN的API中提供了Native在初始化JS页面时传递数据给JS的方式,这种传递数据的方式比下文中所讲的其他几种传递数据的方式发生的时机都早。
因为很少有资料介绍这种方式,所以可能有很多朋友还不知道这种方式,不过不要紧,接下来我就向大家介绍如何使用这种方式来传递数据给JS。
概念
RN允许我们在初始化JS页面时向 顶级的JS 组件
传递 props
数据,顶级组件可以通过 this.props
来获取这些数据。
iOS
[[RCTRootView alloc] initWithBundleURL: jsCodeLocation moduleName: self.moduleName //这个"App1"名字一定要和我们在index.js中注册的名字保持一致 initialProperties:@{@"params":self.paramsInit}//RN初始化时传递给JS的初始化数据 launchOptions: nil]; 复制代码
接下来,我们先来看一下如何在 iOS
上来传递这些初始化数据。
iOS向RN传递初始化数据 initialProperties
RN的RCTRootView提供了 initWithBundleURL
方法来渲染一个JS 组件,在这个方法中提供了一个用于传递给这个JS 组件的初始化数据的参数。
方法原型:
- (instancetype)initWithBundleURL:(NSURL *)bundleURL moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties launchOptions:(NSDictionary *)launchOptions 复制代码
-
jsCodeLocation
:要渲染的RN的JS页面的路径; -
moduleName
:要加载的JS模块名; -
initialProperties
:要传递给顶级JS组件
的初始化数据; -
launchOptions
:主要在AppDelegate加载JS Bundle时使用,这里传nil就行;
通过上述方法的第三个参数就可以将一个 NSDictionary
类型的数据传递给 顶级JS组件
。
示例代码:
[[RCTRootView alloc] initWithBundleURL: jsCodeLocation moduleName: self.moduleName initialProperties:@{@"params":@"这是传递给顶级JS组件的数据"}//RN初始化时传递给JS的初始化数据 launchOptions: nil]; 复制代码
在上述代码中,我们将一个名为 params
的数据 这是传递给顶级JS组件的数据
传递给了 顶级的JS 组件
,然后在 顶级的JS 组件
中就可以通过如下方法来获取这个数据了:
render() { const {params}=this.props; return ( <View style={styles.container}> <Text style={styles.data}>来自Native初始化数据:{params}</Text> </View> ); } 复制代码
另外,如果要在非顶级页面如 CommonPage
中使用这个初始化数据,则可以通过如下方式将数据传递到 CommonPage
页面:
export default class App extends Component<Props> { ... render() { return <CommonPage {...this.props}/>; } ... } 复制代码
2. Native到JS的通信(Native发送数据给JS)
在RN的iOS SDK中提供了一个 RCTEventEmitter
接口,我们可以通过该接口实现Native到JS的通信,也就是Native将数据传递给JS。
方法原型:
- (void)sendEventWithName:(NSString *)name body:(id)body; 复制代码
所以只要我们获得 RCTEventEmitter
的实例就可以借助它将数据传递给JS。为了获得 RCTEventEmitter
的实例我们可以通过继承 RCTEventEmitter <RCTBridgeModule>
的方式来实现:
DataToJSPresenter.h
/** * React Native JS Native通信 * Author: CrazyCodeBoy * 视频教程:https://coding.imooc.com/lesson/89.html#mid=2702 * GitHub:https://github.com/crazycodeboy * Email:crazycodeboy@gmail.com */ #import <React/RCTBridgeModule.h> #import <React/RCTEventEmitter.h> @interface DataToJSPresenter : RCTEventEmitter <RCTBridgeModule> @end 复制代码
DataToJSPresenter.m
/** * React Native JS Native通信 * Author: CrazyCodeBoy * 视频教程:https://coding.imooc.com/lesson/89.html#mid=2702 * GitHub:https://github.com/crazycodeboy * Email:crazycodeboy@gmail.com */ #import "DataToJSPresenter.h" @implementation DataToJSPresenter RCT_EXPORT_MODULE(); - (NSArray<NSString *> *)supportedEvents { return @[@"testData"]; } - (instancetype)init { if (self = [super init]) {//在module初始化的时候注册fireData广播 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fireData:) name:@"fireData" object:nil]; } return self; } - (void)fireData:(NSNotification *)notification{//发送数据给RN NSString *eventName = notification.object[@"name"]; NSDictionary *params = notification.object[@"params"]; [self sendEventWithName:eventName body:params]; } @end 复制代码
在上述方法中,我们通过 RCTEventEmitter
的 sendEventWithName
方法将名为 eventName
的数据 params
传递给了JS。
提示:在 DataToJSPresenter
中我们实现了 (NSArray<NSString *> *)supportedEvents
方法,该方法用于指定能够发送给JS的事件名,所以发送给JS的 eventName
一定要在这个方法中进行配置否则无法发送。
实现Native到JS的通信所需要的步骤
接下来我们来总结一下,要实现Native到JS的通信所需要的步骤:
- 首先要实现
RCTEventEmitter <RCTBridgeModule>
; - 通过
RCTEventEmitter
的sendEventWithName
方法将数据传递给JS;
通过上述步骤,我们就可以将数据从Native发动到JS,那么如何在JS中来获取这些数据呢?
在JS中获取Native通过 RCTEventEmitter
传过来的数据
在JS中可以通过 NativeEventEmitter
来获取Native通过 RCTEventEmitter
传过来的数据,具体方法如下:
import {NativeEventEmitter} from 'react-native'; export default class CommonPage extends Component<Props> { constructor(props) { super(props); this.state = { data: "", result: null } } componentWillMount() { this.dataToJSPresenter = new NativeEventEmitter(NativeModules.DataToJSPresenter); this.dataToJSPresenter.addListener('testData', (e) => {// for iOS this.setState({ data: e.data }) }) } componentWillUnmount() { if (this.dataToJSPresenter){ this.dataToJSPresenter.removeListener('testData'); } } render() { return ( <View style={styles.container}> <Text style={styles.data}>收到Native的数据:{this.state.data}</Text> </View> ); } } 复制代码
在上述代码中,我们通过 NativeEventEmitter
的 addListener
添加了一个监听器,该监听器会监听Native发过来的名为 testData
的数据,这个 testData
要和上文中所讲的 eventName
要保持一致:
[self sendEventWithName:eventName body:params]; 复制代码
coding.imooc.com/lesson/89.h… 另外,记得在JS组件卸载的时候及时移除监听器。
以上就是在iOS中实现Native到JS通信的原理及方式,接下来我们来看一下实现JS到Native之间通信的原理及方式。
3. JS到Native的通信(JS发送数据给Native)
我们所封装的NativeModule就是给JS用的,它是一个JS到Native通信的桥梁,JS可以通过它来实现向Native的通信(传递数据,打开Native页面等),接下来我就来借助NativeModule来实现JS到Native的通信。
关于如何实现NativeModule大家可以学习参考 React Native原生模的封装
首先实现JSBridgeModule
首先我们需要实现 RCTBridgeModule
:
JSBridgeModule.h
/** * React Native JS Native通信 * Author: CrazyCodeBoy * 视频教程:https://coding.imooc.com/lesson/89.html#mid=2702 * GitHub:https://github.com/crazycodeboy * Email:crazycodeboy@gmail.com */ #import <React/RCTBridgeModule.h> @interface JSBridgeModule : NSObject <RCTBridgeModule> @end 复制代码
JSBridgeModule.m
/** * React Native JS Native通信 * Author: CrazyCodeBoy * 视频教程:https://coding.imooc.com/lesson/89.html#mid=2702 * GitHub:https://github.com/crazycodeboy * Email:crazycodeboy@gmail.com */ #import "JSBridgeModule.h" @implementation JSBridgeModule RCT_EXPORT_MODULE(); - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue();//让RN在主线程回调这些方法 } RCT_EXPORT_METHOD(sendMessage:(NSDictionary*)params){//接受RN发过来的消息 [[NSNotificationCenter defaultCenter] postNotificationName:@"sendMessage" object:params]; } @end 复制代码
代码解析
- 在
JSBridgeModule
中,我们实现了一个RCT_EXPORT_METHOD(sendMessage:(NSDictionary*)params)
方法,该方法主要用于暴露给JS调用,来传递数据params
给Native; - 当收到数据后,通过
NSNotificationCenter
以通知的形式将数据发送出去;
JS调用JSBridgeModule发送数据给Native
import {NativeModules} from 'react-native'; const JSBridge = NativeModules.JSBridgeModule; JSBridge.sendMessage({text: this.text}) 复制代码
通过上述代码我就可以将一个Map类型的数据 {text: this.text}
传递给Native。
4. JS发送数据给Native,然后Native回传数据给JS
通过上文所讲的 JS到Native的通信(JS发送数据给Native)
,我们已经实现了JS到Native的通信,当时我们借助的是 JSBridgeModule
,其实它的功能还不局限于此,借助它我们还可以实现Native到JS的数据回传。
在Native的实现
在 JSBridgeModule
中添加如下方法:
RCT_EXPORT_METHOD(doAdd:(NSInteger )num1 num2:(NSInteger )num2 resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { NSInteger result=num1+num2; resolve([NSString stringWithFormat:@"%ld",(long)result]);//回调JS } 复制代码
上述代码暴露给了JS一个简单的两个整数之间的加法运算,并将运算结果回传给JS,在这里我们用的是 RCTPromiseResolveBlock
与 RCTPromiseRejectBlock
两种类型的回调,分别代表成功和失败。
在JS中的实现
import {NativeModules} from 'react-native'; const JSBridge = NativeModules.JSBridgeModule; JSBridge.doAdd(parseInt(this.num1), parseInt(this.num2)).then(e => { this.setState({ result: e }) }) 复制代码
在JS中我们通过 JSBridge.doAdd
方法将两个整数 num1
与 num2
传递给了Native,然后通过 then
来监听回传结果,整个过程采用了 Promise
的链式调用方式。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 现有Android项目中集成Flutter/Flutter混合开发实战(一)
- Flutter 混合开发实战问题记录(四)编译运行时问题的一些总结
- Flutter 混合开发实战问题记录(三)打包并上传flutter aar 到maven
- 《React Native 精解与实战》书籍连载「iOS 平台与 React Native 混合开发」
- 《React Native 精解与实战》书籍连载「Android 平台与 React Native 混合开发」
- Flutter混合开发小记
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。