爱奇艺开源轻量级插件化方案 Neptune

来自:开源中国社区

爱奇艺近日开源了其轻量级插件化方案 Neptune,项目地址:https://github.com/iqiyi/Neptune

插件化框架可以在主程序不重新安装的情况下,针对单个业务模块进行动态加载达到模块更新的目的,整个加载更新过程,对用户来说也是无感知的。

在爱奇艺APP快速发展的历程中,需要插件化的原因,归结起来有以下几点:

  • 业务快速发展,代码膨胀,APP不可避免地遇到了65536的大坑

  • 代码量增大带来了APK包体积的增加,而爱奇艺APK包体积一直在竞品中保持领先地位

  • 模块耦合度高,协作开发困难,编译时间长

  • 应用频繁更新,用户粘性降低,新版本覆盖率和覆盖速度不满足业务需求

  • 新功能开发,需要支持动态升级,插件动态下发形式可以完成模块的热部署和实时更新

爱奇艺APP从2013年就开始了插件化技术的研究和改造,截止目前一共有20多个独立业务模块以插件化的方式运行和并行迭代,其中包括APP首页的奇秀、文学、电影票、漫画等业务。开发插件化框架的Demo并不是很难,但是要开发一款完善的插件化框架,兼容适配国产各种碎片化的ROM,同时满足业务需求,却不是那么容易。插件框架的稳定性和兼容性,从原有代码模块解耦到插件化的迁移成本、后期维护成本等方面都需要考虑到。本文将介绍插件化实现的技术原理,分享爱奇艺APP在插件化实践过程的解决方案。

Neptune是爱奇艺移动端研发的一套灵活,稳定,轻量级的插件化解决方案。经过不断的研发,迭代和线上验证,目前已经完全适配了Android P,能够在数亿的设备上动态加载和运行插件APK,为爱奇艺众多的垂直业务团队提供了稳定的服务。

Neptune的特性

功能完善,支持Activity/Service/Recevier,几乎支持所有Android原生特性。由于ContentProvider使用场景较少,暂时没有支持。

  • 四大组件无需在宿主Manifest中预先注册,组件具备完整的生命周期

  • Activity:支持显式和隐式调用,支持theme,luanchMode,taskAffinity,支持透明主题

  • Service:支持显式和隐式调用,支持start,stop,bind,unbind等操作

  • BroadcastReceiver:支持静态广播和动态广播

  • 支持共享宿主的代码和资源,实现资源分区

  • 支持插件之间存在相互依赖,代码共享

  • 插件ClassLoader和资源互相隔离,避免类冲突和资源重名

  • 宿主Activity容器支持加载插件中的Fragment和View


兼容性和稳定性

  • 几乎兼容市面上所有的Android设备

  • 极少的Hook,核心Hook点只有Instrumentation和AssetManager,没有binder hook

  • 插件可以运行在独立进程,与宿主完全隔离,互不干扰

  • 插件之间类是隔离的,不会出现重复类的问题

  • 插件使用自身的AssetManager,没有Hook宿主的Resources,无需适配小米,vivo等ROM


侵入性低

  • 插件开发和开发原生APP类似

  • 插件可以依赖宿主的代码和资源,也可以完全不依赖

  • 插件和宿主可以独立打包和编译,并行迭代

  • 插件依赖宿主的资源,通过Gradle插件自动完成资源适

    配和处理,对开发者透明

Neptune的架构图

Neptune整个框架实现是非常轻量级的,没有包含插件下载/安装/版本管理的逻辑,提供了PluginClassLoader,PluginContextWrapper,ActivityProxy,ResourcesProxy等基础组件实现了全面插件化。更多细节欢迎访问Github,Read the fucking source code。

插件管理中心

在Neptune框架之上,爱奇艺APP针对插件业务,实现了一套完备的插件管理方案,负责插件的下载,安装,升级,版本管理,插件启动控制,插件与宿主之间的通信。由于这部分涉及具体APP业务的交互形态,且与后端数据结构关联,因此没有开源。

这里简单介绍下设计思路。对于每一个插件版本数据,在APP层是一个OnLineInstance实例,里面字段与后端数据结构保持一致,包含基本的插件包名,插件版本,插件依赖,还包含一些下载控制策略,patch升级策略等。APP层的OnLineInstance,对应于Neptune框架的PluginLiteInfo。由于一些插件可能会来自不同的地方或者配置不同的版本,如内置插件,本地缓存的旧版本插件,线上最新插件。因此在APP层一个插件业务会关联多个OnLineInstance,我们会选择最高版本的兼容插件进行升级,安装。


插件实例状态机

一个插件OnLineInstance从初始状态(OriginalState)到可用状态(InstalledState)有一套严格的状态机演变。版本不兼容的插件实例会被下线,优先使用本地已安装版本,空闲时机下载升级最新的插件,尽量做到让用户使用无感知。



插件增量更新

插件包体积越大,下载成功率和转化率越低,为了提高插件升级的覆盖率和成功率,我们采用了增量更新的机制。插件后台更新插件时,后台会基于历史版本插件生成增量的diff包。APP端在请求插件数据时,后端接口额外返回增量patch的url及生成patch所有的base插件版本。前端根据本地已安装插件的版本,选择使用patch增量合成新版本插件apk还是走全量下载新插件,优化网络下载流量。

推荐↓↓↓
开源最前线
上一篇:开源作者痛斥京东重量级项目抄袭 下一篇:代码搜索引擎和代码浏览器 Sourcegraph 宣布开源