动态加载能力组件 dex & so

最后更新: 2020/3/31

动态加载能力组件 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