Spec-Zone.ru › React Native

Модули iOS Native

Добро пожаловать в модули Native для iOS. Начните с чтения Введения в модули Native, чтобы узнать, что такое модули native.

Создание модуля Native для календаря

В этом руководстве вы создадите модуль native, CalendarModule, который позволит вам получать доступ к API календаря Apple из JavaScript. В результате вы сможете вызывать CalendarModule.createCalendarEvent('Dinner Party', 'My House'); из JavaScript, вызывая нативный метод, который создаёт событие в календаре.

Команда React Native в настоящее время работает над рефакторингом системы модулей Native. Эта новая система называется TurboModules, и она поможет обеспечить более эффективную и безопасную по типам коммуникацию между JavaScript и нативным кодом, без использования моста React Native. Она также позволит создавать новые расширения, которые были невозможны с системой модулей Native предыдущего поколения. Вы можете узнать больше об этом здесь. В этих документах мы добавили примечания относительно частей модулей Native, которые изменятся в релизе TurboModules, и как лучше подготовиться к плавному обновлению до TurboModules.

Настройка

Для начала откройте проект iOS в вашей React Native-приложения в Xcode. Вы найдете свой проект iOS здесь внутри React Native-приложения:

Image of opening up an iOS project within a React Native app inside of xCode.
Изображение того, где вы можете найти свой проект iOS

Мы рекомендуем использовать Xcode для написания вашего нативного кода. Xcode разработан для разработки под iOS, и его использование поможет вам быстро устранять мелкие ошибки, такие как синтаксические ошибки кода.

Создание пользовательских файлов модулей Native

Первый шаг — создание основных файлов заголовка и реализации пользовательского модуля Native. Создайте новый файл под названием RCTCalendarModule.h

Image of creating a class called  RCTCalendarModule.h.
Изображение создания файла пользовательского модуля Native в той же папке, что и AppDelegate

и добавьте в него следующее:

//  RCTCalendarModule.h
#import <React/RCTBridgeModule.h>
@interface RCTCalendarModule : NSObject <RCTBridgeModule>
@end

Вы можете использовать любое имя, которое подходит для создаваемого модуля Native. Назовите класс RCTCalendarModule, так как вы создаёте модуль Native для календаря. Поскольку Objective-C не поддерживает уровень языка для пространств имён, как Java или C++, принято добавлять к имени класса префикс. Это может быть аббревиатура имени вашего приложения или вашего инфраструктурного названия. RCT в данном примере относится к React.

Как вы можете видеть ниже, класс CalendarModule реализует протокол RCTBridgeModule. Модуль Native — это класс Objective-C, который реализует протокол RCTBridgeModule

Далее, давайте начнем реализовывать модуль Native. Создайте соответствующий файл реализации RCTCalendarModule.m в той же папке и добавьте в него следующее содержимое:

// RCTCalendarModule.m
#import "RCTCalendarModule.h"

@implementation RCTCalendarModule

// To export a module named RCTCalendarModule
RCT_EXPORT_MODULE();

@end

Имя модуля

Пока ваш RCTCalendarModule.m модуль Native содержит только макрос RCT_EXPORT_MODULE, который экспортирует и регистрирует класс нативного модуля в React Native. Макрос RCT_EXPORT_MODULE также принимает необязательный аргумент, который определяет имя, под которым модуль будет доступен в вашем коде JavaScript.

Этот аргумент не является строковой литеральной. В примере ниже передаётся RCT_EXPORT_MODULE(CalendarModuleFoo), а не RCT_EXPORT_MODULE("CalendarModuleFoo")

// To export a module named CalendarModuleFoo
RCT_EXPORT_MODULE(CalendarModuleFoo);

К модулю Native можно получить доступ в JS следующим образом:

const { CalendarModuleFoo } = ReactNative.NativeModules;

Если вы не укажете имя, имя модуля JavaScript будет соответствовать имени класса Objective-C, из которого удалены префиксы "RCT" или "RK".

Давайте последим за примером ниже и вызовем RCT_EXPORT_MODULE без аргументов. В результате модуль будет доступен в React Native под именем CalendarModule, так как это имя класса Objective-C, из которого удален префикс 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();

К модулю Native можно получить доступ в JS следующим образом:

const { CalendarModule } = ReactNative.NativeModules;

Экспорт нативного метода в JavaScript

React Native не будет экспортировать никакие методы нативного модуля в JavaScript, если это не будет явно указано. Это можно сделать с помощью макроса RCT_EXPORT_METHOD. Методы, написанные в макросе RCT_EXPORT_METHOD, являются асинхронными, и поэтому возвращаемый тип всегда void. Для передачи результата из метода RCT_EXPORT_METHOD в JavaScript вы можете использовать обратные вызовы или генерировать события (это будет рассмотрено ниже). Давайте создадим нативный метод для нашего модуля CalendarModule Native Module, используя макрос RCT_EXPORT_METHOD. Назовём его createCalendarEvent() и пусть он принимает в качестве аргументов имя и местоположение как строки. Параметры типов аргументов будут рассмотрены в ближайшее время.

RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)name location:(NSString *)location)
{
}

Обратите внимание, что макрос RCT_EXPORT_METHOD не понадобится с TurboModules, если ваш метод не использует преобразование аргументов RCT (см. типы аргументов ниже). В конечном счете, React Native удалит RCT_EXPORT_MACRO,, поэтому мы не рекомендуем использовать RCTConvert. Вместо этого вы можете выполнить преобразование аргументов внутри тела метода.

Прежде чем разрабатывать функциональность метода createCalendarEvent(), добавьте в него запись в консоль, чтобы убедиться, что он был вызван из JavaScript в вашем React Native-приложении. Используйте API RCTLog из React. Давайте импортируем этот заголовок в начало вашего файла, а затем добавим вызов записи в консоль.

#import <React/RCTLog.h>
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)name location:(NSString *)location)
{
 RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
}

Синхронные методы

Вы можете использовать RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD для создания синхронного нативного метода.

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getName)
{
return [[UIDevice currentDevice] name];
}

Возвращаемый тип этого метода должен быть типа объекта (id) и должен быть сериализуем в JSON. Это означает, что обработчик может вернуть только nil или значения JSON (например, NSNumber, NSString, NSArray, NSDictionary).

В настоящее время мы не рекомендуем использовать синхронные методы, так как вызов методов синхронно может привести к снижению производительности и введению ошибок, связанных с потоками, в ваши модули Native. Кроме того, обратите внимание, что если вы решите использовать RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD, ваше приложение больше не может использовать отладчик Google Chrome. Это связано с тем, что для синхронных методов требуется, чтобы JS-виртуальная машина делила память с приложением. Для отладчика Google Chrome React Native выполняется внутри JS-виртуальной машины в Google Chrome и асинхронно взаимодействует с мобильными устройствами через WebSockets.

Протестируйте созданное

На этом этапе вы настроите базовые элементы структуры своего модуля Native в iOS. Проверьте это, обратившись к модулю Native и вызвав его экспортированный метод в JavaScript.

Найдите место в вашем приложении, где вы хотите добавить вызов метода нативного модуля createCalendarEvent(). Ниже приведен пример компонента NewModuleButton, который вы можете добавить в своё приложение. Вы можете вызвать нативный модуль внутри функции NewModuleButton компонента onPress()

import React from 'react';
import { NativeModules, 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;

Для доступа к вашему нативному модулю из JavaScript вам необходимо сначала импортировать NativeModules из React Native:

import { NativeModules } from 'react-native';

Затем вы можете получить доступ к модулю Native CalendarModule из NativeModules

const { CalendarModule } = NativeModules;

Теперь, когда у вас есть модуль Native CalendarModule, вы можете вызвать свой нативный метод createCalendarEvent(). Ниже он добавлен в метод onPress() в NewModuleButton:

const onPress = () => {
  CalendarModule.createCalendarEvent('testName', 'testLocation');
};

Последний шаг — перестроить приложение React Native, чтобы сделать доступным последний нативный код (с вашим новым модулем Native)! В командной строке, где расположено приложение React Native, выполните следующее:

npx react-native run-ios

Компиляция при итерации

При работе с этими руководствами и итерации над вашим модулем Native вам потребуется перекомпиляция приложения для доступа к вашим последним изменениям из JavaScript. Это связано с тем, что написанный вами код находится в нативной части приложения. Хотя сборщик пакетов React Native Metro может отслеживать изменения в JavaScript и перестраивать пакет JS в реальном времени, он не делает этого для нативного кода. Поэтому, если вы хотите протестировать ваши последние изменения в нативном коде, вам необходимо перекомпилировать его, используя команду npx react-native run-ios

Резюме✨

Теперь вы должны иметь возможность вызывать метод createCalendarEvent() в нативном модуле в JavaScript. Поскольку вы используете RCTLog в функции, вы можете подтвердить вызов вашего нативного метода, включив режим отладки в приложении и просмотрев консоль JavaScript в Chrome или отладчик Flipper для мобильных приложений. Вы должны увидеть сообщение RCTLogInfo(@"Pretending to create an event %@ at %@", name, location); каждый раз, когда вызываете метод модуля Native.

Image of logs.
Изображение журналов iOS в Flipper

На этом этапе вы создали модуль iOS Native и вызвали метод в нём из JavaScript в вашем приложении React Native. Вы можете продолжить изучение таких аспектов, как типы аргументов, которые принимает метод вашего нативного модуля, и как настроить обратные вызовы и обещания в вашем нативном модуле.

Выходя за рамки модуля Native для календаря

Лучший экспорт нативного модуля

Импорт вашего модуля Native, вытягивая его из NativeModules как выше, немного неудобно.

Чтобы сэкономить время потребителей вашего модуля Native, им не нужно было бы делать это каждый раз, когда они хотят получить доступ к вашему нативному модулю, вы можете создать JavaScript-обёртку для модуля. Создайте новый файл JavaScript с именем NativeCalendarModule.js со следующим содержимым:

/**
* 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;

Этот файл JavaScript также станет хорошим местом для добавления любой функциональности со стороны JavaScript. Например, если вы используете систему типов, такую как TypeScript, вы можете добавить аннотации типов для вашего нативного модуля здесь. Хотя React Native пока не поддерживает безопасность типов от Native к JS, с этими аннотациями весь ваш JS-код будет безопасным по типам. Эти аннотации также упростят переход к модулям Native с безопасностью типов в будущем. Вот пример добавления безопасности типов в модуль Calendar:

/**
* 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;

В других ваших файлах JavaScript вы можете получить доступ к нативному модулю и вызвать его метод следующим образом:

import NativeCalendarModule from './NativeCalendarModule';
NativeCalendarModule.createCalendarEvent('foo', 'bar');

Обратите внимание, что это предполагает, что место импорта CalendarModule находится в той же иерархии, что и CalendarModule.js. Пожалуйста, обновите относительный импорт по мере необходимости.

Типы аргументов

Когда метод нативного модуля вызывается в JavaScript, React Native преобразует аргументы из объектов JS в их аналоги объектов Objective-C/Swift. Например, если ваш метод нативного модуля Objective-C принимает NSNumber, в JS вам нужно вызвать метод с числом. React Native выполнит преобразование за вас. Ниже приведен список поддерживаемых типов аргументов для методов нативных модулей и соответствующие им эквиваленты в JavaScript.

Objective-C JavaScript
NSString string, ?string
BOOL boolean
NSNumber ?boolean
double number
NSNumber ?number
NSArray Array, ?Array
NSDictionary Object, ?Object
RCTResponseSenderBlock Function (success)
RCTResponseSenderBlock, RCTResponseErrorBlock Function (failure)
RCTPromiseResolveBlock, RCTPromiseRejectBlock Promise

Следующие типы в настоящее время поддерживаются, но не будут поддерживаться в TurboModules. Пожалуйста, избегайте их использования.

  • Function (failure) -> RCTResponseErrorBlock
  • Number -> NSInteger
  • Number -> CGFloat
  • Number -> float

Для iOS вы также можете писать методы нативных модулей с любым типом аргумента, который поддерживается классом RCTConvert (см. RCTConvert для получения подробностей о поддерживаемых типах). Вспомогательные функции RCTConvert принимают значение JSON в качестве входных данных и отображают его на тип или класс Objective-C.

Экспорт констант

Нативный модуль может экспортировать константы, переопределив нативный метод constantsToExport(). Ниже constantsToExport() переопределяется и возвращает словарь, содержащий свойство имени события по умолчанию, к которому вы можете получить доступ в JavaScript следующим образом:

- (NSDictionary *)constantsToExport
{
 return @{ @"DEFAULT_EVENT_NAME": @"New Event" };
}

К константе можно получить доступ, вызвав getConstants() на нативном модуле в JS следующим образом:

const { DEFAULT_EVENT_NAME } = CalendarModule.getConstants();
console.log(DEFAULT_EVENT_NAME);

Технически, можно получить доступ к константам, экспортированным в constantsToExport(), непосредственно из объекта NativeModule. Эта возможность больше не будет поддерживаться с TurboModules, поэтому мы рекомендуем сообществу переключиться на вышеописанный подход, чтобы избежать необходимости миграции в будущем.

Обратите внимание, что константы экспортируются только во время инициализации, поэтому изменение значений constantsToExport() во время выполнения не повлияет на среду JavaScript.

Для iOS, если вы переопределяете constantsToExport(), то также необходимо реализовать + requiresMainQueueSetup, чтобы сообщить React Native, нужно ли инициализировать ваш модуль в главном потоке перед выполнением любого кода JavaScript. В противном случае вы увидите предупреждение о том, что в будущем ваш модуль может быть инициализирован в фоновом потоке, если вы явно не откажетесь от этого с помощью + requiresMainQueueSetup:. Если ваш модуль не требует доступа к UIKit, то вы должны ответить на + requiresMainQueueSetup значением NO.

Обратные вызовы

Нативные модули также поддерживают особый тип аргумента — обратный вызов. Обратные вызовы используются для передачи данных из Objective-C в JavaScript для асинхронных методов. Они также могут использоваться для асинхронного выполнения JavaScript со стороны нативного кода.

Для iOS обратные вызовы реализуются с помощью типа RCTResponseSenderBlock. Ниже параметр обратного вызова myCallBack добавлен в createCalendarEventMethod():

RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)title
                location:(NSString *)location
                myCallback:(RCTResponseSenderBlock)callback)

Затем вы можете вызвать обратный вызов в своем нативном методе, передав любые данные, которые вы хотите передать в JavaScript в массиве. Обратите внимание, что RCTResponseSenderBlock принимает только один аргумент — массив параметров для передачи в JavaScript-обратный вызов. Ниже вы вернете идентификатор созданного ранее события.

Важно отметить, что обратный вызов не вызывается сразу после завершения нативного метода — помните, что общение асинхронно.

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);
}

Этот метод можно получить в JavaScript следующим образом:

const onSubmit = () => {
  CalendarModule.createCalendarEvent(
    'Party',
    '04-12-2020',
    (eventId) => {
      console.log(`Created a new event with id ${eventId}`);
    }
  );
};

Нативный модуль должен вызвать свой обратный вызов только один раз. Однако он может сохранить обратный вызов и вызвать его позже. Этот шаблон часто используется для обертывания iOS-API, требующих делегатов — см. RCTAlertManager для примера. Если обратный вызов никогда не вызывается, происходит утечка памяти.

Существует два подхода к обработке ошибок с обратными вызовами. Первый — следовать конвенциям Node и рассматривать первый аргумент, переданный в массив обратного вызова, как объект ошибки.

RCT_EXPORT_METHOD(createCalendarEventCallback:(NSString *)title location:(NSString *)location callback: (RCTResponseSenderBlock)callback)
{
  NSNumber *eventId = [NSNumber numberWithInt:123];
  callback(@[[NSNull null], eventId]);
}

В JavaScript вы можете проверить первый аргумент, чтобы узнать, была ли передана ошибка:

const onPress = () => {
  CalendarModule.createCalendarEventCallback(
    'testName',
    'testLocation',
    (error, eventId) => {
      if (error) {
        console.error(`Error found! ${error}`);
      }
      console.log(`event id ${eventId} returned`);
    }
  );
};

Другой вариант — использовать два отдельных обратных вызова: onFailure и 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]);
  }
}

Затем в JavaScript вы можете добавить отдельный обратный вызов для обработки ошибок и успешных ответов:

const onPress = () => {
  CalendarModule.createCalendarEventCallback(
    'testName',
    'testLocation',
    (error) => {
      console.error(`Error found! ${error}`);
    },
    (eventId) => {
      console.log(`event id ${eventId} returned`);
    }
  );
};

Если вы хотите передать объекты-ошибки в JavaScript, используйте RCTMakeError из RCTUtils.h.. В данный момент это просто передает словарь типа Error в JavaScript, но React Native планирует автоматически генерировать реальные объекты ошибок JavaScript в будущем. Вы также можете указать аргумент RCTResponseErrorBlock, который используется для обратных вызовов ошибок и принимает NSError \* object. Обратите внимание, что этот тип аргумента не будет поддерживаться в TurboModules.

Обещания

Нативные модули также могут выполнять обещания, что упростит ваш JavaScript, особенно при использовании синтаксиса ES2016's async/await . Когда последний параметр метода нативного модуля является RCTPromiseResolveBlock и RCTPromiseRejectBlock, соответствующий JS-метод вернет JS-объект Promise.

Рефакторинг вышеприведенного кода для использования обещаний вместо обратных вызовов выглядит следующим образом:

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);
  }
}

JavaScript-эквивалент этого метода возвращает объект Promise. Это означает, что вы можете использовать ключевое слово await внутри асинхронной функции для вызова метода и ожидания его результата:

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);
  }
};

Отправка событий в JavaScript

Нативные модули могут сигнализировать события в JavaScript без прямого вызова. Например, вы можете сигнализировать JavaScript о том, что вскоре наступит напоминание о событии календаря из приложения календаря iOS. Лучший способ сделать это — наследоваться от RCTEventEmitter, реализовать supportedEvents и вызвать self sendEventWithName:

Обновите класс заголовка, чтобы импортировать RCTEventEmitter и унаследовать от RCTEventEmitter:

//  CalendarModule.h

#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

@interface CalendarModule : RCTEventEmitter <RCTBridgeModule>
@end

Код JavaScript может подписываться на эти события, создав новый экземпляр NativeEventEmitter вокруг вашего модуля.

Вы получите предупреждение, если необоснованно потратите ресурсы, отправив событие, когда нет слушателей. Чтобы избежать этого и оптимизировать нагрузку вашего модуля (например, отписавшись от уведомлений или приостановив фоновые задачи), вы можете переопределить startObserving и stopObserving в вашем подклассе RCTEventEmitter.

@implementation CalendarManager
{
  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}];
  }
}

Потоки

Если нативный модуль не предоставляет собственную очередь методов, он не должен делать никаких предположений о том, в каком потоке он вызывается. В настоящее время, если нативный модуль не предоставляет очередь методов, React Native создаст для него отдельную очередь GCD и вызовет его методы там. Пожалуйста, обратите внимание, что это деталь реализации и может измениться. Если вы хотите явно указать очередь методов для нативного модуля, переопределите метод (dispatch_queue_t) methodQueue в нативном модуле. Например, если он должен использовать API iOS, который доступен только в главном потоке, он должен указать это следующим образом:

- (dispatch_queue_t)methodQueue
{
  return dispatch_get_main_queue();
}

Аналогично, если операция может занимать много времени, нативный модуль может указать собственную очередь для выполнения операций. Опять же, в настоящее время React Native предоставит отдельную очередь методов для вашего нативного модуля, но это деталь реализации, на которую не следует полагаться. Если вы не предоставите собственную очередь методов, в будущем ваши длительные операции нативного модуля могут заблокировать выполнение асинхронных вызовов в других не связанных нативных модулях. Модуль RCTAsyncLocalStorage , например, создаёт собственную очередь, чтобы очередь React не блокировалась, ожидая потенциально медленного доступа к диску.

- (dispatch_queue_t)methodQueue
{
 return dispatch_queue_create("com.facebook.React.AsyncLocalStorageQueue", DISPATCH_QUEUE_SERIAL);
}

Указанная methodQueue будет использоваться всеми методами в вашем модуле. Если только один из ваших методов является длительным (или должен выполняться в другой очереди, по какой-либо причине), вы можете использовать dispatch_async внутри метода, чтобы выполнить код этого метода в другой очереди, не затрагивая остальные:

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(@[...]);
 });
}

Обмен очередями диспетчеризации между модулями

Метод methodQueue будет вызван один раз при инициализации модуля и затем удерживается React Native, поэтому нет необходимости сохранять ссылку на очередь самостоятельно, если вы не хотите использовать её в вашем модуле. Однако, если вы хотите использовать одну и ту же очередь для нескольких модулей, вам нужно убедиться, что вы сохраняете и возвращаете один и тот же экземпляр очереди для каждого из них.

Инъекция зависимостей

React Native автоматически создаст и инициализирует любые зарегистрированные нативные модули. Однако вы можете захотеть создать и инициализировать свои собственные экземпляры модулей, чтобы, например, ввести зависимости.

Вы можете сделать это, создав класс, который реализует протокол RCTBridgeDelegate, инициализируя RCTBridge с делегатом в качестве аргумента и инициализируя RCTRootView с инициализированным мостом.

id<RCTBridgeDelegate> moduleInitialiser = [[classThatImplementsRCTBridgeDelegate alloc] init];

RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:moduleInitialiser launchOptions:nil];

RCTRootView *rootView = [[RCTRootView alloc]
                        initWithBridge:bridge
                            moduleName:kModuleName
                     initialProperties:nil];

Экспорт Swift

Swift не поддерживает макросы, поэтому для экспорта нативных модулей и их методов в JavaScript в React Native требуется немного больше настроек. Однако, это работает примерно так же. Допустим, у вас есть тот же CalendarModule , но как класс Swift:

// CalendarManager.swift

@objc(CalendarManager)
class CalendarManager: 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"]
 }

}

Важно использовать модификаторы @objc , чтобы убедиться, что класс и функции должным образом экспортируются в Objective-C-среду выполнения.

Затем создайте частный файл реализации, который зарегистрирует необходимую информацию в React Native:

// CalendarManagerBridge.m
#import <React/RCTBridgeModule.h>

@interface RCT_EXTERN_MODULE(CalendarManager, NSObject)

RCT_EXTERN_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)date)

@end

Для тех из вас, кто новичок в Swift и Objective-C, всякий раз, когда вы смешиваете эти два языка в проекте iOS, вам также понадобится дополнительный файл моста, известный как заголовок моста, чтобы экспортировать Objective-C файлы в Swift. Xcode предложит вам создать этот заголовок, если вы добавите ваш Swift-файл в приложение через опцию меню Xcode File>New File . Вам необходимо импортировать RCTBridgeModule.h в этот файл заголовка.

// CalendarManager-Bridging-Header.h
#import <React/RCTBridgeModule.h>

Вы также можете использовать RCT_EXTERN_REMAP_MODULE и _RCT_EXTERN_REMAP_METHOD для изменения имени модуля или методов JavaScript, которые вы экспортируете. Для получения дополнительной информации см. RCTBridgeModule.

Важно при создании модулей сторонних разработчиков: Статические библиотеки с Swift поддерживаются только в Xcode 9 и более поздних версиях. Для того, чтобы проект Xcode компилировался при использовании Swift в статической библиотеке iOS, которую вы включаете в модуль, ваш основной проект приложения должен содержать код Swift и собственный заголовочный файл для моста. Если ваш проект приложения не содержит никакого кода Swift, решением может быть один пустой файл .swift и пустой заголовочный файл моста.

Зарезервированные имена методов

invalidate()

Модули нативных платформ могут соответствовать протоколу RCTInvalidating на iOS, реализовав метод invalidate(). Этот метод может быть вызван при аннулировании нативного моста (например, при перезагрузке в режиме разработки). Используйте этот механизм по мере необходимости, чтобы выполнить необходимые действия по очистке для вашего нативного модуля.

© 2022 Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://reactnative.dev/docs/native-modules-ios

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API