集成到现有原生应用
如果你正准备从头开始制作一个新的应用,那么 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": "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 添加到你的应用中
配置 Gradle
React Native 使用 React Native Gradle Plugin 来配置您的依赖项和项目设置。
首先,让我们通过添加以下行来编辑您的settings.gradle
文件:
includeBuild('../node_modules/@react-native/gradle-plugin')
然后你需要打开顶层的 build.gradle
文件并添加这一行:
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 Plugin 在您的项目中可用。
最后,在 app/build.gradle
文件中添加以下行(注意它的路径不同于上面,是app/build.gradle
):
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{}
块中定义它。
我们故意不为这些implementation
依赖项指定版本,因为 React Native Gradle Plugin 会自动处理它。如果您不使用 React Native Gradle Plugin,则必须手动指定版本。
启用原生模块的自动链接
要使用自动链接的功能,我们必须将其应用于几个地方。首先,将以下内容添加到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" />
开发者菜单一般仅用于在开发时从 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';
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. 配置权限以便开发中的红屏错误能正确显示
如果你的应用会运行在 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 包!其步骤基本和原生应用一样,只是如果你没有使用 React Native Gradle Plugin 的话,则在每次编译打包之前需要先执行 js 文件的打包(即生成离线的 jsbundle 文件)。具体的 js 打包命令如下:
# 注:如果你使用了 React Native Gradle Plugin,则其会自动执行以下命令,不需要手动执行
$ 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 和 macOS 开发的包管理工具。我们用它来把 React Native 框架的代码下载下来并添加到你当前的项目中。
我们建议使用Homebrew来安装 CocoaPods。
$ brew install cocoapods
把 React Native 添加到你的应用中
在本教程中我们用于示范的 app是一个2048类型的游戏。下面是这个游戏还没有集成 React Native 时的主界面:
Xcode 命令行工具
安装 Xcode 命令行工具。在 Xcode 菜单中选择Settings... (或者是 Preferences...),进入 Locations 面板并通过在 Command Line Tools 下拉菜单中选择最新版本来安装工具。
配置 CocoaPods 的依赖
提示,此部分说明可能落后于最新版本。建议使用
npx react-native init NewProject
创建一个最新版本的纯 RN 项目,去参考其 Podfile 的配置。
React Native 框架整体是作为 node 模块安装到项目中的。下一步我们需要在 CocoaPods 的Podfile
中指定我们所需要使用的"subspecs"。
可用的subspec
都列在node_modules/react-native/React.podspec
中,基本都是按其功能命名的。一般来说你首先需要添加Core
,这一subspec
包含了必须的AppRegistry
、StyleSheet
、View
以及其他的一些 React Native 核心库。如果你想使用 React Native 的Text
库(即<Text>
组件),那就需要添加RCTText
的subspec
。同理,Image
需要加入RCTImage
,等等。
我们需要在Podfile
文件中指定所需的subspec
。创建Podfile
的最简单的方式就是在/ios
子目录中使用 CocoaPods 的init
命令:
$ pod init
Podfile
会创建在执行命令的目录中。你需要调整其内容以满足你的集成需求。调整后的Podfile
的内容看起来类似下面这个模板文件(也可以用npx react-native init 项目名
命令创建一个纯 RN 项目,然后去参考其 ios 目录中的 Podfile 文件):
Podfile 示范模板
创建好了Podfile
后,就可以开始安装 React Native 的 pod 包了。
$ pod install
然后你应该可以看到类似下面的输出(译注:同样由于众所周知的网络原因,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 中的 Preferences > Locations 中分配了命令行工具。
代码集成
现在我们已经准备好了所有依赖,可以开始着手修改原生代码来把 React Native 真正集成到应用中了。在我们的 2048 示例中,首先尝试添加一个显示有"High Score"(得分排行榜)的 React Native 页面。
React Native 组件
我们首先要写的是"High Score"(得分排行榜)的 JavaScript 端的代码。
1. 创建一个 index.js
文件
首先在项目根目录下创建一个空的index.js
文件。
index.js
是 React Native 应用在 iOS 上的入口文件。而且它是不可或缺的!它可以是个很简单的文件,简单到可以只包含一行require/import
导入语句。本教程中为了简单示范,把全部的代码都写到了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,
},
});
// 模块名称
AppRegistry.registerComponent('RNHighScores', () => RNHighScores);
RNHighScores
是整体 js 模块(即 你所有的 js 代码)的名称。你在 iOS 原生代码中添加 React Native 视图时会用到这个名称。
核心组件:RCTRootView
现在我们已经在index.js
中创建了 React Native 组件,下一步就是把这个组件添加给一个新的或已有的ViewController
。最简单的方法是可选地为您的组件创建一个事件路径,然后将该组件添加到现有的“ViewController”中。
我们将把 React Native 组件与名为“RCTRootView”的新原生视图绑定在一起,该视图实际上包含它。
1. 创建一个事件路径
你可以在主游戏菜单上添加一个新链接,以便前往 "High Score" 的 React Native 页面。
2. 事件处理
现在我们将从菜单链接中添加一个事件处理程序。一个方法将被添加到你的应用程序的主ViewController
中。这就是RCTRootView
发挥作用的地方。
当你构建一个 React Native 应用时,需要使用 Metro(以前叫做 react packager)来创建一个index.bundle
。index.bundle
里面包含了我们的RNHighScore
模块。因此,我们需要将RCTRootView
指向index.bundle
资源的位置(通过NSURL
),并将其与模块绑定。
为了便于调试,我们将在事件处理程序被调用时输出日志。然后创建一个 URL 字符串,指向index.bundle
的位置。最后,我们将创建主RCTRootView
。请注意我们需要把上面创建的moduleName
填进去,也就是RNHighScores
。
首先导入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 VM。为了节省资源并简化原生应用程序中不同部分的 RN 视图之间的通信,您可以拥有多个由 React Native 提供支持且与单个 JS 运行时相关联的视图。要实现这一点,请使用RCTBridge initWithBundleURL
创建桥接器,然后使用RCTRootView initWithBridge
。
在将应用程序移至生产环境时,
NSURL
可以通过类似于[[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
的方式指向磁盘上预打包文件。您可以在node_modules/react-native/scripts/
中使用react-native-xcode.sh
脚本生成该预打包文件。
3. 连接起来
将主菜单中的新链接与新增的事件处理程序方法连接起来。
其中一种更简单的方法是在 Storyboard 中打开视图,右键单击新链接。选择诸如“Touch Up Inside”事件之类的内容,将其拖到 Storyboard 上,然后从提供的列表中选择所创建的方法。
测试集成结果
您现在已经完成了将 React Native 与当前应用程序集成的所有基本步骤。现在我们将启动[Metro bundler][metro]来构建index.bundle
包,并运行服务器以在localhost
上提供服务。
1. 添加 App Transport Security 例外
Apple 现在默认会阻止读取不安全的 HTTP 链接。所以我们需要把本地运行的 Metro 服务添加到Info.plist
的例外中,以便能正常访问 Metro 服务:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
App Transport Security 对于用户来说是有利的。所以最好记得在发布之前重新启用这些安全限制。
2. 运行 Metro
要运行应用,首先需要启动开发服务器(即 Metro,它负责实时监测 js 文件的变动并实时打包,输出给客户端运行)。具体只需简单进入到项目根目录中,然后运行:
yarn start
3. 运行应用
如果你使用的是 Xcode,那么照常编译和运行应用即可。如果你没有使用 Xcode(但是你仍然必须安装 Xcode),则可以在命令行中使用以下命令来运行应用:
# 在项目的根目录中执行:
$ npx react-native run-ios
在我们的示例应用程序中,您应该会看到"High Scores"链接,然后当您单击它时,将会看到 React Native 组件的呈现。
这是应用原生部分的主页面:
这是应用React Native部分的 high score 页面:
如果在运行应用时遇到模块解析问题,请参阅此 GitHub 问题以获取信息和可能的解决方案。 这个评论似乎是最新的可能解决方案。
然后呢?
然后就可以开发啦~可是我完全不会 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
把 React Native 添加到你的应用中
在本教程中我们用于示范的 app是一个2048类型的游戏。下面是这个游戏还没有集成 React Native 时的主界面:
Xcode 命令行工具
安装 Xcode 命令行工具。在 Xcode 菜单中选择Settings... (或者是 Preferences...),进入 Locations 面板并通过在 Command Line Tools 下拉菜单中选择最新版本来安装工具。
配置 CocoaPods 的依赖
提示,此部分说明可能落后于最新版本。建议使用
npx react-native init NewProject
创建一个最新版本的纯 RN 项目,去参考其 Podfile 的配置。
React Native 框架整体是作为 node 模块安装到项目中的。下一步我们需要在 CocoaPods 的Podfile
中指定我们所需要使用的"subspecs"。
可用的subspec
都列在node_modules/react-native/React.podspec
中,基本都是按其功能命名的。一般来说你首先需要添加Core
,这一subspec
包含了必须的AppRegistry
、StyleSheet
、View
以及其他的一些 React Native 核心库。如果你想使用 React Native 的Text
库(即<Text>
组件),那就需要添加RCTText
的subspec
。同理,Image
需要加入RCTImage
,等等。
我们需要在Podfile
文件中指定所需的subspec
。创建Podfile
的最简单的方式就是在/ios
子目录中使用 CocoaPods 的init
命令:
$ pod init
Podfile
会创建在执行命令的目录中。你需要调整其内容以满足你的集成需求。调整后的Podfile
的内容看起来类似下面这个模板文件(也可以用npx react-native init 项目名
命令创建一个纯 RN 项目,然后去参考其 ios 目录中的 Podfile 文件):
Podfile 示范模板
创建好了Podfile
后,就可以开始安装 React Native 的 pod 包了。
$ pod install
然后你应该可以看到类似下面的输出(译注:同样由于众所周知的网络原因,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 中的 Preferences > Locations 中分配了命令行工具。
如果你看到类似"The
swift-2048 [Debug]
target overrides theFRAMEWORK_SEARCH_PATHS
build setting defined inPods/Target Support Files/Pods-swift-2048/Pods-swift-2048.debug.xcconfig
. This can lead to problems with the CocoaPods installation"的警告,请查看 Xcode 的Build Settings
中的Framework Search Paths
选项,确保其中的Debug
和Release
都只包含$(inherited)