RN与现有的原生app集成

时间:2020-12-15 08:55:46

https://facebook.github.io/react-native/docs/integration-with-existing-apps.html

  RN可以很好地支持往一个原生的app上添加RN的组件。通过简单的步骤,我们可以添加RN基础的特征、组件等。后面以android为例。

关键思想(概要)

  1. 设置RN的依赖和结构目录
  2. 用JS开发RN组件
  3. 添加一个ReactRootView到android app上,这会作为RN组件的容器
  4. 开启RN服务器和运行原生app
  5. 检查RN组件是否正常工作

预备知识

  按照官方指引,设置好RN开发环境。

  1. 设置目录结构。把android项目“内容”复制到RN项目根目录下的android文件夹中(初始化的RN项目中就已经有这样一个文件夹了,里面有初始的android项目内容)
  2. 安装JS依赖。在RN项目创建一个package.json,内容如下(初始的RN项目也有这些内容了)
    {
    "name": "MyReactNativeApp",
    "version": "0.0.1",
    "private": true,
    "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
    }
    }

    然后安装react和react-native依赖

    npm install --save react@16.0.0-beta.5 react-native

把RN添加到app中

配置maven仓库

  把RN依赖添加到android/app/build.gradle中(测试发现不能使用+,应该指定版本,将+替换为npm中对应的RN版本号,如package.json中 ^0.5,则将+替换为0.5):

dependencies {
...
compile "com.facebook.react:react-native:+" // From node_modules.
}

  光光以上这么配置,gradle会找不到这个依赖,需要在android/build.gradle中配置一个仓库告诉gradle去哪里找依赖(确保添加到allproject这个块中,而且要在所有其他maven仓库之上。同时确保下面的url是正确的):

allprojects {
repositories {
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
...
}
...
}

配置权限

  往AndroidManifest.xml清单文件中加上:

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

  如果需要在原生app中打开开发者菜单,也需要在清单文件中加上(如果要发布则把下面这行去掉):

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

代码集成

  在项目的根目录创建一个index.js,这是RN程序的入口点,往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);

ReactRootView

  现在需要写一些原生代码来启动RN runtime和渲染界面。在activity中创建ReactRootView,并作为主内容显示:

public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index")
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null); setContentView(mReactRootView);
} @Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
}

  以上的ReactInstanceManager可以在多个activity和fragment之间共享。接着使RN与activity的生命周期同步(这是为了让JS代码能处理这些生命周期,如JS可以检测到用户按了后退):

@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);
}
} @Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}

  如果API大于23,需要配置开发模式下错误信息的显示权限,因为错误信息必须要显示在所有窗口之上。在activity的onCreate中添加如下代码:

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);
}
}

  接着需要重写activity的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...
}
}
}
}

  接着设置开发者菜单的弹出:  

@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进行声明

<activity
android:name=".MyReactActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>

运行

  到根目录下执行npm start来打包生成js bundle。然后直接构建app(如使用android studio)启动app看效果。

实践

  通过android studio创建一个项目,项目目录指定为root/android/。

  项目地址:https://github.com/947133297/rn-ntegration-with-existing-apps