Android编译的知识点有哪些

发布时间:2021-12-21 10:29:57 作者:iii
来源:亿速云 阅读:144

本篇内容主要讲解“Android编译的知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android编译的知识点有哪些”吧!

Android 编译的基础知识

无论是微信的编译优化,还是 Tinker 项目,都涉及比较多的编译相关知识,因此我在 Android 编译方面研究颇多,经验也比较丰富。Android 的编译构建流程主要包括代码、资源以及 Native Library 三部分,整个流程可以参考官方文档的构建流程图。

Android编译的知识点有哪些

Gradle是 Android 官方的编译工具,它也是 GitHub 上的一个开源项目。从 Gradle 的更新日志可以看到,当前这个项目还更新得非常频繁,基本上每一两个月都会有新的版本。对于 Gradle,我感觉最痛苦的还是 Gradle Plugin 的编写,主要是因为 Gradle 在这方面没有完善的文档,因此一般都只能靠看源码或者断点调试的方法。最近我所在的公司就准备用Gradle搞一个渠道打包工具,对于项目的打包和构建过程,也是深有体会。

但是编译实在太重要了,每个公司的情况又各不相同,必须强行造一套自己的“轮子”。已经开源的项目有 Facebook 的Buck以及 Google 的Bazel。

为什么要自己“造轮子”呢?主要有下面几个原因:

Android编译的知识点有哪些

“程序员最痛恨写文档,还有别人不写文档”,所以它们的文档也是比较少的,如果想做二次定制开发会感到很痛苦。如果你想把编译工具切换到 Buck 和 Bazel,需要下很大的决心,而且还需要考虑和其他上下游项目的协作。当然即使我们不去直接使用,它们内部的优化思路也非常值得我们学习和参考。

Gradle、Buck、Bazel 都是以更快的编译速度、更强大的代码优化为目标,我们下面一起来看看它们做了哪些努力。


编译速度

回想一下我们的 Android 开发生涯,在编译这件事情上面究竟浪费了多少时间和生命。正如前面我所说,编译速度对团队效率非常重要。

关于编译速度,我们最关心的可能还是编译 Debug 包的速度,尤其是增量编译(incremental build)的速度,我们希望可以做到更加快速的调试。正如下图所示,我们每次代码验证都要经过编译和安装两个步骤。

Android编译的知识点有哪些

此处,我们从编译时间和安装时间两个纬度来看Android的编译速度。

对于增量编译,我先来讲讲 Gradle 的官方方案Instant Run。在 Android Plugin 2.3 之前,它使用的 Multidex 实现。在 Android Plugin 2.3 之后,它使用 Android 5.0 新增的 Split APK 机制。

如下图所示,资源和 Manifest 都放在 Base APK 中, 在 Base APK 中代码只有 Instant Run 框架,应用的本身的代码都在 Split APK 中。

Android编译的知识点有哪些

Instant Run 有三种模式,如果是热交换和温交换,我们都无需重新安装新的 Split APK,它们的区别在于是否重启 Activity。对于冷交换,我们需要通过adb install-multiple -r -t重新安装改变的 Split APK,应用也需要重启。

虽然无论哪一种模式,我们都不需要重新安装 Base APK。这让 Instant Run 看起来是不是很不错,但是在大型项目里面,它的性能依然非常糟糕,主要原因是:

你还可以看看这一个 Issue:“full rebuild if a class contains a constant”,假设修改的类中包含一个“public static final”的变量,那同样也不好意思,本次修改以及它依赖的模块都需要全量 javac。这是为什么呢?因为常量池是会直接把值编译到其他类中,Gradle 并不知道有哪些类可能使用了这个常量。

询问 Gradle 的工作人员,他们出给的解决方案是下面这个:

// 原来的常量定义:
public static final int MAGIC = 23
// 将常量定义替换成方法: 
public static int magic() {
 return 23;
}

对于大型项目来说,这肯定是不可行的。正如我在 Issue 中所写的一样,无论我们是不是真正改到这个常量,Gradle 都会无脑的全量 javac,这样肯定是不对的。事实上,我们可以通过比对这次代码修改,看看是否有真正改变某一个常量的值。

但是可能用过阿里的Freeline或者蘑菇街的极速编译的同学会有疑问,它们的方案为什么不会遇到 Annotation 和常量的问题?

事实上,它们的方案在大部分情况比 Instant Run 更快,那是因为牺牲了正确性。也就是说它们为了追求更快的速度,直接忽略了 Annotation 和常量改变可能带来错误的编译产物。Instant Run 作为官方方案,它优先保证的是 100% 的正确性。

当然 Google 的人也发现了 Instant Run 的种种问题,在 Android Studio 3.5 之后,对于 Android 8.0 以后的设备将会使用新的方案“Apply Changes”代替 Instant Run。目前我还没找到关于这套方案更多的资料,不过我认为应该是抛弃了 Split APK 机制。

一直以来,我心目中都有一套理想的编译方案,这套方案安装的 Base APK 依然只是一个壳 APK,真正的业务代码放到 Assets 的 ClassesN.dex 中,它的架构图如下。

Android编译的知识点有哪些

对于编译速度的优化,我还有几个建议:

相比之下,可能目前最热的 Flutter 中Hot Reload秒级编译功能会更有吸引力。

当然最近几个 Android Studio 版本,Google 也做了大量的其他优化,例如使用AAPT2替代了 AAPT 来编译 Android 资源。AAPT2 实现了资源的增量编译,它将资源的编译拆分成 Compile 和 Link 两个步骤。前者资源文件以二进制形式编译 Flat 格式,后者合并所有的文件再打包。

除了 AAPT2,Google 还引入了 d8 和 R8,下面分别是 Google 提供的一些测试数据,如下图。

Android编译的知识点有哪些

Android编译的知识点有哪些

那什么是 d8 和 R8 呢?除了编译速度的优化,它们还有哪些其他的作用?可以参考下面的介绍:Android D8 和 R8


代码优化

对于 Debug 包编译,我们更关心速度。但是对于 Release 包来说,代码的优化更加重要,因为我们会更加在意应用的性能。

下面我就分别讲讲 ProGuard、d8、R8 和 ReDex 这四种我们可能会用到的代码优化工具。

ProGuard

在微信 Release 包 12 分钟的编译过程里,单独 ProGuard 就需要花费 8 分钟。尽管 ProGuard 真的很慢,但是基本每个项目都会使用到它。加入了 ProGuard 之后,应用的构建过程流程如下:

Android编译的知识点有哪些

ProGuard 主要有混淆、裁剪、优化这三大功能,它的整个处理流程如下:

Android编译的知识点有哪些

其中优化包括内联、修饰符、合并类和方法等 30 多种,具体介绍与使用方法你可以参考官方文档。

D8

Android Studio 3.0 推出了d8,并在 3.1 正式成为默认工具。它的作用是将“.class”文件编译为 Dex 文件,取代之前的 dx 工具。

Android编译的知识点有哪些

d8 除了更快的编译速度之外,还有一个优化是减少生成的 Dex 大小。根据 Google 的测试结果,大约会有 3%~5% 的优化。

Android编译的知识点有哪些

R8

R8 在 Android Studio 3.1 中引入,它的志向更加高远,它的目标是取代 ProGuard 和 d8。我们可以直接使用 R8 把“.class”文件变成 Dex。

Android编译的知识点有哪些

同时,R8 还支持 ProGuard 中混淆、裁剪、优化这三大功能。由于目前 R8 依然处于实验阶段,网上的介绍资料并不多,你可以参考下面这些资料:

ProGuard 和 R8 对比:

ProGuard and R8: a comparison of optimizers。

Jake Wharton 大神的博客最近有很多 R8 相关的文章:https://jakewharton.com/blog/。

R8 的最终目的跟 d8 一样,一个是加快编译速度,一个是更强大的代码优化。

ReDex

如果说 R8 是未来想取代的 ProGuard 的工具,那 Facebook 的内部使用的ReDex其实已经做到了。Facebook 内部的很多项目都已经全部切换到 ReDex,不再使用 ProGuard 了。跟 ProGuard 不同的是,它直接输入的对象是 Dex,而不是“.class”文件,也就是它是直接针对最终产物的优化,所见即所得。

在前面的文章中,我已经不止一次提到 ReDex 这个项目,因为它里面的功能实在是太强大了,具体可以参考专栏前面的文章《包体积优化(上):如何减少安装包大小?》。

此外,ReDex 中例如Type Erasure和去除代码中的Aceess 方法也是非常不错的功能,它们无论对包体积还是应用的运行速度都有帮助,因此我也鼓励你去研究和实践一下它们的用法和效果。

但是 ReDex 的文档也是万年不更新的,而且里面掺杂了一些 Facebook 内部定制的逻辑,所以它用起来的确非常不方便。目前我主要还是直接研究它的源码,参考它的原理,然后再直接单独实现。

事实上,Buck 里面其实也还有很多好用的东西,但是文档里面依然什么都没有提到,所以还是需要“read the source code”。

Library Merge 和 Relinker

持续交付

Gradle、Buck、Bazel 它们代表的都是狭义上的编译,我认为广义的编译应该包括打包构建、Code Review、代码工程管理、代码扫描等流程,也就是业界最近经常提起的持续集成。

Android编译的知识点有哪些

目前最常用的持续集成工具有 Jenkins、GitLab CI、Travis CI 等,GitHub 也有提供自己的持续集成服务。每个大公司都有自己的持续集成方案,例如腾讯的 RDM、阿里的摩天轮、大众点评的MCI等。

下面我来简单讲一下我对持续集成的一些经验和看法:

持续集成涉及的流程有很多,你需要结合自己团队的现状。如果只是一味地去增加流程,有时候可能适得其反。

到此,相信大家对“Android编译的知识点有哪些”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

推荐阅读:
  1. android编译错误
  2. android编译系统之后刷img

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

android

上一篇:Web应用主动侦测工具Skipfish有什么用

下一篇:Web应用扫描测试工具Vega有什么用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》