欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android原生集成react-native

程序员文章站 2022-06-23 15:40:12
在原有的 android 应用中集成 react-native。假设我们现在已经有了一个 android 原生应用 myapplication。 #第一步:进入到项目更目录下,新建一个空文件夹,命...

在原有的 android 应用中集成 react-native。假设我们现在已经有了一个 android 原生应用 myapplication。


#第一步:进入到项目更目录下,新建一个空文件夹,命名为 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 中添加网络权限:

当然如果是在 debug 模式下,方便调试还可以在内加上:

添加完之后大概为:

…………>

…… ……

 

 


#第五步:新建 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 文件下对应的活动下修改视图的主题就可以了

android:theme="@style/theme.appcompat.light.noactionbar">

 


#第八步:将活动的生命周期传递给 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/