1.设置目录结构
创建一个空目录用于存放 React Native 项目,然后在其中创建一个/android
子目录,把你现有的 Android 项目拷贝到/android
子目录中。
2.安装javascript依赖包
在项目根目录下创建一个名为package.json
的空文本文件,然后填入以下内容:
{
"name": "rntestthree",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"react": "16.8.3",
"react-native": "^0.59.5"
}
}
scripts
中是用于启动 packager 服务的命令。dependencies
中的 react 和 react-native 的版本取决于你的具体需求。一般来说我们推荐使用最新版本。你可以使用npm info react
和npm info react-native
来查看当前的最新版本。另外,react-native 对 react 的版本有严格要求,高于或低于某个范围都不可以。本文无法在这里列出所有 react native 和对应的 react 版本要求,只能提醒读者先尝试执行 npm install,然后注意观察安装过程中的报错信息,例如require react@某.某.某版本, but none was installed
,然后根据这样的提示,执行npm i -S react@某.某.某版本
。如果你使用多个第三方依赖,可能这些第三方各自要求的 react 版本有所冲突,此时应优先满足react-native
所需要的react
版本。其他第三方能用则用,不能用则只能考虑选择其他库。
接下来我们使用 npm(node 包管理器,Node package manager)来安装 React 和 React Native 模块。 请打开一个终端/命令提示行,进入到项目目录中(即包含有 package.json 文件的目录),然后运行下列命令来安装:
$ npm install
这些模块会被安装到项目根目录下的node_modules/
目录中(所有通过 npm install 命令安装的模块都会放在这个目录中。这个目录我们原则上不复制、不移动、不修改、不上传,随用随装)。
3.把React Native项目添加到你的应用中
3.1 在你的 app 中 build.gradle
文件中添加 React Native 依赖:
dependencies { ... compile "com.facebook.react:react-native:+" // From node_modules. }
如果想要指定特定的 React Native 版本,可以用具体的版本号替换 +
,当然前提是你从 npm 里下载的是这个版本 。
在项目的 build.gradle
文件中为 React Native 添加一个 maven 依赖的入口,必须写在 "allprojects" 代码块中:
allprojects { repositories { ... maven { // All of React Native (JS, Android binaries) is installed from npm url "$rootDir/../node_modules/react-native/android" } } ... }
3.2 屏蔽某些平台产生的错误
在app的build.gradle中的defaultConfig配置
ndk {
abiFilters "armeabi-v7a", "x86"
}
一些SDK版本也可能产生错误,minSdkVersion 16以上
android {
compileSdkVersion 28
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId "com.example.wind.my_react_app"
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk {
abiFilters "armeabi-v7a", "x86"
}
}
packagingOptions {
exclude "lib/arm64-v8a/librealm-jni.so"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
compile "com.facebook.react:react-native:+"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
3.2 配置权限:
接着,在 AndroidManifest.xml
清单文件中声明网络权限:
<uses-permission android:name="android.permission.INTERNET" />
如果需要访问 DevSettingsActivity
界面(即开发者菜单),则还需要在 AndroidManifest.xml
中声明:
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
4. 代码集成:
4.1 React Native 组件
创建一个index.js
文件
首先在项目根目录中创建一个空的index.js
文件。(注意在 0.49 版本之前是 index.android.js 文件)
index.js
是 React Native 应用在 Android 上的入口文件。而且它是不可或缺的!它可以是个很简单的文件,简单到可以只包含一行require/import
导入语句。本教程中为了简单示范,把全部的代码都写到了index.js
里
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);
4.2 配置运行RN的原生activity
我们还需要添加一些原生代码来启动 React Native 的运行时环境并让它开始渲染。首先需要在一个Activity
中创建一个ReactRootView
对象,然后在这个对象之中启动 React Native 应用,并将它设为界面的主视图。
如果你想在安卓 5.0 以下的系统上运行,请用 com.android.support:appcompat
包中的 AppCompatActivity
代替 Activity
。
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
public class MyReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
public static void start(Context context) {
context.startActivity(new Intent(context, MyReactActivity.class));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setCurrentActivity(this)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index")
.addPackage(new MainReactPackage())
.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();
}
@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();
}
}
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
}
}
如果你使用的是 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>
5.测试集成结果
5.1 启动开发服务器:
运行应用首先需要启动开发服务器(Packager)。你只需在项目根目录中执行以下命令即可:
$ npm start
如果Packager服务器启动成功,则http://localhost:8081/index.android.bundle?platform=android
能看到如下信息:
var __DEV__=true,__BUNDLE_START_TIME__=this.nativePerformanceNow?nativePerformanceNow():Date.now(),process=this.process||{};process.env=process.env||{};process.env.NODE_ENV="development";
(function (global) {
"use strict";
global.__r = metroRequire;
global.__d = define;
global.__c = clear;
global.__registerSegment = registerSegment;
var modules = clear();
var EMPTY = {};
var _ref = {},
hasOwnProperty = _ref.hasOwnProperty;
function clear() {
modules = Object.create(null);
return modules;
}
if (__DEV__) {
var verboseNamesToModuleIds = Object.create(null);
var initializingModuleIds = [];
}
否则,会出现错误信息。
可以重置包服务器:
adb reverse tcp:8081 tcp:8081
npm start
5.2 运行应用:
保持 packager 的窗口运行不要关闭,然后像往常一样编译运行你的 Android 应用(在命令行中执行./gradlew installDebug
或是在 Android Studio 中编译运行)。
如果你是使用 Android Studio 来编译运行,有可能会导致 packager 报错退出。这种情况下你需要安装watchman。但是 watchman 目前没有稳定的 Windows 版本,所以在 Windows 下这种崩溃情况暂时没有特别好的解决方案。
编译执行一切顺利进行之后,在进入到 MyReactActivity 时应该就能立刻从 packager 中读取 JavaScript 代码并执行和显示: