Получите ранний доступ к TurboModules и Codegen в React Native.

При использовании React Native ранее мы взаимодействовали между «родным» слоем нашего приложения и слоем «JavaScript» с помощью моста JavaScript. Хотя мост выполнял свою задачу, у него было несколько серьезных проблем.

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

Во-вторых, мост не был типобезопасным. Вы в значительной степени передавали по мосту все, что хотели, и нативный уровень должен был что-то делать для обработки этих данных. Наконец, при запуске приложения все нативные модули должны быть загружены в память. Это означало медленное время запуска для пользователей.

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

Codegen решает проблему безопасности типов, поскольку позволяет нам создавать интерфейсы, которые мы можем использовать, чтобы убедиться, что наш собственный код остается синхронизированным с данными, которые мы передаем из уровня JavaScript.

Это руководство покажет вам, как использовать Codegen и TurboModules вместе с React Native в Android. Вторая статья из этой серии будет посвящена тому же самому в iOS. Обратите внимание, что это руководство для первых пользователей, предназначенное для React Native с 0.68.2 по 0.69.0. Новая архитектура React Native все еще находится в процессе разработки и со временем может меняться. Если вы застряли, не стесняйтесь взглянуть на мой пример проекта здесь. Если вас заинтересовал мой видео-урок на эту тему, посмотрите мое видео здесь.

РЕДАКТИРОВАТЬ: пользователи React-Native 0.69.0 увидят ложные ошибки в Android Studio о том, что импорт не может быть найден. Я жаловался на эту проблему здесь, и Мета, кажется, знает об этом. Если вы будете следовать этим инструкциям и при необходимости импортировать из моего примера проекта, приложение все равно скомпилируется. Ошибки Android Studio возникают из-за ошибки в их IDE, а не в этом коде. Возможно, имеет смысл выполнить это руководство в коде Visual Studio, чтобы избежать шума ошибок Android Studio.

Что мы строим?

В этой статье мы собираемся создать простое приложение, которое вызывает TurboModule и печатает сообщение. Просто, я знаю, но с Codegen вы можете создавать функции настолько сложными, насколько вам нравится, после прочтения этого блога. Это будет выглядеть так:

Нативная установка React

Начните с создания проекта TypeScript с помощью следующей команды:

npx react-native init TurboModuleSampleProject --template react-native-template-typescript

Важно, чтобы мы использовали TypeScript, потому что Codegen требует, чтобы мы использовали типы. Ванильный JS-проект здесь не годится.

Далее давайте создадим папку с именем js в корне проекта. Внутри js мы собираемся создать файл с именем NativeSampleModule.ts. Будьте очень осторожны, всегда добавляйте префикс имени вашего файла и модуля со словом Native. Если вы этого не сделаете, Codegen не сможет найти ваш код и ничего не сгенерирует. Это не дает вам никаких ошибок здесь и молча терпит неудачу. В завершение скопируйте и вставьте этот код в свой файл.

import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {
  getHelloWorld(first: string, second: string): string;
}
export default TurboModuleRegistry.getEnforcing<Spec>('NativeSampleModule');

Настройка Android Gradle

В Android мы начинаем с перехода на уровень приложения build.gradle и добавления этой строки в начало файла.

apply plugin: "com.facebook.react"

После этого нам нужно сообщить Android, где находится наш файл Codegen. Мы делаем это, добавляя этот код в строку 88

react {
  jsRootDir = rootProject.file("../js/")
}

Затем найдите свойство enableHermes и установите для него значение true. Новая архитектура для React-Native не будет работать, если вы не используете Hermes. После этого раскомментируйте строку:

preBuild.dependsOn("generateCodegenArtifactsFromSchema")

Наконец, перейдите к gradle.properties и установите newArchEnabled=true

Запускаем yarn android для генерации нужных нам файлов

Написание нашего Java-кода

Теперь, когда мы настроили нашу сборку и сгенерировали привязки для функций JavaScript, давайте откроем папку android в Android Studio и напишем собственный код.

Начните с поиска пакета com.turbomodulessampleproject

В этом пакете создайте новый файл с именем NativeSampleModuleImpl.java . Внутри этого файла мы собираемся расширить интерфейс, созданный Codegen. Это будет выглядеть так.

package com.turbomodulesampleproject;

import androidx.annotation.NonNull;

import com.facebook.fbreact.specs.NativeSampleModuleSpec;
import com.facebook.react.bridge.ReactApplicationContext;

public class NativeSampleModuleImpl extends NativeSampleModuleSpec {

    public static String NAME = "NativeSampleModule";

    public NativeSampleModuleImpl(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getHelloWorld(String first, String second) {
        return "HelloWorld: " + first + " " + second;
    }

    @NonNull
    @Override
    public String getName() {
        return NAME;
    }
}

Далее мы хотим добавить наш пакет на хост приложения. Для этого найдите каталог newarchitecture под пакетом турбо-модулей сверху и найдите файл MainApplicationReactNativeHost.java. Переопределите метод getPackages следующим образом. Импортируйте любые классы, которые вам нужны, с помощью alt + enter

@Override
protected List<ReactPackage> getPackages() {
  List<ReactPackage> packages = new PackageList(this).getPackages();

  packages.add(new TurboReactPackage() {
    @Nullable
    @Override
    public NativeModule getModule(String name, ReactApplicationContext reactContext) {
      if (name.equals(NativeSampleModuleImpl.NAME)) {
        return new NativeSampleModuleImpl(reactContext);
      } else {
        return null;
      }
    }

    @Override
    public ReactModuleInfoProvider getReactModuleInfoProvider() {
      return () -> {
        final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
        moduleInfos.put(
                NativeSampleModuleImpl.NAME,
                new ReactModuleInfo(
                        NativeSampleModuleImpl.NAME,
                        NativeSampleModuleImpl.NAME,
                        false, // canOverrideExistingModule
                        false, // needsEagerInit
                        true, // hasConstants
                        false, // isCxxModule
                        true // isTurboModule
                )
        );
        return moduleInfos;
      };
    }
  });


  return packages;
}

Написание кода C++

Последний шаг, который нам нужно сделать, — настроить сторону C++. Начните с поиска файла Android.mk по этому пути.

TurboModuleSample/android/app/src/main/jni/Android.mk

Затем раскомментируйте пути Codegen следующим образом:

include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk

затем

LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni

Внизу добавьте свою библиотеку. Он должен называться react_codegen_AppSpec, он будет выглядеть так:

LOCAL_SHARED_LIBRARIES := \
  react_codegen_AppSpec \
  libfabricjni \
  libfbjni \
  libfolly_futures \
  libfolly_json \
  libglog \
  libjsi \
  libreact_codegen_rncore \
  libreact_debug \
  libreact_nativemodule_core \
  libreact_render_componentregistry \
  libreact_render_core \
  libreact_render_debug \
  libreact_render_graphics \
  librrc_view \
  libruntimeexecutor \
  libturbomodulejsijni \
  libyoga \

Затем в файле android/app/src/main/jni/MainApplicationModuleProvider.cpp добавьте #include <AppSpec.h> и раскомментируйте и замените следующие строки:

#include <AppSpec.h>
....
auto module = AppSpec_ModuleProvider(moduleName, params);
if (module != nullptr) {
    return module;
}

На этом этапе давайте запустим yarn android, чтобы убедиться, что приложение скомпилировано.

Триумфальное возвращение к React Native

Давайте закончим, проверив все. В любом месте вашего файла App.tsx добавьте следующий код.

import NativeSampleModule from './js/NativeSampleModule';
...
const showMessage = () => {
  const message = NativeSampleModule.getHelloWorld('Daniel', 'Friyia');
  alert(message);
};
...
<Button title="Click here" onPress={showMessage} />

Когда вы нажимаете кнопку, вы должны увидеть всплывающее предупреждение с сообщением, которое мы создали в собственном слое.

Заключение

Надеюсь, вам понравилось это введение в TurboModules в React Native для Android. Достаточно скоро они уберут старый мост, поэтому нам будет важно быть в курсе того, как развиваются турбомодули. Пожалуйста, ознакомьтесь со второй частью, где я покажу вам, как заставить TurboModules и Codegen работать на iOS.

Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter и LinkedIn. Посетите наш Community Discord и присоединитесь к нашему Коллективу талантов.