集成到现有原生应用
如果你正准备从头开始制作一个新的应用,那么 React Native 会是个非常好的选择。但如果你只想给现有的原生应用中添加一两个视图或是业务流程,React Native 也同样不在话下。只需简单几步,你就可以给原有应用加上新的基于 React Native 的特性、画面和视图等。
具体的步骤根据你所开发的目标平台不同而不同。
译注:本文档可能更新不够及时,不能保证适用于最新版本,欢迎了解的朋友使用页面底部的编辑链接帮忙改进此文档。一个实用的建议是可以使用
npx react-native init NewProject
创建一个最新版本的纯 RN 项目,去参考其 Podfile 或是 gradle 等的配置,以它们为准。
- Android (Java)
- iOS (Objective-C)
- iOS (Swift)
核心概念
把 React Native 组件集成到 Android 应用中有如下几个主要步骤:
- 配置好 React Native 依赖和项目结构。
- 创建 js 文件,编写 React Native 组件的 js 代码。
- 在应用中添加一个
ReactRootView
。这个ReactRootView
正是用来承载你的 React Native 组件的容器。 - 启动 React Native 的 Metro 服务,运行应用。
- 验证这部分组件是否正常工作。
开发环境准备
首先按照开发环境搭建教程来安装 React Native 在 Android 平台上所需 的一切依赖软件。
1. 配置项目目录结构
首先创建一个空目录用于存放 React Native 项目,然后在其中创建一个/android
子目录,把你现有的 Android 项目拷贝到/android
子目录中。
2. 安装 JavaScript 依赖包
在项目根目录下创建一个名为package.json
的空文本文件,然后填入以下内容:
{
"name": "MyReactNativeApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "yarn react-native start"
}
}
示例中的
version
字段没有太大意义(除非你要把你的项目发布到 npm 仓库)。scripts
中是用于启动 Metro 服务的命令。
接下来我们使用 yarn 或 npm(两者都是 node 的包管理器)来安装 React 和 React Native 模块。请打开一个终端/命令提示行,进入到项目目录中(即包含有 package.json 文件的目录),然后运行下列命令来安装:
$ yarn add react-native
这样默认会安装最新版本的 React Native,同时会打印出类似下面的警告信息(你可能需要滚动屏幕才能注意到):
warning "react-native@0.52.2" has unmet peer dependency "react@16.2.0".
这是正常现象,意味着我们还需要安装指定版本的 React:
$ yarn add react@16.2.0
注意必须严格匹配警告信息中所列出的版本,高了或者低了都不可以。
如果你使用多个第三方依赖,可能这些第三方各自要求的 react 版本有所冲突,此时应优先满足
react-native
所需要的react
版本。其他第三方能用则用,不能用则只能考虑选择其他库。
所有 JavaScript 依赖模块都会被安装到项目根目录下的node_modules/
目录中(这个目录我们原则上不复制、不移动、不修改、不上传, 随用随装)。
把node_modules/
目录记录到.gitignore
文件中(即不上传到版本控制系统,只保留在本地)。
把 React Native 添加到你的应用中
配置 maven
在你的 app 中 build.gradle
文件中添加 React Native 和 JSC 引擎依赖:
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 版本,可以用具体的版本号替换
+
,当然前提是你从 npm 里下载的是这个版本。
在项目的 build.gradle
文件中为 React Native 和 JSC 引擎添加 maven 源的路径,必须写在 "allprojects" 代码块中
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")
}
...
}
...
}
确保依赖路径的正确!以免在 Android Studio 运行 Gradle 同步构建时抛出 “Failed to resolve: 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
清单文件中声明网络权限:
如果需要访问 DevSettingsActivity
界面(即开发者菜单),则还需要在 AndroidManifest.xml
中声明:
开发者菜单一般仅用于在开发时从 Packager 服务器刷新 JavaScript 代码,所以在正式发布时你可以去掉这一权限。
允许明文传输(http 接口) (API level 28+)
从 Android 9 (API level 28)开始,默认情况下明文传输(http 接口)是禁用的,只能访问 https 接口。这将阻止应用程序连接到Metro bundler。下面的更改允许调试版本中的明文通信。
1. 为 debug 版本启用 usesCleartextTraffic
选项
在src/debug/AndroidManifest.xml
中添加usesCleartextTraffic
选项:
<!-- ... -->
<application
android:usesCleartextTraffic="true" tools:targetApi="28" >
<!-- ... -->
</application>
<!-- ... -->
如果希望在正式打包后也能继续访问 http 接口,则需要在src/main/AndroidManifest.xml
中也添加这一选项。
要了解有关网络安全配置和明文通信策略的更多信息,请参阅此链接。
代码集成
现在我们将修改原生 Android 应用程序以集成 React Native。
React Native 组件
我们首先要写的是"High Score"(得分排行榜)的 JavaScript 端的代码。
1. 创建一个index.js
文件
首先在项目根目录中创建一个空的index.js
文件。(注意一些老的教程可能提到,在 0.49 版本之前是 index.android.js 文件)
index.js
是 React Native 应用在 Android 上的入口文件。而且它是不可或缺的!它可以是个很简单的文件,简单到可以只包含一行require/import
导入语句。本教程中为了简单示范,把全部的代码都写到了index.js
里(当然实际开发中我们并不推荐这样做)。
2. 添加你自己的 React Native 代码
在index.js
中添加你自己的组件。这里我们只是简单的添加一个<Text>
组件,然后用一个带有样式的<View>
组件把它包起来。
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
class HelloWorld extends React.Component {
render() {
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 6.0(API level 23)或更高版本,请确保你在开发版本中有打开悬浮窗(overlay)
权限。你可以在代码中使用Settings.canDrawOverlays(this);
来检查。之所以需要这一权限,是因为我们会把开发中的报错显示在悬浮窗中(仅在开发阶段需要)。在 Android 6.0(API level 23)中用户需要手动同意授权。具体请求授权的做法是在onCreate()
中添加如下代码。其中OVERLAY_PERMISSION_REQ_CODE
是用于回传授权结果的字 段。
private final int OVERLAY_PERMISSION_REQ_CODE = 1; // 任写一个值
...
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 方法。
@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 的运行时环境并让它开始渲染。首先需要在一个Activity
中创建一个ReactRootView
对象,然后在这个对象之中启动 React Native 应用,并将它设为界面的主视图。
如果你要在安卓 5.0 以下的系统上运行,请用
com.android.support:appcompat
包中的AppCompatActivity
代替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.add(new MyReactNativePackage());
// 同时需要手动把他们添加到`settings.gradle`和 `app/build.gradle`配置文件中。
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setCurrentActivity(this)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index")
.addPackages(packages)
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
// 注意这里的MyReactNativeApp 必须对应"index.js"中的
// "AppRegistry.registerComponent()"的第一个参数
mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
}
执行"Sync Project files with Gradle"操作。
如果你使用的是 Android Studio , 可以使用Alt + Enter
快捷键来自动为 MyReactActivity 类补上缺失的 import 语句。注意BuildConfig
应该是在你自己的包中自动生成,无需额外引入。千万不要从com.facebook...
的包中引入!
我们需要把 MyReactActivity
的主题设定为 Theme.AppCompat.Light.NoActionBar
,因为里面有许多组件都使用了这一主题。
<activity
android:name=".MyReactActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>
一个
ReactInstanceManager
可以在多个 activities 或 fragments 间共享。你将需要创建自己的ReactFragment
或ReactActivity
,并拥有一个保存ReactInstanceManager
的单例持有者。当你需要ReactInstanceManager
(例如,将ReactInstanceManager
连接到这些 Activities 或 Fragments 的生命周期)时,请使用单例提供的那个。
下一步我们需要把一些 activity 的生命周期回调传递给ReactInstanceManager
:
@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
。
最后,我们需要连接开发菜单。默认情况下通过(狂)摇晃设备来激活,但这在模拟器中不是很有用,只有当你按下设备菜单按钮时才显示(如果你使用的是 Android Studio 模拟器,请使用Ctrl + M
):
@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 代码了。
测试集成结果
你已经完成了将 React Native 与当前应用程序集成的所有基本步骤。现在我们将启动Metro bundler来构建index.bundle
包,并通过本地主机提供服务。
1. 运行 Metro 服务
运行应用首先需要启动开发服务器(Metro)。你只需在项目根目录中执行以下命令即可:
$ yarn start
2. 运行你的应用
保持 Metro 的窗口运行不要关闭,然后像往常一样编译运行你的 Android 应用(在命令行中执行./gradlew installDebug
或是在 Android Studio 中编译运行)。
编译执行一切顺利进行之后,在进入到 MyReactActivity 时应该就能立刻从 Metro 中读取 JavaScript 代码并执行和显示:
在 Android Studio 中打包
你也可以使用 Android Studio 来打 release 包!其步骤基本和原生应用一样,只是在每次编译打包之前需要先执行 js 文件的打包(即生成离线的 jsbundle 文件)。具体的 js 打包命令如下:
$ 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 中正常生成 release 版本即可!
然后呢?
然后就可以开发啦~可是我完全不会 React Native 怎么办?
我们建议你先通读本站的所有文档,看看博客,看看论坛。如果觉得知识太零散,不够系统,那么你也可以考虑下购买我们的付费咨询服务。
核心概念
把 React Native 组件集成到 iOS 应用中有如下几个主要步骤:
- 配置好 React Native 依赖和项目结构。
- 了解你要集成的 React Native 组件。
- 使用 CocoaPods 把这些组件以依赖的形式加入到项目中。
- 创建 js 文件,编写 React Native 组件的 js 代码。
- 在应用中添加一个
RCTRootView
。这个RCTRootView
正是用来承载你的 React Native 组件的容器。 - 启动 React Native 的 Packager 服务,运行应用。
- 验证这部分组件是否正常工作。
开发环境准备
首先按照开发环境搭建教程来安装 React Native 在 iOS 平台上所需的一切依赖软件。
1. 配置项目目录结构
首先创建一个空目录用于存放 React Native 项目,然后在其中创建一个/ios
子目录,把你现有的 iOS 项目拷贝到/ios
子目录中。
2. 安装 JavaScript 依赖包
在项目根目录下创建一个名为package.json
的空文本文件,然后填入以下内容:
{
"name": "MyReactNativeApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "yarn react-native start"
}
}
示例中的
version
字段没有太大意义(除非你要把你的项目发布到 npm 仓库)。scripts
中是用于启动 Metro 服务的命令。
接下来我们使用 yarn 或 npm(两者都是 node 的包管理器)来安装 React 和 React Native 模块。请打开一个终端/命令提示行,进入到项目目录中(即包含有 package.json 文件的目录),然后运行下列命令来安装:
$ yarn add react-native
这样默认会安 装最新版本的 React Native,同时会打印出类似下面的警告信息(你可能需要滚动屏幕才能注意到):
warning "react-native@0.52.2" has unmet peer dependency "react@16.2.0".
这是正常现象,意味着我们还需要安装指定版本的 React:
$ yarn add react@16.2.0
注意必须严格匹配警告信息中所列出的版本,高了或者低了都不可以。
如果你使用多个第三方依赖,可能这些第三方各自要求的 react 版本有所冲突,此时应优先满足
react-native
所需要的react
版本。其他第三方能用则用,不能用则只能考虑选择其他库。
所有 JavaScript 依赖模块都会被安装到项目根目录下的node_modules/
目录中(这个目录我们原则上不复制、不移 动、不修改、不上传,随用随装)。
把node_modules/
目录记录到.gitignore
文件中(即不上传到版本控制系统,只保留在本地)。
3. 安装 CocoaPods
CocoaPods是针对 iOS 和 Mac 开发的包管理工具。我们用它来把 React Native 框架的代码下载下来并添加到你当前的项目中。
我们建议使用Homebrew来安装 CocoaPods。
$ brew install cocoapods