代码改变世界

Android 编译

2019-08-13 11:30  般若Android  阅读(555)  评论(0编辑  收藏  举报

  什么是编译

  编译是将高级语言转换为机器或者虚拟机所能识别的低级语言的过程,对于android来说,这个过程就是把java转变为android虚拟机运行的Dalvik字节码的过程

编译的整个过程会涉及词法分析,语法分析、语义检查和代码优化等步骤,对于底层编译原理感兴趣的同学,可以看下编译原理三大巨著 龙书 虎书 鲸鱼书

  Android编译需要解决的问题是什么,目前又遇到哪些挑战

  1.编译的基础知识

  android的编译构建流程主要包括代码、资源以及Native Library三部分 流程图如下

 

 

 

  Gradle是Android官方的编译工具,它也是GitHub上的一个开源项目,从Gradle的更新日志可以看到,当前这个项目还更新的非常频繁,对于Gradle,最痛苦的还是Gradle Plugin的编写,主要是因为Gradle在这方面没有完善的文档

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


为什么要自己造轮子那:主要原因如下

  • 统一编译工具
  • 代码组织管理架构
  • 极致的性能追求

     

 2.编译速度

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

  编译时间:把java代码编译为.class文件,然后通过dx编译为Dex文件。对于增量编译,我们希望编译尽可能少的代码和资源,最理想的是只编译变化的部分,但是由于代码之间的依赖,大部分情况并不可行,这个时候退而求其次,希望编译更少的模块,Android Plugin3.0使用Implementation代替compile,正是为了优化依赖关系

  安装时间:我们要先经过签名校验,校验成功后会有一大堆的文件拷贝工作,例如APK文件、Library文件、Dex文件等。之后我们还需要编译Odex文件,这个过程特别是在Android5.0和6.0会非常耗时。对于增量编译,最好的优化是直接应用新的代码,无需重新安装APK

 

  对于Instant Run在android Plugin2.3之前,使用的是Multidex实现,在android Plugin2.3之后,它使用Android5.0新增的Split APK机制 如下图所示资源和Manifext都放在Base APK中,在Base APK中代码只有Instant Run框架,应用本身的代码都在Split APK中

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

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

  多进程问题:如果应用存在多进程,热交换和温交换都不能生效,因为大部分应用都会存在多进程情况

  Split APK安装问题:虽然Splite APK的安装不会生成Odex文件,但是这里依然会有签名校验和文件拷贝 这个时间在几秒到几十秒

  Javac问题:在Gradle4.6之前,如果项目中运用了Annotation Processor。本次修改以及它依赖的模块都要全量javac,而这个过程是非常慢的,可能会需要几十秒,在Gradle 4.7解决

  假设修改类中包含一个 public static final的变量,本次修改也需要全量javac,因为全量池会直接把值编译到其他类中,Gradle并不知道有哪些类可能使用了这个常量

  编译速度的优化建议

  • 更换编译机器 直接更换为Mac或其他更给力的设备作为编译机
  • Build Cache可以将大部分不常改变的项目拆离出去,并使用远端Cache模式保留编译后的缓存
  • 升级Gradle 和SDK Build Tools:我们应该及时去升级最新的编译工具链,享受Google的最新优化成果
  • 使用Buck:无论是Buck的exopachage,还是代码的增量编译,Buck都更加高效,但一个大型项目要切换到Buck,其实顾虑的还是比较多的

  3.代码优化

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

  下面分别讲讲ProGuard、d8、r8和ReDex这四种我们常会用到的代码优化工具

  ProGuard

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

  

  ProGuard主要有混淆、裁剪、优化这三大功能,整体流程如下

 

  其中优化包括内联,修饰符,合并类和方法等30分钟

  d8

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

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

  R8

  R8在Android Studio3.1中引入,它的志向更加高远,取代ProGuard和d8,我们直接使用R8把.class文件变成Dex

  同时R8还支持ProGuard中的混淆、裁剪、优化这三大功能,由于目前R8依然处于试验阶段,