神刀安全网

将React Native整合进Android项目超详细图文教程

不得不吐个槽,按照官方文档,已经不可能顺利实现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) 选项,在当前目录下打开一个命令窗口,如下所示:
将React Native整合进Android项目超详细图文教程
command_line_window.png

图中的ReactNativeWithNativeApp就是第一步中创建的Android项目的名字。

在上面的命令行窗口中输入:
npm init
这个命令会引导你在ReactNativeWithNativeApp目录下创建一个package.json文件。如图所示:

将React Native整合进Android项目超详细图文教程
packagejson.png

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目录里面内容如下:

将React Native整合进Android项目超详细图文教程
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文件中,保存并关闭它。

至此,我们的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);        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

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 将React Native整合进Android项目超详细图文教程

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址