JS調用Native
我們知道,在React Native中,經常需要JS和native交互,在項目RN化的初期,我們在通過JS端編寫完頁面后,往往還需要調用Native端的方法或屬性,來實現一些邏輯交互.
這里我們就介紹一下,JS端調用Native方法的幾種情況
異步方法調用
React Native提供了組件(Module)的概念,Native通過遵守協議<RCTBridgeModule>
,實現RCT_EXPORT_MODULE()
方法來輸出組件.
需要注意的是,該類內的屬性和方法,模式是不會輸出到JS端的,必須單獨聲明.
輸出方法使用RCT_EXPORT_METHOD()
來實現.默認在異步線程調用,可以通過- (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); }
去回歸主線程.
如果想拿到返回結果,可以使用callback的方式,
RCT_EXPORT_METHOD(getCacheSize:(RCTResponseSenderBlock)callback){
callback(@[[NSNull null], @(cacheSize)]);
}
在JS的使用為
import { NativeModules } from 'react-native'
const SettingTool = NativeModules.RNSettingTool
SettingTool.getCacheSize((error, events) => {
if (error) {
console.error(error)
} else {
this.setState({cacheSize: events.toFixed(2)})
}
})
這種方式,每次在使用時都需要實現callback的函數,并且無法做同步調用
同步方法調用
RN提供了一個同步調用的方法RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD()
,直接在方法內return 返回值,在前端通過appVersion = PXUserInfoTool.appVersion()
的方式來獲得,下面我們討論一下這個方法的內部實現.
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD()
通過宏定義我們可以看到,同步輸出方法,最終是生成了一個RCTMethodInfo并且返回.我們看一下RCTMethodInfo,是一個結構體定義.
typedef struct RCTMethodInfo {
const char *const jsName;
const char *const objcName;
const BOOL isSync;
} RCTMethodInfo;
繼續通過RCTMethodInfo內部的isSync參數的使用情況,我們知道在- (id)invokeWithBridge:(RCTBridge *)bridge module:(id)module arguments:(NSArray *)arguments
方法內部用到了.
這個方法是,JS端在調用Native代碼時觸發的方法,繼續查看.
在JS端的實現是在NativeModules.js
內部,在function genMethod(moduleID: number, methodID: number, type: MethodType)
內通過判斷三種調用方式實現的.
方法調用分為: Promise, sync, 普通方法.
sync在客戶端的調用,是在JSCExecutor.cpp
內的JSValueRef JSCExecutor::nativeCallSyncHook( size_t argumentCount, const JSValueRef arguments[])
方法,
最終調用到了RCTNativeModule.mm
內的MethodCallResult RCTNativeModule::callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic &¶ms)
方法,
進一步,RCTModuleMethod.mm
內的- (id)invokeWithBridge:(RCTBridge *)bridge module:(id)module arguments:(NSArray *)arguments
方法.
- (id)invokeWithBridge:(RCTBridge *)bridge
module:(id)module
arguments:(NSArray *)arguments
{
...
if (_methodInfo->isSync) {
void *returnValue;
[_invocation getReturnValue:&returnValue];
return (__bridge id)returnValue;
}
}
內部調用了invocation getReturnValue:&returnValue
,在這里會同步等待invocation的執行結果,阻塞等待,拿到返回值時,才繼續執行。
全部都是同步執行的,并且注意手動指定methodQueue對sync方法無效。