本文要講的交互場(chǎng)景是JS調(diào)用原生方法拗盒,最后由原生方法將結(jié)果回調(diào)到JS里面闸与。
react-native是在原生的基礎(chǔ)上浩峡,將接口調(diào)用統(tǒng)一為js可岂。也就是說,react-native調(diào)起原生的能力非常重要翰灾。
本文基于react-native 0.44.3
1,引入頭文件
#import <React/RCTBridgeModule.h>
2缕粹,遵守協(xié)議
@interface BaseNativeModule :? NSObject? <RCTBridgeModule>
3稚茅,導(dǎo)出模塊
@implementation? BaseNativeModule
RCT_EXPORT_MODULE( moduleName ); //用于導(dǎo)出模塊,可以設(shè)置導(dǎo)出的模塊名致开,默認(rèn)就是類名峰锁。
@end
4,導(dǎo)出方法:
RCT_EXPORT_METHOD(addEvent:(NSString*)name location:(NSString*)location)
{
//在js控制臺(tái)上打印log信息双戳。
RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
}
這個(gè)方法是一個(gè)實(shí)例方法虹蒋。
5,js端調(diào)用飒货。
import? { NativeModules } from 'react-native
NativeModules.XXX.addEvent( param1, param2 );
需要注意魄衅,jsbundle加載需要一個(gè)js線程,在jsbundle加載的時(shí)候塘辅,react-native會(huì)去配置NativeModules晃虫,它是一個(gè)對(duì)象,或者看成是一個(gè)map扣墩,key就是模塊名哲银,value就是原生的對(duì)象。一個(gè)key對(duì)應(yīng)的原生對(duì)象只有一個(gè)呻惕,也就是說無論在RN頁面的哪個(gè)地方調(diào)用這個(gè)原生模塊荆责,實(shí)際調(diào)用的是同一個(gè)對(duì)象,需要考慮對(duì)象狀態(tài)的問題亚脆。
6做院,js回調(diào)
橋接到Javascript的方法返回值類型必須是void。React Native的橋接操作是異步的濒持,在queue里面異步執(zhí)行键耕,所以如果要返回結(jié)果給Javascript,就必須通過回調(diào)或者觸發(fā)事件來進(jìn)行柑营。這里講的是回調(diào)屈雄。回調(diào)對(duì)應(yīng)于iOS端就是通過block來回調(diào)的官套。
js回調(diào)的特點(diǎn)棚亩,發(fā)起方是js,必須是js端先發(fā)起虏杰,然后由native方回調(diào)結(jié)果到j(luò)s端處理讥蟆。
6.1 RCTResponseSenderBlock
這個(gè)block接受一個(gè)數(shù)組參數(shù),數(shù)組里面有兩個(gè)元素纺阔,第一個(gè)參數(shù)用于表示錯(cuò)誤信息瘸彤,第二個(gè)參數(shù)可以是一個(gè)數(shù)組,也可以是一個(gè)對(duì)象笛钝,總之第二個(gè)代表原生方法的返回結(jié)果质况,第一個(gè)代表獲取成功還是失敗愕宋。
6.2 Promise樣式的回調(diào)。一般用于js端try-catch結(jié)構(gòu)结榄,和Promise調(diào)用中贝。
RCTPromiseResolveBlock,對(duì)應(yīng)js里面的resolve臼朗。
RCTPromiseRejectBlock邻寿,對(duì)應(yīng)js里面的reject。
7视哑,多線程
js代碼的執(zhí)行是在js線程里面绣否,原生模塊的執(zhí)行默認(rèn)是在一個(gè)串行的GCD queue里面異步執(zhí)行的。對(duì)于原生模塊的執(zhí)行來說挡毅,默認(rèn)一個(gè)串行的GCD queue是不夠的蒜撮,我們有時(shí)候需要指定模塊所有任務(wù)執(zhí)行所在的queue。
這個(gè)可以通過重寫methodQueue的getter方法
?- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
此外跪呈,如果一個(gè)模塊里面的幾個(gè)任務(wù)段磨,個(gè)別任務(wù)需要在一個(gè)特殊的線程里面執(zhí)行,那么只去在任務(wù)執(zhí)行的邏輯里面耗绿,指定該任務(wù)執(zhí)行所在的線程苹支。
RCT_EXPORT_METHOD(doSomethingExpensive:(NSString *)param callback:(RCTResponseSenderBlock) callback)
{
? ? ? ? dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
????????// 在這里執(zhí)行長(zhǎng)時(shí)間的操作...
????????// 你可以在任何線程/隊(duì)列中執(zhí)行回調(diào)函數(shù)callback(@[...]); });
}
在模塊之間共享分發(fā)隊(duì)列:
?methodQueue方法會(huì)在模塊被初始化的時(shí)候被執(zhí)行一次,然后會(huì)被React Native的橋接機(jī)制保存下來缭乘,所以你不需要自己保存隊(duì)列的引用沐序,除非你希望在模塊的其它地方使用它琉用。但是堕绩,如果你希望在若干個(gè)模塊中共享同一個(gè)隊(duì)列,則需要自己保存并返回相同的隊(duì)列實(shí)例邑时;僅僅是返回相同名字的隊(duì)列是不行的奴紧。
8,參數(shù)類型轉(zhuǎn)換晶丘。
js與原生互相調(diào)用黍氮,除了方法簽名的不同,參數(shù)類型也是不同的浅浮,要把參數(shù)類型對(duì)應(yīng)起來沫浆。react-native框架本身做了一些轉(zhuǎn)換。包括下面這些:
string (NSString)
number ( NSInteger, float, double, CGFloat, NSNumber)
boolean (BOOL,NSNumber)
array (NSArray) 包含本列表中任意類型
object (NSDictionary) 包含string類型的鍵和本列表中任意類型的值
function (RCTResponseSenderBlock)
除此以外滚秩,任何RCTConvert類支持的的類型也都可以使用(參見RCTConvert了解更多信息)专执。RCTConvert還提供了一系列輔助函數(shù),用來接收一個(gè)JSON值并轉(zhuǎn)換到原生Objective-C類型或類郁油。