动态加载能力组件 dex & so

最后更新: 2020/7/27

动态加载能力组件 dex & so

平台开始支持rom版本
豹小秘4.21
豹花/大屏4.18
M 平台5.2


这项功能可以做到什么?

可以加载纯业务性的代码和 so,以及基于现有代码的扩展

这项功能的限制:

  1. 不能加载带 layout drawable string 等资源的
  2. 和原生有代码 和 so 有冲突的,类名和 so 名称不能有冲突
  3. 新写的 ReactContextBaseJavaModule 中返回的 name 不能和已有的 NativeModules 重名,否则会影响原有功能
  4. 不能加载需要在 manifest.xml 预埋内容的
  5. 不能加载需要使用 assets 资源的

生成 dex 和 so

  1. 首先可以创建一个空的 RN 工程,会自动生成 Android 工程,在 Android 工程中创建 lib module
  2. 然后在内部实现相应的业务逻辑,并将这些业务逻辑封装为 RN NativeModules 和 ReactPackage
  3. 业务逻辑实现完成之后,可以执行 gradlew dexRelease 命令,打出 dex 文件(在 libmodule/build/intermediates/dex/release/out 目录下)
  4. 如果需要引用第三方 jar 库,也需要把第三方库打成 dex 文件,和业务逻辑的 dex 一起,命令如下
dx --dex --output=fastjson.dex ./fastjson-1.2.61.jar

dx 是 android sdk buildtools 里的一个命令行工具,更多使用方式可以查看官网,在 Android/sdk/build-tools/28.0.3/中(也可以是其他版本),需要把这个路径配置系统环境变量中

dex 和 so 放置目录的规则
动态加载的 dex 和 so 要遵循下面的目录存放规则,要放在 opk 的 extraResource/libs/ 下

豹小秘、豹大/花瓶

在豹小秘、豹大/花瓶上需要确定系统运行的 abi ,以及是否为 64 位,然后提供对应的 so 文件。

extraResource
└── libs
├── amap
│ ├── 3dmap-6.6.0.jar
│ ├── config.json
│ ├── dexlib
│ │ ├── amap.dex
│ │ └── amaprnclasses.dex
│ └── jnilib
│ └── libAMapSDK_MAP_v6_6_0.so
└── test
├── config.json
├── dexlib
│ ├── classes1.dex
│ ├── classes2.dex
│ ├── core-3.3.0.dex
│ └── retrofit.dex
└── jnilib
├── libhello-jni.so
└── libplus.so

安装完成之后在 sdcard 上的路径如下

sdcard
└── appid or debug(debug 模式)
└── extra
└── libs
├── amap
│ ├── 3dmap-6.6.0.jar
│ ├── config.json
│ ├── dexlib
│ │ ├── amap.dex
│ │ └── amaprnclasses.dex
│ └── jnilib
│ └── libAMapSDK_MAP_v6_6_0.so
└── test
├── config.json
├── dexlib
│ ├── classes1.dex
│ ├── classes2.dex
│ ├── core-3.3.0.dex
│ └── retrofit.dex
└── jnilib
├── libhello-jni.so
└── libplus.so


jnilib 目录中存放 .so 文件
dexlib 目录中存放 .dex 文件
config.json 中配置 ReactPackge 子类的 classname,如下

{
"packageClassNames": [
"com.ainirobot.testsdk.HelloModuleReactPackage",
"com.ainirobot.testsdk2.Test2ReactPackage"
]
}

M 平台

从 M 平台 开始支持不同 abi 的 so ,系统会根据当前运行的状态去加载不同的 abi 的so 文件,so 文件放置规则和 Android 项目的 jnilibs 目录一致,如下

extraResource
└── libs
├── testsdk
│ ├── config.json
│ ├── dexlib
│ │ └── classes.dex
│ └── jnilib
│ ├── arm64-v8a
│ │ ├── libhello-jni.so
│ │ └── libjianjian.so
│ ├── armeabi-v7a
│ │ ├── libhello-jni.so
│ │ └── libjianjian.so
│ ├── x86
│ │ ├── libhello-jni.so
│ │ └── libjianjian.so
│ └── x86_64
│ ├── libhello-jni.so
│ └── libjianjian.so
└── testsdk2
├── config.json
└── dexlib
├── fastjson.dex
├── retrofit.dex
└── testsdk2.dex

安装完成之后在 sdcard 上的路径如下

sdcard
└── appid or debug(debug 模式)
└── extra
└── libs
├── testsdk
│ ├── config.json
│ ├── dexlib
│ │ └── classes.dex
│ └── jnilib
│ ├── arm64-v8a
│ │ ├── libhello-jni.so
│ │ └── libjianjian.so
│ ├── armeabi-v7a
│ │ ├── libhello-jni.so
│ │ └── libjianjian.so
│ ├── x86
│ │ ├── libhello-jni.so
│ │ └── libjianjian.so
│ └── x86_64
│ ├── libhello-jni.so
│ └── libjianjian.so
└── testsdk2
├── config.json
└── dexlib
├── fastjson.dex
├── retrofit.dex
└── testsdk2.dex


这样 dex 和 so 就可以在 opk 运行的时候被动态 load 起来。
接下来只需要在 RN 工程的业务代码中,直接使用封装的 NativeModules ,又或者是你用的是一个第三方库,那需要在 package.json 中加上这个库的依赖。

import { NativeModules } from 'react-native';

const Hello = NativeModules.Hello;
const Test2 = NativeModules.Test2;

export class HelloUtil {
public static getStringFromJNI() {
return Hello && Hello.getStringFromJNI();
}

public static getStringFromKT() {
return Hello && Hello.getStringFromKT();
}

public static jianjian(num: number) {
return Hello && Hello.jianjian(num);
}

public static far() {
return Test2 && Test2.far();
}
}


Debug 模式

debug 模式需要把 libs 目录 push 进 /sdcard/debug/extra/ 下

示例:

豹小秘、豹大/花瓶参考 DEMO

M 平台参考 DEMO