【Gradle-5】Gradle常用命令與引數

語言: CN / TW / HK

本文為稀土掘金技術社群首發簽約文章,14天內禁止轉載,14天后未獲授權禁止轉載,侵權必究!

1、前言

Gradle的命令有很多,熟悉常用命令之後,在日常開發中,不僅可以提升效率,也可以輔助我們快速定位並解決編譯問題;而且某些情況下命令列(CLI)與按鈕執行的編譯結果是不一樣的,比如構建時要傳參(-P),所以就單拎出來一篇講解,希望對你有幫助~

1、Gradle命令

1.1、gradlew

Gradle執行命令列主要用到的是Gradle Wrapper,關於Gradle Wrapper的介紹,在前文(【Gradle-2】一文搞懂Gradle配置)中有介紹,這裡不再贅述。

所以我們常用的./gradlew(Mac),gradlew即Gradle Wrapper的簡寫。

Gradle Wrapper工作流:

再來看下gradlew的指令碼內容

```

!/usr/bin/env sh

Copyright 2015 the original author or authors.

Licensed under the Apache License, Version 2.0 (the "License");

you may not use this file except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an "AS IS" BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.

Gradle start up script for UN*X

Attempt to set APP_HOME

Resolve links: $0 may be a link

PRG="$0"

Need this for relative symlinks.

while [ -h "$PRG" ] ; do ls=ls -ld "$PRG" link=expr "$ls" : '.*-> (.*)$' if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=dirname "$PRG""/$link" fi done SAVED="pwd" cd "dirname "$PRG"/" >/dev/null APP_HOME="pwd -P" cd "$SAVED" >/dev/null

APP_NAME="Gradle" APP_BASE_NAME=basename "$0"

Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

Use the maximum available, or set MAX_FD != -1 to use that value.

MAX_FD="maximum"

warn () { echo "$*" }

die () { echo echo "$*" echo exit 1 }

OS specific support (must be 'true' or 'false').

cygwin=false msys=false darwin=false nonstop=false case "uname" in CYGWIN ) cygwin=true ;; Darwin ) darwin=true ;; MINGW ) msys=true ;; NONSTOP ) nonstop=true ;; esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

Determine the Java command to use to start the JVM.

if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi

Increase the maximum file descriptors if we can.

if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=ulimit -H -n if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi

For Darwin, add options to specify how the application appears in the dock

if $darwin; then GRADLE_OPTS="$GRADLE_OPTS "-Xdock:name=$APP_NAME" "-Xdock:icon=$APP_HOME/media/gradle.icns"" fi

For Cygwin or MSYS, switch paths to Windows format before running java

if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=cygpath --path --mixed "$APP_HOME" CLASSPATH=cygpath --path --mixed "$CLASSPATH"

JAVACMD=`cygpath --unix "$JAVACMD"`

# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
    ROOTDIRS="$ROOTDIRS$SEP$dir"
    SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
    OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
    CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
    CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

    if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
        eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
    else
        eval `echo args$i`=""$arg""
    fi
    i=`expr $i + 1`
done
case $i in
    0) set -- ;;
    1) set -- "$args0" ;;
    2) set -- "$args0" "$args1" ;;
    3) set -- "$args0" "$args1" "$args2" ;;
    4) set -- "$args0" "$args1" "$args2" "$args3" ;;
    5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
    6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
    7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
    8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
    9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac

fi

Escape application args

save () { for i do printf %s\n "$i" | sed "s/'/'\''/g;1s/^/'/;$s/$/' \/" ; done echo " " } APP_ARGS=save "$@"

Collect all arguments for the java command, following the shell quoting and substitution rules

eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS ""-Dorg.gradle.appname=$APP_BASE_NAME"" -classpath ""$CLASSPATH"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

exec "$JAVACMD" "$@" ```

程式碼量不多,gradlew主要乾了幾件事:

  1. 獲取電腦系統核心的資訊,JRE環境資訊等;
  2. 設定classpath路徑;
  3. 執行java命令工具,呼叫gradle jar包的class檔案;

1.2、命令大全

當我們想知道一個工具有哪些命令的時候,最簡單直接的方式就是使用help命令檢視支援哪些,然後從中找到我們想要的。

執行:

./gradlew --help

輸出:

``` USAGE: gradlew [option...] [task...]

-?, -h, --help Shows this help message. -a, --no-rebuild Do not rebuild project dependencies. -b, --build-file Specify the build file. [deprecated] --build-cache Enables the Gradle build cache. Gradle will try to reuse outputs from previous builds. -c, --settings-file Specify the settings file. [deprecated] --configuration-cache Enables the configuration cache. Gradle will try to reuse the build configuration from previous builds. [incubating] --configuration-cache-problems Configures how the configuration cache handles problems (fail or warn). Defaults to fail. [incubating] --configure-on-demand Configure necessary projects only. Gradle will attempt to reduce configuration time for large multi-project builds. [incubating] --console Specifies which type of console output to generate. Values are 'plain', 'auto' (default), 'rich' or 'verbose'. --continue Continue task execution after a task failure. -D, --system-prop Set system property of the JVM (e.g. -Dmyprop=myvalue). -d, --debug Log in debug mode (includes normal stacktrace). --daemon Uses the Gradle daemon to run the build. Starts the daemon if not running. --export-keys Exports the public keys used for dependency verification. -F, --dependency-verification Configures the dependency verification mode. Values are 'strict', 'lenient' or 'off'. --foreground Starts the Gradle daemon in the foreground. -g, --gradle-user-home Specifies the Gradle user home directory. Defaults to ~/.gradle -I, --init-script Specify an initialization script. -i, --info Set log level to info. --include-build Include the specified build in the composite. -M, --write-verification-metadata Generates checksums for dependencies used in the project (comma-separated list) -m, --dry-run Run the builds with all task actions disabled. --max-workers Configure the number of concurrent workers Gradle is allowed to use. --no-build-cache Disables the Gradle build cache. --no-configuration-cache Disables the configuration cache. [incubating] --no-configure-on-demand Disables the use of configuration on demand. [incubating] --no-daemon Do not use the Gradle daemon to run the build. Useful occasionally if you have configured Gradle to always run with the daemon by default. --no-parallel Disables parallel execution to build projects. --no-scan Disables the creation of a build scan. For more information about build scans, please visit http://gradle.com/build-scans. --no-watch-fs Disables watching the file system. --offline Execute the build without accessing network resources. -P, --project-prop Set project property for the build script (e.g. -Pmyprop=myvalue). -p, --project-dir Specifies the start directory for Gradle. Defaults to current directory. --parallel Build projects in parallel. Gradle will attempt to determine the optimal number of executor threads to use. --priority Specifies the scheduling priority for the Gradle daemon and all processes launched by it. Values are 'normal' (default) or 'low' --profile Profile build execution time and generates a report in the /reports/profile directory. --project-cache-dir Specify the project-specific cache directory. Defaults to .gradle in the root project directory. -q, --quiet Log errors only. --refresh-dependencies Refresh the state of dependencies. --refresh-keys Refresh the public keys used for dependency verification. --rerun-tasks Ignore previously cached task results. -S, --full-stacktrace Print out the full (very verbose) stacktrace for all exceptions. -s, --stacktrace Print out the stacktrace for all exceptions. --scan Creates a build scan. Gradle will emit a warning if the build scan plugin has not been applied. (http://gradle.com/build-scans) --status Shows status of running and recently stopped Gradle daemon(s). --stop Stops the Gradle daemon if it is running. -t, --continuous Enables continuous build. Gradle does not exit and will re-execute tasks when task file inputs change. --update-locks Perform a partial update of the dependency lock, letting passed in module notations change version. [incubating] -v, --version Print version info. -w, --warn Set log level to warn. --warning-mode Specifies which mode of warnings to generate. Values are 'all', 'fail', 'summary'(default) or 'none' --watch-fs Enables watching the file system for changes, allowing data about the file system to be re-used for the next build. --write-locks Persists dependency resolution for locked configurations, ignoring existing locking information if it exists -x, --exclude-task Specify a task to be excluded from execution. ```

簡寫:

./gradlew -? // or ./gradlew -h

可以看到上面的輸出已經列出來了很多命令,可能有些見過有些沒見過,下面將把常用的提煉出來講解,並進行分類。

1.3、命令結構

gradle [taskName...] [--option-name...]

多個任務用空格分隔。

2、Gradle相關

2.1、檢視Gradle版本

常見的檢視Gradle版本有兩種方式。

第一種是直接在gradle>wrapper>gradle-wrapper.properties檔案下檢視distributionUrl所使用的gradle版本下載地址:

distributionUrl=http://services.gradle.org/distributions/gradle-7.4-bin.zip

這裡的distributionUrl即表示當前所用的gradle版本為7.4。

第二種就是使用命令列的方式檢視當前版本。

執行:

./gradlew -version // or ./gradlew -v

輸出:

```

Gradle 7.4

Build time: 2022-02-08 09:58:38 UTC Revision: f0d9291c04b90b59445041eaa75b2ee744162586

Kotlin: 1.5.31 Groovy: 3.0.9 Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021 JVM: 11 (Oracle Corporation 11+28) OS: Mac OS X 10.16 x86_64 ```

2.2、升級Gradle

常見的升級Gradle有3種方式。

第一種,先手動修改wrapper.properties檔案下distributionUrl指向的版本,再手動修改Android Gradle Plugin(AGP)版本,然後重新sync。

第二種,開啟file>Project Structure修改AGP和Gradle的版本,然後apply。

第三種,用命令列的方式(官方推薦,不過跟著AS一起升也是可以的):

./gradlew wrapper --gradle-version 7.5.1

3、編譯命令

3.1、檢查依賴並編譯打包

./gradlew build

3.2、編譯並打出Debug包

./gradlew assembleDebug

3.3、編譯打出Debug包並安裝

./gradlew installDebug

3.4、編譯並打出Release包

./gradlew assembleRelease

3.5、編譯打出Release包並安裝

./gradlew installRelease

3.6、Debug/Release編譯並列印日誌

./gradlew assembleDebug --info // or ./gradlew assembleRelease --info

4、清除命令

清除構建目錄下的產物。

./gradlew clean

等同於Build->Clean Project。

5、解除安裝命令

5.1、解除安裝Debug/Release安裝包

./gradlew uninstallDebug // or ./gradlew uninstallRelease

輸出:

Uninstalling com.yechaoa.gradlex (from app:debug) from device 'Pixel_5_API_31(AVD) - 12' (emulator-5554). Uninstalled com.yechaoa.gradlex from 1 device.

5.2、adb解除安裝

在Android Studio中執行是直接解除安裝的當前專案安裝包,如果是adb執行則需要指定包名

adb uninstall com.yechaoa.gradlex

6、除錯命令

除錯命令在定位編譯問題的時候非常有用。

當我們遇到編譯錯誤的時候,經常會看到這個提示:

``` * 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. ```

6.1、編譯並列印堆疊日誌

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

詳細版:

./gradlew assembleDebug --full-stacktrace // or ./gradlew assembleDebug -S

6.2、日誌級別

有時候構建日誌會有很多,看到的可能不全,甚至不是真正的編譯問題,而構建日誌又不能像logcat那樣可以視覺化的篩選,這個時候就需要用日誌級別來篩選一下。

``` -q,--quiet 僅記錄錯誤。

-w,--warn 將日誌級別設定為警告。

-i,--info 將日誌級別設定為資訊。

-d,--debug 除錯模式(包括正常的stacktrace)。 ```

示例:

./gradlew assembleDebug -w

7、任務相關

7.1、檢視主要Task

./gradlew tasks

7.2、檢視所有Task

./gradlew tasks --all

7.3、執行Task

./gradlew taskName // or ./gradlew :moduleName:taskName

同時,可在AS右側工具類Gradle中檢視專案及module的Task,並可以點選執行對應Task。

8、檢視依賴

編譯有很多問題都是依賴導致的錯誤,檢視依賴能幫我們快速定位問題所在。

8.1、檢視專案根目錄下的依賴

./gradlew dependencies

8.2、檢視app模組下的依賴

./gradlew app:dependencies

8.3、檢視依賴輸出到檔案

./gradlew app:dependencies > dependencies.txt

示例:

9、效能相關

9.1、離線編譯

./gradlew assembleDebug --offline

9.2、構建快取

``` ./gradlew assembleDebug --build-cache // 開啟

./gradlew assembleDebug --no-build-cache // 不開啟 ```

9.3、配置快取

``` ./gradlew assembleDebug --configuration-cache // 開啟

./gradlew assembleDebug --no-configuration-cache // 不開啟 ```

9.4、並行構建

``` ./gradlew assembleDebug --parallel // 開啟

./gradlew assembleDebug --no-parallel // 不開啟 ```

以上9.1-9.4的配置也都可以在gradle.properties中配置。

示例:

```

並行編譯

org.gradle.parallel=true

構建快取

org.gradle.caching=true ```

9.5、編譯並輸出效能報告

./gradlew assembleDebug --profile

效能報告位於構建專案的GradleX/build/reports/profile/路徑下

See the profiling report at: file:///Users/yechao/AndroidStudioProjects/GradleX/build/reports/profile/profile-2022-11-29-23-13-29.html

輸出的是html檔案,用瀏覽器開啟:

9.6、編譯並輸出更詳細效能報告

./gradlew assembleDebug --scan

首次執行需要郵箱驗證,授權即可,完事之後即可開啟連結,scan報告內容比profile更加詳細。

10、動態傳參

再來介紹一個比較常用的傳參屬性,--project-prop,我們一般常用-P表示,用來設定根專案的專案屬性。

10.1、獲取引數

示例:

./gradlew assembleDebug -PisTest=true

這裡我們用-P傳了一個isTest欄位,並賦值為true

那在程式碼裡如何獲取這個引數呢?然後在build.gradle中編寫如下程式碼:

if (hasProperty("isTest")){ println("---hasProperty isTest yes") }else { println("---hasProperty isTest no") }

我們可以用hasProperty來獲取命令列(CLI)的引數,module或者外掛也可以這麼獲取:

project.property('isTest')

然後我們用上面的命令編譯看下輸出:

``` ➜ GradleX git:(master) ✗ ./gradlew assembleDebug -PisTest=true ---Gradle:開始初始化了 ---Gradle:settingsEvaluated Settings物件評估完畢 ---Gradle:projectsLoaded 準備載入Project物件了

Configure project : ---Gradle:Projec beforeEvaluate Project開始評估,物件是 = GradleX ---hasProperty isTest yes // --- 看這裡 --- ---Gradle:Projec afterEvaluate Project評估完畢,物件是 = GradleX

Configure project :app ---Gradle:buildFinished 構建結束了 ```

可以看到已經打印出來了。

還沒完,獲取到引數是不錯,但是還沒獲取到引數的值。

10.2、獲取引數值

我們可以用getProperty()來獲取:

if (hasProperty("isTest")) { println("---hasProperty isTest yes") if (Boolean.valueOf(getProperty('isTest'))) { println("---isTest true") } else { println("---isTest false") } } else { println("---hasProperty isTest no") }

注意,getProperty('isTest')這裡要用單引號,另外命令列裡面的引數值都是物件,還需要基本資料型別轉換一下,即Boolean.valueOf(getProperty('isTest'))

10.3、自定義操作

ok,現在我們就可以針對獲取的引數去做一些自定義的操作了,比如修改我們的依賴。

app>build.gradle:

``` dependencies {

implementation 'androidx.core:core-ktx:1.7.0'

if (project.hasProperty("isTest")) {
    println("---hasProperty isTest yes")
    if (Boolean.valueOf(getProperty('isTest'))) {
        println("---isTest true")

        implementation 'com.yechaoa.gradlex.devtools:devtools:1.1.1'

    } else {
        println("---isTest false")

        implementation 'com.yechaoa.gradlex.devtools:devtools:2.2.2'
    }
} else {
    println("---hasProperty isTest no")
}

testImplementation 'junit:junit:4.13.2'

} ```

這裡舉例,在isTest=true的時候依賴了devtools 1.1.1版本,isTest=false時依賴了devtools 2.2.2版本。

除了dependencies裡面的依賴之外,Plugin、Task之類的也可以通過動態傳參的方式去做自定義操作。

11、總結

本文介紹了Gradle Command-Line Interface(CLI)相關的知識,像除錯命令、檢視依賴、效能相關、動態傳參這些,在定位問題、提升效率的時候還是非常有用的,希望能給你帶來收穫。(別忘了三連啊喂~)

12、Github

http://github.com/yechaoa/GradleX

13、相關文件