Android解耦式so库加载方案

背景说明java

在业务开发过程当中常常会进入一些三方sdk,这些三方的sdk引入so库,有些so库文件还比较大,这时候咱们就须要考虑so库从网络获取异步加载,减小发布包的体积编程

传统方案segmentfault

关于so异步加载方案,网上的资料随便搜下大把,核心思想
so库文件放到网络->下载到本地沙盒->经过System.load载入
看起来挺简单的 然而挺多资料没提到的是网络

so库存在依赖关系app

好比当你把友链交易libunity.so下载下来经过
System.load("/data/data/com.example.soload/files/libunity.so")
加载的时候会获得以下异常异步

java.lang.UnsatisfiedLinkError: dlopen failed: library “libmain.so” not found
at java.lang.Runtime.loadLibrary0(Runtime.java:1071)
at java.lang.Runtime.loadLibrary0(Runtime.java:1007)
at java.lang.System.loadLibrary(System.java:1667)函数

解决方案url

载入libunity.so以前须要先载入libmain.so日志

以上2个开源库 都有处理相关逻辑
核心思想就是解析so库ELF格式,分析依赖并递归,直到依赖库都加载完成再载入自身
这里不扩展开来 有兴趣的伙伴能够看源码研究下递归

text relocations问题

当你把liblbs.so下载下来经过

System.load("/data/data/com.example.soload/files/liblbs.so")的时候又出现意外了
java.lang.UnsatisfiedLinkError: dlopen failed: “/data/data/com.example.soload/files/liblbs.so” has
at java.lang.Runtime.load0(Runtime.java:938)
at java.lang.System.load(System.java:1631)==

扩展思考:

咱们能够经过命令进行自查

有源码的能够从新编译,没有源码的只能经过下降targetSdkVersion处理(然而也是治标不治本)

进阶方案

除了System.load方案 还有没有其余方案呢
答案固然是确定的
核心思路:经过反射把自定义的native库path插入nativeLibraryDirect ories最前面,即便安装包libs目录里面有同名的so,也优先加载指定路径的外部so
这里截取tinker部分代码
com.tencent.tinker.lib.library.TinkerLoadLibrary.java

这个方案是否是看起来更简单了,因为这个方案是很是规手段,存在兼容风险, 咱们须要验证该方案的兼容性,写个helloword的so,经过该方案加载,提早找个版本线上带上去,进行埋点统计
截至目前最新版上线2天 统计到数据以下

其中失败的1例是上线前自测故意让校验失败产生的
也就是说截至目前能够认为改方案是靠谱的
固然了若是后续有新的Android系统版本更新
咱们还须要关注新版本的兼容状况

项目应用

上面铺垫了那么多,如今进入正题
技术方案是一回事,落实到实际项目是另外一回事
如今开始咱们思考下以下几个问题

项目中引用的so库都是那些功能再用什么时候载入

三方jar(aar)引入的so库加载时机不受咱们代码逻辑控制

使用的so库那些适合作异步加载

so库文件没有下载完成以前 用户用相关功能如何处理

版本迭代so文件升级如何处理

打包阶段如何把so文件进行剔除

解决问题一、二、3

咱们能够经过切面编程的思路解决,这里用到了开源因为so库的加载都是经过调用系统函数System.loadLibrary进行,那么咱们全局拦截该函数的调用并打印调用链,运行app,配合日志,就能分析so库的具体使用状况

相关文章
相关标签/搜索