36

Aura插件化框架演进以及思考

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzUyMDAxMjQ3Ng%3D%3D&%3Bmid=2247491737&%3Bidx=1&%3Bsn=dd095101eddcbfc5a9285157097a58e9
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
  • 在Android开发行业里,插件化已经不是一门新鲜的技术了,早在12年就已经被提出,发展到今天已经逐渐趋于成熟,各大厂商基本都有自己的一套插件化方案。

  • 京东的插件化框架Aura起始于2014年,相比于现在Android平台上的插件化框架百花齐放的盛况,在当时插件化框架可谓是凤毛麟角,可供参考的资料比较少,而仅有的几个开源项目也有它们各自的局限性,不适合大项目使用。我们在研究了当时的一些开源的技术之后,逐渐走出了一条自己的插件化框架之路,到如今形成了比较完善的插件化框架。

为什么要插件化

插件化技术的好处是显而易见的:

  • 模块解耦:随着业务的不断增加,代码库会逐渐臃肿,各个业务耦合情况将会越来越严重,造成开发调试的困难。插件间一般是没有耦合关系的,因此天然的支持模块解耦。

  • 协同开发:插件可以独立仓库开发,各个模块互不影响。

  • 提高编译速度:编译速度会极大的影响开发效率,话说编码五分钟,编译两小时,插件化后,宿主的编译速度会显著提升,并且各个插件也可以独立编译调试。

  • 动态发布:各个插件可以脱离宿主的发版限制独立发版,既可用于解决线上bug,也可以快速上线新业务。

  • 65536问题:插件化方案可以减少宿主的方法数。

  • 减小包体积:包体积和下载转化率有很大关系,Google曾经统计过包体积每增加6MB就会带来转化率1%的下降,并且Google Play也有过规定:对于发布到 Google Play 的应用,其下载大小限制为不超过100MB。插件包可动态下载,是减小宿主包体积的利器。

插件化带来这么多便利的同时,也会面临不少问题:

  • 兼容性:插件化技术或多或少会涉及hook系统的API,Google从Android 9.0开始限制私有API的调用,因此需要考虑兼容Android的各个版本,并且Android碎片化比较严重,需要兼容各大厂商的rom。

  • 复杂性:插件化技术的整体流程是比较复杂的,不仅涉及框架sdk,还需要Gradle插件甚至修改aapt等工具来实现插件包的编译。接入插件化方案也会有一定的成本。

插件化技术现状

  • Android插件化的历史并不长,自12年的AndroidDynamicLoader框架开始,到15年的DroidPlugin,16年的Small,再到17年的Atlas、Replugin、VirtualAPK,可谓是日新月异,百家争鸣,至此插件化技术进入了成熟阶段。 但好景不长,随着Android P的发布,Google官方推出了大杀器 -- 禁止调用私有API[1],插件化框架或多或少都会反射系统的隐藏API,Google此举似乎给插件化技术画上了句号。 不过好在私有API分为黑名单、灰名单、白名单三种方式,市面上大多数插件框架都作了兼容,调用系统API最多是在灰名单里,所以目前插件化框架仍然是可用的。 但这并不代表万无一失,灰名单是根据Target sdk 版本去划分的,后续的Android 系统仍会将某些API设为黑名单里,无疑给插件化技术的发展蒙上了一层阴影。 这里不得不佩服Replugin团队的技术前瞻性,仅使用一处hook点,hook点越少,涉及私有API的风险也就越低。 此后,插件化技术的发展似乎停滞不前,热度也越来越低。

  • 2018年Google发布了一种新的应用发布方式:Android App Bundle,可将应用拆分为多个Feature Apk,支持动态下发。这似乎是插件化的官方版本,不过这套服务依赖Google Play,国内环境无法使用,这种方式对插件化技术带来了新的方案。

  • 2019年,经过了一段时间的沉寂后,随着基于Android App     Bundle的Qigsaw插件化方案 和零反射全动态Android插件框架Shadow的开源,插件化技术似乎又活跃了起来。

Aura插件化方案

Aura是京东自研的一款插件化框架,目前不仅支持京东商城70+个业务插件的落地,还支持的京东到家、泰国站、拼购等App的使用,经过线上亿级用户量的检验,逐渐沉淀出的一套稳定的、灵活的插件化方案,并且提供了一整套编译、集成、动态升级流程,极大的简化了开发流程。 整体框架见下图:

VRnMzaQ.jpg!web

  • 系统层:hook了ClassLoader和Assetmanager用于插件类和资源的加载。

  • 框架层:包含Aura框架和公共库,公共库包含了插件和宿主共同依赖的类和资源。Aura框架则提供了插件化能力。

  • 插件层:基于公共库和插件框架进行开发,有业务插件和公共插件之分。

实现原理

目前市面上的插件化方案已经很多,实现原理也都比较透明了,这里再简单介绍下。 实现插件化框架主要是解决两个问题: 类的加载和资源加载。

  • 类加载:

1、Aura通过反射将系统的PathClassLoader替换成我们自己的DelegateClassLoader。

2、加载插件的时候会给每个插件创建自己的ClassLoader。

3、当启动插件中Activity或其他组件时候,DelegateClassLoader则会根据Activity名称找到对应的插件,执行安装过程,最终调用插件的ClassLoader进行类的加载。插件ClassLoader会优先加载插件内部的类,加载失败再用宿主的ClassLoader去加载。因此插件中是可以正常使用宿主中的API的。

  • 资源加载:

1、公 共资源是宿主工程和插件工程共用的部分,包括资源(图片、布局、样式、字符等)和代码,公共资源集成在宿主工程, 插件可以直接使用。 为了保证能正确的使用公共库里的资源,Aura通过维护公共资源的public.xml文件来保证插件工程和宿主工程使用相同的资源id,不出现资源错乱的问题。 并且插件包中只集成插件内部的资源和代码,不会集成公共库里的内容,以减小插件包的体积。

2、插件工程是独立编译的,正常apk的资源packageId是0x7f,为了保证插件内部的资源不和宿主冲突,需要修改插件的packageId,保证每个插件都分配有自己唯一的packageId,packageId范围0x21~0x7E相对比较稳妥。

3、运行期间通过反射宿主AssetManager中的addAssetPath方法,将插件的路径添加到宿主的资源路径里去,这样就实现了插件资源的加载。

IvM3UvR.jpg!web

插件管理

插件编译流程比较复杂,需要对packageId进行重排,以及 去除公共库里的资源及代码,并且由于插件是独立编译的,宿主如何正确、高效的集成插件包也是需要考虑的问题。 因此我们也开发了一套对应的管理平台和Gradle工具来简化这一流程,插件编译、版本管理、集成进 宿 以及宿主的编译都可以在管理平台里进行操作。

rQ3yauE.jpg!web

插件升级

插件可 以脱离宿主的发版限制独立发版,既可用于解决线上bug,也可以快速上线新业务。 Aura插件化框架提供了完整的插件升级服务,可以针对宿主VersionName、VersionCode、系统api版本等多个维度进行升级发布。

2UJFbum.jpg!web

Aura插件化框架的思考

  • Aura框架hook了系统的API,因此需要紧跟Android的版本节奏进行兼容, Android 9、Android 10等系统的兼容,小米、索尼等rom的兼容,因此后续如何减少私有API的调用,以及寻求更稳健的实现方式,是我们需要关注的一个点。

  • Aura插件使用我们提供的Grade工具AuraPlugin进行编译,由于Grade版本和Android Gradle Plugin的版本更新速度很快,因此AuraPlugin对各个版本的Grade进行兼容也是项繁重的工作。前面提到过,Google在2018年推出了“官方动态化组件技术” App Bundle[2],虽然在国内环境无法使用,但却和插件化技术的思路不谋而合。从下图可以看出,App Bundle会包含三种类型的APK:Base APK,Configuration APK和Dynamic feature APK。这里重点关注下Dynamic     feature APK,该APK的packageId是小于0x7f的,不同的Feature Apk的packageId也都是不同的,并且Dynamic feature模块的编译也会移除宿主app里的依赖。这和Aura插件的构建流程是类似的,因此兼容官方的Feature Apk构建也是一个重要的方向。

JZRNniu.jpg!web

s plit APKs结构[3]

总结

Aura插件化框架的目标是打造一套更加稳定高效的开发引擎,不断完善自身的能力,以满足不同的业务场景,并围绕框架打造一套开发工具和平台,从而帮助开发者能更专注与业务层代码,提升开发效率。 我们仍在努力完善中。

参考链接

[1]https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces

[2] https://developer.android.com/platform/technology/app-bundle

[3] https://developer.android.com/studio/projects/dynamic-delivery


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK