Android 插件化技术:动态加载综述与核心原理
背景知识
1. 什么是动态加载?
动态加载技术是指应用在运行时通过加载一些本地不存在的可执行文件来实现特定功能的技术。其核心特征包括:
- 运行时加载:应用运行过程中动态引入外部代码。
- 可替换性:加载的可执行文件可以被更新或替换,无需重新安装主程序。
- 非静态资源:仅更换启动图、主题或使用参数开关控制广告显示等静态资源变更不属于动态加载范畴。
- 核心机制:在 Android 中,动态加载的核心思想是动态调用外部的 dex 文件。极端情况下,APK 自身带有的 Dex 文件仅作为程序入口(空壳),所有业务逻辑均通过从服务器下载最新的 Dex 文件完成。
2. 动态加载的类型
Android 项目中的动态加载技术按照加载的可执行文件不同,大致分为两种:
2.1 动态加载 SO 库
Android NDK 中广泛使用了动态加载技术,即动态加载 .so 库并通过 JNI 调用其封装好的方法。这些库通常由 C/C++ 编译而成,运行在 Native 层,效率远高于虚拟机层的 Java 代码。因此,Android 经常通过动态加载 .so 库来完成对性能有需求的工作,例如 T9 搜索、Bitmap 解码、图片高斯模糊处理等。
此外,由于 .so 库是由 C/C++ 编译而来的,反编译后得到的是汇编代码,相比 Dex 文件反编译得到的 Smali 代码更难被破解,因此 .so 库常被用于安全领域。虽然一般情况下我们将 .so 库打包在 APK 内部,但它们也可以从外部存储路径加载。
2.2 动态加载 Dex/Jar/APK 文件
这是常规 Android 开发中最常提到的'动态加载'技术,即基于 ClassLoader 的动态加载 Dex/Jar/APK 文件。目前网络上大多数关于动态加载的文章指的都是这种模式。
3. Android 中的动态加载技术
Java 的可执行文件是 Jar,运行在 JVM 上,虚拟机通过 ClassLoader 加载 Jar 文件并执行其中的代码。Android 项目中,所有 Java 代码都会被编译成 dex 文件,应用运行时通过执行 dex 文件里的业务代码逻辑来工作。
使用动态加载技术可以在 Android 应用运行时加载外部的 dex 文件,而通过网络下载新的 dex 文件并替换原有的 dex 文件,就可以达到不安装新 APK 文件就升级应用(改变代码逻辑)的目的。
4. Android 动态加载的大致过程
无论哪种动态加载,基本原理都是在程序运行时加载一些外部的可执行文件,然后调用这些文件的某个方法执行业务逻辑。
重要安全限制:出于安全问题,Android 并不允许直接加载手机外部存储这类 noexec(不可执行)存储路径上的可执行文件。
对于这些外部的可执行文件,在 Android 应用中调用它们前,都要先把它们拷贝到 data/packagename/ 内部储存文件路径,确保库不会被第三方应用恶意修改或拦截,然后再将它们加载到当前的运行环境并调用需要的方法执行相应的逻辑。
动态加载的大致过程如下:
- 拷贝文件:将可执行文件(
.so/dex/jar/apk)拷贝到应用 APP 内部存储。 - 加载文件:使用类加载器加载可执行文件。
- 调用方法:调用具体的方法执行业务逻辑。
5. 动态加载 SO 库详解
动态加载 SO 库应该是 Android 最早期的动态加载形式。SO 库不仅可以存放在 APK 文件内部,还可以存放在外部存储。Android 开发中,更换 SO 库的情形并不多,但可以通过把 SO 库挪动到 APK 外部,减少 APK 的体积。毕竟许多 SO 库文件的体积是非常大的,尤其是涉及图形处理或加密算法时。


