这篇文章主要总结了在使用Small框架改造老项目过程中遇到的问题和相应的解决方案,也总结了使用Small框架的基础知识点,并从一个使用者的角度来分析Small框架的优缺点。如果你的项目也面临业务模块耦合,边界不清晰,没有动态部署方案等等需要插件化方案来解决的问题,不妨先看下这篇文章再试一试Small框架,Small的功能未必全面但绝对聚焦了插件化框架需要解决的的核心问题。
什么是Small框架? Small是一个轻量级的插件化框架,Small也是一个dex分包方案,Small也是一个业务模块解耦方案,同时Small也是一个动态化加载和更新方案。先去看官网文档了解Small的基础知识~~
关于Small插件化的其他文档:
《Android插件化之Small框架原理》
《Android插件化之资源加载机制》
《Android插件化之从入门到放弃》
0x01 Small必知必会
- Small框架将工程模块分为这几个角色,宿主,宿主分身,app插件,公共lib插件
- 宿主不依赖任何模块,宿主分身被所有app和lib依赖,但是宿主和宿主分身都被打包在主应用的主dex中,app插件和公共lib插件被单独打包在自己的插件so中
- Small如何编译?
- ./gradlew cleanLib
- 编译公共库: ./gradlew buildLib
- ./gradlew cleanBundle
- 编译app插件: ./gradle buildBundle
- 编译宿主app: ./gradle :app:assembleDaily 注意:这里不是assembleDaily 而是:app:assembleDaily
- app插件的模块名称必须是app.* , 公共库lib插件的模块名称必须是lib.*。
- 在宿主app assets目录的bundle.json文件中声明每个插件的包名、类型和页面路由等信息。当app插件的包名为
**.app.*
或**.app*
时, small框架会默认该插件模块为app插件。 - app插件和app插件之间无法相互依赖,app插件之间可以通过路由uri传参,或者LocalBroadcast、Eventbus等消息机制实现通信。
- Small中插件的packageId是自动根据模块名称hash计算生成,有可能会遇到插件模块packageId冲突的情况,在这种情况下需要在发生冲突模块的build.gradle重新声明packageId, 如下:
1 | ext { |
- 生成插件到 x86 架构下./gradlew buildLib -q -Dbundle.arch=x86,需要注意 宿主的ndk abiFilters 要和
bundle.arch
一致哦。 - 如何启动其他插件模块的页面?通过
Small.openUri()
方法打开页面的路由地址。 - 动态更新插件时,需要升级插件的versionCode才会生效
- 非Activity组件需要声明在宿主或者宿主分身的manifest中
0x02 Small框架的优缺点
选择small框架的原因:
- 集成简单
- 开发方式非常接近Android app的原生开发方式
- 不需要更换编译工具,已有项目中针对业务需求开发的编译工具依然可以继续使用
- 优雅,特别是对资源id冲突的处理方式
- 轻量化,尽可能少的hook系统变量,兼容性问题较少
不选择small框架的原因:
- 插件的加载并不是按需加载
- 插件的更新实现较简单,且没有回滚方案
- 有些隐藏bug还未解决,但可以绕过
- 功能相对其他插件化框架(比如atlas)来说还不够完善,但足够解决项目插件化目标中遇到的80%问题
0x03 Small插件化实践踩过的那些坑
遇到问题怎么办?到github issues里查询你遇到的问题,一般都可以找到答案。这里大致总结了我们团队在small框架使用过程中遇到的常见问题。
- lib插件中增加或减少资源时,需要删除模块目录下public.xml再重新编译。public.xml是为了锁定lib中资源id
- 增加或修改插件中ndk module覆盖安装不生效,需要将native module编译生成的so文件放在宿主中才能实现更新
- 遇到ClassNotFoundException异常或者无法启动某些activity companentInfo,排查问题的方法:
- 查看Fatal Runtime Exception日志,查看日志中已经加载的so是否包含你的插件so
- 如果插件so被加载,再确定相应代码已经被编译进插件so中,查看方法很简单,将插件so重命名为apk直接在Android Studio中打开
- 确认是否将插件so正确声明在bundle.json文件中
- 确认该异常类继承的父类或者接口满足上述几个条件
- Class ref in pre-verified class resolved to unexpected implementation ,使用gradle smallLint命令查看是否有class重复了 https://github.com/wequick/Small/issues/423
- Activity launch mode为singletop时在activity style中设置透明背景无效 https://github.com/wequick/Small/issues/94
- 无法通过Small.openUri()方法启动页面怎么办?一定是你用法不对,debug找原因。
0x04 Small插件化规范
- 不要在宿主中添加业务代码
- native module so放在宿主中, 原因关注Github issue: 增加或修改插件中ndk module覆盖安装不生效
- 不同插件模块中依赖相同第三方aar或jar的版本号要相同,建议将aar或jar的版本号统一声明在gradle.properties中,将共同依赖的第三方sdk声明在宿主分身中
- 所有Theme的定义都放在宿主和宿主分身中,具体原因看我的另一篇问题总结:Android插件化之资源加载
Small插件化项目的完全体
0x05 参考
Small官网文档 http://code.wequick.net/Small/cn/quickstart
Small github主页 https://github.com/wequick/Small