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

RN 擁有畫(huà)UI的跨平臺(tái)能力,主要是加入Virtual DOM編程模型,該方法一方面可以照顧到JS開(kāi)發(fā)者在html DOM的部分傳承, 讓JS 開(kāi)發(fā)者可以用類(lèi)似DOM編程模型就可以開(kāi)發(fā)原生APP , 另一方面則可以讓Virtual DOM適配實(shí)現(xiàn)到各個(gè)平臺(tái),實(shí)現(xiàn)跨平臺(tái)的能力
JS與Native模塊之間通信,主要有三種方法:
- 使用回調(diào)函數(shù)Callback,它提供了一個(gè)函數(shù)來(lái)把返回值傳回給JavaScript。
- 使用Promise來(lái)實(shí)現(xiàn)。
- 原生模塊向JavaScript發(fā)送事件。
JS調(diào)用Native
js調(diào)用原生功能模塊需要用到RN模塊NativeModules并獲取到native的指定module
import { NativeModules } from 'react-native'
var jsToNativeEmitter = NativeModules.KJSToNativeEmitter
js調(diào)用原生組件需要用到RN模塊requireNativeComponent并獲取到native的指定組件
import { requireNativeComponent } from 'react-native'
let RTCView = requireNativeComponent('RNCustomView', RNCustomView, {})
功能模塊和組件的需要在Native中先聲明定義.如下:
JS調(diào)用Native之iOS
RCTBridgeModule橋接模塊,管理JS和OC交互, 一個(gè)“原生模塊”就是一個(gè)實(shí)現(xiàn)了“RCTBridgeModule”協(xié)議的 Objective-C 類(lèi),很重要!!
類(lèi)名:RCT_EXPORT_MODULE 標(biāo)記宏
常量:constantsToExport. 導(dǎo)出常量給js
方法:RCT_EXPORT_METHOD 導(dǎo)出方法
...等等
模塊的定義:
RCT_EXPORT_METHOD:原生方法導(dǎo)出,生成對(duì)應(yīng)js方法,供JS調(diào)用.很重要!一般通過(guò)這個(gè)宏定義的路由.但是回調(diào)不帶有屬性傳遞!!!
把callBack傳回給 JavaScript
typedef void (^RCTResponseSenderBlock)(NSArray *response);
typedef void (^RCTResponseErrorBlock)(NSError *error);
把Promise對(duì)象傳回給 JavaScript
typedef void (^RCTPromiseResolveBlock)(id result);
typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError *error);
封裝組件的定義:
繼承RCTViewManager
實(shí)現(xiàn)view的定義
屬性:RCT_EXPORT_VIEW_PROPERTY。通過(guò)該宏完成屬性的映射和導(dǎo)出
自定義屬性:RCT_CUSTOM_VIEW_PROPERTY
事件導(dǎo)出:RCTBubblingEventBlock 通過(guò)屬性實(shí)現(xiàn)RCT_EXPORT_VIEW_PROPERTY(onXXX, RCTBubblingEventBlock)
JS調(diào)用Native之Android
類(lèi)名:需要實(shí)現(xiàn)方法public String getName()
常量: 需要實(shí)現(xiàn)public Map<String, Object> getConstants()
方法:@ReactMethod
模塊的定義:
需要在createNativeModules中聲明
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new KJSToNativeEmitter(reactContext));
}
封裝組件的定義:
需要實(shí)現(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調(diào)用JS
native調(diào)用原生分為兩種:被動(dòng)和主動(dòng)
被動(dòng):通過(guò)js調(diào)native返回callBack或Promise的方式
主動(dòng):通過(guò)RCTDeviceEventEmitter強(qiáng)制發(fā)起事件
js調(diào)用native需要用到RN中的NativeEventEmitter和NativeModules模塊,并獲取到原生指定的模塊
import { NativeEventEmitter, NativeModules } from 'react-native'
var nativeBridge = NativeModules.KNativeToJSEmitter //未定義module 就是你的類(lèi)名
const NativeModule = new NativeEventEmitter(nativeBridge)
componentDidMount(){
this.listener = RCTDeviceEventEmitter.addListener('通知名稱(chēng)',(value)=>{
// 接受到通知后的處理
})
}
componentWillUnmount(){
// 移除 一定要寫(xiě)
this.listener.remove()
}
Native調(diào)用JS之iOS:
繼承RCTEventEmitter,并實(shí)現(xiàn)RCTBridgeModule協(xié)議
RCT_EXPORT_MODULE(xxx);指定module名
///指定module名,不傳入就是類(lèi)名
RCT_EXPORT_MODULE();
#pragma mark - 重寫(xiě)父類(lèi)方法
///返回所有原生端發(fā)往js端的消息名字
- (NSArray<NSString *> *)supportedEvents
{
return EventEmitterNames;
}
//發(fā)起事件
[self sendEventWithName:emitterName body:object];
Native調(diào)用JS之Android:
需要獲取到當(dāng)前的ReactContext,并通過(guò)它來(lái)發(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);
}
}
總結(jié)
對(duì)于大多數(shù)app開(kāi)發(fā)者來(lái)說(shuō),ReactNative沒(méi)有想象中的難,但也有不少坑.個(gè)人覺(jué)得RN不宜覆蓋整個(gè)app,適用于app內(nèi)某些活動(dòng)頁(yè), 使用時(shí)盡量少用原生層次自定義的組件,可以用js來(lái)封裝基礎(chǔ)組件!這樣子在版本迭代的時(shí)候會(huì)輕松點(diǎn).
js調(diào)用native統(tǒng)一入口,定個(gè)規(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:事件類(lèi)型
msg:傳遞的具體消息 類(lèi)似路由
附:
React-Native官方安裝教程:https://reactnative.cn/docs/getting-started.html
@ReactMethod注明的方法中 native 與 js類(lèi)型之間關(guān)系
js與iOS:
string (NSString)
number (NSInteger, float, double, CGFloat, NSNumber)
boolean (BOOL, NSNumber)
array (NSArray) 可包含本列表中任意類(lèi)型
object (NSDictionary) 可包含 string 類(lèi)型的鍵和本列表中任意類(lèi)型的值
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)