Android插件化之Small框架实践总结

这篇文章主要总结了在使用Small框架改造老项目过程中遇到的问题和相应的解决方案,也总结了使用Small框架的基础知识点,并从一个使用者的角度来分析Small框架的优缺点。如果你的项目也面临业务模块耦合,边界不清晰,没有动态部署方案等等需要插件化方案来解决的问题,不妨先看下这篇文章再试一试Small框架,Small的功能未必全面但绝对聚焦了插件化框架需要解决的的核心问题。

什么是Small框架? Small是一个轻量级的插件化框架,Small也是一个dex分包方案,Small也是一个业务模块解耦方案,同时Small也是一个动态化加载和更新方案。先去看官网文档了解Small的基础知识~~

Small官网文档

关于Small插件化的其他文档:

《Android插件化之Small框架原理》
《Android插件化之资源加载机制》
《Android插件化之从入门到放弃》

0x01 Small必知必会

Small角色关系

  1. Small框架将工程模块分为这几个角色,宿主,宿主分身,app插件,公共lib插件
  2. 宿主不依赖任何模块,宿主分身被所有app和lib依赖,但是宿主和宿主分身都被打包在主应用的主dex中,app插件和公共lib插件被单独打包在自己的插件so中
  3. Small如何编译?
    • ./gradlew cleanLib
    • 编译公共库: ./gradlew buildLib
    • ./gradlew cleanBundle
    • 编译app插件: ./gradle buildBundle
    • 编译宿主app: ./gradle :app:assembleDaily 注意:这里不是assembleDaily 而是:app:assembleDaily
  4. app插件的模块名称必须是app.* , 公共库lib插件的模块名称必须是lib.*。
  5. 在宿主app assets目录的bundle.json文件中声明每个插件的包名、类型和页面路由等信息。当app插件的包名为 **.app.***.app*时, small框架会默认该插件模块为app插件。
  6. app插件和app插件之间无法相互依赖,app插件之间可以通过路由uri传参,或者LocalBroadcast、Eventbus等消息机制实现通信。
  7. Small中插件的packageId是自动根据模块名称hash计算生成,有可能会遇到插件模块packageId冲突的情况,在这种情况下需要在发生冲突模块的build.gradle重新声明packageId, 如下:
1
2
3
ext {
packageId = 0x33
}
  1. 生成插件到 x86 架构下./gradlew buildLib -q -Dbundle.arch=x86,需要注意 宿主的ndk abiFilters 要和bundle.arch一致哦。
  2. 如何启动其他插件模块的页面?通过Small.openUri()方法打开页面的路由地址。
  3. 动态更新插件时,需要升级插件的versionCode才会生效
  4. 非Activity组件需要声明在宿主或者宿主分身的manifest中

0x02 Small框架的优缺点

选择small框架的原因:

  1. 集成简单
  2. 开发方式非常接近Android app的原生开发方式
  3. 不需要更换编译工具,已有项目中针对业务需求开发的编译工具依然可以继续使用
  4. 优雅,特别是对资源id冲突的处理方式
  5. 轻量化,尽可能少的hook系统变量,兼容性问题较少

不选择small框架的原因:

  1. 插件的加载并不是按需加载
  2. 插件的更新实现较简单,且没有回滚方案
  3. 有些隐藏bug还未解决,但可以绕过
  4. 功能相对其他插件化框架(比如atlas)来说还不够完善,但足够解决项目插件化目标中遇到的80%问题

0x03 Small插件化实践踩过的那些坑

遇到问题怎么办?到github issues里查询你遇到的问题,一般都可以找到答案。这里大致总结了我们团队在small框架使用过程中遇到的常见问题。

  1. lib插件中增加或减少资源时,需要删除模块目录下public.xml再重新编译。public.xml是为了锁定lib中资源id
  2. 增加或修改插件中ndk module覆盖安装不生效,需要将native module编译生成的so文件放在宿主中才能实现更新
  3. 遇到ClassNotFoundException异常或者无法启动某些activity companentInfo,排查问题的方法:
    • 查看Fatal Runtime Exception日志,查看日志中已经加载的so是否包含你的插件so
    • 如果插件so被加载,再确定相应代码已经被编译进插件so中,查看方法很简单,将插件so重命名为apk直接在Android Studio中打开
    • 确认是否将插件so正确声明在bundle.json文件中
    • 确认该异常类继承的父类或者接口满足上述几个条件
  4. Class ref in pre-verified class resolved to unexpected implementation ,使用gradle smallLint命令查看是否有class重复了 https://github.com/wequick/Small/issues/423
  5. Activity launch mode为singletop时在activity style中设置透明背景无效 https://github.com/wequick/Small/issues/94
  6. 无法通过Small.openUri()方法启动页面怎么办?一定是你用法不对,debug找原因。

0x04 Small插件化规范

  1. 不要在宿主中添加业务代码
  2. native module so放在宿主中, 原因关注Github issue: 增加或修改插件中ndk module覆盖安装不生效
  3. 不同插件模块中依赖相同第三方aar或jar的版本号要相同,建议将aar或jar的版本号统一声明在gradle.properties中,将共同依赖的第三方sdk声明在宿主分身中
  4. 所有Theme的定义都放在宿主和宿主分身中,具体原因看我的另一篇问题总结:Android插件化之资源加载

Small插件化项目的完全体

Small插件化完全体

0x05 参考

Small官网文档 http://code.wequick.net/Small/cn/quickstart

Small github主页 https://github.com/wequick/Small

GMTC演讲PPT

转载请标明出处病已blog https://ivonhoe.github.io/