动态加载能力组件 dex & so

最后更新: 2021/2/3

动态加载能力组件 dex & so

平台开始支持rom版本
豹小秘4.21
豹花/大屏4.18
豹小秘 Mini5.13


这项功能可以加载纯业务性的代码和 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"
    ]
}

 

豹小秘 Mini 平台

从 豹小秘 Mini 平台 开始支持不同 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

豹小秘 Mini 平台参考 DEMO