速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

滴滴插件化项目 VirtualAPK 开源

  • 2017-06-29
  • 本文字数:3244 字

    阅读完需:约 11 分钟

在 Android 插件化技术日新月异的今天,开发并落地一款插件化框架到底是简单还是困难,这个问题不同人会有不同的答案。但是我相信,完成一个插件化框架的 demo 并不是多难的事,但是要开发一款完善的插件化框架却不是一件容易的事,尤其在国内,各大 Rom 厂商都对 Android 系统做了一定程度的定制,这进一步加剧了 Android 本身的碎片化问题。

我们在 2016 年开始研究这方面的技术,经过半年的开发、测试、适配和线上验证,目前推出了一款比较完善的插件化框架:VirtualAPK。

之所以现在推出来,是因为 VirtualAPK 在我们内部已经得到了很好的验证,我们在迭代过程中不断地做机型适配和细节特性的支持,目前已经达到一个非常稳定的状况,足以支撑滴滴部分乃至全部业务的动态发版需求。目前 VirtualAPK 应用于滴滴乘客端和优步中国 APP 中,大家可以去体验。

为了更好地体现出 VirtualAPK 的价值,我们决定将其开源,请猛击 https://github.com/didi/VirtualAPK

VirtualAPK 也是滴滴公司的首个对外开源项目,欢迎大家 star、发送 pull request,也欢迎大家来使用 VirtualAPK,我们会给予一定的技术支持。

VirtualAPK 能为我们带来什么?

在传统的 APP 发布过程中,总是存在着固定的发版节奏,比如两周或者一个月更新一次,这固然没有问题。但考虑一种情况,如果一个版本刚发布出去,却发现存在大量 crash,这个时候我们会怎么办?大多数公司都会选择立刻发一个紧急版本,然后一批人需要手忙脚乱甚至加班来准备这个版本,所以紧急版本还是越少越好。

其实不仅仅是因为致命 crash 而紧急发版,比如一个早期创业公司,需要通过迅速的“试错”来尝试找准市场的方向,这个时候就需要更加紧凑的发版方式,有些时候甚至想一天发一次版。在正常的发版流程中,这显然是不现实的。但是如果这家创业公司必须要随时可以发版,否则就可能被竞争对手抢占先机,这个时候该怎么办呢?

上述的这两个问题,通过 VirtualAPK,将不再是问题。通过 VirtualAPK 将业务模块插件化,然后就可以随时通过更新插件的方式来发布新功能,不管是修复致命 crash 还是进行业务“试错”,都是一种很爽快的体验。

VirtualAPK 的特性

VirtualAPK 是滴滴出行自研的一款优秀的插件化框架,主要有如下几个特性。

功能完备

  • 支持几乎所有的 Android 特性;
  • 四大组件方面

四大组件均不需要在宿主manifest中预注册,每个组件都有完整的生命周期。

  1. Activity:支持显示和隐式调用,支持 Activity 的 theme 和 LaunchMode,支持透明主题;
  2. Service:支持显示和隐式调用,支持 Service 的 start、stop、bind 和 unbind,并支持跨进程 bind 插件中的 Service;
  3. Receiver:支持静态注册和动态注册的 Receiver;
  4. ContentProvider:支持 provider 的所有操作,包括 CRUD 和 call 方法等,支持跨进程访问插件中的 Provider。
  5. 自定义 View:支持自定义 View,支持自定义属性和 style,支持动画;
  6. PendingIntent:支持 PendingIntent 以及和其相关的 Alarm、Notification 和 AppWidget;
  7. 支持插件 Application 以及插件 manifest 中的 meta-data;
  8. 支持插件中的 so。

优秀的兼容性

  • 兼容市面上几乎所有的 Android 手机,这一点已经在滴滴出行客户端中得到验证;
  • 资源方面适配小米、Vivo、Nubia 等,对未知机型采用自适应适配方案;
  • 极少的 Binder Hook,目前仅仅 hook 了两个 Binder:AMS 和 IContentProvider,hook 过程做了充分的兼容性适配;
  • 插件运行逻辑和宿主隔离,确保框架的任何问题都不会影响宿主的正常运行。

入侵性极低

  • 插件开发等同于原生开发,四大组件无需继承特定的基类;
  • 精简的插件包,插件可以依赖宿主中的代码和资源,也可以不依赖;
  • 插件的构建过程简单,通过 Gradle 插件来完成插件的构建,整个过程对开发者透明。

VirtualAPK 和主流开源框架的对比

如下是 VirtualAPK 和主流的插件化框架之间的对比。

为什么选择VirtualAPK

已经有那么多优秀的开源的插件化框架,滴滴为什么要重新造一个轮子呢?

1. 大部分开源框架所支持的功能还不够全面 除了 DroidPlugin,大部分都只支持 Activity。

2. 兼容性问题严重,大部分开源方案不够健壮 由于国内 Rom 尝试深度定制 Android 系统,这导致插件框架的兼容性问题特别多,而目前已有的开源方案中,除了 DroidPlugin,其他方案对兼容性问题的适配程度是不足的。

3. 已有的开源方案不适合滴滴的业务场景 虽然说 DroidPlugin 从功能的完整性和兼容性上来看,是一款非常完善的插件框架,然而它的使用场景和滴滴的业务不符。

DroidPlugin 侧重于加载第三方独立插件,比如微信,并且插件不能访问宿主的代码和资源。而在滴滴打车中,其他业务模块均需要宿主提供的订单、定位、账号等数据,因此插件不可能和宿主没有交互。

其实在大部分产品中,一个业务模块实际上并不能轻而易举地独立出来,它们往往都会和宿主有交互,在这种情况下,DroidPlugin 就有点力不从心了。

基于上述几点,我们只能重新造一个轮子,它不但功能全面、兼容性好,还必须能够适用于有耦合的业务插件,这就是 VirtualAPK 存在的意义。

在加载耦合插件方面,VirtualAPK是开源方案的首选,推荐大家使用

通俗易懂地说

  1. 如果你是要加载微信、支付宝等第三方 APP,那么推荐选择 DroidPlugin;
  2. 如果你是要加载一个内部业务模块,并且这个业务模块很难从主工程中解耦,那么 VirtualAPK 是最好的选择。

抽象地说

  1. 如果你要加载一个插件,并且这个插件无需和宿主有任何耦合,也无需和宿主进行通信,并且你也不想对这个插件重新打包,那么推荐选择 DroidPlugin;
  2. 除此之外,在同类的开源中,推荐大家选择 VirtualAPK。

VirtualAPK 的工作过程

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

如何使用

第一步: 初始化插件引擎

复制代码
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
PluginManager.getInstance(base).init();
}

第二步:加载插件

复制代码
public class PluginManager {
public void loadPlugin(File apk);
}

当插件入口被调用后,插件的后续逻辑均不需要宿主干预,均走原生的Android流程。 比如,在插件内部,如下代码将正确执行:

复制代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_book_manager);
LinearLayout holder = (LinearLayout)findViewById(R.id.holder);
TextView imei = (TextView)findViewById(R.id.imei);
imei.setText(IDUtil.getUUID(this));
// bind service in plugin
Intent service = new Intent(this, BookManagerService.class);
bindService(service, mConnection, Context.BIND_AUTO_CREATE);
// start activity in plugin
Intent intent = new Intent(this, TCPClientActivity.class);
startActivity(intent);
}

探究原理

基本原理

  • 合并宿主和插件的 ****ClassLoader 需要注意的是,插件中的类不可以和宿主重复
  • 合并插件和宿主的资源 重设插件资源的 packageId,将插件资源和宿主资源合并
  • 去除插件包对宿主的引用 构建时通过 Gradle 插件去除插件对宿主的代码以及资源的引用

四大组件的实现原理

  • Activity 采用宿主 manifest 中占坑的方式来绕过系统校验,然后再加载真正的 activity;
  • Service 动态代理 AMS,拦截 service 相关的请求,将其中转给 Service Runtime 去处理,Service Runtime 会接管系统的所有操作;
  • Receiver 将插件中静态注册的 receiver 重新注册一遍;
  • ContentProvider 动态代理 IContentProvider,拦截 provider 相关的请求,将其中转给 Provider Runtime 去处理,Provider Runtime 会接管系统的所有操作。

如下是 VirtualAPK 的整体架构图,更详细的内容请大家阅读源码和 wiki。

2017-06-29 22:496037

评论

发布
暂无评论
发现更多内容

webstorm2024激活码永久版 webstorm2024下载安装 Mac/win

Rose

autodesk maya 2025.1破解版(玛雅2025中文版) 下载

Rose

敏捷开发最佳实践:需求管理实践案例之业务驱动开发

爱吃小舅的鱼

需求管理 敏捷实践

LeetCode题解:9. 回文数,翻转一半数字,JavaScript,详细注释

Lee Chen

什么是生产报工系统、有哪些优势

万界星空科技

制造业 mes 万界星空科技 生产管理 生产报工

新鲜干货|「隐语城市行·成都站 x 蓉数大讲堂」硬核技术分享、多元场景实践、未来趋势洞察及前沿学术探秘

隐语SecretFlow

ChatGPT怎么注册使用?新手如何从入门到精通玩转ChatGPT?

蓉蓉

openai GPT-4 ChatGPT4

蓝易云 - 关于openfeign的http和rpc

百度搜索:蓝易云

Linux 运维 Web 云服务器 openfeign

DeepRec Extension 打造稳定高效的分布式训练

阿里云大数据AI技术

人工智能 阿里云 分布式

Qualcomm IPQ9554 vs. IPQ8074: A new comparison of leading technologies

wifi6-yiyi

WiFi7 ipq9554

视觉特效制作解决方案 Autodesk Flame 2025 mac系统要求

Rose

开源无代码 / 低代码平台 NocoBase 1.0.0-alpha.15: 新增插件、改进「配置操作」交互

NocoBase

GitHub 开源 低代码 无代码开发 开源开发工具

厦门大学站回顾|大模型时代的联邦学习

隐语SecretFlow

GeminiDB PITR,让游戏回档“进退自如”!

华为云开发者联盟

数据库 华为云 华为云开发者联盟 华为云GeminiDB 企业号2024年5月PK榜

2024华为影像品牌之夜,科技赋能艺术,影像创新无界

新消费日报

Volcano社区新版本发布!7大功能全面增强队列能力与调度稳定性

华为云开发者联盟

Kubernetes 华为云 Volcano 华为云开发者联盟 企业号2024年5月PK榜

分布式任务调度内的 MySQL 分页查询优化

vivo互联网技术

ICP MySQL分页查询优化 主键分页查询执行过程

蓝易云 - CIP或者EtherNET/IP中的PATH是什么含义?

百度搜索:蓝易云

云计算 Linux 运维 云服务器 CIP

蓝易云 - Linux安全Capabilities机制

百度搜索:蓝易云

Linux 运维 服务器 云服务器 Capabilities

蓝易云 - Spring之BeanFactory

百度搜索:蓝易云

spring 服务器 高防服务器 免备案服务器

华为云受邀出席AICon2024 分享AI Agent在企业生产中的技术实践

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 AI Agent 企业号2024年5月PK榜

Tower for Mac:Git管理的终极利器!

Rose

滴滴插件化项目VirtualAPK开源_移动_滴滴App架构组_InfoQ精选文章