基本調(diào)用方法
1.創(chuàng)建原生代碼,實(shí)現(xiàn)代理
- 在CalendarManager.h文件中
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTLog.h>
NS_ASSUME_NONNULL_BEGIN
@interface CalendarManager : NSObject<RCTBridgeModule>
@end
NS_ASSUME_NONNULL_END
- 在CalendarManager.m中
#import "CalendarManager.h"
@implementation CalendarManager
/*
RCT_EXPORT_MODULE()宏。這個(gè)宏也可以添加一個(gè)參數(shù)用來(lái)指定在 JavaScript中訪問(wèn)這個(gè)模塊的名字峦萎。如果你不指定糟袁,默認(rèn)就會(huì)使用這個(gè)Objective-C 類的名字掸哑。如果類名以 RCT 開(kāi)頭蒸辆,則 JavaScript 端引入的模塊名會(huì)自動(dòng)移除這個(gè)前綴跟磨。
*/
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
NSLog(@"Pretending to create an event %@ at %@", name, location);
RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
}
@end
- 在React-native調(diào)用
import React, {
Component
} from 'react';
import {
NativeModules,
Button,
Alert,
SafeAreaView
} from 'react-native';
const CalendarManager = NativeModules.CalendarManager;
export default class IScrolledDown extends Component {
onclickAction() {
Alert.alert('調(diào)用原生');
CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey');
}
render() {
return (
<SafeAreaView>
<Button onPress={this.onclickAction} title="點(diǎn)我"></Button>
</SafeAreaView>
);
}
}
支持的類型
RCT_EXPORT_METHOD 支持所有標(biāo)準(zhǔn) JSON 類型定罢,包括:
- string (NSString)
- number (NSInteger, float, double, CGFloat, NSNumber)
- boolean (BOOL, NSNumber)
- array (NSArray) 可包含本列表中任意類型
- object (NSDictionary) 可包含 string 類型的鍵和本列表中任意類型的值
- function (RCTResponseSenderBlock)
類型轉(zhuǎn)換
- 在iOS中通過(guò)RCTConvert類轉(zhuǎn)換
#import <React/RCTConvert.h>
RCT_EXPORT_METHOD(addEvent:(NSString *)name details:(NSDictionary *)details)
{
NSString *location = [RCTConvert NSString:details[@"location"]];
NSDate *time = [RCTConvert NSDate:details[@"time"]];
...
}
- 在JS中
CalendarManager.addEvent('Birthday Party', {
location: '4 Privet Drive, Surrey',
time: date.getTime(),
description: '...',
});
帶有回調(diào)函數(shù)
- 在iOS原生中
RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback)
{
NSArray *events = ...
callback(@[[NSNull null], events]);
}
RCTResponseSenderBlock只接受一個(gè)參數(shù)——傳遞給 JavaScript 回調(diào)函數(shù)的參數(shù)數(shù)組糠溜。在上面這個(gè)例子里我們用 Node.js 的常用習(xí)慣:第一個(gè)參數(shù)是一個(gè)錯(cuò)誤對(duì)象(沒(méi)有發(fā)生錯(cuò)誤的時(shí)候?yàn)?null)淳玩,而剩下的部分是函數(shù)的返回值。
- 在js中
CalendarManager.findEvents((error, events) => {
if (error) {
console.error(error);
} else {
this.setState({events: events});
}
});
原生模塊通常只應(yīng)調(diào)用回調(diào)函數(shù)一次非竿。但是蜕着,它可以保存 callback 并在將來(lái)調(diào)用。這在封裝那些通過(guò)“委托函數(shù)”來(lái)獲得返回值的 iOS API 時(shí)最為常見(jiàn)红柱。
RCTAlertManager
中就屬于這種情況
Promises
- 在原生中
RCT_REMAP_METHOD(findEvents,
findEventsWithResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSArray *events = ...
if (events) {
resolve(events);
} else {
NSError *error = ...
reject(@"no_events", @"There were no events", error);
}
}
- 在js中
async function updateEvents() {
try {
const events = await CalendarManager.findEvents();
this.setState({events});
} catch (e) {
console.error(e);
}
}
updateEvents();
現(xiàn)在 JavaScript 端的方法會(huì)返回一個(gè) Promise承匣。這樣你就可以在一個(gè)聲明了async的異步函數(shù)內(nèi)使用await關(guān)鍵字來(lái)調(diào)用,并等待其結(jié)果返回锤悄。(雖然這樣寫(xiě)著看起來(lái)像同步操作韧骗,但實(shí)際仍然是異步的,并不會(huì)阻塞執(zhí)行來(lái)等待)
多線程
- CalendarManager所有方法都在主線程
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
- CalendarManager所有方法在另一個(gè)線程
- (dispatch_queue_t)methodQueue
{
return dispatch_queue_create("com.facebook.React.AsyncLocalStorageQueue", DISPATCH_QUEUE_SERIAL);
}
- CalendarManager中只有一個(gè)方法在多線程
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(@[...]);
});
}
methodQueue方法會(huì)在模塊被初始化的時(shí)候被執(zhí)行一次零聚,然后會(huì)被 React Native 的橋接機(jī)制保存下來(lái)袍暴,所以你不需要自己保存隊(duì)列的引用,除非你希望在模塊的其它地方使用它
導(dǎo)出常量
- 原生
- (NSDictionary *)constantsToExport
{
return @{ @"firstDayOfTheWeek": @"Monday" };
}
- js中
console.log(CalendarManager.firstDayOfTheWeek);
但是注意這個(gè)常量?jī)H僅在初始化的時(shí)候?qū)С隽艘淮瘟ブⅲ约词鼓阍谶\(yùn)行期間改變constantToExport返回的值容诬,也不會(huì)影響到 JavaScript 環(huán)境下所得到的結(jié)果。
給 JavaScript 端發(fā)送事件
即使沒(méi)有被 JavaScript 調(diào)用沿腰,原生模塊也可以給 JavaScript 發(fā)送事件通知。最好的方法是繼承RCTEventEmitter狈定,實(shí)現(xiàn)suppportEvents方法并調(diào)用self sendEventWithName:颂龙。
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface CalendarManager : RCTEventEmitter <RCTBridgeModule>
@end
// CalendarManager.m
#import "CalendarManager.h"
@implementation CalendarManager
RCT_EXPORT_MODULE();
- (NSArray<NSString *> *)supportedEvents
{
return @[@"EventReminder"];
}
- (void)calendarEventReminderReceived:(NSNotification *)notification
{
NSString *eventName = notification.userInfo[@"name"];
[self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
}
@end
JavaScript 端的代碼可以創(chuàng)建一個(gè)包含你的模塊的NativeEventEmitter實(shí)例來(lái)訂閱這些事件
import { NativeEventEmitter, NativeModules } from 'react-native';
const { CalendarManager } = NativeModules;
const calendarManagerEmitter = new NativeEventEmitter(CalendarManager);
const subscription = calendarManagerEmitter.addListener(
'EventReminder',
(reminder) => console.log(reminder.name)
);
...
// 別忘了取消訂閱习蓬,通常在componentWillUnmount生命周期方法中實(shí)現(xiàn)。
subscription.remove();