Nativne moduły iOS
Ta strona została przetłumaczona przez PageTurner AI (beta). Nie jest oficjalnie zatwierdzona przez projekt. Znalazłeś błąd? Zgłoś problem →
Ta strona została przetłumaczona przez PageTurner AI (beta). Nie jest oficjalnie zatwierdzona przez projekt. Znalazłeś błąd? Zgłoś problem →
Native Module i Native Components to nasze stabilne technologie używane w starszej architekturze. Zostaną one wycofane w przyszłości, gdy Nowa Architektura stanie się stabilna. Nowa Architektura wykorzystuje Turbo Native Module i Fabric Native Components, aby osiągnąć podobne rezultaty.
Witamy w przewodniku po nativnych modułach dla iOS. Zachęcamy do rozpoczęcia od lektury Wprowadzenia do nativnych modułów, które wyjaśnia podstawowe koncepcje.
Tworzenie natywnego modułu kalendarza
W poniższym przewodniku utworzysz nativny moduł CalendarModule, który umożliwi dostęp do kalendarza Apple'a z poziomu JavaScript. Na końcu będziesz mógł wywołać CalendarModule.createCalendarEvent('Dinner Party', 'My House'); z JavaScriptu, co uruchomi natywną metodę tworzącą wydarzenie w kalendarzu.
Konfiguracja
Aby rozpocząć, otwórz projekt iOS w swojej aplikacji React Native w Xcode. Projekt iOS znajdziesz tutaj w strukturze aplikacji React Native:

Zalecamy używanie Xcode do pisania kodu natywnego. Xcode jest stworzony do rozwoju na iOS i pomoże ci szybko rozwiązywać drobne błędy, takie jak składnia kodu.
Tworzenie własnych plików modułu natywnego
Pierwszym krokiem jest utworzenie głównych plików nagłówkowego i implementacyjnego dla naszego modułu. Stwórz nowy plik o nazwie RCTCalendarModule.h

i dodaj do niego następującą zawartość:
// RCTCalendarModule.h
#import <React/RCTBridgeModule.h>
@interface RCTCalendarModule : NSObject <RCTBridgeModule>
@end
Możesz użyć dowolnej nazwy pasującej do tworzonego modułu. Nadaj klasie nazwę RCTCalendarModule, ponieważ tworzysz moduł kalendarza. Ponieważ ObjC nie obsługuje przestrzeni nazw na poziomie języka (jak Java czy C++), przyjęło się dodawać prefiks do nazwy klasy. Może to być skrót nazwy aplikacji lub infrastruktury. RCT w tym przykładzie odnosi się do React.
Jak widać poniżej, klasa CalendarModule implementuje protokół RCTBridgeModule. Moduł natywny to klasa Objective-C implementująca protokół RCTBridgeModule.
Przejdźmy teraz do implementacji modułu. Utwórz odpowiadający plik implementacyjny używając klasy cocoa touch w Xcode, RCTCalendarModule.m, w tym samym folderze i umieść w nim następującą zawartość:
// RCTCalendarModule.m
#import "RCTCalendarModule.h"
@implementation RCTCalendarModule
// To export a module named RCTCalendarModule
RCT_EXPORT_MODULE();
@end
Nazwa modułu
Na razie twój natywny moduł RCTCalendarModule.m zawiera tylko makro RCT_EXPORT_MODULE, które eksportuje i rejestruje klasę modułu w React Native. Makro RCT_EXPORT_MODULE przyjmuje opcjonalny argument określający nazwę, pod którą moduł będzie dostępny w kodzie JavaScript.
Argument ten nie jest literałem stringowym. W poniższym przykładzie przekazano RCT_EXPORT_MODULE(CalendarModuleFoo), a nie RCT_EXPORT_MODULE("CalendarModuleFoo").
// To export a module named CalendarModuleFoo
RCT_EXPORT_MODULE(CalendarModuleFoo);
Moduł natywny może być następnie dostępny w JS w następujący sposób:
const {CalendarModuleFoo} = ReactNative.NativeModules;
Jeśli nie określisz nazwy, nazwa modułu w JavaScript będzie odpowiadać nazwie klasy Objective-C, z usuniętymi prefiksami "RCT" lub "RK".
Postępujmy zgodnie z poniższym przykładem i wywołajmy RCT_EXPORT_MODULE bez argumentów. W rezultacie moduł będzie dostępny w React Native pod nazwą CalendarModule, ponieważ jest to nazwa klasy Objective-C bez prefiksu RCT.
// Without passing in a name this will export the native module name as the Objective-C class name with “RCT” removed
RCT_EXPORT_MODULE();
Moduł natywny może być następnie dostępny w JS w następujący sposób:
const {CalendarModule} = ReactNative.NativeModules;
Eksportowanie natywnej metody do JavaScriptu
React Native nie udostępnia żadnych metod z natywnego modułu w JavaScript, chyba że zostanie to wyraźnie określone. Można to zrobić za pomocą makra RCT_EXPORT_METHOD. Metody zapisane w makrze RCT_EXPORT_METHOD są asynchroniczne, a ich typ zwracany to zawsze void. Aby przekazać wynik z metody RCT_EXPORT_METHOD do JavaScriptu, możesz użyć callbacków lub emitować zdarzenia (omówione później). Utwórzmy teraz metodę natywną dla naszego modułu CalendarModule używając makra RCT_EXPORT_METHOD. Nazwij ją createCalendarEvent() i na razie przyjmij argumenty name i location jako stringi. Opcje typów argumentów zostaną omówione wkrótce.
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)name location:(NSString *)location)
{
}
Należy pamiętać, że makro
RCT_EXPORT_METHODnie będzie wymagane w TurboModules, chyba że twoja metoda korzysta z konwersji argumentów RCT (patrz typy argumentów poniżej). Ostatecznie React Native usunieRCT_EXPORT_MACRO,, dlatego odradzamy używanieRCTConvert. Zamiast tego konwersję argumentów można przeprowadzić w ciele metody.
Zanim rozbudujesz funkcjonalność metody createCalendarEvent(), dodaj log konsolowy wewnątrz metody, aby potwierdzić jej wywołanie z JavaScript w twojej aplikacji React Native. Użyj API RCTLog z Reacta. Zaimportuj ten nagłówek na górze pliku, a następnie dodaj wywołanie loga.
#import <React/RCTLog.h>
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)name location:(NSString *)location)
{
RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
}
Metody synchroniczne
Możesz użyć RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD do tworzenia synchronicznych metod natywnych.
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getName)
{
return [[UIDevice currentDevice] name];
}
Typ zwracany przez tę metodę musi być typu obiektowego (id) i możliwy do serializacji do JSON. Oznacza to, że metoda może zwracać tylko nil lub wartości JSON (np. NSNumber, NSString, NSArray, NSDictionary).
Obecnie nie zalecamy używania metod synchronicznych, ponieważ ich wywoływanie może powodować znaczne spadki wydajności i wprowadzać błędy związane z wątkami w twoich modułach natywnych. Dodatkowo pamiętaj, że jeśli użyjesz RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD, twoja aplikacja nie będzie mogła korzystać z debugera Google Chrome. Wynika to z faktu, że metody synchroniczne wymagają współdzielenia pamięci między maszyną JS a aplikacją. W przypadku debugera Chrome, React Native działa wewnątrz maszyny JS w przeglądarce i komunikuje się asynchronicznie z urządzeniami mobilnymi przez WebSockety.
Przetestuj swoją implementację
W tym momencie masz już podstawową strukturę modułu natywnego w iOS. Przetestuj ją, uzyskując dostęp do modułu i wywołując jego eksportowaną metodę w JavaScript.
Znajdź miejsce w swojej aplikacji, gdzie chcesz dodać wywołanie metody createCalendarEvent() modułu natywnego. Poniżej znajduje się przykład komponentu NewModuleButton, który możesz dodać w swojej aplikacji. Moduł natywny możesz wywołać wewnątrz funkcji onPress() komponentu NewModuleButton.
import React from 'react';
import {Button} from 'react-native';
const NewModuleButton = () => {
const onPress = () => {
console.log('We will invoke the native module here!');
};
return (
<Button
title="Click to invoke your native module!"
color="#841584"
onPress={onPress}
/>
);
};
export default NewModuleButton;
Aby uzyskać dostęp do modułu natywnego z JavaScript, najpierw zaimportuj NativeModules z React Native:
import {NativeModules} from 'react-native';
Następnie możesz uzyskać dostęp do modułu natywnego CalendarModule poprzez NativeModules.
const {CalendarModule} = NativeModules;
Gdy moduł CalendarModule jest już dostępny, możesz wywołać metodę natywną createCalendarEvent(). Poniżej dodano ją do metody onPress() w NewModuleButton:
const onPress = () => {
CalendarModule.createCalendarEvent('testName', 'testLocation');
};
Ostatnim krokiem jest przebudowanie aplikacji React Native, aby mieć dostęp do najnowszego kodu natywnego (z twoim nowym modułem!). W linii poleceń, w lokalizacji twojej aplikacji React Native, wykonaj:
- npm
- Yarn
npm run ios
yarn ios
Budowanie w trakcie iteracji
Podczas pracy z tymi przewodnikami i iterowania nad modułem natywnym, będziesz musiał przebudować natywną część aplikacji, aby mieć dostęp do najnowszych zmian z JavaScript. Dzieje się tak, ponieważ tworzony kod znajduje się w natywnej części aplikacji. Podczas gdy bundler Metro w React Native może śledzić zmiany w JavaScript i na bieżąco przebudowywać paczkę JS, nie robi tego dla kodu natywnego. Jeśli więc chcesz przetestować swoje najnowsze zmiany natywne, musisz przebudować aplikację przy użyciu powyższego polecenia.
Podsumowanie ✨
Powinieneś teraz móc wywołać metodę createCalendarEvent() twojego modułu natywnego z JavaScript. Ponieważ używasz RCTLog w funkcji, możesz potwierdzić wywołanie metody natywnej, włączając tryb debugowania w aplikacji i sprawdzając konsolę JS w Chrome lub debugerze mobilnym Flipper. Powinieneś widzieć komunikat RCTLogInfo(@"Pretending to create an event %@ at %@", name, location); przy każdym wywołaniu metody modułu natywnego.

W tym momencie utworzyłeś moduł natywny dla iOS i wywołałeś jego metodę z JavaScript w twojej aplikacji React Native. Możesz kontynuować czytanie, aby dowiedzieć się więcej o typach argumentów przyjmowanych przez metody modułu natywnego oraz o konfigurowaniu callbacków i promise'ów w module natywnym.
Poza modułem natywnym kalendarza
Lepszy eksport modułu natywnego
Importowanie modułu natywnego poprzez pobieranie go z NativeModules, jak pokazano powyżej, jest nieco toporne.
Aby użytkownicy Twojego modułu natywnego nie musieli tego robić za każdym razem, możesz utworzyć wrapper JavaScript dla modułu. Stwórz nowy plik JavaScript o nazwie NativeCalendarModule.js z następującą zawartością:
/**
* This exposes the native CalendarModule module as a JS module. This has a
* function 'createCalendarEvent' which takes the following parameters:
* 1. String name: A string representing the name of the event
* 2. String location: A string representing the location of the event
*/
import {NativeModules} from 'react-native';
const {CalendarModule} = NativeModules;
export default CalendarModule;
Ten plik JavaScript to również dobre miejsce na dodanie funkcjonalności po stronie JavaScript. Na przykład, jeśli używasz systemu typów takiego jak TypeScript, możesz tutaj dodać adnotacje typów dla swojego modułu natywnego. Chociaż React Native nie obsługuje jeszcze bezpieczeństwa typów od strony natywnej do JS, te adnotacje zapewnią bezpieczeństwo typów w całym kodzie JavaScript. Ułatwią również późniejsze przejście na typowane moduły natywne. Poniżej przykład dodania bezpieczeństwa typów do modułu kalendarza:
/**
* This exposes the native CalendarModule module as a JS module. This has a
* function 'createCalendarEvent' which takes the following parameters:
*
* 1. String name: A string representing the name of the event
* 2. String location: A string representing the location of the event
*/
import {NativeModules} from 'react-native';
const {CalendarModule} = NativeModules;
interface CalendarInterface {
createCalendarEvent(name: string, location: string): void;
}
export default CalendarModule as CalendarInterface;
W innych plikach JavaScript możesz uzyskać dostęp do modułu natywnego i wywołać jego metodę w następujący sposób:
import NativeCalendarModule from './NativeCalendarModule';
NativeCalendarModule.createCalendarEvent('foo', 'bar');
Uwaga: zakłada to, że miejsce importu
CalendarModuleznajduje się w tej samej hierarchii coNativeCalendarModule.js. W razie potrzeby zaktualizuj ścieżkę importu względnego.
Typy argumentów
Gdy metoda modułu natywnego jest wywoływana w JavaScripcie, React Native konwertuje argumenty z obiektów JS na ich odpowiedniki w Objective-C/Swift. Na przykład, jeśli metoda modułu natywnego w Objective-C przyjmuje NSNumber, w JS musisz wywołać metodę z liczbą. React Native zajmie się konwersją. Poniżej lista obsługiwanych typów argumentów dla metod modułów natywnych i ich odpowiedników w JavaScripcie.
| Objective-C | JavaScript |
|---|---|
| NSString | string, ?string |
| BOOL | boolean |
| double | number |
| NSNumber | ?number |
| NSArray | Array, ?Array |
| NSDictionary | Object, ?Object |
| RCTResponseSenderBlock | Function (success) |
| RCTResponseSenderBlock, RCTResponseErrorBlock | Function (failure) |
| RCTPromiseResolveBlock, RCTPromiseRejectBlock | Promise |
Poniższe typy są obecnie obsługiwane, ale nie będą wspierane w TurboModules. Należy unikać ich używania.
- Function (failure) -> RCTResponseErrorBlock
- Number -> NSInteger
- Number -> CGFloat
- Number -> float
W iOS możesz również pisać metody modułów natywnych z dowolnymi typami argumentów obsługiwanymi przez klasę RCTConvert (szczegóły w RCTConvert). Funkcje pomocnicze RCTConvert akceptują wartość JSON jako wejście i mapują ją na natywny typ lub klasę Objective-C.
Eksportowanie stałych
Moduł natywny może eksportować stałe poprzez nadpisanie natywnej metody constantsToExport(). Poniżej constantsToExport() jest nadpisana i zwraca słownik zawierający domyślną nazwę wydarzenia, do której możesz uzyskać dostęp w JavaScripcie:
- (NSDictionary *)constantsToExport
{
return @{ @"DEFAULT_EVENT_NAME": @"New Event" };
}
Do stałej można następnie uzyskać dostęp poprzez wywołanie getConstants() na module natywnym w JS:
const {DEFAULT_EVENT_NAME} = CalendarModule.getConstants();
console.log(DEFAULT_EVENT_NAME);
Technicznie możliwy jest bezpośredni dostęp do stałych z constantsToExport() poprzez obiekt NativeModule. To podejście nie będzie obsługiwane w TurboModules, dlatego zachęcamy do przejścia na powyższą metodę, aby uniknąć migracji w przyszłości.
Ważne: stałe są eksportowane tylko podczas inicjalizacji, więc zmiana wartości
constantsToExport()w czasie działania nie wpłynie na środowisko JavaScript.
W iOS, jeśli nadpisujesz constantsToExport(), powinieneś również zaimplementować + requiresMainQueueSetup, aby poinformować React Native, czy Twój moduł wymaga inicjalizacji w wątku głównym przed wykonaniem kodu JavaScript. W przeciwnym razie pojawi się ostrzeżenie, że w przyszłości moduł może być inicjalizowany w wątku w tle, chyba że jawnie zrezygnujesz poprzez + requiresMainQueueSetup:. Jeśli moduł nie wymaga dostępu do UIKit, powinieneś w odpowiedzi na + requiresMainQueueSetup zwrócić NO.
Callbacki
Moduły natywne obsługują również specjalny rodzaj argumentu - funkcję zwrotną. Callbacki służą do przekazywania danych z Objective-C do JavaScript dla metod asynchronicznych. Mogą też asynchronicznie wykonywać JS po stronie natywnej.
W iOS callbacki implementuje się za pomocą typu RCTResponseSenderBlock. Poniżej parametr callbacku myCallBack został dodany do createCalendarEventMethod():
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)title
location:(NSString *)location
myCallback:(RCTResponseSenderBlock)callback)
Następnie możesz wywołać callback w swojej natywnej funkcji, przekazując dowolny wynik do JavaScript w postaci tablicy. Pamiętaj, że RCTResponseSenderBlock przyjmuje tylko jeden argument - tablicę parametrów do przekazania do callbacku JavaScript. Poniżej przekazujesz ID wydarzenia utworzonego wcześniej.
Kluczowe jest podkreślenie, że callback nie jest wywoływany natychmiast po zakończeniu funkcji natywnej – pamiętaj, że komunikacja jest asynchroniczna.
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)title location:(NSString *)location callback: (RCTResponseSenderBlock)callback)
{
NSInteger eventId = ...
callback(@[@(eventId)]);
RCTLogInfo(@"Pretending to create an event %@ at %@", title, location);
}
Tę metodę można następnie wywołać w JavaScript w następujący sposób:
const onSubmit = () => {
CalendarModule.createCalendarEvent(
'Party',
'04-12-2020',
eventId => {
console.log(`Created a new event with id ${eventId}`);
},
);
};
Moduł natywny powinien wywołać swój callback tylko raz. Może jednak przechować callback i wywołać go później. Ten wzorzec jest często używany do opakowywania interfejsów API iOS wymagających delegatów — zobacz przykład w RCTAlertManager. Jeśli callback nigdy nie zostanie wywołany, nastąpi wyciek pamięci.
Istnieją dwa podejścia do obsługi błędów z callbackami. Pierwsze to zastosowanie konwencji z Node.js, gdzie pierwszy argument przekazany do tablicy callbacków traktowany jest jako obiekt błędu.
RCT_EXPORT_METHOD(createCalendarEventCallback:(NSString *)title location:(NSString *)location callback: (RCTResponseSenderBlock)callback)
{
NSNumber *eventId = [NSNumber numberWithInt:123];
callback(@[[NSNull null], eventId]);
}
W JavaScripcie możesz sprawdzić pierwszy argument, aby wykryć błąd:
const onPress = () => {
CalendarModule.createCalendarEventCallback(
'testName',
'testLocation',
(error, eventId) => {
if (error) {
console.error(`Error found! ${error}`);
}
console.log(`event id ${eventId} returned`);
},
);
};
Inną opcją jest użycie dwóch oddzielnych callbacków: onFailure i onSuccess.
RCT_EXPORT_METHOD(createCalendarEventCallback:(NSString *)title
location:(NSString *)location
errorCallback: (RCTResponseSenderBlock)errorCallback
successCallback: (RCTResponseSenderBlock)successCallback)
{
@try {
NSNumber *eventId = [NSNumber numberWithInt:123];
successCallback(@[eventId]);
}
@catch ( NSException *e ) {
errorCallback(@[e]);
}
}
W JavaScripcie możesz dodać osobne callbacki dla odpowiedzi sukcesu i błędu:
const onPress = () => {
CalendarModule.createCalendarEventCallback(
'testName',
'testLocation',
error => {
console.error(`Error found! ${error}`);
},
eventId => {
console.log(`event id ${eventId} returned`);
},
);
};
Jeśli chcesz przekazywać do JavaScript obiekty przypominające błędy, użyj RCTMakeError z RCTUtils.h.. Obecnie przekazuje to tylko słownik przypominający Error, ale React Native planuje automatycznie generować prawdziwe obiekty JavaScript Error w przyszłości. Możesz też użyć argumentu typu RCTResponseErrorBlock, który służy do callbacków błędów i akceptuje NSError \* object. Pamiętaj, że ten typ argumentu nie będzie obsługiwany w TurboModules.
Promisy
Moduły natywne mogą również rozwiązywać obietnice (promise), co upraszcza kod JavaScript, szczególnie przy użyciu składni async/await z ES2016. Gdy ostatnim parametrem metody modułu natywnego jest RCTPromiseResolveBlock i RCTPromiseRejectBlock, odpowiadająca jej metoda JS zwróci obiekt Promise.
Refaktoryzacja powyższego kodu do użycia promisa zamiast callbacków wygląda następująco:
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)title
location:(NSString *)location
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSInteger eventId = createCalendarEvent();
if (eventId) {
resolve(@(eventId));
} else {
reject(@"event_failure", @"no event id returned", nil);
}
}
Odpowiednik tej metody w JavaScript zwraca Promisa. Oznacza to, że możesz użyć słowa kluczowego await wewnątrz funkcji asynchronicznej, aby ją wywołać i poczekać na wynik:
const onSubmit = async () => {
try {
const eventId = await CalendarModule.createCalendarEvent(
'Party',
'my house',
);
console.log(`Created a new event with id ${eventId}`);
} catch (e) {
console.error(e);
}
};
Wysyłanie zdarzeń do JavaScript
Moduły natywne mogą sygnalizować zdarzenia do JavaScript bez bezpośredniego wywołania. Na przykład możesz chcieć powiadomić JavaScript o zbliżającym się wydarzeniu z kalendarza natywnej aplikacji iOS. Preferowanym sposobem jest podklasyfikowanie RCTEventEmitter, zaimplementowanie supportedEvents i wywołanie sendEventWithName:
Zaktualizuj klasę w pliku nagłówkowym, aby importowała RCTEventEmitter i dziedziczyła po RCTEventEmitter:
// CalendarModule.h
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface CalendarModule : RCTEventEmitter <RCTBridgeModule>
@end
Kod JavaScript może subskrybować te zdarzenia, tworząc nową instancję NativeEventEmitter wokół twojego modułu.
Otrzymasz ostrzeżenie, jeśli niepotrzebnie zużyjesz zasoby emitując zdarzenie bez aktywnych słuchaczy. Aby tego uniknąć i zoptymalizować obciążenie modułu (np. przez rezygnację z subskrypcji powiadomień lub wstrzymanie zadań w tle), możesz nadpisać startObserving i stopObserving w swojej podklasie RCTEventEmitter.
@implementation CalendarModule
{
bool hasListeners;
}
// Will be called when this module's first listener is added.
-(void)startObserving {
hasListeners = YES;
// Set up any upstream listeners or background tasks as necessary
}
// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopObserving {
hasListeners = NO;
// Remove upstream listeners, stop unnecessary background tasks
}
- (void)calendarEventReminderReceived:(NSNotification *)notification
{
NSString *eventName = notification.userInfo[@"name"];
if (hasListeners) {// Only send events if anyone is listening
[self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
}
}
Zarządzanie wątkami
O ile moduł natywny nie zapewnia własnej kolejki metod, nie powinien zakładać, na którym wątku jest wywoływany. Obecnie, jeśli moduł natywny nie zapewnia kolejki metod, React Native utworzy dla niego osobną kolejkę GCD i wywoła jego metody w niej. Pamiętaj, że to szczegół implementacyjny i może ulec zmianie. Jeśli chcesz jawnie zapewnić kolejkę metod dla modułu natywnego, nadpisz metodę (dispatch_queue_t) methodQueue w module natywnym. Na przykład, jeśli musi używać API iOS dostępnego tylko w wątku głównym, powinien to określić poprzez:
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
Podobnie, jeśli operacja może zająć dużo czasu, moduł natywny może określić własną kolejkę do uruchamiania operacji. Obecnie React Native zapewnia osobną kolejkę metod dla twojego modułu natywnego, ale jest to szczegół implementacyjny, na którym nie powinieneś polegać. Jeśli nie zapewnisz własnej kolejki metod, długotrwałe operacje twojego modułu mogą blokować wywołania asynchroniczne w innych, niezwiązanych modułach natywnych. Na przykład moduł RCTAsyncLocalStorage tworzy własną kolejkę, aby kolejka Reacta nie była blokowana przez potencjalnie wolny dostęp do dysku.
- (dispatch_queue_t)methodQueue
{
return dispatch_queue_create("com.facebook.React.AsyncLocalStorageQueue", DISPATCH_QUEUE_SERIAL);
}
Określona methodQueue będzie współdzielona przez wszystkie metody w twoim module. Jeśli tylko jedna z twoich metod jest długotrwała (lub musi być uruchomiona w innej kolejce niż pozostałe), możesz użyć dispatch_async wewnątrz metody, aby wykonać kod tej konkretnej metody w innej kolejce, bez wpływu na pozostałe:
RCT_EXPORT_METHOD(doSomethingExpensive:(NSString *)param callback:(RCTResponseSenderBlock)callback)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Call long-running code on background thread
...
// You can invoke callback from any thread/queue
callback(@[...]);
});
}
Współdzielenie kolejek dispatch między modułami
Metoda
methodQueuezostanie wywołana raz podczas inicjalizacji modułu i zostanie zachowana przez React Native, więc nie ma potrzeby samodzielnie przechowywać referencji do kolejki, chyba że chcesz jej użyć wewnątrz modułu. Jeśli jednak chcesz współdzielić tę samą kolejkę między wieloma modułami, musisz zapewnić, że każdy z nich zachowuje i zwraca tę samą instancję kolejki.
Wstrzykiwanie zależności
React Native automatycznie tworzy i inicjalizuje zarejestrowane moduły natywne. Możesz jednak utworzyć i zainicjalizować własne instancje modułów, aby np. wstrzykiwać zależności.
Możesz to zrobić, tworząc klasę implementującą protokół RCTBridgeDelegate, inicjalizując RCTBridge z delegatem jako argumentem i inicjalizując RCTRootView z zainicjalizowanym mostem (bridge).
id<RCTBridgeDelegate> moduleInitialiser = [[classThatImplementsRCTBridgeDelegate alloc] init];
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:moduleInitialiser launchOptions:nil];
RCTRootView *rootView = [[RCTRootView alloc]
initWithBridge:bridge
moduleName:kModuleName
initialProperties:nil];
Eksportowanie Swifta
Swift nie obsługuje makr, więc udostępnianie modułów natywnych i ich metod w JavaScript wewnątrz React Native wymaga więcej konfiguracji. Działa to jednak podobnie. Załóżmy, że masz ten sam moduł CalendarModule jako klasę Swift:
// CalendarModule.swift
@objc(CalendarModule)
class CalendarModule: NSObject {
@objc(addEvent:location:date:)
func addEvent(_ name: String, location: String, date: NSNumber) -> Void {
// Date is ready to use!
}
@objc
func constantsToExport() -> [String: Any]! {
return ["someKey": "someValue"]
}
}
Ważne jest używanie modyfikatorów
@objc, aby zapewnić prawidłowe eksportowanie klasy i funkcji do środowiska wykonawczego Objective-C.
Następnie utwórz prywatny plik implementacyjny, który zarejestruje wymagane informacje w React Native:
// CalendarModuleBridge.m
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(CalendarModule, NSObject)
RCT_EXTERN_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)date)
@end
Jeśli dopiero zaczynasz pracę ze Swiftem i Objective-C, podczas mieszania obu języków w projekcie iOS potrzebujesz dodatkowego pliku bridgingowego (bridging header), aby udostępnić pliki Objective-C w Swift. Xcode zaproponuje utworzenie tego pliku, jeśli dodasz plik Swift przez menu File>New File. Musisz zaimportować RCTBridgeModule.h w tym pliku nagłówkowym.
// CalendarModule-Bridging-Header.h
#import <React/RCTBridgeModule.h>
Możesz użyć RCT_EXTERN_REMAP_MODULE i _RCT_EXTERN_REMAP_METHOD, aby zmienić nazwę modułu lub metod w JavaScript. Więcej informacji: RCTBridgeModule.
Ważne przy tworzeniu modułów osób trzecich: biblioteki statyczne w Swift są obsługiwane tylko w Xcode 9 i nowszych. Aby projekt Xcode mógł się zbudować podczas używania Swifta w statycznej bibliotece iOS dołączanej do modułu, główny projekt aplikacji musi zawierać kod Swift i własny bridging header. Jeśli projekt aplikacji nie zawiera kodu Swift, obejściem może być pojedynczy pusty plik .swift i pusty bridging header.
Zarezerwowane nazwy metod
invalidate()
Moduły natywne mogą być zgodne z protokołem RCTInvalidating na iOS poprzez implementację metody invalidate(). Ta metoda może zostać wywołana gdy natywny mostek zostanie unieważniony (np. przy przeładowaniu w trybie deweloperskim). Używaj tego mechanizmu w razie potrzeby do przeprowadzenia wymaganego sprzątania w twoim module natywnym.