Android原生集成react-native

在原有的 Android 应用中集成 react-native。假设我们现在已经有了一个 Android 原生应用 MyApplication。
主要参考:
https://reactnative.cn/docs/0.51/integration-with-existing-apps.html#content
https://facebook.github.io/react-native/docs/integration-with-existing-apps.html
https://stackoverflow.com/questions/40694285/react-native-expection-java-lang-unsatisfiedlinkerror-
dlopen-failed-data-dat?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
https://blog.csdn.net/chichengjunma/article/details/53815299

#第一步:进入到项目更目录下,新建一个空文件夹,命名为 android,然后将原本目录下所有的文件都移动到这个 android 文件夹下。
所以现在项目的根目录就是 MyApplication,更目录下有一个 android 文件夹,里面是原来所有 android 原生应用的文件。

#第二步:在项目更目录下新建一个 package.json 文件用来安装所需要的 npm 依赖。package.json 文件内容大概为
{
"name": "MyApplication",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"@babel/core": "^7.0.0-beta.42",
"babel-core": "^7.0.0-bridge.0",
"react": "16.3.0-alpha.1",
"react-native": "^0.54.2"
}
}
需要注意的是这里的 name 一定要与项目的名称保持一样。 react 和 react-native 以及其它库的版本根据当前最新版本适当修改即可。
然后在更目录下执行 npm install 即可。

#第三部:用 android studio 打开 android 下面的原生应用。在 app 的 build.gradle 文件中的 dependencies 闭包下加上一句
compile "com.facebook.react:react-native:+"
官网上是这么说的,同时官网上还要求了
compile 'com.android.support:appcompat-v7:23.0.1'
但是实际应用中发现一方面并不需要一定是 v7:23.0.1,而且更重要的是 compile 方式即将不支持了。换用 implementation。
而且新建 android 原生应用的时候会默认使用最新的编译库(当前是27)所以要是按照官网上的话,不仅需要修改便宜版本为23,
同时使用 compile。这样会导致很多问题。所以直接按照下面的配置就可以了:
//app: build.gradle
dependencies {
implementation 'com.android.support:appcompat-v7:27.1.1'
…… ……
implementation "com.facebook.react:react-native:+"
}
这样就不会有问题了。接着修改 project 的 build.gradle 文件,在 allprojects 闭包中的 repositories 闭包下添加 maven 依赖,
//project: build.gradle
allprojects {
repositories {
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
...
}
...
}
这两部都修改完之后点击提示的 Sync Now. 构建完成之后应该不会出现错误。

#第四步:在 AndroidManifest.xml 中添加网络权限: <uses-permission android:name="android.permission.INTERNET" />
当然如果是在 Debug 模式下,方便调试还可以在<Application> </ Application >内加上:
< activity android:name= "com.facebook.react.devsupport.DevSettingsActivity" />
添加完之后大概为:
< manifest ………… >
< uses-permission android:name= "android.permission.INTERNET" />
< application
………… >
…… ……
< activity android:name= "com.facebook.react.devsupport.DevSettingsActivity" />
</ application >
</ manifest >

#第五步:新建 App.js 和 index.js 文件,就像原本的 react-native 项目中那样,只是要记住在 index.js 文件中注册的组件名称比如
AppRegistry.registerComponent('MyApplication', () => App); 这里的 MyApplication

#第六步:因为在 Debug 模式下的错误信息都是显示在悬浮窗中的,所以如果是在 android 6.0 或者以上的系统中,
我们需要动态的申请这个权限(当然,如果是在 Release 模式下并不需要这个权限)。权限在希望启动 react-native 界面的活动下申请,
比如这里我们希望在 Main2Activity 这个活动中启动
private final int OVERLAY_PERMISSION_REQ_CODE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
…… ……
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);
}
}
}
接着重写活动的 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
}
}
}
}

#第七部:将 react-native 组件加进来,在我们希望启动 react-native 的活动(这里的 Main2Activity)类实现
DefaultHardwareBackBtnHandler 接口,然后通过 ReactRootView 这个类将 react-native 组件加进来
public class Main2Activity extends AppCompatActivity 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();
// 注意这里的名称(MyApplication)必须与 index.js 文件中注册的名称一样
mReactRootView.startReactApplication(mReactInstanceManager, "MyApplication", null);

setContentView(mReactRootView);
}

@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
}
这里可以看到,通过 setContentView(mReactRootView) 方法将 react-native 的视图作为了这个活动的视图了。
做完这一步之后还需要注意,因为 react-native 界面顶部是没有 android 自带的 actionBar 的,所以我们需要把这个活动下视图的
actionBar 去掉,只要在
AndroidManifest.xml 文件下对应的活动下修改视图的主题就可以了
< activity android:name= ".Main2Activity"
android:theme= "@style/Theme.AppCompat.Light.NoActionBar" >
</ activity >

#第八步:将活动的生命周期传递给 ReactInstanceManager:
@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();
}
}
同时在这个活动下,把后退按钮传递给 react-native:
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
另外,如果是在模拟器环境下,Ctrl + M 按键调出调试面板是非常有用的,所以我们也可以重写这个按钮的事件
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
}

#第九步:到此,集成已经完毕了,可以运行程序了。但是直接 react-native run-android 一般会有问题,不能正确的打开本地服务器。
一般用 android studio 将程序安装到手机或者模拟器上之后再通过 npm start 手动打开本地服务器.

#最后还有一个问题,如果是运行在 64 位的手机或者模拟器上,程序会失败,提示错误信息为
dlopen failed: "/data/data/package/lib-main/libgnustl_shared.so" is 32-bit instead of 64-bit
这个好像是因为 react-native 要求的 .so 文件不支持 64 位的手机,解决办法就是 在 app:build.gradle 文件中在加上两个闭包
defaultConfig {
…… ……
ndk {
abiFilters "armeabi-v7a", "x86"
}
packagingOptions {
exclude "lib/arm64-v8a/libgnustl_shared.so"
}
}
好了,到此就成功将 react-native 集成到 Android 原生应用中啦!!!
下面是完整的 Main2Activity 活动的文件内容:
=========================================================================================================

import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
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 Main2Activity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {

private final int OVERLAY_PERMISSION_REQ_CODE = 1;
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

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


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, "MyApplication", null);
setContentView(mReactRootView);

}

@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}

@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)) {
// 如果悬浮窗权限申请失败的话……
}
}
}
}

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


===================================================================================================
react-native android 打包命令:
事先在 ./android/app/src/main/ 下要有一个 assets 文件夹,没有的话就手动建立一个即可
(附带,引用这个文件夹下的资源可通过 file:///android_asset/xxx)
react-native bundle --platform android --dev false --entry-file index.js --bundle-output
android/com/your-company-name/app-package-name/src/main/assets/index.android.bundle --assets-dest
android/com/your-company-name/app-package-name/src/main/res/
例如这里就用
react-native bundle --platform android --dev false --entry-file index.js --bundle-output
./android/app/src/main/assets/index.android.bundle --assets-dest ./android/app/src/main/res/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值