Android Studio Project Marble: Apply Changes

深入了解 Android Studio 的工作团队是如何构建 Instant Run 的继任者 Apply Changes。 

这是由 Android Studio 团队发布的一系列深入了解 Project Marble 一些细节和背后原理文章的第一篇。从 Android Studio 3.3版本开始,Project Marble 是一个多发行版, 专注于使得IDE的基本功能更加可靠和完善。以下文章内容是由 Apply Changes 团队的 Jon Tsao (product manager), Esteban de la Canal (tech lead), Fabien Sanglard (engineer), and Alan Leung (engineer) 编写。

Android Studio 的主要目标是提供一个允许快速编辑和检验app代码变化的工具。当我们创建Instant Run的时候,我们希望加快你们的开发流程,但是我们知道这个功能并没有达到预期的效果。作为 Project Marble 的一部分,我们重新思考过Instant Run,并在Android Studio 中将它替换成一个更实用的名为 Apply Changes 的方案。最初在Android Studio 3.5的canary渠道中预览, Apply Changes 是可以预见能够加速开发流程的新方式。在这篇文章中,我们将进一步介绍这个功能,它是怎样工作的,以及目前为止我们的计划。

Instant Run

对于 Instant Run,我们想要解决两个问题:

  1. 较少构建和部署到设备上的时间
  2. 能够在不丢失状态的情况下部署应用功能

为了实现这个目标,我们依赖于在构建阶段修改APK注入钩子回调,允许类的即时替换。更多关于 Instant Run 背后的技术架构,可见几年前的文章

对于简单的应用这个方案通常是很好的,但是相对复杂的应用,这将会导致更长的构建时间 或 因应用和Instant Run构建流程上冲突导致的错误。由于这些问题的产生,我们在随后的版本持续投入改善Instant Run,然而我们一直无法完全解决问题并使功能达我们的期望。

我们退一步并决定从头开始构建一个新的架构,即 Apply Changes。与 Instant Run 不同,Apply Changes 不在构建阶段修改APK。我们依赖于Android 8.0 (Oreo)或者更高版本的设备和模拟器支持的runtime instrumentation来实现动态重新定义类。

Apply Changes

对于运行着Android 8.0 或更高版本的设备和模拟器,Android Studio 现在由3个按钮组成来控制应用重启:

  • Run 将部署所有的变化并重启应用 。
  • Apply Changes 将尝试应用变化的资源和代码, 并仅重启Activity而不重启应用。
  • Apply Code Changes 将尝试在不重启操作的情况下应用变化的代码。

兼容性代码的变更通常仅限于在方法的内部。

Principles

基于从Instant Run获取的经验和反馈,我们为 Apply Changes 采取一些规则,来指导我们的架构和策略制定:

  1. 拆分构建/部署速度 和 状态丢失
    我们期望将 关于降低构建和部署速度的问题 和 能够在不丢失状态的情况下看到您的修改 分开。不管是一个常规的 run/debug 或者是代码热替换,快速的构建和部署是所有类型部署的目标。作为 Apply Changes 构建的一部分,我们发现了一些关于优化构建和部署速度的领域,我们将会在以后的文章中详细介绍。

  2. 新特性的稳定性是至关重要的
    即使新特性在100次中有99次都是极快的构建速度,如果应用因为新特性导致闪退一次并且您需要花费半个小时的时间来找出原因,那么您已经失去了其他99次获得的效率。我们坚持这一原则,不像 Instant run,Apply Changes 不在构建阶段修改APK。由于在初始的版本中我们致力于优化稳定性,这导致一个副作用 :Apply Changes 平均速度会比 Instant Run 稍慢,但将来我们会持续优化构建和部署的速度。

  3. 没有魔法
    我们结合了您对 Instant run 按钮的不可预测和不一致行为的反馈,将自动决定是否需要重启您的app或者Activity。我们希望在任何时刻都保持清晰透明,您对 Apply Changes的期望效果 和 不兼容修改时会发生什么事情,因此现在如果我们检测到与Apply Changes不兼容时,我们将明确的提示您。

Architecture

让我们深入了解 Apply Changes 是如何工作的。Apply Changes 需要清楚如何应用 “安装或者运行在设备上的app” 和 “Android Studio刚刚编译出来的APK” 之间的不同。这个过程可以分成两个不同的步骤:
1) 找出两者之间的不同
2) 发送不同的部分到设备并应用

为了快速的确定差异部分, Apply Changes 避免从设备中获取完整的APK文件。相反,它向设备执行一个快速请求拉取安装APK的 table of contentssignature。通过这两部分信息与新构建的APK进行对比,Apply Changes 可以高效生成自从上一次部署以后变化的文件列表,而不需要检查全部的内容。值得注意的是这个算法并不依赖于构建系统,这是因为差异算法并没有和上一次的构建内容做比较,而是与安装在设备上的APK比较。由于Apply Changes 仅操作APK之间不同的部分,它不需要Gradle Plugin的版本与Gradle的版本同步。实际上,Apply Changes将能够在所有的构建系统上工作。

Resource/asset files have changed.
这种情况下应用会被重装,但应用仅重启Activity和收集那些被修改的资源,仅将发生变化的资源发送到设备上。

.dex fils have changed.
Android 8.0以后的运行环境提供了替换已加载类字节码的能力,只要新的字节码没有修改内存中现有的对象布局。这意味着代码修改与Apply Change的兼容限制:即方法、类名称和签名不能改变,字段也有同样的限制。

这个机制(替换字节码)并不是作用于.dex的级别而是类级别。否则,如果一个.dex文件包含成百上千类,仅一个类发生了变化时,它要替换所有的类,这将会是很低效的。相反的,我们比较.dex文件的内容并计算那些确切改变的类,尝试仅替换这些类。如果替换成功了(即 类布局结构没有变化),接着app会在后台安装以避免正在运行的版本与已安装版本的不一致。

.dex files and resources files have change.
这种情况包含了上面提到的两种情况。 首先代码变更的步骤会执行,如果成功安装进程才会处理新的资源。main Activity将需要重启以重新加载新的资源。这是一个全无或者全有的操作,即如果无法应用代码的修改,那么运行的应用将不会有修改。

Anything else has changed.
最糟糕的情况,Androidmanifest.xml或.so文件的改变。在这种情况下,我不可能在不重启应用的情况下应用变更。“Apply Changes” 和 “Apply Code Changes” 操作将不会尝试进行部署,并会通知用户应用需要重启。
在这里插入图片描述
更多关于架构的详细信息

Comparing .dex files

在上一节中解释了, Apply Changes 需要比较和提取个别变更(修改/增加/删除)的类。为了避免从设备上获取大内容块的开销,它利用D8的DEX文件分析能力,在后台进程中计算每一个Android Studio部署到设备上的.dex文件。对.dex文件内的每一个类的计算指纹信息并将结果临时保存在工作主机的缓存数据库中。通过对比新编译的指纹信息和上一次编译指纹信息,Apply Changes 能够在短时间内高效的提取变化的类。

Delta push

如上面提到的,仅发生变化的文件会被发送到设备上。我们把它叫做"delta push"。类似于上面提到的DEX文件比较,Apply Changes 需要计算已安装的APK和最新编译的APK的文件不同,不需要从设备上获取所有的内容。此时它仅获取zip文件的核心目录信息并保守估计APK的不同部分。通过仅传输变化的部分,Android Studio传输的数据将会比传输整个APK少很多。大多数情况下,总发送负载从几M减少到几KB。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值