Skip to main content

与现有应用集成

当你从头开始开发新的移动应用时,React Native 非常有用。但是,它也适用于向现有原生应用添加单个视图或用户流。只需几个步骤,你就可以添加新的基于 React Native 的功能、屏幕、视图等。

¥React Native is great when you are starting a new mobile app from scratch. However, it also works well for adding a single view or user flow to existing native applications. With a few steps, you can add new React Native based features, screens, views, etc.

具体步骤会有所不同,具体取决于你的目标平台。

¥The specific steps are different depending on what platform you're targeting.

关键概念

¥Key Concepts

将 React Native 组件集成到 Android 应用中的关键是:

¥The keys to integrating React Native components into your Android application are to:

  1. 设置 React Native 依赖和目录结构。

    ¥Set up React Native dependencies and directory structure.

  2. 使用 JavaScript 开发 React Native 组件。

    ¥Develop your React Native components in JavaScript.

  3. ReactRootView 添加到你的 Android 应用中。该视图将用作 React Native 组件的容器。

    ¥Add a ReactRootView to your Android app. This view will serve as the container for your React Native component.

  4. 启动 React Native 服务器并运行你的原生应用。

    ¥Start the React Native server and run your native application.

  5. 验证应用的 React Native 方面是否按预期工作。

    ¥Verify that the React Native aspect of your application works as expected.

先决条件

¥Prerequisites

按照 设置你的开发环境 上的指南配置你的开发环境以构建适用于 Android 的 React Native 应用。

¥Follow the guide on setting up your development environment to configure your development environment for building React Native apps for Android.

1. 设置目录结构

¥ Set up directory structure

为了确保流畅的体验,请为集成的 React Native 项目创建一个新文件夹,然后将现有的 Android 项目复制到 /android 子文件夹。

¥To ensure a smooth experience, create a new folder for your integrated React Native project, then copy your existing Android project to an /android subfolder.

2. 安装 JavaScript 依赖

¥ Install JavaScript dependencies

转到项目的根目录并创建一个新的 package.json 文件,其中包含以下内容:

¥Go to the root directory for your project and create a new package.json file with the following contents:

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

接下来,安装 reactreact-native 软件包。打开终端或命令提示符,然后导航到包含 package.json 文件的目录并运行:

¥Next, install the react and react-native packages. Open a terminal or command prompt, then navigate to the directory with your package.json file and run:

npm install react-native

这将打印一条类似于以下内容的消息(在安装命令输出中向上滚动以查看它):

¥This will print a message similar to the following (scroll up in the installation command output to see it):

警告“react-native@0.70.5”未满足对等依赖“react@18.1.0

¥warning "react-native@0.70.5" has unmet peer dependency "react@18.1.0"

没关系,这意味着我们还需要安装 React:

¥This is OK, it means we also need to install React:

npm install react@version_printed_above

安装过程创建了一个新的 /node_modules 文件夹。此文件夹存储构建项目所需的所有 JavaScript 依赖。

¥Installation process has created a new /node_modules folder. This folder stores all the JavaScript dependencies required to build your project.

node_modules/ 添加到 .gitignore 文件中。

¥Add node_modules/ to your .gitignore file.

将 React Native 添加到你的应用

¥Adding React Native to your app

配置 Gradle

¥Configuring Gradle

React Native 使用 React Native Gradle 插件来配置依赖和项目设置。

¥React Native uses the React Native Gradle Plugin to configure your dependencies and project setup.

首先,让我们通过添加以下行来编辑 settings.gradle 文件:

¥First, let's edit your settings.gradle file by adding this line:

includeBuild('../node_modules/@react-native/gradle-plugin')

然后你需要打开顶层 build.gradle 并包含以下行:

¥Then you need to open your top level build.gradle and include this line:

buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:7.3.1")
+ classpath("com.facebook.react:react-native-gradle-plugin")
}
}

这可确保 React Native Gradle 插件在你的项目中可用。最后,将这些行添加到应用的 build.gradle 文件中(它是应用文件夹中的不同 build.gradle 文件):

¥This makes sure the React Native Gradle Plugin is available inside your project. Finally, add those lines inside your app's build.gradle file (it's a different build.gradle file inside your app folder):

apply plugin: "com.android.application"
+apply plugin: "com.facebook.react"

repositories {
mavenCentral()
}

dependencies {
// Other dependencies here
+ implementation "com.facebook.react:react-android"
+ implementation "com.facebook.react:hermes-android"
}

这些依赖在 mavenCentral() 上可用,因此请确保在 repositories{} 块中定义了它。

¥Those depedencies are available on mavenCentral() so make sure you have it defined in your repositories{} block.

信息

我们故意不指定这些 implementation 依赖的版本,因为 React Native Gradle 插件会处理它。如果你不使用 React Native Gradle 插件,则必须手动指定版本。

¥We intentionally don't specify the version for those implementation dependencies as the React Native Gradle Plugin will take care of it. If you don't use the React Native Gradle Plugin, you'll have to specify version manually.

启用原生模块自动链接

¥Enable native modules autolinking

为了发挥 autolinking 的威力,我们必须在几个地方应用它。首先将以下条目添加到 settings.gradle

¥To use the power of autolinking, we have to apply it a few places. First add the following entry to settings.gradle:

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

接下来在 app/build.gradle 的最底部添加以下条目:

¥Next add the following entry at the very bottom of the app/build.gradle:

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

配置权限

¥Configuring permissions

接下来,确保你的 AndroidManifest.xml 具有 Internet 权限:

¥Next, make sure you have the Internet permission in your AndroidManifest.xml:

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

如果你需要访问 DevSettingsActivity,请添加到你的 AndroidManifest.xml

¥If you need to access to the DevSettingsActivity add to your AndroidManifest.xml:

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

这仅在从开发服务器重新加载 JavaScript 时在开发模式下使用,因此如果需要,你可以在发布版本中删除它。

¥This is only used in dev mode when reloading JavaScript from the development server, so you can strip this in release builds if you need to.

明文流量(API 级别 28+)

¥Cleartext Traffic (API level 28+)

从 Android 9(API 级别 28)开始,默认禁用明文流量;这会阻止你的应用连接到 Metro 打包器。以下更改允许调试版本中的明文流量。

¥Starting with Android 9 (API level 28), cleartext traffic is disabled by default; this prevents your application from connecting to the Metro bundler. The changes below allow cleartext traffic in debug builds.

1. 将 usesCleartextTraffic 选项应用于你的调试 AndroidManifest.xml

¥ Apply the usesCleartextTraffic option to your Debug AndroidManifest.xml

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

对于发布版本来说这不是必需的。

¥This is not required for Release builds.

了解有关网络安全配置和明文流量策略 看到这个链接 的更多信息。

¥To learn more about Network Security Config and the cleartext traffic policy see this link.

代码集成

¥Code integration

现在我们将实际修改原生 Android 应用以集成 React Native。

¥Now we will actually modify the native Android application to integrate React Native.

React Native 组件

¥The React Native component

我们将编写的第一段代码是将新的 "高分" 屏幕的实际 React Native 代码集成到我们的应用中。

¥The first bit of code we will write is the actual React Native code for the new "High Score" screen that will be integrated into our application.

1. 创建 index.js 文件

¥ Create a index.js file

首先,在 React Native 项目的根目录中创建一个空的 index.js 文件。

¥First, create an empty index.js file in the root of your React Native project.

index.js 是 React Native 应用的起点,并且始终是必需的。它可以是一个小文件,或者是 React Native 组件或应用中的其他文件,也可以包含它所需的所有代码。在我们的例子中,我们将把所有内容都放在 index.js 中。

¥index.js is the starting point for React Native applications, and it is always required. It can be a small file that requires other file that are part of your React Native component or application, or it can contain all the code that is needed for it. In our case, we will put everything in index.js.

2. 添加你的 React Native 代码

¥ Add your React Native code

index.js 中,创建你的组件。在我们的示例中,我们将在样式化的 <View> 中添加 <Text> 组件:

¥In your index.js, create your component. In our sample here, we will add a <Text> component within a styled <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>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
hello: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});

AppRegistry.registerComponent(
'MyReactNativeApp',
() => HelloWorld,
);
3. 配置开发错误覆盖的权限

¥ Configure permissions for development error overlay

如果你的应用面向 Android API level 23 或更高版本,请确保你拥有为开发版本启用的权限 android.permission.SYSTEM_ALERT_WINDOW。你可以通过 Settings.canDrawOverlays(this); 进行检查。这在开发版本中是必需的,因为 React Native 开发错误必须显示在所有其他窗口之上。由于 API 级别 23(Android M)中引入了新的权限系统,需要用户批准。这可以通过将以下代码添加到你的 Activity 的 onCreate() 方法中来实现。

¥If your app is targeting the Android API level 23 or greater, make sure you have the permission android.permission.SYSTEM_ALERT_WINDOW enabled for the development build. You can check this with Settings.canDrawOverlays(this);. This is required in dev builds because React Native development errors must be displayed above all the other windows. Due to the new permissions system introduced in the API level 23 (Android M), the user needs to approve it. This can be achieved by adding the following code to your Activity's in onCreate() method.

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 的原生模块,我们需要将结果传递给 ReactInstanceManager 实例的 onActivityResult 方法。

¥Finally, the onActivityResult() method (as shown in the code below) has to be overridden to handle the permission Accepted or Denied cases for consistent UX. Also, for integrating Native Modules which use startActivityForResult, we need to pass the result to the onActivityResult method of our ReactInstanceManager instance.

@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

¥The Magic: ReactRootView

让我们添加一些原生代码来启动 React Native 运行时并告诉它渲染我们的 JS 组件。为此,我们将创建一个 Activity,它创建一个 ReactRootView,在其中启动一个 React 应用并将其设置为主要内容视图。

¥Let's add some native code in order to start the React Native runtime and tell it to render our JS component. To do this, we're going to create an Activity that creates a ReactRootView, starts a React application inside it and sets it as the main content view.

如果你的目标是 Android 版本 <5,请使用 com.android.support:appcompat 包中的 AppCompatActivity 类而不是 Activity

¥If you are targeting Android version <5, use the AppCompatActivity class from the com.android.support:appcompat package instead of 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() 方法的第一个参数)。

¥If you are using a starter kit for React Native, replace the "HelloWorld" string with the one in your index.js file (it’s the first argument to the AppRegistry.registerComponent() method).

执行“与 Gradle 同步项目文件”操作。

¥Perform a “Sync Project files with Gradle” operation.

如果你使用的是 Android Studio,请使用 Alt + Enter 在 MyReactActivity 类中添加所有缺少的导入。请小心使用你的包中的 BuildConfig,而不是 facebook 包中的包。

¥If you are using Android Studio, use Alt + Enter to add all missing imports in your MyReactActivity class. Be careful to use your package’s BuildConfig and not the one from the facebook package.

我们需要将 MyReactActivity 的主题设置为 Theme.AppCompat.Light.NoActionBar,因为一些 React Native UI 组件依赖于该主题。

¥We need set the theme of MyReactActivity to Theme.AppCompat.Light.NoActionBar because some React Native UI components rely on this theme.

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

ReactInstanceManager 可以由多个活动和/或片段共享。你将想要制作自己的 ReactFragmentReactActivity,并拥有一个可容纳 ReactInstanceManager 的单括号。当你需要 ReactInstanceManager(例如,将 ReactInstanceManager 连接到这些活动或片段的生命周期)时,请使用单例提供的 ReactInstanceManager

¥A ReactInstanceManager can be shared by multiple activities and/or fragments. You will want to make your own ReactFragment or ReactActivity and have a singleton holder that holds a ReactInstanceManager. When you need the ReactInstanceManager (e.g., to hook up the ReactInstanceManager to the lifecycle of those Activities or Fragments) use the one provided by the singleton.

接下来,我们需要将一些 Activity 生命周期回调传递给 ReactInstanceManagerReactRootView

¥Next, we need to pass some activity lifecycle callbacks to the ReactInstanceManager and 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:

¥We also need to pass back button events to React Native:

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

这允许 JavaScript 控制用户按下硬件后退按钮时发生的情况(例如实现导航)。当 JavaScript 不处理后退按钮按下时,你的 invokeDefaultOnBackPressed 方法将被调用。默认情况下,这将完成你的 Activity

¥This allows JavaScript to control what happens when the user presses the hardware back button (e.g. to implement navigation). When JavaScript doesn't handle the back button press, your invokeDefaultOnBackPressed method will be called. By default this finishes your Activity.

最后,我们需要连接开发菜单。默认情况下,这是通过(愤怒)摇动设备来激活的,但这在模拟器中不是很有用。因此,我们让它在你按下硬件菜单按钮时显示(如果你使用的是 Android Studio 模拟器,请使用 Ctrl + M):

¥Finally, we need to hook up the dev menu. By default, this is activated by (rage) shaking the device, but this is not very useful in emulators. So we make it show when you press the hardware menu button (use Ctrl + M if you're using Android Studio emulator):

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

现在你的 Activity 已准备好运行一些 JavaScript 代码。

¥Now your activity is ready to run some JavaScript code.

测试你的集成

¥Test your integration

你现在已经完成了将 React Native 与当前应用集成的所有基本步骤。现在我们将启动 Metro 打包器 来构建 index.bundle 包,并在本地主机上运行服务器来为其提供服务。

¥You have now done all the basic steps to integrate React Native with your current application. Now we will start the Metro bundler to build the index.bundle package and the server running on localhost to serve it.

1. 运行打包器

¥ Run the packager

要运行你的应用,你需要首先启动开发服务器。为此,请在 React Native 项目的根目录中运行以下命令:

¥To run your app, you need to first start the development server. To do this, run the following command in the root directory of your React Native project:

npm start
2. 运行应用

¥ Run the app

现在正常构建并运行你的 Android 应用。

¥Now build and run your Android app as normal.

一旦你到达应用内由 React 支持的活动,它应该从开发服务器加载 JavaScript 代码并显示:

¥Once you reach your React-powered activity inside the app, it should load the JavaScript code from the development server and display:

Screenshot

在 Android Studio 中创建发布版本

¥Creating a release build in Android Studio

你也可以使用 Android Studio 创建你的发布版本!它就像为你之前存在的原生 Android 应用创建发布版本一样快。

¥You can use Android Studio to create your release builds too! It’s as quick as creating release builds of your previously-existing native Android app.

如果你如上所述使用 React Native Gradle 插件,则从 Android Studio 运行应用时一切都应该正常。

¥If you use the React Native Gradle Plugin as described above, everything should work when running app from Android Studio.

如果你不使用 React Native Gradle 插件,则在每次发布构建之前都必须执行一个额外步骤。你需要执行以下命令来创建 React Native 打包包,该打包包将包含在你的原生 Android 应用中:

¥If you're not using the React Native Gradle Plugin, there’s one additional step which you’ll have to do before every release build. You need to execute the following to create a React Native bundle, which will be included with your native Android app:

$ 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/

不要忘记用正确的路径替换路径,并创建资源文件夹(如果不存在)。

¥Don’t forget to replace the paths with correct ones and create the assets folder if it doesn’t exist.

现在,像往常一样从 Android Studio 中创建原生应用的发布版本,你应该可以开始了!

¥Now, create a release build of your native app from within Android Studio as usual and you should be good to go!

怎么办?

¥Now what?

此时,你可以像往常一样继续开发你的应用。请参阅我们的 debuggingdeployment 文档,了解有关使用 React Native 的更多信息。

¥At this point you can continue developing your app as usual. Refer to our debugging and deployment docs to learn more about working with React Native.