React-Native分析
RN的優(yōu)點:
- 頁面熱更新
- RN頁面不需要移動端發(fā)版本
- 純web思維,開發(fā)速度快,且體驗優(yōu)于h5,
- 第三方插件也比較多
- 部分功能代碼實現(xiàn)一端開發(fā)多端共用(“Learn once,write anywhere”?)
RN的缺點:
- 下載包體變大,多了一個RN的sdk
- 調試相對麻煩
- 兼容性問題放大了
- 開發(fā)要求高了,js、native都需要了解
數(shù)據(jù)的傳遞(交互):

RN 擁有畫UI的跨平臺能力,主要是加入Virtual DOM編程模型,該方法一方面可以照顧到JS開發(fā)者在html DOM的部分傳承, 讓JS 開發(fā)者可以用類似DOM編程模型就可以開發(fā)原生APP , 另一方面則可以讓Virtual DOM適配實現(xiàn)到各個平臺,實現(xiàn)跨平臺的能力
JS與Native模塊之間通信,主要有三種方法:
- 使用回調函數(shù)Callback,它提供了一個函數(shù)來把返回值傳回給JavaScript。
- 使用Promise來實現(xiàn)。
- 原生模塊向JavaScript發(fā)送事件。
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交互, 一個“原生模塊”就是一個實現(xiàn)了“RCTBridgeModule”協(xié)議的 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
實現(xiàn)view的定義
屬性:RCT_EXPORT_VIEW_PROPERTY。通過該宏完成屬性的映射和導出
自定義屬性:RCT_CUSTOM_VIEW_PROPERTY
事件導出:RCTBubblingEventBlock 通過屬性實現(xiàn)RCT_EXPORT_VIEW_PROPERTY(onXXX, RCTBubblingEventBlock)
JS調用Native之Android
類名:需要實現(xiàn)方法public String getName()
常量: 需要實現(xiàn)public Map<String, Object> getConstants()
方法:@ReactMethod
模塊的定義:
需要在createNativeModules中聲明
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new KJSToNativeEmitter(reactContext));
}
封裝組件的定義:
需要實現(xiàn)createViewInstance(ThemedReactContext reactContext)
需要在createViewManagers中聲明
需要繼承ViewManager或BaseViewManager或SimpleViewManager
屬性:@ReactProp和@ReactPropGroup
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
// return Collections.emptyList();
return Arrays.<ViewManager>asList(new RNCustomViewManager());
}
Native調用JS
native調用原生分為兩種:被動和主動
被動:通過js調native返回callBack或Promise的方式
主動:通過RCTDeviceEventEmitter強制發(fā)起事件
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,并實現(xiàn)RCTBridgeModule協(xié)議
RCT_EXPORT_MODULE(xxx);指定module名
///指定module名,不傳入就是類名
RCT_EXPORT_MODULE();
#pragma mark - 重寫父類方法
///返回所有原生端發(fā)往js端的消息名字
- (NSArray<NSString *> *)supportedEvents
{
return EventEmitterNames;
}
//發(fā)起事件
[self sendEventWithName:emitterName body:object];
Native調用JS之Android:
需要獲取到當前的ReactContext,并通過它來發(fā)事件
//發(fā)消息
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);
}
}
總結
對于大多數(shù)app開發(fā)者來說,ReactNative沒有想象中的難,但也有不少坑.個人覺得RN不宜覆蓋整個app,適用于app內某些活動頁, 使用時盡量少用原生層次自定義的組件,可以用js來封裝基礎組件!這樣子在版本迭代的時候會輕松點.
js調用native統(tǒng)一入口,定個規(guī)則
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
```
](https://upload-images.jianshu.io/upload_images/2906485-59f348c9fb8a682a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)