【Gradle-16】直接Run和使用命令行编译有什么区别

4,329 阅读5分钟

本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!

1、前言

如题,这俩操作呢,都是编译,但是在日常开发中可能很多人都没注意到这俩的区别是什么,比如谁编译更快?

不过我们可以根据黄金三点论来分析,即开始、过程、结果三个方面来看。

Gradle的生命周期正好也是三个阶段:

Gradle分三个阶段评估和运行构建,分别是 Initialization (初始化)、Configuration (配置) 和 Execution (执行),且任何的构建任务都会执行这个三个阶段。

  • 在 Initialization (初始化) 阶段,Gradle会决定构建中包含哪些项目,并会为每个项目创建Project实例。为了决定构建中会包含哪些项目,Gradle首先会寻找settings.gradle来决定此次为单项目构建还是多项目构建,单项目就是module,多项目即project+app+module(1+n)。
  • 在 Configuration (配置) 阶段,Gradle会评估构建项目中包含的所有构建脚本,随后应用插件、使用DSL配置构建,并在最后注册Task,同时惰性注册它们的输入,因为并不一定会执行。
  • 最后,在 Execution (执行) 阶段,Gradle会执行构建所需的Task集合。

今天我就根据自己的经验,给大家介绍下直接Run和使用命令行编译这两者的区别是什么。

2、开始

2.1、交互

先看两者执行的命令

Run:

命令行:

Command-Line Interface,简称CLI

./gradlew assembleDebug

assembleDebug只是打包,并不会安装,也不会打开app。

安装是:

./gradlew installDebug
// or
adb install path/to/your_app.apk

打开是:

adb shell am start -n com.yechaoa.gradlex/.MainActivity

从交互上看,Run要比CLI更方便,只需要点一下就会完成编译、安装和启动应用的过程,CLI还需要输入多个命令才行。

2.2、控制

从控制上看,CLI要更灵活一些,可以有动态参数、性能报告、跳过某个Task等。

动态参数

 ./gradlew assembleDebug -PisTest=true 

性能报告

./gradlew assembleDebug --scan

跳过Task

gradle build -x testTask

以上只是部分命令行的控制指令,在前面第5章【Gradle-5】Gradle常用命令与参数有更多的介绍。

3、过程

3.1、编译日志

Run的过程中,会把每一步执行的日志打在build控制台,命令行默认是没有的。

但是有时候遇到编译异常,编译日志里会提示你:

* Try:
> Run gradle tasks to get a list of available tasks.
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

这时候就会用到stacktrace来看详细日志:

./gradlew assembleDebug --stacktrace
// or
./gradlew assembleDebug -s

命令行查看日志要比Run的更加详细一些,对于排查问题更有帮助。

3.2、执行过程

一般来说执行过程是区别不大的,Run和CLI都可以使用缓存,但是也要看项目和诉求。

比如命令行里面加跳过某个Task的命令,亦或者是有动态参数之类的可以影响到执行过程的,这个就得具体看了。

4、结果

只要Variant是一致的,编译产物(apk)就是一样的。

所以就来到大家最关心的环节,编译耗时。

4.1、编译耗时

抛开硬件性能和项目大小等因素,以我这个项目github.com/yechaoa/Gra…为例。

Run首次编译:

BUILD SUCCESSFUL in 2s

Run二次编译:

BUILD SUCCESSFUL in 134ms

CLI首次编译:

BUILD SUCCESSFUL in 7s

CLI二次编译:

BUILD SUCCESSFUL in 387ms
Type首次(无缓存)二次(有缓存)
Run2s134ms
CLI7s387ms

结论

默认情况下,Run要比CLI编译速度更快

主要因素有一下几个:

  1. AS的Apply Changes只有改动的代码或资源参与编译,在Gradle增量编译的基础之上又进一步;
  2. AS不断的迭代,不断的优化构建性能,比如任务调度、内存等;

还有一个可能大家不知道,就是Android Studio对Dex的预处理,官方文档是这么说的:

To mitigate longer incremental build times, use pre-dexing to reuse multidex output between builds. Pre-dexing relies on an ART format available only on Android 5.0 (API level 21) and higher. If you're using Android Studio, the IDE automatically uses pre-dexing when deploying your app to a device running Android 5.0 (API level 21) or higher. However, if you're running Gradle builds from the command line, you need to set the minSdkVersion to 21 or higher to enable pre-dexing.

直接Run的时候,在AS 2.3及更高版本中,识别到设备是Android 5.0及以上的话,会自动启用Dex预处理,这会缩短编译耗时,因为dex的过程就是把类分到不同的dex文件中,这是复杂且耗时的。

5、总结

5.1、Run

  • 简单快捷:可视化操作只需一点,就会自动完成编译、安装和启动app;
  • 编译日志:编译时,控制台会输出编译过程的日志,方便实时查看;
  • 编译耗时:IDE自带的优化让其在编译速度上更有优势;

5.2、CLI

  • 灵活控制:通过命令行,可以精确控制构建过程,比如制定动态参数、跳过自定义Task执行等;
  • CICD自动化:命令行编译比较适合CICD持续集成以及自动化的场景;

总而言之,直接Run简单方便,对项目编译没有特殊处理和不熟悉命令行的同学来说比较友好,也是日常开发中使用频次比较多的一种编译方式;CLI有很强的定制化,比较灵活,但编译耗时相对慢一些,适用于CICD持续集成以及自动化的场景,同时需要对命令行指令有一定的了解。

6、打包脚本示例

一个简单的打包脚本示例,新建一个buildDebug.sh的shell脚本文件。

命令如下:

#!/bin/bash
./gradlew clean
./gradlew assembleDebug --stacktrace -PisDebug=true
adb install -r  build/outputs/apk/debug/app-debug.apk
adb shell am start -n com.yechaoa.gradlex/.MainActivity
echo "install and start app"

想要加什么控制命令,就在assembleDebug后面补就可以了。远端打包的话,去掉安装和打开就可以了。

本地使用的话直接在Terminal里输入:

./buildDebug.sh

7、GitHub

github.com/yechaoa/Gra…

8、相关文档