背景说明
在业务开发过程中经常会进入一些三方sdk,这些三方的sdk引入so库,有些so库文件还比较大,这时候我们就需要考虑so库从网络获取异步加载,减少发布包的体积
传统方案
关于so异步加载方案,网上的资料随便搜下大把,核心思想
so库文件放到网络->下载到本地沙盒->通过System.load载入
看起来挺简单的 然而挺多资料没提到的是
so库存在依赖关系
比如当你把libunity.so下载下来通过
System.load("/data/data/com.example.soload/files/libunity.so")
加载的时候会得到如下异常
原因分析
解决方案
载入libunity.so之前需要先载入libmain.so
扩展思考
我们写代码的时候怎么控制加载顺序呢
github.com/facebook/S.…
github.com/KeepSafe/R.…
以上2个开源库 都有处理相关逻辑
核心思想就是解析so库ELF格式,分析依赖并递归,直到依赖库都加载完成再载入自身
这里不扩展开来 有兴趣的伙伴可以看源码研究下
text relocations问题
当你把liblbs.so下载下来通过
原因分析:
blog.csdn.net/chjqxxx...
扩展思考:
我们可以通过命令进行自查
有源码的可以重新编译,没有源码的只能通过降低targetSdkVersion处理(然而也是治标不治本)
进阶方案
除了System.load方案 还有没有其他方案呢
答案当然是肯定的
github.com/Tencent/ti.…
核心思路:通过反射把自定义的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文件进行剔除
解决问题1、2、3
我们可以通过切面编程的思路解决,这里用到了开源库github.com/HujiangTec.…
由于so库的加载都是通过调用系统函数System.loadLibrary进行,
那么我们全局拦截该函数的调用并打印调用链,
运行app,配合日志,就能分析so库的具体使用情况
这里我们需要根据自己业务场景分析,比如app进入到首页依赖的库不建议进行异步加载,需要异步加载的库最好是完成一个功能(我们需要按照经验进行逻辑分组 参考文章开头的图)
解决问题4、5
Android是依据Activity作为活动单位,启动Activity是通过startActivity函数调用进行的,那么我们就可以拦截织入自己的逻辑
大致思路如下
对应实现部分代码截图
通过规则配置化+字节码拦截的逻辑 对原有业务无侵入即可实现动态加载
研发关注正常的业务逻辑 不需要针对性编写代码
后续引入新的so库,修改配置文件即可
在实现的过程中有些细节是需要考虑的
比如校验下载文件的完整性,下载要不要支持断点续传,so文件需要更新如何处理等
解决问题6
通过上面的介绍,我们实现了so文件的异步加载
但是打包的时候 我们如何剔除so 减少最终发布包的大小
可以在build.gradle进行配置
但是上面提到了我们是通过json配置的规则
这样再重复配置一遍
而且还有可能2处配置不一致
而且我们的大原则是解耦
那么我们就继续hook打包流程
汇总小结
通过上面的介绍大致说明了原理
有兴趣的伙伴可以评论区留言,提出自己的想法
目前还在灰度验证阶段,等线上验证稳定后在评论区放出相关代码
so异步加载方案大同小异,该方案跟其他方案相比
个人感觉特色就是侵入性低
接入只需要3个步骤
未完待续
目前该方案还存在几个点有待优化
====================
问题1
目前用的是进阶方案实现的so库加载 比较理想的方式是传统方案和进阶方案都应该支持 一开始其实我想用传统方案去实现 但是该方案在unity那块有问题(unity相关so的加载逻辑有点特殊 存在通过jni直接加载so的情况 由于没有源码 内部逻辑不太清楚 ) 后续还需要研究完善 毕竟官方System.load是官方提供的api 更可靠
问题2
进度加载的dialog是依附于调用startActivity的窗口
如果startActivuty之后里面 立马调用finish会导致dialog泄露
这个是需要注意的一个点 也就意味着对原有逻辑存在一定依赖
这个可以通过启动一个FLAG_ACTIVITY_NEW_TASK类型的activity
代理解决 但是感觉这样有点重 目前还有点纠结
问题3
目前文件只是放到了阿里云,用户的网络环境复杂多变,需要考虑支持腾讯云,七牛云等更多的服务商。
问题4
上传到oss的动作目前是动手完成的,需要做成脚本。
前端
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!