Spec-Zone.ru › React Native

Интеграция с существующими приложениями

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

Конкретные шаги зависят от платформы, на которую вы ориентируетесь.

  • Android (Kotlin)
  • Android (Java)
  • iOS (Objective-C)
  • iOS (Swift)

Основные понятия

Ключи к интеграции компонентов React Native в ваше приложение Android:

  1. Настройка зависимостей React Native и структуры каталогов.
  2. Разработка ваших компонентов React Native на JavaScript.
  3. Добавление ReactRootView в ваше приложение Android. Этот вид будет служить контейнером для вашего компонента React Native.
  4. Запуск сервера React Native и выполнение вашего приложения нативных.
  5. Проверка того, что React Native-аспект вашего приложения работает как ожидается.

Предварительные требования

Следуйте руководству React Native CLI Quickstart в руководстве по настройке среды для конфигурации вашей среды разработки для создания приложений React Native для Android.

1. Настройка структуры каталогов

Для обеспечения плавного процесса создайте новую папку для вашего интегрированного проекта React Native, затем скопируйте ваш существующий проект Android в папку /android.

2. Установка зависимостей JavaScript

Перейдите в корневой каталог вашего проекта и создайте новый файл package.json с указанным содержимым:

{
  "name": "MyReactNativeApp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "yarn react-native start"
  }
}

Далее, убедитесь, что у вас установлен менеджер пакетов yarn установка yarn.

Установите пакеты react и react-native. Откройте терминал или командную строку, перейдите в каталог с файлом package.json и выполните:

$ yarn add react-native

Это выведет сообщение, подобное следующему (прокрутите вывод yarn вверх, чтобы увидеть его):

Предупреждение "react-native@0.52.2" имеет неудовлетворённую зависимость "react@16.2.0".

Это нормально, это означает, что нам также нужно установить React:

$ yarn add react@version_printed_above

Yarn создал новую папку /node_modules. Эта папка хранит все необходимые для сборки проекта JavaScript-зависимости.

Добавьте node_modules/ в ваш файл .gitignore.

Добавление React Native в ваше приложение

Настройка maven

Добавьте зависимость React Native и JSC в файл build.gradle вашего приложения:

dependencies {
    implementation "com.android.support:appcompat-v7:27.1.1"
    ...
    implementation "com.facebook.react:react-native:+" // From node_modules
    implementation "org.webkit:android-jsc:+"
}

Если вы хотите гарантировать, что всегда используете определённую версию React Native в своём приложении, замените + на фактическую версию React Native, которую вы скачали с npm.

Добавьте запись для локальных каталогов maven React Native и JSC в верхнеуровневый файл settings.gradle. Убедитесь, что вы добавили её в блок “dependencyResolutionManagement”, выше других репозиториев maven:

dependencyResolutionManagement {
    ...
    repositories {
        ...
        maven {
            url "$rootDir/../node_modules/react-native/android"
        }
        maven {
            url("$rootDir/../node_modules/jsc-android/dist")
        }
    }
}

Если в вашем проекте репозитории зависимостей настроены в верхнеуровневом файле build.gradle, убедитесь, что вы добавили записи в блок “allprojects”, выше других репозиториев maven:

allprojects {
    repositories {
        maven {
            // All of React Native (JS, Android binaries) is installed from npm
            url "$rootDir/../node_modules/react-native/android"
        }
        maven {
            // Android JSC is installed from npm
            url("$rootDir/../node_modules/jsc-android/dist")
        }
        ...
    }
    ...
}

Убедитесь, что путь правильный! После синхронизации Gradle в Android Studio вы не должны столкнуться с ошибками типа "Не удалось разрешить: com.facebook.react:react-native:0.x.x".

Включить автоматическое подключение нативных модулей

Для использования возможностей автоподключения необходимо внести изменения в нескольких местах. Сначала добавьте следующую запись в settings.gradle:

apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)

Затем добавьте следующую запись в самом низу файла app/build.gradle:

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

Настройка разрешений

Далее, убедитесь, что в вашем файле AndroidManifest.xml включено разрешение на доступ к интернету:

<uses-permission android:name="android.permission.INTERNET" />

Если вам нужен доступ к DevSettingsActivity, добавьте его в ваш файл AndroidManifest.xml:

<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />

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

Открытый трафик (API уровень 28+)

Начиная с Android 9 (API уровень 28), открытый трафик по умолчанию отключён; это предотвращает подключение вашего приложения к Metro bundler. Изменения ниже позволяют открытый трафик в сборках отладки.

1. Примените опцию usesCleartextTraffic к вашей файлу отладки AndroidManifest.xml

<!-- ... -->
<application
  android:usesCleartextTraffic="true" tools:targetApi="28" >
  <!-- ... -->
</application>
<!-- ... -->

Это не требуется для релизных сборок.

Дополнительную информацию о конфигурации безопасности сети и политике открытого трафика см. здесь.

Интеграция кода

Теперь мы фактически изменим приложение Android, чтобы интегрировать React Native.

Компонент React Native

Первый фрагмент кода, который мы напишем, это фактический код React Native для нового экрана "Высокий рейтинг", который будет интегрирован в наше приложение.

1. Создайте файл index.js

Сначала создайте пустой файл index.js в корне вашего проекта React Native.

index.js — это отправная точка для приложений React Native, и она всегда требуется. Это может быть небольшой файл, который require другие файлы, которые являются частью вашего компонента или приложения React Native, или он может содержать весь необходимый код. В нашем случае мы поместим всё в index.js.

2. Добавьте свой код React Native

В файле index.js создайте свой компонент. В нашем примере мы добавим компонент <Text> внутри стилизованного компонента <View>:

import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

const HelloWorld = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.hello}>Hello, World</Text>
    </View>
  );
};
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center'
  },
  hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10
  }
});

AppRegistry.registerComponent(
  'MyReactNativeApp',
  () => HelloWorld
);
3. Настройка разрешений для перекрытия ошибок разработки

Если ваше приложение ориентировано на Android API level 23 или выше, убедитесь, что разрешение android.permission.SYSTEM_ALERT_WINDOW включено для сборки отладки. Вы можете проверить это с помощью Settings.canDrawOverlays(this). Это необходимо в сборках отладки, потому что ошибки разработки React Native должны отображаться поверх всех других окон. Из-за новой системы разрешений, введённой в API уровне 23 (Android M), пользователь должен её одобрить. Это можно сделать, добавив следующий код в метод Activity в файле onCreate().

companion object {
    const val OVERLAY_PERMISSION_REQ_CODE = 1  // Choose any value
}

...

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if(!Settings.canDrawOverlays(this)) {
        val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                                    Uri.parse("package: $packageName"))
        startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
    }
}

Наконец, метод onActivityResult() (как показано в коде ниже) необходимо переопределить, чтобы обработать случаи принятия или отклонения разрешения для согласованного пользовательского опыта. Также, для интеграции нативных модулей, использующих startActivityForResult, необходимо передать результат методу onActivityResult нашего экземпляра ReactInstanceManager.

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(this)) {
                // SYSTEM_ALERT_WINDOW permission not granted
            }
        }
    }
    reactInstanceManager?.onActivityResult(this, requestCode, resultCode, data)
}

Магия: ReactRootView

Добавим немного нативного кода, чтобы запустить среду выполнения React Native и указать ей отрисовать наш JS-компонент. Для этого мы создадим Activity, который создаст ReactRootView, запустит React-приложение внутри него и установит его в качестве основного содержимого представления.

Если вы ориентируетесь на Android версии <5, используйте класс AppCompatActivity из пакета com.android.support:appcompat вместо Activity.

class MyReactActivity : Activity(), DefaultHardwareBackBtnHandler {
    private lateinit var reactRootView: ReactRootView
    private lateinit var reactInstanceManager: ReactInstanceManager
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        SoLoader.init(this, false)
        reactRootView = ReactRootView(this)
        val packages: List<ReactPackage> = PackageList(application).packages
        // Packages that cannot be autolinked yet can be added manually here, for example:
        // packages.add(MyReactNativePackage())
        // Remember to include them in `settings.gradle` and `app/build.gradle` too.
        reactInstanceManager = ReactInstanceManager.builder()
            .setApplication(application)
            .setCurrentActivity(this)
            .setBundleAssetName("index.android.bundle")
            .setJSMainModulePath("index")
            .addPackages(packages)
            .setUseDeveloperSupport(BuildConfig.DEBUG)
            .setInitialLifecycleState(LifecycleState.RESUMED)
            .build()
        // The string here (e.g. "MyReactNativeApp") has to match
        // the string in AppRegistry.registerComponent() in index.js
        reactRootView?.startReactApplication(reactInstanceManager, "MyReactNativeApp", null)
        setContentView(reactRootView)
    }

    override fun invokeDefaultOnBackPressed() {
        super.onBackPressed()
    }
}

Если вы используете стартовый набор для React Native, замените строку "HelloWorld" на строку из файла index.js (это первый аргумент для метода AppRegistry.registerComponent()).

Выполните операцию «Синхронизировать файлы проекта с Gradle».

Если вы используете Android Studio, используйте Alt + Enter, чтобы добавить все необходимые импорты в класс MyReactActivity. Убедитесь, что используете BuildConfig из вашего пакета, а не из пакета facebook.

Нам нужно установить тему MyReactActivity на Theme.AppCompat.Light.NoActionBar, так как некоторые компоненты пользовательского интерфейса React Native полагаются на эту тему.

<activity
  android:name=".MyReactActivity"
  android:label="@string/app_name"
  android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>

Объект ReactInstanceManager можно использовать в нескольких активностях и/или фрагментах. Вам нужно создать свой ReactFragment или ReactActivity и иметь синглтон holder, который содержит ReactInstanceManager. Когда вам нужен ReactInstanceManager (например, для подключения ReactInstanceManager к жизненному циклу этих активностей или фрагментов), используйте тот, который предоставляет синглтон.

Далее, нам нужно передать некоторые обратные вызовы жизненного цикла активности в ReactInstanceManager и ReactRootView:

override fun onPause() {
    super.onPause()
    reactInstanceManager.onHostPause(this)
}

override fun onResume() {
    super.onResume()
    reactInstanceManager.onHostResume(this, this)
}

override fun onDestroy() {
    super.onDestroy()
    reactInstanceManager.onHostDestroy(this)
    reactRootView.unmountReactApplication()
}

Также нам нужно передать события нажатия кнопки «Назад» в React Native:

override fun onBackPressed() {
    reactInstanceManager.onBackPressed()
    super.onBackPressed()
}

Это позволяет JavaScript управлять действиями при нажатии пользователем аппаратной кнопки «Назад» (например, для реализации навигации). Если JavaScript не обрабатывает нажатие кнопки «Назад», будет вызван ваш метод invokeDefaultOnBackPressed. По умолчанию это завершает вашу Activity.

Наконец, нам нужно подключить меню разработчика. По умолчанию оно активируется встряхиванием устройства, но это не очень удобно в эмуляторах. Поэтому мы сделаем его видимым при нажатии аппаратной кнопки меню (используйте Ctrl + M, если вы используете эмулятор Android Studio):

override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
    if (keyCode == KeyEvent.KEYCODE_MENU && reactInstanceManager != null) {
        reactInstanceManager.showDevOptionsDialog()
        return true
    }
    return super.onKeyUp(keyCode, event)
}

Теперь ваша активность готова для выполнения кода JavaScript.

Тестирование интеграции

Вы выполнили все основные шаги по интеграции React Native с вашим приложением. Теперь запустим сервер Metro bundler, чтобы скомпилировать пакет index.bundle и запустить сервер на localhost для его обслуживания.

1. Запуск packager

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

$ yarn start
2. Запуск приложения

Теперь скомпилируйте и запустите ваше приложение Android как обычно.

После перехода к вашей активности React в приложении, оно должно загрузить код JavaScript с сервера разработки и отобразить:

Screenshot

Создание релизной сборки в Android Studio

Вы также можете использовать Android Studio для создания релизных сборок! Это так же быстро, как создание релизных сборок вашего уже существующего приложения для Android. Есть один дополнительный шаг, который нужно выполнить перед каждой релизной сборкой. Вам нужно выполнить следующее, чтобы создать пакет React Native, который будет включен в ваше приложение для Android:

$ npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/com/your-company-name/app-package-name/src/main/assets/index.android.bundle --assets-dest android/com/your-company-name/app-package-name/src/main/res/

Не забудьте заменить пути на правильные и создать папку assets, если она не существует.

Теперь создайте релизную сборку вашего приложения для Android в Android Studio, как обычно, и всё готово!

Что дальше?

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

Основные понятия

Ключи к интеграции компонентов React Native в ваше приложение Android:

  1. Настройка зависимостей React Native и структуры каталогов.
  2. Разработка ваших компонентов React Native на JavaScript.
  3. Добавление ReactRootView в ваше приложение Android. Этот вид будет служить контейнером для вашего компонента React Native.
  4. Запуск сервера React Native и запуск вашего нативного приложения.
  5. Проверка того, что компонент React Native вашего приложения работает как ожидается.

Предварительные требования

Следуйте руководству быстрого запуска React Native CLI в руководстве по настройке среды для настройки вашей среды разработки для создания приложений React Native для Android.

1. Настройка структуры каталогов

Для обеспечения плавной работы создайте новую папку для вашего интегрированного проекта React Native, затем скопируйте ваш существующий проект Android в подпапку /android.

2. Установка зависимостей JavaScript

Перейдите в корневой каталог вашего проекта и создайте новый файл package.json со следующим содержимым:

{
  "name": "MyReactNativeApp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "yarn react-native start"
  }
}

Далее, убедитесь, что у вас установлен менеджер пакетов yarn.

Установите пакеты react и react-native. Откройте терминал или командную строку, перейдите в каталог с вашим файлом package.json и выполните:

$ yarn add react-native

Это выведет сообщение, аналогичное следующему (прокрутите вывод yarn вверх, чтобы увидеть его):

предупреждение "react-native@0.52.2" имеет неудовлетворённую зависимость от "react@16.2.0".

Это нормально, это означает, что нам также нужно установить React:

$ yarn add react@version_printed_above

Yarn создал новую папку /node_modules. Эта папка хранит все зависимости JavaScript, необходимые для сборки вашего проекта.

Добавьте node_modules/ в ваш файл .gitignore.

Добавление React Native в ваше приложение

Настройка maven

Добавьте зависимость React Native и JSC в файл build.gradle вашего приложения:

dependencies {
    implementation "com.android.support:appcompat-v7:27.1.1"
    ...
    implementation "com.facebook.react:react-native:+" // From node_modules
    implementation "org.webkit:android-jsc:+"
}

Если вы хотите гарантировать, что вы всегда используете определённую версию React Native в вашей нативной сборке, замените + фактической версией React Native, которую вы скачали с npm.

Добавьте запись для локальных каталогов maven React Native и JSC в верхнеуровневый файл build.gradle. Убедитесь, что вы добавили её в блок “allprojects”, над другими репозиториями maven:

allprojects {
    repositories {
        maven {
            // All of React Native (JS, Android binaries) is installed from npm
            url "$rootDir/../node_modules/react-native/android"
        }
        maven {
            // Android JSC is installed from npm
            url("$rootDir/../node_modules/jsc-android/dist")
        }
        ...
    }
    ...
}

Убедитесь, что путь правильный! После синхронизации Gradle в Android Studio у вас не должно возникнуть ошибок типа «Не удалось разрешить: com.facebook.react:react-native:0.x.x».

Включить автоматическую привязку нативных модулей

Чтобы использовать возможности автоматической привязки, нам нужно её применить в нескольких местах. Сначала добавьте следующую запись в settings.gradle:

apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)

Далее, добавьте следующую запись в самом низу файла app/build.gradle:

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

Настройка разрешений

Далее, убедитесь, что у вас есть разрешение на доступ к Интернету в вашем файле AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

Если вам нужен доступ к DevSettingsActivity, добавьте его в ваш файл AndroidManifest.xml:

<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />

Это используется только в режиме разработки при перезагрузке JavaScript с сервера разработки, поэтому вы можете убрать это в релизных сборках, если нужно.

Незашифрованный трафик (уровень API 28+)

Начиная с Android 9 (уровень API 28), незашифрованный трафик по умолчанию отключен; это предотвращает подключение вашего приложения к Metro bundler. Изменения ниже позволяют использовать незашифрованный трафик в отладочных сборках.

1. Примените опцию usesCleartextTraffic к вашему отладочному файлу AndroidManifest.xml

<!-- ... -->
<application
  android:usesCleartextTraffic="true" tools:targetApi="28" >
  <!-- ... -->
</application>
<!-- ... -->

Это не требуется для релизных сборок.

Чтобы узнать больше о конфигурации сетевой безопасности и политике незашифрованного трафика, см. эту ссылку.

Интеграция кода

Теперь мы фактически изменим нативное приложение Android для интеграции React Native.

Компонент React Native

Первая часть кода, которую мы напишем, — это фактический код React Native для нового экрана «Высокий рейтинг», который будет интегрирован в наше приложение.

1. Создайте файл index.js

Сначала создайте пустой файл index.js в корне вашего проекта React Native.

index.js — точка входа для приложений React Native, и она всегда необходима. Это может быть небольшой файл, который require другие файлы, являющиеся частью вашего компонента или приложения React Native, или он может содержать весь необходимый для этого код. В нашем случае мы поместим всё в index.js.

2. Добавьте свой код React Native

В вашем файле index.js создайте свой компонент. В нашем примере мы добавим компонент <Text> внутри стилизованного <View>:

import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

const HelloWorld = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.hello}>Hello, World</Text>
    </View>
  );
};
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center'
  },
  hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10
  }
});

AppRegistry.registerComponent(
  'MyReactNativeApp',
  () => HelloWorld
);
3. Настройте разрешения для наложения отладки ошибок

Если ваше приложение ориентировано на Android API level 23 или более позднюю версию, убедитесь, что разрешение android.permission.SYSTEM_ALERT_WINDOW включено для отладочной сборки. Вы можете проверить это с помощью Settings.canDrawOverlays(this);. Это необходимо в отладочных сборках, так как ошибки React Native должны отображаться поверх всех других окон. Из-за новой системы разрешений, введённой в уровне API 23 (Android M), пользователю необходимо её одобрить. Этого можно добиться, добавив следующий код в метод onCreate() вашей Activity.

private final int OVERLAY_PERMISSION_REQ_CODE = 1;  // Choose any value

...

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (!Settings.canDrawOverlays(this)) {
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                                   Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
    }
}

Наконец, метод onActivityResult() (как показано в коде ниже) необходимо переопределить для обработки случаев одобрения или отклонения разрешения для согласованного пользовательского интерфейса. Кроме того, для интеграции нативных модулей, использующих startActivityForResult, нам необходимо передать результат методу onActivityResult нашего экземпляра ReactInstanceManager.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(this)) {
                // SYSTEM_ALERT_WINDOW permission not granted
            }
        }
    }
    mReactInstanceManager.onActivityResult( this, requestCode, resultCode, data );
}

Магия: ReactRootView

Добавим немного нативного кода, чтобы запустить среду выполнения React Native и указать ей отобразить наш JS-компонент. Для этого мы создадим Activity, который создаёт ReactRootView, запускает React-приложение внутри него и устанавливает его в качестве основного содержимого представления.

Если вы ориентируетесь на версию Android <5, используйте класс AppCompatActivity из пакета com.android.support:appcompat вместо Activity.

public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SoLoader.init(this, false);

        mReactRootView = new ReactRootView(this);
        List<ReactPackage> packages = new PackageList(getApplication()).getPackages();
        // Packages that cannot be autolinked yet can be added manually here, for example:
        // packages.add(new MyReactNativePackage());
        // Remember to include them in `settings.gradle` and `app/build.gradle` too.

        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setCurrentActivity(this)
                .setBundleAssetName("index.android.bundle")
                .setJSMainModulePath("index")
                .addPackages(packages)
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        // The string here (e.g. "MyReactNativeApp") has to match
        // the string in AppRegistry.registerComponent() in index.js
        mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null);

        setContentView(mReactRootView);
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }
}

Если вы используете стартовый набор для React Native, замените строку "HelloWorld" той, что в вашем файле index.js (это первый аргумент метода AppRegistry.registerComponent()).

Выполните операцию «Синхронизация файлов проекта с Gradle».

Если вы используете Android Studio, воспользуйтесь Alt + Enter, чтобы добавить все отсутствующие импорты в ваш класс MyReactActivity. Обратите внимание, чтобы использовать BuildConfig вашего пакета, а не из пакета facebook.

Нам необходимо установить тему MyReactActivity на Theme.AppCompat.Light.NoActionBar, так как некоторые компоненты пользовательского интерфейса React Native зависят от неё.

<activity
  android:name=".MyReactActivity"
  android:label="@string/app_name"
  android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>

ReactInstanceManager может использоваться несколькими activity и/или фрагментами. Вы можете создать свой ReactFragment или ReactActivity и иметь синглтон хранилище, содержащий ReactInstanceManager. Когда вам нужен ReactInstanceManager (например, для привязки ReactInstanceManager к жизненному циклу этих Activity или фрагментов), используйте предоставленный синглтоном.

Далее, нам нужно передать некоторые колбэки жизненного цикла активности в ReactInstanceManager и ReactRootView:

@Override
protected void onPause() {
    super.onPause();

    if (mReactInstanceManager != null) {
        mReactInstanceManager.onHostPause(this);
    }
}

@Override
protected void onResume() {
    super.onResume();

    if (mReactInstanceManager != null) {
        mReactInstanceManager.onHostResume(this, this);
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();

    if (mReactInstanceManager != null) {
        mReactInstanceManager.onHostDestroy(this);
    }
    if (mReactRootView != null) {
        mReactRootView.unmountReactApplication();
    }
}

Мы также должны передавать события нажатия кнопки «Назад» в React Native:

@Override
 public void onBackPressed() {
    if (mReactInstanceManager != null) {
        mReactInstanceManager.onBackPressed();
    } else {
        super.onBackPressed();
    }
}

Это позволяет JavaScript управлять действиями при нажатии пользователем аппаратной кнопки «Назад» (например, для реализации навигации). Если JavaScript не обрабатывает нажатие кнопки «Назад», будет вызван метод invokeDefaultOnBackPressed. По умолчанию этот метод завершает работу вашей активности Activity.

Наконец, нам нужно подключить меню разработчика. По умолчанию оно активируется встряхиванием устройства (по типу rage), но это не очень удобно в эмуляторах. Поэтому мы заставим его отображаться при нажатии аппаратной кнопки меню (используйте Ctrl + M, если вы используете эмулятор Android Studio):

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
        mReactInstanceManager.showDevOptionsDialog();
        return true;
    }
    return super.onKeyUp(keyCode, event);
}

Теперь ваша активность готова для выполнения JavaScript-кода.

Тестирование интеграции

Вы выполнили все основные шаги по интеграции React Native в ваше приложение. Теперь запустим Metro-компилятор, чтобы собрать пакет index.bundle, и сервер, работающий на localhost, для его предоставления.

1. Запуск packager

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

$ yarn start
2. Запуск приложения

Теперь скомпилируйте и запустите ваше Android-приложение в обычном режиме.

Как только вы перейдете к вашей React-активности внутри приложения, оно должно загрузить JavaScript-код с сервера разработки и отобразить:

Screenshot

Создание релизной сборки в Android Studio

Вы можете использовать Android Studio для создания релизных сборок! Это так же быстро, как создание релизных сборок вашего уже существующего нативного Android-приложения. Есть одно дополнительное действие, которое нужно выполнить перед каждой релизной сборкой. Вам нужно выполнить следующее, чтобы создать React Native-пакет, который будет включен в ваше нативное Android-приложение:

$ npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/com/your-company-name/app-package-name/src/main/assets/index.android.bundle --assets-dest android/com/your-company-name/app-package-name/src/main/res/

Не забудьте заменить пути на правильные и создать папку assets, если она не существует.

Теперь создайте релизную сборку вашего нативного приложения в Android Studio, как обычно, и всё должно работать!

Что дальше?

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

Основные понятия

Ключи к интеграции компонентов React Native в ваше приложение iOS:

  1. Настройка зависимостей React Native и структуры каталогов.
  2. Понимание компонентов React Native, которые вы будете использовать в своем приложении.
  3. Добавление этих компонентов в качестве зависимостей с помощью CocoaPods.
  4. Разработка компонентов React Native на JavaScript.
  5. Добавление RCTRootView в ваше приложение iOS. Этот вид будет служить контейнером для вашего компонента React Native.
  6. Запуск сервера React Native и выполнение вашего приложения нативно.
  7. Проверка того, что React Native часть вашего приложения работает как ожидается.

Предварительные требования

Следуйте руководству по быстрому началу работы с React Native CLI в руководстве по настройке среды, чтобы настроить свою среду разработки для создания приложений React Native для iOS.

1. Настройка структуры каталогов

Для обеспечения гладкой работы создайте новую папку для вашего проекта React Native, затем скопируйте существующий проект iOS в подпапку /ios.

2. Установка зависимостей JavaScript

Перейдите в корневой каталог своего проекта и создайте новый файл package.json с содержимым:

{
  "name": "MyReactNativeApp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "yarn react-native start"
  }
}

Затем убедитесь, что у вас установлен менеджер пакетов yarn.

Установите пакеты react и react-native. Откройте терминал или командную строку, перейдите в каталог с вашим файлом package.json и выполните:

  • npm
  • Yarn
npm install react-native
yarn add react-native

Это выведет сообщение, подобное следующему (прокрутите вывод yarn вверх, чтобы увидеть его):

предупреждение "react-native@0.52.2" имеет неудовлетворённую зависимость "react@16.2.0".

Это нормально, это означает, что нам также нужно установить React:

  • npm
  • Yarn
npm install react@version_printed_above
yarn add react@version_printed_above

Процесс установки создал новую папку /node_modules. Эта папка хранит все зависимости JavaScript, необходимые для сборки вашего проекта.

Добавьте node_modules/ в ваш файл .gitignore.

3. Установка CocoaPods

CocoaPods — это инструмент управления пакетами для iOS и macOS разработки. Мы используем его, чтобы добавить фактический код фреймворка React Native локально в ваш текущий проект.

Мы рекомендуем установить CocoaPods с помощью Homebrew.

brew install cocoapods

Технически возможно не использовать CocoaPods, но это потребует ручных добавлений библиотек и линков, что чрезмерно усложнит этот процесс.

Добавление React Native в ваше приложение

Предположим, что приложение для интеграции приложение для интеграции — это игра 2048. Вот как выглядит главный экран приложения без React Native.

Before RN Integration

Инструменты командной строки для Xcode

Установите инструменты командной строки. Выберите «Настройки...» в меню Xcode. Перейдите на вкладку «Расположение» и установите инструменты, выбрав последнюю версию в раскрывающемся списке «Инструменты командной строки».

Xcode Command Line Tools

Настройка зависимостей CocoaPods

Прежде чем интегрировать React Native в своё приложение, вы должны определиться с частями фреймворка React Native, которые вы хотите интегрировать. Мы будем использовать CocoaPods для указания, от каких "подмодулей" ваше приложение будет зависеть.

Список поддерживаемых subspec доступен в /node_modules/react-native/React.podspec. Они обычно названы по функциональности. Например, вы обычно всегда захотите Core subspec. Это даст вам AppRegistry, StyleSheet, View и другие основные библиотеки React Native. Если вы хотите добавить библиотеку React Native Text (например, для <Text> элементов), вам понадобится RCTText subspec. Если вы хотите библиотеку Image (например, для <Image> элементов), вам понадобится RCTImage subspec.

Вы можете указать, от каких subspec ваше приложение будет зависеть в файле Podfile. Самый простой способ создать Podfile — запустить команду CocoaPods init в подпапке /ios вашего проекта:

pod init

Podfile будет содержать шаблонную настройку, которую вы будете подстраивать под свои цели интеграции.

Версия Podfile зависит от вашей версии react-native. Обратитесь к https://react-native-community.github.io/upgrade-helper/ для получения конкретной версии Podfile, которую вы должны использовать.

В конечном счете, ваш Podfile должен выглядеть примерно так:

# The target name is most likely the name of your project.
target 'NumberTileGame' do

  # Your 'node_modules' directory is probably in the root of your project,
  # but if not, adjust the `:path` accordingly
  pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
  pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
  pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
  pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
  pod 'React', :path => '../node_modules/react-native/'
  pod 'React-Core', :path => '../node_modules/react-native/'
  pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
  pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
  pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
  pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
  pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
  pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
  pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
  pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
  pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
  pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
  pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
  pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'

  pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
  pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
  pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
  pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
  pod 'ReactCommon/callinvoker', :path => "../node_modules/react-native/ReactCommon"
  pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
  pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'

  pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
  pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
  pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'

end

После создания вашего Podfile, вы готовы установить подмодуль React Native.

$ pod install

Вы должны увидеть вывод, подобный следующему:

Analyzing dependencies
Fetching podspec for `React` from `../node_modules/react-native`
Downloading dependencies
Installing React (0.62.0)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There are 3 dependencies from the Podfile and 1 total pod installed.

Если это завершится ошибками, связанными с xcrun, убедитесь, что в Xcode в Настройки > Расположение указаны инструменты командной строки.

Примечание для пользователей Mac M1

Архитектура Mac M1 несовместима напрямую с CocoaPods. Если у вас возникнут проблемы при установке подмодулей, вы можете решить их, выполнив:

  • sudo arch -x86_64 gem install ffi
  • arch -x86_64 pod install

Эти команды устанавливают пакет ffi для динамической загрузки библиотек и позволяют правильно запускать pod install, а также запускает pod install с правильной архитектурой.

Интеграция кода

Теперь мы фактически изменим приложение iOS, чтобы интегрировать React Native. Для нашего примера игры 2048 мы добавим экран «Рекорды» в React Native.

Компонент React Native

Первая часть кода, которую мы напишем, — это фактический код React Native для нового экрана «Рекорды», который будет интегрирован в наше приложение.

1. Создание файла index.js

Сначала создайте пустой файл index.js в корне вашего проекта React Native.

index.js — это отправная точка для приложений React Native, и она всегда необходима. Это может быть небольшой файл, который require другие файлы, которые являются частью вашего компонента или приложения React Native, или он может содержать весь необходимый код. В нашем случае мы поместим всё в index.js.

2. Добавление вашего кода React Native

В вашем файле index.js создайте свой компонент. В нашем примере здесь мы добавим компонент <Text> внутри стилизованного <View>

import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

const RNHighScores = ({ scores }) => {
  const contents = scores.map((score) => (
    <Text key={score.name}>
      {score.name}:{score.value}
      {'\n'}
    </Text>
  ));
  return (
    <View style={styles.container}>
      <Text style={styles.highScoresTitle}>
        2048 High Scores!
      </Text>
      <Text style={styles.scores}>{contents}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#FFFFFF'
  },
  highScoresTitle: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10
  },
  scores: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5
  }
});

// Module name
AppRegistry.registerComponent('RNHighScores', () => RNHighScores);

RNHighScores — это имя вашего модуля, которое будет использоваться при добавлении представления в React Native из вашего приложения iOS.

Магия: RCTRootView

Теперь, когда ваш компонент React Native создан через index.js, вам нужно добавить этот компонент в новый или существующий ViewController. Самый простой способ — создать путь к вашему компоненту, а затем добавить этот компонент в существующий ViewController.

Мы свяжем наш компонент React Native с новым нативным представлением в ViewController, которое фактически будет его содержать, под названием RCTRootView.

1. Создание пути события

Вы можете добавить новую ссылку в главное меню игры, чтобы перейти на страницу "Рекорды" React Native.

Event Path

2. Обработчик событий

Теперь мы добавим обработчик событий для ссылки в меню. Метод будет добавлен в основной ViewController вашего приложения. Именно здесь RCTRootView вступает в игру.

При создании приложения React Native вы используете Metro-сборщик, чтобы создать index.bundle, который будет обслуживаться сервером React Native. Внутри index.bundle будет наш модуль RNHighScore. Поэтому нам нужно указать нашему RCTRootView местоположение ресурса index.bundle (через NSURL) и связать его с модулем.

В целях отладки мы будем регистрировать вызов обработчика событий. Затем мы создадим строку с местоположением нашего кода React Native, который находится внутри index.bundle. Наконец, мы создадим основной RCTRootView. Обратите внимание, как мы предоставляем RNHighScores в качестве moduleName, который мы создали выше при написании кода для нашего компонента React Native.

Сначала import заголовок RCTRootView.

#import <React/RCTRootView.h>

initialProperties представлены здесь для иллюстрации, поэтому у нас есть данные для экрана рекордов. В нашем компоненте React Native мы будем использовать this.props для доступа к этим данным.

- (IBAction)highScoreButtonPressed:(id)sender {
    NSLog(@"High Score Button Pressed");
    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];

    RCTRootView *rootView =
      [[RCTRootView alloc] initWithBundleURL: jsCodeLocation
                                  moduleName: @"RNHighScores"
                           initialProperties:
                             @{
                               @"scores" : @[
                                 @{
                                   @"name" : @"Alex",
                                   @"value": @"42"
                                  },
                                 @{
                                   @"name" : @"Joel",
                                   @"value": @"10"
                                 }
                               ]
                             }
                               launchOptions: nil];
    UIViewController *vc = [[UIViewController alloc] init];
    vc.view = rootView;
    [self presentViewController:vc animated:YES completion:nil];
}

Обратите внимание, что RCTRootView initWithURL запускает новую виртуальную машину JSC. Чтобы сохранить ресурсы и упростить взаимодействие между представлениями RN в разных частях вашего нативного приложения, вы можете иметь несколько представлений, работающих на React Native, которые связаны с одним исполняемым модулем JavaScript. Для этого вместо использования [RCTRootView alloc] initWithURL используйте RCTBridge initWithBundleURL, чтобы создать мост, а затем используйте RCTRootView initWithBridge.

При перемещении приложения в производство NSURL может указывать на предварительно собранный файл на диске, например, через [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];. Вы можете использовать сценарий react-native-xcode.sh в node_modules/react-native/scripts/ для генерации этого предварительно собранного файла.

3. Подключение

Подключите новую ссылку в главном меню к методу обработчика событий, который вы только что добавили.

Event Path

Один из более простых способов сделать это — открыть представление в схеме и щелкнуть правой кнопкой мыши по новой ссылке. Выберите такое событие, как Touch Up Inside, перетащите его на схему, а затем выберите созданный метод из списка.

Тестирование интеграции

Вы выполнили все основные шаги по интеграции React Native с вашим текущим приложением. Теперь мы запустим Metro-сборщик, чтобы скомпилировать пакет index.bundle, и сервер, работающий на localhost, чтобы обслуживать его.

1. Добавление исключения App Transport Security

Apple заблокировал неявную загрузку HTTP-ресурсов без шифрования. Поэтому нам нужно добавить следующее в файл Info.plist (или аналогичный) нашего проекта.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

App Transport Security полезен для ваших пользователей. Убедитесь, что вы снова активировали его перед выпуском приложения в производство.

2. Запуск пакета

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

  • npm
  • Yarn
npm start
yarn start
3. Запуск приложения

Если вы используете Xcode или ваш любимый редактор, создайте и запустите ваше нативное iOS-приложение в обычном режиме. В качестве альтернативы, вы можете запустить приложение из командной строки, используя:

# From the root of your project
$ npx react-native run-ios

В нашем примере приложения вы должны увидеть ссылку на "Рекорды", а затем, при нажатии на неё, увидите отображение вашего компонента React Native.

Вот домашний экран нативного приложения:

Home Screen

Вот экран React Native с рекордами:

High Scores

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

Что дальше?

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

Основные понятия

Ключи к интеграции компонентов React Native в ваше приложение iOS:

  1. Настройка зависимостей React Native и структуры каталогов.
  2. Понимание, какие компоненты React Native вы будете использовать в своем приложении.
  3. Добавление этих компонентов в качестве зависимостей с помощью CocoaPods.
  4. Разработка компонентов React Native на JavaScript.
  5. Добавление RCTRootView в ваше приложение iOS. Этот вид будет служить контейнером для вашего компонента React Native.
  6. Запуск сервера React Native и запуск вашего приложения.
  7. Проверка того, что аспект React Native вашего приложения работает как ожидается.

Предварительные условия

Следуйте инструкциям по быстрой настройке React Native CLI в руководстве по настройке среды для настройки среды разработки для создания приложений React Native для iOS.

1. Настройка структуры каталогов

Для обеспечения плавной работы создайте новую папку для своего интегрированного проекта React Native, затем скопируйте существующий проект iOS в папку /ios.

2. Установка зависимостей JavaScript

Перейдите в корневой каталог своего проекта и создайте новый файл package.json со следующим содержимым:

{
  "name": "MyReactNativeApp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "yarn react-native start"
  }
}

Далее, убедитесь, что у вас установлен менеджер пакетов yarn yarn package manager.

Установите пакеты react и react-native. Откройте терминал или командную строку, перейдите в каталог с вашим файлом package.json и выполните:

$ yarn add react-native

Это выведет сообщение, подобное следующему (прокрутите вывод yarn вверх, чтобы увидеть его):

предупреждение "react-native@0.52.2" имеет неудовлетворенную зависимость от "react@16.2.0".

Это нормально, это означает, что нам также необходимо установить React:

$ yarn add react@version_printed_above

Yarn создал новую папку /node_modules. Эта папка хранит все зависимости JavaScript, необходимые для построения вашего проекта.

Добавьте node_modules/ в ваш файл .gitignore.

3. Установка CocoaPods

CocoaPods — это инструмент управления пакетами для iOS и macOS. Мы используем его для добавления фактического кода фреймворка React Native локально в ваш текущий проект.

Рекомендуется установить CocoaPods с помощью Homebrew.

$ brew install cocoapods

Технически можно не использовать CocoaPods, но это потребует ручного добавления библиотек и линков, что чрезмерно усложнит этот процесс.

Добавление React Native в ваше приложение

Предположим, что приложение для интеграции приложение для интеграции — игра 2048. Вот как выглядит главное меню приложения без React Native.

Before RN Integration

Инструменты командной строки для Xcode

Установите инструменты командной строки. Выберите «Настройки...» в меню Xcode. Перейдите во вкладку «Расположения» и установите инструменты, выбрав последнюю версию в раскрывающемся списке «Инструменты командной строки».

Xcode Command Line Tools

Настройка зависимостей CocoaPods

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

Список поддерживаемых subspec доступен в /node_modules/react-native/React.podspec. Они обычно называются по функциональности. Например, вы, как правило, всегда захотите использовать Core subspec. Это даст вам AppRegistry, StyleSheet, View и другие основные библиотеки React Native. Если вы хотите добавить библиотеку React Native Text (например, для <Text> элементов), вам понадобится RCTText subspec. Если вам нужна библиотека Image (например, для <Image> элементов), вам понадобится RCTImage subspec.

Вы можете указать, от каких subspec будет зависеть ваше приложение в файле Podfile. Самый простой способ создать файл Podfile — запустить команду CocoaPods init в папке /ios вашего проекта:

$ pod init

Файл Podfile будет содержать шаблонную настройку, которую вы будете изменять для целей интеграции.

Версия Podfile зависит от вашей версии react-native. Обратитесь к https://react-native-community.github.io/upgrade-helper/ для получения конкретной версии Podfile, которую вы должны использовать.

В конечном итоге ваш файл Podfile должен выглядеть примерно так:

source 'https://github.com/CocoaPods/Specs.git'

# Required for Swift apps
platform :ios, '8.0'
use_frameworks!

# The target name is most likely the name of your project.
target 'swift-2048' do

  # Your 'node_modules' directory is probably in the root of your project,
  # but if not, adjust the `:path` accordingly
  pod 'React', :path => '../node_modules/react-native', :subspecs => [
    'Core',
    'CxxBridge', # Include this for RN >= 0.47
    'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
    'RCTText',
    'RCTNetwork',
    'RCTWebSocket', # needed for debugging
    # Add any other subspecs you want to use in your project
  ]
  # Explicitly include Yoga if you are using RN >= 0.42.0
  pod "Yoga", :path => "../node_modules/react-native/ReactCommon/yoga"

  # Third party deps podspec link
  pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
  pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
  pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'

end

После создания вашего файла Podfile вы готовы установить React Native pod.

$ pod install

Вы должны увидеть вывод, подобный этому:

Analyzing dependencies
Fetching podspec for `React` from `../node_modules/react-native`
Downloading dependencies
Installing React (0.62.0)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There are 3 dependencies from the Podfile and 1 total pod installed.

Если это завершится ошибками, упоминающими xcrun, убедитесь, что в Xcode в Настройки > Расположения назначены инструменты командной строки.

Если вы получите предупреждение, такое как «Целевой swift-2048 [Debug] переопределяет параметр сборки FRAMEWORK_SEARCH_PATHS, определенный в Pods/Target Support Files/Pods-swift-2048/Pods-swift-2048.debug.xcconfig. Это может привести к проблемам с установкой CocoaPods», убедитесь, что Framework Search Paths в Build Settings для Debug и Release содержит только $(inherited).

Примечание для пользователей Mac M1

Архитектура Mac M1 несовместима с CocoaPods напрямую. Если у вас возникнут проблемы с установкой под, вы можете решить их, выполнив:

  • sudo arch -x86_64 gem install ffi
  • arch -x86_64 pod install

Эти команды устанавливают пакет ffi, чтобы загрузить динамически связанные библиотеки и позволить вам правильно запустить pod install, и запускает pod install с правильной архитектурой.

Интеграция кода

Теперь мы фактически изменим приложение iOS, чтобы интегрировать React Native. Для нашего приложения 2048 мы добавим экран «Высокий рейтинг» в React Native.

Компонент React Native

Первый фрагмент кода, который мы напишем, — это фактический код React Native для нового экрана «Высокий рейтинг», который будет интегрирован в наше приложение.

1. Создайте файл index.js

Сначала создайте пустой файл index.js в корне вашего проекта React Native.

index.js — это отправная точка для приложений React Native, и он всегда необходим. Это может быть небольшой файл, require другие файлы, которые являются частью вашего компонента или приложения React Native, или он может содержать весь необходимый для него код. В нашем случае мы поместим все в index.js.

2. Добавьте свой код React Native

В вашем файле index.js создайте свой компонент. В нашем примере здесь мы добавим компонент <Text> внутри стилизованного <View>

import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

const RNHighScores = ({ scores }) => {
  const contents = scores.map((score) => (
    <Text key={score.name}>
      {score.name}:{score.value}
      {'\n'}
    </Text>
  ));
  return (
    <View style={styles.container}>
      <Text style={styles.highScoresTitle}>
        2048 High Scores!
      </Text>
      <Text style={styles.scores}>{contents}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#FFFFFF'
  },
  highScoresTitle: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10
  },
  scores: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5
  }
});

// Module name
AppRegistry.registerComponent('RNHighScores', () => RNHighScores);

RNHighScores — это имя вашего модуля, которое будет использоваться при добавлении представления в React Native из вашего приложения iOS.

Магия: RCTRootView

Теперь, когда ваш компонент React Native создан через index.js, вам нужно добавить этот компонент в новый или существующий ViewController. Самый простой путь — необязательно создать путь события к вашему компоненту, а затем добавить этот компонент в существующий ViewController.

Мы свяжем наш компонент React Native с новым нативным представлением в ViewController, который фактически будет его содержать, под названием RCTRootView .

1. Создание пути события

Вы можете добавить новую ссылку в главное меню игры для перехода на страницу «Высокий рейтинг» приложения React Native.

Event Path

2. Обработчик событий

Теперь мы добавим обработчик событий для ссылки в меню. В основной ViewController вашего приложения будет добавлен метод. Именно здесь используется RCTRootView.

При создании приложения React Native вы используете Metro-бандлер, чтобы создать index.bundle, который будет обслуживаться сервером React Native. Внутри index.bundle будет наш модуль RNHighScore. Поэтому нам нужно указать нашему RCTRootView расположение ресурса index.bundle (через NSURL) и связать его с модулем.

В целях отладки мы будем регистрировать вызов обработчика событий. Затем мы создадим строку с расположением нашего кода React Native, который находится внутри index.bundle. Наконец, мы создадим основной RCTRootView. Обратите внимание, как мы предоставляем RNHighScores в качестве moduleName, который мы создали выше при написании кода для нашего компонента React Native.

Сначала подключите библиотеку import.

import React

Эти initialProperties представлены для демонстрации, чтобы у нас были данные для экрана с высоким рейтингом. В нашем компоненте React Native мы будем использовать this.props для доступа к этим данным.

@IBAction func highScoreButtonTapped(sender : UIButton) {
  NSLog("Hello")
  let jsCodeLocation = URL(string: "http://localhost:8081/index.bundle?platform=ios")
  let mockData:NSDictionary = ["scores":
      [
          ["name":"Alex", "value":"42"],
          ["name":"Joel", "value":"10"]
      ]
  ]

  let rootView = RCTRootView(
      bundleURL: jsCodeLocation,
      moduleName: "RNHighScores",
      initialProperties: mockData as [NSObject : AnyObject],
      launchOptions: nil
  )
  let vc = UIViewController()
  vc.view = rootView
  self.present(vc, animated: true, completion: nil)
}

Обратите внимание, что RCTRootView bundleURL запускает новую виртуальную машину JSC. Чтобы сохранить ресурсы и упростить взаимодействие между представлениями RN в разных частях вашего нативного приложения, вы можете иметь несколько представлений, управляемых React Native, связанных с одним исполняемым файлом JavaScript. Для этого вместо использования RCTRootView bundleURL используйте RCTBridge initWithBundleURL для создания моста, а затем используйте RCTRootView initWithBridge.

При развертывании приложения в продакшене NSURL может указывать на предварительно скомпилированный файл на диске, например, через let mainBundle = NSBundle(URLForResource: "main" withExtension:"jsbundle"). Для создания предварительно скомпилированного файла вы можете использовать скрипт react-native-xcode.sh в node_modules/react-native/scripts/.

3. Подключение

Подключите новую ссылку в главном меню к новому методу обработчика событий.

Event Path

Один из более простых способов сделать это — открыть представление в макете и щелкнуть правой кнопкой мыши по новой ссылке. Выберите какой-либо элемент, например, событие Touch Up Inside, перетащите его в макет, а затем выберите созданный метод из представленного списка.

Тестирование интеграции

Вы выполнили все основные шаги по интеграции React Native с вашим текущим приложением. Теперь мы запустим Metro-бандлер для построения пакета index.bundle и сервер, работающий на localhost, для его обслуживания.

1. Добавление исключения App Transport Security

Apple заблокировал неявную загрузку ресурсов HTTP в открытом виде. Поэтому нам необходимо добавить следующее в файл Info.plist (или эквивалент) проекта.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

App Transport Security полезен для ваших пользователей. Убедитесь, что вы включили его перед выпуском приложения в продакшн.

2. Запуск пакета

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

$ npm start
3. Запуск приложения

Если вы используете Xcode или ваш любимый редактор, скомпилируйте и запустите ваше нативное приложение iOS в обычном режиме. Или вы можете запустить приложение из командной строки с помощью:

# From the root of your project
$ npx react-native run-ios

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

Вот домашний экран нативного приложения:

Home Screen

Вот экран React Native с высоким рейтингом:

High Scores

Если при запуске приложения возникают проблемы с разрешением модулей, см. этот вопрос на GitHub для получения информации и возможных решений. Этот комментарий кажется последним возможным решением.

Что дальше?

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

© 2022 Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://reactnative.dev/docs/integration-with-existing-apps

Spec-Zone.ru

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