弹射起步:Android原生项目集成React Native模块


说明和前提

1、由于通过命令react-native init初始化的React Native(以下简称RN)项目结构与原生项目有区别,所以不能单纯直接在已有项目的根目录下运行该命令。

2、RN需要Android4.1或以上的环境,故集成RN的Android项目的minSdkVersion需设置为API16或以上。

3、本机安装NPM支持:
新版的RN依赖都将发布在NPM(包管理工具,如同Maven仓库)中,故需安装NPM。

4、本文安装环境为MAC,Windows或Linux上的命令差异请参考官方文档

集成步骤

1. 安装NPM

之后于同时需要NodeJS服务器,故只需安装NodeJS,NPM会随同安装。

1
2
brew install node
brew install watchman

2. 添加NPM依赖

进入Android项目根目录,新建文件package.json,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "react-native-module",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"react": "15.3.2",
"react-native": "0.34.1"
}
}

之后拉取NPM组件,在package.json同目录位置下运行

1
npm install

完成后将出现node_modules文件夹。

3.添加页面文件

在根目录下,新建文件index.android.js,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';

class RN_Demo extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Double tap R on your keyboard to reload,{'\n'}
Shake or press menu button for dev menu
</Text>
</View>
);
}
}

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

AppRegistry.registerComponent('RN_Demo', () => RN_Demo);

记住上面的组件名RN_Demo

4.添加RN依赖

编辑app目录下的build.gradle,添加

1
compile 'com.facebook.react:react-native:0.34.1'  // From node_modules

之所以此处不根据官方文档的配置(compile ‘com.facebook.react:react-native:+’),你会发现通过Gradle Sync进行同步后会报错,所以需要在项目下的build.gradle中添加

1
2
3
4
5
6
7
8
9
allprojects {
repositories {
jcenter()
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$projectDir/../node_modules/react-native/android"
}
}
}

否则未写明版本的RN依赖可能是jcenter中的旧版本。

5.新建Activity与Application

新建一个继承自ReactActivityactivity,内容如下:

1
2
3
4
5
6
7
8
9
import com.facebook.react.ReactActivity;

public class MainActivity extends ReactActivity {

@Override
protected String getMainComponentName() {
return "RN_Demo";
}
}

注意此处实现的getMainComponentName方法返回的字符串与index.android.js中注册的Component名的要一致。

之后编辑自定义Application,实现ReactApplication接口,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MainApplication extends Application implements ReactApplication {

private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
// 表示是否启用开发者模式
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}

@Override
// 模块列表,可添加原生Java模块
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage()
);
}
};

@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
}

6.编辑AndroidManifest.xml

添加应用的网络访问权限,以及刚刚新建的ActivityApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.doslin.rndemo">

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

<application
android:name=".MainApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="false"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

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

</manifest>

7.添加NDK支持

gradle.properties中添加如下内容:

1
android.useDeprecatedNdk=true

app下的build.gradle中添加如下内容:

1
2
3
ndk {
abiFilters 'armeabi', 'armeabi-v7a'
}

如果你的app需要在x86下运行,请额外进行配置x86

8.启动Packager Server

package.json同级目录下运行
react-native start
之后为了防止出现error “Could not get BatchedBridge, make sure your bundle is packaged properly” on start of app的异常,先运行

1
curl "http://localhost:8081/index.android.bundle?platform=android" -o "./app/src/main/assets/index.android.bundle"

将在assets目录下下载一份index.android.bundle文件。

如果你是用的手机而非模拟器测试,还需要运行如下命令设置反向代理:

1
adb reverse tcp:8081 tcp:8081

最后执行AS的绿色RUN按钮等待apk上传并运行。
在主界面摇晃手机会出现调试界面,注意开启显示悬浮窗权限。


参考链接

[1] http://facebook.github.io/react-native/docs/native-components-android.html

[2] http://gold.xitu.io/entry/57a0d03ed342d300572e9ffc

[3] http://www.imbeta.cn/react-native-for-android-huan-jing-da-jian-ji-cai-keng.html

[4] http://acgtofe.com/posts/2016/06/react-native-embedding-android

[5] http://stackoverflow.com/questions/38870710/error-could-not-get-batchedbridge-make-sure-your-bundle-is-packaged-properly

相关资料

1.React-Native学习指南

2.react-native-android-guide