不得不吐个槽,按照官方文档,已经不可能顺利实现React Native与已有项目的整合,因为世界变化太快,Android Studio发展到了2.2,React Native 已经是0.33版。为了帮助大家顺利攻克这个知识点,我写了这个教程。
一、基础信息
在整合的过程中,一些坑是与所用手机型号、Android Studio版本等特定信息紧密相关的,所以有必要明确我所用的配置:
- Android Stuidio 2.2稳定版
- 64位win7操作系统
- 红米note3双网通普配版
- React Native 0.33版
二、具体步骤
1、创建Android项目
这一步按照AS新建项目向导一步步完成即可,完成后,需要做如下准备工作:
- 在app module下的build.gradle文件的dependencies中添加React Native 依赖:compile "com.facebook.react:react-native:+"
- 在Manifest文件中添加权限和Activity:
<uses-permission android:name="android.permission.INTERNET" />
<application ...>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
我们新建的项目的一些关键配置如下:
- compile SDK 和target SDK都是24
- 所用的支持包的版本是:
compile 'com.android.support:appcompat-v7:24.2.1'
Note:网上有文章讲,使用的appcompat-v7支持包版本必须是23.0.1,compile SDK和target SDK也必须是23 。经我测试,使用最新版本24也可以。如果你的机器上不行,出现了这样的错误:
Caused by: java.lang.IllegalAccessError: Method 'void
android.support.v4.net.ConnectivityManagerCompat.<init>()'
is inaccessible to class
'com.facebook.react.modules.netinfo.NetInfoModule'
(declaration of 'com.facebook.react.modules.netinfo.NetInfoModule'
appears in /data/app/com.milter.www.awesomeproject2-2/base.apk)
可以尝试将appcompat-v7、compile SDK、target SDK调整为23,这是保险的做法。
2、将Android项目变成一个React Native项目
整合后的项目,实际上是三种项目的混合体,首先它是一个普通的Android项目,其次它是一个React Native项目,最后它还是一个Node.js项目。这就是为什么整合比较困难。
下面,我们需要将上步中创建的Android项目变成一个React Native项目。
- 创建并修改package.json文件
进入Android项目的根目录,按住shift键并右键单击鼠标,从弹出的菜单中选择:**在此处打开命令窗口(W) ** 选项,在当前目录下打开一个命令窗口,如下所示:
图中的ReactNativeWithNativeApp就是第一步中创建的Android项目的名字。
在上面的命令行窗口中输入:
npm init
这个命令会引导你在ReactNativeWithNativeApp目录下创建一个package.json文件。如图所示:
package.json文件的内容如下:
{
"name": "reactnativewithnativeapp",
"version": "1.0.0",
"description": "integrate RN with existing app",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "milter",
"license": "ISC",
"dependencies": {
"react-native": "^0.33.1"
}
}
修改上面的 package.json文件,将其中的
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}
修改为:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
,"start": "node node_modules/react-native/local-cli/cli.js start"
}
这样修改后,我们在项目根目录的命令行窗口中输入命令:
npm start
就相当于执行如下命令:
node node_modules/react-native/local-cli/cli.js start
Note:创建package.json文件,意味着原先的Android项目同时也变成了一个Node.js项目,下面,我们给这个Node.js项目引入react native 模块,进一步将它变成一个react native 项目
- 引入React Native 模块
还是在原先的命令行窗口中,输入如下命令:
npm install --save react react-native
执行这个命令后,在项目根目录(ReactNativeWithNativeApp)下会创建一个node_modules目录里面内容如下:
node-modules.png里面主要有react-native模块以及它所依赖的模块,还是挺多的。
- 创建.flowconfig文件
同一命令行窗口下,执行如下命令:
curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
这一命令的作用是将命令中url指向的.flowconfig文件下载到项目的根目录。在上面的图packagejson中可以看到这个下载后的文件。
如果你不知道怎么才能使用curl命令,可参考这篇文章:
windows(64位)下使用curl命令
Tips:如果你不想使用curl命令,这里给一个简单的方法:在根目录中建一个.flowconfig文件,用记事本打开它。
在浏览器中打开网址:
https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
将网页内容拷贝进打开的.flowconfig文件中,保存并关闭它。
Tips:在window系统下创建.flowconfig文件的方法是:
- 在项目根目录下打开cmd命令行窗口
- 输入 copy con .flowconfig
- 按下回车
- 按下Ctrl+Z
- 再按下回车
- OK!
至此,我们的Android项目已经变成了一个Android项目和React Native项目的合体项目。下面,我们将创建React Native项目程序并整合到Android项目中。
3、创建RN程序
在根目录下创建index.android.js文件,内容如下:
'use strict';
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('HelloWorld', () => HelloWorld);
这个文件是一个完全的React Native程序,现在我们需要把它整合到Android项目中去。
整合思路:在Android项目中创建一个Activity,然后利用React Native提供的工具,将上面的index.android.js程序包装进该Activity的contentView中。
4、将RN程序整合进Android项目
- 基础配置
在项目根目录的build.gradle中(注意:不是app模块中的build.gradle文件)添加依赖,如下所示:
allprojects {
repositories {
jcenter()
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$projectDir/../node_modules/react-native/android"
}
}
maven是我们添加的内容。
- 整合
主要是修改MainActivity内容,如下所示:
/* 这里省略了包名和import语句*/
public class MainActivity extends AppCompatActivity
implements DefaultHardwareBackBtnHandler {
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
private LifecycleState mLifecycleState
= LifecycleState.BEFORE_RESUME;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* 下面的版本判断代码官方文档中没有,
如果不添加,在6.0以上的Android版本中会报错 */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent serviceIntent = new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(serviceIntent);
}
}
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(mLifecycleState)
.build();
//下面代码中的"HelloWorld"来自index.android.js文件中最后一行代码
mReactRootView.startReactApplication(mReactInstanceManager,
"HelloWorld", null);
setContentView(mReactRootView);
}
@Override
protected void onPause() {
super.onPause();
mLifecycleState = LifecycleState.BEFORE_RESUME;
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause();
}
}
@Override
protected void onResume() {
super.onResume();
mLifecycleState = LifecycleState.RESUMED;
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this, this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mReactRootView.unmountReactApplication();
mReactRootView = null;
if (mReactInstanceManager != null) {
mReactInstanceManager.destroy();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (mReactInstanceManager != null) {
mReactInstanceManager.onActivityResult(this,requestCode,
resultCode, data);
}
}
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
}
else {
super.onBackPressed();
}
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
}
三、项目试运行
现在可以尝试运行下整合的项目。
首先,在项目根目录下的命令行窗口运行如下命令:
npm start
前面讲过,这个命令就相当于执行如下命令:
node node_modules/react-native/local-cli/cli.js start
然后,就可以点击Android Studio界面上的运行按钮啦!
不要高兴的太早,你很可能会遇到这个错误:
java.lang.UnsatisfiedLinkError: could find DSO to load: libreactnativejni.so
这个错误的原因是React Native提供的libreactnativejni.so文件是32位,而我们的项目中用了一些不兼容的64位so文件,二者混在一起产生的。
解决的办法就是禁止使用那些64位的so文件。为此,我们需要先做点准备工作。
第一,在项目根目录下的gradle.properties文件最后加上这样一句:
android.useDeprecatedNdk=true
第二、在app module下的build.gradle文件中添加如下内容:
android {
...
defaultConfig {
...
ndk{
abiFilters "armeabi-v7a", "x86"
}
...
}
...
}
第三、找出不兼容的64位so文件并禁止它们
在目录...\ReactNativeWithNativeApp\app\build\outputs\apk
下找到app-debug.apk,并把它解压,查看一下,解压后的文件的lib目录下有没有这个目录:
arm64-v8a
一般情况下是没有的,此时我们就真正大功告成了!!!
如果有这个目录,看看里面的so文件,都是我们要禁止的,禁止的方法如下:
假设里面有一个 1.so文件,我们要在app module下的build.gradle文件中做如下修改:
android {
...
defaultConfig {
...
ndk{
abiFilters "armeabi-v7a", "x86"
}
packagingOptions {
exclude "lib/arm64-v8a/1.so"
}
...
}
...
}
如果arm64-v8a目录下还有2.so、3.so等文件,处理方法与1.so一样。
好了,撒花庆祝!!:)
该项目已分享到GitHub,地址是:
https://github.com/like4hub/ReactNativeWithNativeApp
网友评论
还是说RN的内容并没有在apk里,得去服务器里获取过来?
我对rn并不是很熟,有说错的请见谅
还可以这样,学习了