React-Native分析
RN的优点:
- 页面热更新
- RN页面不需要移动端发版本
- 纯web思维,开发速度快,且体验优于h5,
- 第三方插件也比较多
- 部分功能代码实现一端开发多端共用(“Learn once,write anywhere”?)
RN的缺点:
- 下载包体变大,多了一个RN的sdk
- 调试相对麻烦
- 兼容性问题放大了
- 开发要求高了,js、native都需要了解
数据的传递(交互):
RN 拥有画UI的跨平台能力,主要是加入Virtual DOM编程模型,该方法一方面可以照顾到JS开发者在html DOM的部分传承, 让JS 开发者可以用类似DOM编程模型就可以开发原生APP , 另一方面则可以让Virtual DOM适配实现到各个平台,实现跨平台的能力
JS与Native模块之间通信,主要有三种方法:
- 使用回调函数Callback,它提供了一个函数来把返回值传回给JavaScript。
- 使用Promise来实现。
- 原生模块向JavaScript发送事件。
JS调用Native
js调用原生功能模块需要用到RN模块NativeModules
并获取到native的指定module
import { NativeModules } from 'react-native'
var jsToNativeEmitter = NativeModules.KJSToNativeEmitter
js调用原生组件需要用到RN模块requireNativeComponent
并获取到native的指定组件
import { requireNativeComponent } from 'react-native'
let RTCView = requireNativeComponent('RNCustomView', RNCustomView, {})
功能模块和组件的需要在Native中先声明定义.如下:
JS调用Native之iOS
RCTBridgeModule
桥接模块,管理JS和OC交互, 一个“原生模块”就是一个实现了“RCTBridgeModule”协议的 Objective-C 类,很重要!!
类名:RCT_EXPORT_MODULE
标记宏
常量:constantsToExport
. 导出常量给js
方法:RCT_EXPORT_METHOD
导出方法
...等等
模块的定义:
RCT_EXPORT_METHOD:原生方法导出,生成对应js方法,供JS调用.很重要!一般通过这个宏定义的路由.但是回调不带有属性传递!!!
把callBack传回给 JavaScript
typedef void (^RCTResponseSenderBlock)(NSArray *response);
typedef void (^RCTResponseErrorBlock)(NSError *error);
把Promise对象传回给 JavaScript
typedef void (^RCTPromiseResolveBlock)(id result);
typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError *error);
封装组件的定义:
继承RCTViewManager
实现view的定义
属性:RCT_EXPORT_VIEW_PROPERTY
。通过该宏完成属性的映射和导出
自定义属性:RCT_CUSTOM_VIEW_PROPERTY
事件导出:RCTBubblingEventBlock
通过属性实现RCT_EXPORT_VIEW_PROPERTY(onXXX, RCTBubblingEventBlock)
JS调用Native之Android
类名:需要实现方法public String getName()
常量: 需要实现public Map
方法:@ReactMethod
模块的定义:
需要在createNativeModules
中声明
public List createNativeModules(ReactApplicationContext reactContext) {
return Arrays.asList(new KJSToNativeEmitter(reactContext));
}
封装组件的定义:
需要实现createViewInstance(ThemedReactContext reactContext)
需要在createViewManagers
中声明
需要继承ViewManager
或BaseViewManager
或SimpleViewManager
属性:@ReactProp
和@ReactPropGroup
@Override
public List createViewManagers(ReactApplicationContext reactContext) {
// return Collections.emptyList();
return Arrays.asList(new RNCustomViewManager());
}
Native调用JS
native调用原生分为两种:被动和主动
被动:通过js调native返回callBack或Promise的方式
主动:通过RCTDeviceEventEmitter
强制发起事件
js调用native需要用到RN中的NativeEventEmitter
和NativeModules
模块,并获取到原生指定的模块
import { NativeEventEmitter, NativeModules } from 'react-native'
var nativeBridge = NativeModules.KNativeToJSEmitter //未定义module 就是你的类名
const NativeModule = new NativeEventEmitter(nativeBridge)
componentDidMount(){
this.listener = RCTDeviceEventEmitter.addListener('通知名称',(value)=>{
// 接受到通知后的处理
})
}
componentWillUnmount(){
// 移除 一定要写
this.listener.remove()
}
Native调用JS之iOS:
继承RCTEventEmitter
,并实现RCTBridgeModule协议
RCT_EXPORT_MODULE(xxx);
指定module名
///指定module名,不传入就是类名
RCT_EXPORT_MODULE();
#pragma mark - 重写父类方法
///返回所有原生端发往js端的消息名字
- (NSArray *)supportedEvents
{
return EventEmitterNames;
}
//发起事件
[self sendEventWithName:emitterName body:object];
Native调用JS之Android:
需要获取到当前的ReactContext
,并通过它来发事件
//发消息
private static final String KEventName = "KNativeToJSEmitter";
public void sendEvent(ReactContext reactContext,
@Nullable WritableMap params) {
if (reactContext==null) {
Log.i(TAG, "reactContext==null");
}else{
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(KEventName, params);
}
}
总结
对于大多数app开发者来说,ReactNative没有想象中的难,但也有不少坑.个人觉得RN不宜覆盖整个app,适用于app内某些活动页, 使用时尽量少用原生层次自定义的组件,可以用js来封装基础组件!这样子在版本迭代的时候会轻松点.
js调用native统一入口,定个规则
RCT_EXPORT_METHOD(sendMsg:(NSInteger)msgType
message:(NSString *)msg)
resolver:(RCTPromiseResolveBlock)resolver
rejecter:(RCTPromiseRejectBlock)reject){
}
@ReactMethod
public void sendMsg(
int msgType,
String msg,
Promise promise)
msgType:事件类型
msg:传递的具体消息 类似路由
附:
React-Native官方安装教程:https://reactnative.cn/docs/getting-started.html
@ReactMethod注明的方法中 native 与 js类型之间关系
js与iOS:
string (NSString)
number (NSInteger, float, double, CGFloat, NSNumber)
boolean (BOOL, NSNumber)
array (NSArray) 可包含本列表中任意类型
object (NSDictionary) 可包含 string 类型的键和本列表中任意类型的值
function (RCTResponseSenderBlock)
Android与js:
Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array
```![![5bc6abb6e4b0534c9c063dc2.png](https://upload-images.jianshu.io/upload_images/2906485-650c96fcb9b89fd0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
](https://upload-images.jianshu.io/upload_images/2906485-59f348c9fb8a682a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)