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;
React Native iOS混合开发实战教程

1. 初始化RN时Native向JS传递数据

React Native iOS混合开发实战教程

在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)

React Native iOS混合开发实战教程

在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
复制代码

在上述方法中,我们通过 RCTEventEmittersendEventWithName 方法将名为 eventName 的数据 params 传递给了JS。

提示:在 DataToJSPresenter 中我们实现了 (NSArray<NSString *> *)supportedEvents 方法,该方法用于指定能够发送给JS的事件名,所以发送给JS的 eventName 一定要在这个方法中进行配置否则无法发送。

实现Native到JS的通信所需要的步骤

接下来我们来总结一下,要实现Native到JS的通信所需要的步骤:

  • 首先要实现 RCTEventEmitter <RCTBridgeModule>
  • 通过 RCTEventEmittersendEventWithName 方法将数据传递给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>
        );
    }
}
复制代码

在上述代码中,我们通过 NativeEventEmitteraddListener 添加了一个监听器,该监听器会监听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)

React Native iOS混合开发实战教程

我们所封装的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
复制代码

代码解析

  1. JSBridgeModule 中,我们实现了一个 RCT_EXPORT_METHOD(sendMessage:(NSDictionary*)params) 方法,该方法主要用于暴露给JS调用,来传递数据 params 给Native;
  2. 当收到数据后,通过 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

React Native iOS混合开发实战教程

通过上文所讲的 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,在这里我们用的是 RCTPromiseResolveBlockRCTPromiseRejectBlock 两种类型的回调,分别代表成功和失败。

在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 方法将两个整数 num1num2 传递给了Native,然后通过 then 来监听回传结果,整个过程采用了 Promise 的链式调用方式。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

联盟

联盟

里德•霍夫曼、本•卡斯诺查、克里斯•叶 / 路蒙佳 / 中信出版社 / 2015-2-5 / 39.00元

在充满变化的世界,联盟潜在的合伙人 将不确定的行业转变为可掌控的职业生涯 与世界紧密连接,开创精彩的事业与未来 终生效忠于一家公司已经成为历史,我们正在经历的自由雇佣制——将员工看作自由人——无法建立创新所需的高度信任与合作的关系。 互联网时代,企业如何用全新的人才策略定义员工的忠诚?未来职业成功的秘诀是什么? 《联盟》提供了一种使雇主与员工之间从商业交易转变为互惠关......一起来看看 《联盟》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具