JS調(diào)用Native
我們知道,在React Native中,經(jīng)常需要JS和native交互,在項目RN化的初期,我們在通過JS端編寫完頁面后,往往還需要調(diào)用Native端的方法或?qū)傩?來實現(xiàn)一些邏輯交互.
這里我們就介紹一下,JS端調(diào)用Native方法的幾種情況
異步方法調(diào)用
React Native提供了組件(Module)的概念,Native通過遵守協(xié)議<RCTBridgeModule>
,實現(xiàn)RCT_EXPORT_MODULE()
方法來輸出組件.
需要注意的是,該類內(nèi)的屬性和方法,模式是不會輸出到JS端的,必須單獨聲明.
輸出方法使用RCT_EXPORT_METHOD()
來實現(xiàn).默認在異步線程調(diào)用,可以通過- (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); }
去回歸主線程.
如果想拿到返回結(jié)果,可以使用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)})
}
})
這種方式,每次在使用時都需要實現(xiàn)callback的函數(shù),并且無法做同步調(diào)用
同步方法調(diào)用
RN提供了一個同步調(diào)用的方法RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD()
,直接在方法內(nèi)return 返回值,在前端通過appVersion = PXUserInfoTool.appVersion()
的方式來獲得,下面我們討論一下這個方法的內(nèi)部實現(xiàn).
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD()
通過宏定義我們可以看到,同步輸出方法,最終是生成了一個RCTMethodInfo并且返回.我們看一下RCTMethodInfo,是一個結(jié)構(gòu)體定義.
typedef struct RCTMethodInfo {
const char *const jsName;
const char *const objcName;
const BOOL isSync;
} RCTMethodInfo;
繼續(xù)通過RCTMethodInfo內(nèi)部的isSync參數(shù)的使用情況,我們知道在- (id)invokeWithBridge:(RCTBridge *)bridge module:(id)module arguments:(NSArray *)arguments
方法內(nèi)部用到了.
這個方法是,JS端在調(diào)用Native代碼時觸發(fā)的方法,繼續(xù)查看.
在JS端的實現(xiàn)是在NativeModules.js
內(nèi)部,在function genMethod(moduleID: number, methodID: number, type: MethodType)
內(nèi)通過判斷三種調(diào)用方式實現(xiàn)的.
方法調(diào)用分為: Promise, sync, 普通方法.
sync在客戶端的調(diào)用,是在JSCExecutor.cpp
內(nèi)的JSValueRef JSCExecutor::nativeCallSyncHook( size_t argumentCount, const JSValueRef arguments[])
方法,
最終調(diào)用到了RCTNativeModule.mm
內(nèi)的MethodCallResult RCTNativeModule::callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic &¶ms)
方法,
進一步,RCTModuleMethod.mm
內(nèi)的- (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;
}
}
內(nèi)部調(diào)用了invocation getReturnValue:&returnValue
碉京,在這里會同步等待invocation的執(zhí)行結(jié)果背传,阻塞等待,拿到返回值時绽慈,才繼續(xù)執(zhí)行意敛。
全部都是同步執(zhí)行的,并且注意手動指定methodQueue對sync方法無效牧挣。