我的Android重构之旅:插件化改造及原理

点击上方“程序员大咖”,选择“置顶公众号”

关键时刻,第一时间送达!640?640?wx_fmt=gif















































































































































































































































































































    先不说楚枫的这般年纪,能够踏入元武一重说明了什么,最主要的是,楚枫在刚刚踏入核心地带时,明明只是灵武七重,而在这两个月不到的时间,连跳两重修为,又跳过一个大境界,踏入了元武一重,这般进步速度,简直堪称变态啊。


    “这楚枫不简单,原来是一位天才,若是让他继续成长下去,绝对能成为一号人物,不过可惜,他太狂妄了,竟与龚师兄定下生死约战,一年时间,他再厉害也无法战胜龚师兄。”有人认识到楚枫的潜力后,为楚枫感到惋惜。


    “哼,何须一年,此子今日就必败,巫九与龚师兄关系甚好,早就看他不顺眼了,如今他竟敢登上生死台挑战巫九,巫九岂会放过他?”但也有人认为,楚枫今日就已是在劫难逃。


    “何人挑战老子?”就在这时,又是一声爆喝响起,而后一道身影自人群之中掠出,最后稳稳的落在了比斗台上。


    这位身材瘦弱,身高平平,长得那叫一个猥琐,金钩鼻子蛤蟆眼,嘴巴一张牙带色儿,说话臭气能传三十米,他若是当面对谁哈口气,都能让那人跪在地上狂呕不止。


    不过别看这位长得不咋地,他在核心地带可是鼎鼎有名,剑道盟创建者,青龙榜第九名,正是巫九是也。


    “你就是巫九?”楚枫眼前一亮,第一次发现,世间还有长得如此奇葩的人。


    巫九鼻孔一张,大嘴一咧,拍着那干瘪的肚子,得意洋洋的道:“老子就是巫九,你挑战老子?”


    “不是挑战你,是要宰了你。”楚枫冷声笑道。


    “好,老子满足你这个心愿,长老,拿张生死状来,老子今日在这里了解了这小子。”巫九扯开嗓子,对着下方吼了一声。


    如果他对内门长老这么说话,也就算了,但是敢这么跟核心长老说话的,他可真是算作胆肥的,就连许多核心弟子,都是倒吸了一口凉气,心想这楚枫够狂,想不到这巫九更狂。


    不过最让人无言的就是,巫九话音落下不久,真有一位核心长老自人群走出,缓缓得来到了比斗台上,左手端着笔墨,右手拿着生死状,来到了巫九的身前。


    “我去,这巫九什么身份,竟能这般使唤核心长老?”有人吃惊不已,那长老修为不低,乃是元武七重,比巫九还要高两个层次,但却这般听巫九的话,着实让人吃惊不已。


    “这你就不知道了吧,巫九在前些时日,拜了钟离长老为师尊,已正式得到钟离长老的亲传。”有人解释道。


    “钟离长老?可是那位性情古怪的钟离一护?”


    “没错,就是他。”


    “天哪,巫九竟然拜入了他的门下?”


    人们再次大吃一惊,那钟离一护在青龙宗可是赫赫有名,若要是论其个人实力,在青龙宗内绝对能够排入前三,连护宗六老单打独斗都不会是他的对手。


    只不过那钟离一护,如同诸葛青云一样,也是一位客卿长老,所以在青龙宗内只是挂个头衔,什么事都不管,更别说传授宗内弟子技艺了,如今巫九竟然能拜入他老人家门下,着实让人羡慕不已。


    “恩怨生死台,的确可以决斗生死,但必须要有所恩怨,你们两个人,可有恩怨?”那位长老开口询问道。































































































作者:杀鱼能手小耗子
链接:https://www.jianshu.com/p/c6f2a516b182


随着项目的不断成长,即便项目采用了 MVP 或是 MVVM 这类优秀的架构,也很难跟得上迭代的脚步,当 APP 端功能越来越庞大、繁琐,人员不断加入后,牵一发而动全局的事情时常发生,后续人员如同如履薄冰似的维护项目,为此我们必须考虑团队壮大后的开发模式,提前对业务进行隔离,同时总结出插件化开发的流程,完善 Android 端基础框架。

本文是“我的Android重构之旅”的第三篇,也是让我最为头疼的一篇,在本文中,我将会和大家聊一聊“插件化”的概念,以及我们在“插件化”框架上的选择与碰到的一些问题。

640?wx_fmt=jpeg

鲁迅如是说道

Plug-in Hello World

插件化是指将 APK 分为宿主和插件的部分,在 APP 运行时,我们可以动态的载入或者替换插件部分。
宿主: 就是当前运行的APP。
插件: 相对于插件化技术来说,就是要加载运行的apk类文件。

插件化分为俩种形态,一种插件与宿主 APP 无交互例如微信与微信小程序,一种插件与宿主极度耦合例如滴滴出行,滴滴出行将用户信息作为独立的模块,需要与其他模块进行数据的交互,由于使用场景不一致,本文只针对插件与宿主有频繁数据交互的情况。

在我们开发的过程中,往往会碰到多人协作进行模块化的开发,我们期望能够独立运行自己的模块而又不受其他人模块的影响,还有一个更为常见的需求,我们在快速的产品迭代过程中,我们往往希望能无缝衔接新的功能至用户手机上,过于频繁的产品迭代或过长的开发周期,这会使得我们在与竟品竞争时失去先机。

640?wx_fmt=png

Git 提交记录

上图是一款人脸识别产品的迭代记录,由于上线的各个城市都有细微的逻辑差别,导致每次核心业务出现 BUG 同事要一个个 Push 至各各版本,然后通知各个城市的推广商下载,这时候我就在想,能不能把我们的应用做成插件的形式动态下发呢,这样就避免了每次都需要的版本升级,在某次 Push 版本的深夜,我决定不能这样下去了,我一定要用上插件化。

插件化框架的选择

下图是主流的插件化、组件化框架

特性DynamicLoadApkDynamicAPKSmallDroidPluginVirtualAPK
支持四大组件只支持Activity只支持Activity只支持Activity全支持全支持
组件无需在宿主manifest中预注册×
插件可以依赖宿主×
支持PendingIntent×××
Android特性支持大部分大部分大部分几乎全部几乎全部
兼容性适配一般一般中等
插件构建部署aaptGradle插件Gradle插件

最终反复推敲决定使用滴滴出行的 VirtualAPK 作为我们的插件化框架,它有以下几个优点:

  • 可与宿主工程通信

  • 兼容性强

  • 使用简单

  • 编译插件方便

  • 经过大规模使用

如果你要加载一个插件,并且这个插件无需和宿主有任何耦合,也无需和宿主进行通信,并且你也不想对这个插件重新打包,那么推荐选择DroidPlugin。

640?wx_fmt=png

Android 插件化技术的典型应用

插件化原理

VirtualAPK 对插件没有额外的约束,原生的apk即可作为插件。插件工程编译生成 Apk 后,即可通过宿主 App 加载,每个插件apk被加载后,都会在宿主中创建一个单独的 LoadedPlugin 对象。如下图所示,通过这些 LoadedPlugin 对象,VirtualAPK 就可以管理插件并赋予插件新的意义,使其可以像手机中安装过的 App 一样运行。

我们在引入一款框架的时候往往不能只单纯的了解如何使用,应去深入的了解它是如何工作的,特别是插件化这种热门的技术,十分感谢开源项目给了我们一把探寻 Android 世界的金钥匙,下面将和大家简易的分析下 VirtualAPK 的原理。

640?wx_fmt=png

VirtualAPK 的工作过程

四大组件对于安卓人员都是再熟悉不过了,我们都清楚四大组建都是需要在 AndroidManifest 中注册的,而对于 VirtualAPK 来说是不可能预先知晓名字,提前注册在宿主 Apk 中的,所以现在基本都采用 hack 方案解决,VirtualAPK 大致方案如下:

  • Activity:在宿主 Apk 中提前占坑,然后通过 Hook Activity 的启动过程,“欺上瞒下”启动插件 Apk 中的 Activity,因为 Activity 存在不同的 LaunchMode 以及一些特殊的熟悉,所以需要多个占坑的“李鬼” Activity。

  • Service:通过代理 Service 的方式去分发;主进程和其他进程,VirtualAPK 使用了两个代理Service。

  • BroadcastReceiver:静态转动态。

  • ContentProvider:通过一个代理Provider进行分发。

在本文,我们主要分析 Activity 的占坑过程,如果需要更深入的了解 VirtualAPK 请点我

Activity 流程

我们如果要启用 VirtualAPK 的话,需要先调用pluginManager.loadPlugin(apk),进行加载插件,然后我们继续向下调用

640?wx_fmt=png

我们可以发现插件 Activity 的解析是交由LoadedPlugin.create 去完成的,完成之后保存至 mPlugins 这个 Map 当中方便下次调用与解绑插件,我们继续往下探索

640?wx_fmt=png

LoadedPlugin 中将我们插件中的资源合并进了宿主 App 中,至此插件 App 的加载过程就已经完成了,这里大家肯定会有疑惑,该Activity必然没有在Manifest中注册,这么启动不会报错吗?

这就要涉及到 Activity 的启动流程了,我们在startActivity之后系统最终会调用 Instrumentation 的 execStartActivity 方法,然后再通过 ActivityManagerProxy 与 AMS 进行交互。

Activity 是否注册在 Manifest 的校验是由 AMS 进行的,所以我们在于 AMS 交互前,提前将 ActivityManagerProxy 提交给 AMS 的 ComponentName替换为我们占坑的名字即可。
通常我们可以选择 Hook Instrumentation 或者 Hook ActivityManagerProxy 都可以达到目标,VirtualAPK 选择了 Hook Instrumentation 。

640?wx_fmt=png

上面我们已经成功的 Hook 了 Instrumentation ,接下来就是需要我们的李鬼上场了

640?wx_fmt=png

我们来看一看 markIntentIfNeeded(intent); 到底做了什么

640?wx_fmt=png

可以看到上面将我们原本的信息保存至 Intent 中,然后调用了 getStubActivity(targetClassName, launchMode, themeObj); 进行了替换

640?wx_fmt=png

640?wx_fmt=png

StubActivityInfo 根据同的 launchMode 启动相应的“李鬼” Activity 至此,我们已经成功的 欺骗了 AMS ,启动了我们占坑的 Activity 但是只成功了一半,为什么这么说呢?因为欺骗过了 AMS,AMS 执行完成后,最终要启动的并非是占坑的 Activity ,所以我们还要能正确的启动目标Activity。

我们在 Hook Instrumentation 的同时一并 Hook 了 handleLaunchActivity,所以我们之间到 Instrumentation 的 newActivity 方法查看启动 Activity 的流程。

640?wx_fmt=png

好了,到此Activity就可以正常启动了。

小结

VritualApk 整理思路很清晰,在这里我们只介绍了 Activity 的启动方式,感兴趣的同学可以去网上了解下其余三大组建的代理方式。不论如何如果想使用插件化框架,一定要了解其中的实现原理,文档上描述的并不是所有的细节,很多一些属性什么的,以及由于其实现的方式造成一些特性的不支持。

引入插件化之痛

由于项目的宿主与插件需要进行较为紧密的交互,在插件化的同时需要对项目进行模块化,但是模块化并不能一蹴而就,在模块化的过程中经常出现,牵一发而动全身的问题,在经历过无数个通宵的夜晚后,我总结出了模块化的几项准则。

640?wx_fmt=jpeg

插件化的使用

VirtualAPK 本身的使用并不困难,困难的是需要逐步整理项目的模块,在这期间问题百出,因为自身没有相关经验在网上看了很多关于模块化的文章,最终我找到有赞模块化的文章,对他们总结出来的经验深刻认同。

在项目模块化时应该遵循以下几个准则

  • 确定业务逻辑边界

  • 模块的更改上保持克制

  • 公共资源及时抽取

确定业务逻辑边界

在模块化之前,我们先要详细的分析业务逻辑,App 作为业务链的末端,由于角色所限,开发人员对业务的理解比后端要浅,所谓欲速则不达,重构不能急,理清楚业务逻辑之后再动手。

640?wx_fmt=jpeg

项目改造前结构

在模块化进行时,我们需要将业务模块进行隔离,业务模块之间不能互相依赖能存在数据传输,只能单向依赖宿主项目,为了达到这个效果 我们需要借用市面上的路由方案 ARouter ,由于篇幅原因,我在这里不做过多介绍,感兴趣的同学可以自行搜索。

640?wx_fmt=png

项目改造前结构

项目改造后宿主只留下最简单的公共基础逻辑,其他部分都由插件的形式装载,这样使得我们在版本更新的过程中自由度很高,从项目结构上我们看起来很像所有插件都依赖了宿主 App 的代码,但实际上在打包的过程中 VirtualAPK 会帮助我们剔除重复资源

640?wx_fmt=png

打包完成的插件

模块的更改上保持克制

在模块化进行时,不要过分的追求完美的目标,简单粗暴一点,后续再逐渐改善,很多业务逻辑经常会和其他业务逻辑产生牵连,它们俩会处于一个相对暧昧的关系,这种时候我们不要去强行的分割它们的业务边界,过分的分割往往会因为编码人员对于模块的不清晰导致项目改造的全盘崩溃。

公共资源及时抽取


VirtualAPK 会帮助我们剔除重复资源,对于一些暧昧不清的资源我们可以索性将它放入宿主项目中,如果将过多的资源存于插件项目中,这样会导致我们的插件失去应有的灵活性和资源的复用性。

总结


最初在公司内部推广插件化的时候,同事们哗然一片大多数都是对插件化的质疑,在这里我要感谢我原来的领导,在关键时刻给我的支持帮我顶住了大家质疑的声音,在十多个日日夜夜的修改重构后,插件化后的第一个上线的版本,插件化灵活的优势体现的淋漓尽致,每个插件只有60 KB 的大小,对服务端的带宽几乎没有丝毫的压力,帮助我们快速的进行了产品的迭代  、Bug的修复。
本文中,只是我自己在项目插件化的一些经验与想法,并没有深入的介绍如何使用 VirtualAPK 感兴趣的同学可以读一下 VirtualAPK 的 WiKi ,希望本文的设计思路能带给你一些帮助。

640.jpeg

  • 来源:程序员头条

  • 程序员大咖整理发布,转载请联系作者获得授权

640?wx_fmt=gif640?【点击成为源码大神】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值