一、Gradle 常用命令與參數
本課程全程基于 Gradle8.0 環境
1、Gradle 命令
介紹 gradle 命令之前我們先來了解下 gradle 命令怎么在項目中執行。
1.1、gradlew
gradlew 即 Gradle Wrapper,在學習小組的第一課時已經介紹過了這里就不多贅述。提一下執行命令,一般網上都是 windows 下用 gradlew
; Mac 或者 Linux 下用 ./gradlew
。實際上 AS Dolphin 2021.3.1 后的版本因為默認終端切換成 powershell 所以命令變成了 .\gradlew
或者 ./gradlew
都可以。我們接下來看看 gradlew
腳本的內容(Android Studio 項目根目錄 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
#
# https://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" ] ; dols=`ls -ld "$PRG"`link=`expr "$ls" : '.*-> \(.*\)$'`if expr "$link" : '/.*' > /dev/null; thenPRG="$link"elsePRG=`dirname "$PRG"`"/$link"fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/nullAPP_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 () {echoecho "$*"echoexit 1
}# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" inCYGWIN* )cygwin=true;;Darwin* )darwin=true;;MINGW* )msys=true;;NONSTOP* )nonstop=true;;
esacCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; thenif [ -x "$JAVA_HOME/jre/sh/java" ] ; then# IBM's JDK on AIX uses strange locations for the executablesJAVACMD="$JAVA_HOME/jre/sh/java"elseJAVACMD="$JAVA_HOME/bin/java"fiif [ ! -x "$JAVACMD" ] ; thendie "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOMEPlease set the JAVA_HOME variable in your environment to match the
location of your Java installation."fi
elseJAVACMD="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" ] ; thenMAX_FD_LIMIT=`ulimit -H -n`if [ $? -eq 0 ] ; thenif [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; thenMAX_FD="$MAX_FD_LIMIT"fiulimit -n $MAX_FDif [ $? -ne 0 ] ; thenwarn "Could not set maximum file descriptor limit: $MAX_FD"fielsewarn "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; thenGRADLE_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" ] ; thenAPP_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 cygpathROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`SEP=""for dir in $ROOTDIRSRAW ; doROOTDIRS="$ROOTDIRS$SEP$dir"SEP="|"doneOURCYGPATTERN="(^($ROOTDIRS))"# Add a user-defined pattern to the cygpath argumentsif [ "$GRADLE_CYGPATTERN" != "" ] ; thenOURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"fi# Now convert the arguments - kludge to limit ourselves to /bin/shi=0for arg in "$@" ; doCHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an optionif [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a conditioneval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`elseeval `echo args$i`="\"$arg\""fii=`expr $i + 1`donecase $i in0) 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/\$/' \\\\/" ; doneecho " "
}
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" "$@"
主要干了這幾件事
- 設置 APP_HOME
- 配置默認的 JVM 選項
- 設置 CLASSPATH 路徑,即指定 gradlew-wrapper.jar 路徑
- 檢查 JAVA 環境配置等
1.2、命令大全
執行 ./gradlew --help
gradle 會為我們輸出幫助信息:(這里只列出了部分,更多可以自己敲命令去看看)
PS D:\workspace\GradleDemo> ./gradlew --helpTo see help contextual to the project, use gradlew helpUSAGE: gradlew [option...] [task...]-?, -h, --help Shows this help message.
-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.
-p, --project-dir
這些命令也是可以簡寫的,例如 --help
可以簡寫為 -?
、-h
1.3、命令格式
gradle 命令的整體格式如下:
gradle [taskName...] [--option-name...]
2 gradle 常見命令
根據命令的功能目的,Gradle 命令大致可以分為下圖的這些類型。
2.1 gradle 自身相關
2.1.1 查看 gradle 版本
查看 gradle 版本一般我們都是直接看項目中的 gradle.property 文件,里面的 distributionUrl
參數。除了這種方式,我們還可以通過gradle 命令查看: 輸入:
./gradlew -version
//or
./gradlew -v
輸出:
------------------------------------------------------------
Gradle 8.0
------------------------------------------------------------Build time: 2023-02-13 13:15:21 UTC
Revision: 62ab9b7c7f884426cf79fbedcf07658b2dbe9e97 Kotlin: 1.8.10
Groovy: 3.0.13
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 17.0.8 (Amazon.com Inc. 17.0.8+7-LTS)
OS: Mac OS X 13.0.1 x86_64
2.1.2 gradle 版本升級
1、直接修改工程 gradle/wrapper/gradle-wrapper.properties 文件的 distributionUrl
修改 gradle 版本 2、File>Project Structure 修改 AndroidGradle Plugin Version 和 Gradle 的版本然后 apply 3、使用命令行輸入命令升級
./gradlew wrapper --gradle-version xxx
2.1.3 列出某個命令將要執行的所有任務(并不是真的執行它)
./gradlew xxx --dry-run
其中xxx就是要執行的命令,我們在學習的時候可以通過這個命令來快速的查看某個命令將要執行哪些任務。也方便快速對比相似功能的命令在執行過程中有哪些差異。
2.2 編譯命令
2.2.1 編譯打包
./gradlew build
//or
./gradlew assemble
這兩個命令都是編譯并輸出全部類型的包。他們之間差別在于,build
命令是包含了 assemble
命令的全生命周期的,從上面的 task --all
命令說明也可以看出。下面的這個圖可以更直觀的反映:
分別執行 ./gradlew assemble --dry-run
和 ./gradlew assemble --dry-run
命令,把輸出結果進行對比。差別就是 build
命令會在 assemble
之后執行額外的 check
任務
2.2.2 編譯 debug 包
./gradlew assembleDebug
//or
//反映
./gradlew installDebug
兩個任務前面步驟一致,最后一步不一樣,分別是執行 :app:assebmleDebug
和 :app:installDebug
2.2.3 編譯 release 包
./gradlew assembleRelease
//or
./gradlew installRelease
兩個任務前面步驟一致,最后一步不一樣,分別是執行 :app:assebmleRelease
和 :app:installRelease
2.2.4 編譯并打印日志
./gradlew assembleDebug --info
//or
./gradlew assembleRelease --info
加上 --info,編譯日志會更完整,方便定位問題。
2.3 清除命令
./gradlew clean
等同于 Build > Clean Project,會清除構建目錄下的產物
2.4 卸載命令
./gradlew uninstallDebug
//or
./gradlew uninstallRelease
這個命令是直接卸載連接設備上的當前項目安裝包,跟 adb 指定包名進行卸載一樣
2.5 調試命令
當我們使用 gradle 進行打包報錯時,調試命令就可以幫我們更方便的定位出問題原因
2.5.1 編譯并輸出堆棧日志
./gradlew assembleDebug --stacktrace
//or
./gradlew assembleDebug -s
或者可以在參數前加上 --full 輸出更詳細的日志信息
./gradlew assembleDebug --full-stacktrace
//or
./gradlew assembleDebug --full-s
2.5.2 設置日志級別
Gradle 的日志分級
Level | 作用 |
---|---|
ERROR | 錯誤 |
WARNING | 警告 |
LIFECYCLE | 生命周期 |
INFO | 信息 |
DEBUG | 調試 |
TRACE | 跟蹤 |
日志過濾
過濾命令 | 作用 |
---|---|
-q 或 -quiet | 只顯示 ERROR 和 WARNING 日志 |
–i 或 --info | 顯示 INFO 及以上日志 |
-d 或 --debug | 顯示 DEBUG 及以上日志 |
示例:
./gradlew assembleDebug -e
2.6 任務相關命令
2.6.1 查看項目 gradle task
./gradlew tasks //只列出關鍵的 task
//or
./gradlew tasks --all //所有的 task 都將列出
這個命令將列出項目所有要執行的 task,并且會有這個 task 的相應說明信息(這里只截取了一部分)
2.6.2 執行 Task
./gradlew <taskName>
//or
./gradlew :<moduleName>:<taskName>
可以在 AndroidStudio 右邊欄的 Gradle 菜單下選擇 Tasks 執行也是一樣的效果
2.7 依賴查看命令
依賴查看命令可以讓我們更清晰的了解引入的依賴庫,解決因為依賴導致的錯誤或者剔除一些不需要的依賴
./gradlew app:dependencies //輸出 app 模塊依賴樹
//or
./gradlew dependencies > xxx.txt //輸出依賴樹到 xxx.txt 文件
依賴關系樹后面有的會跟(*)``(c)
有的又沒有,代表如下意義:
*
:表示該依賴項已被標記為被選中的版本。這意味著它是根據解析規則中的約束條件被選擇的版本,而不是默認的最新版本。這通常是由于在項目的構建配置中明確指定了依賴項的版本或者存在其他依賴項對其版本有限制的情況。c
:表示該依賴項是由于沖突解決而被強制選擇的版本。當項目中存在多個依賴項,它們對同一依賴的版本有不同的要求時,Gradle 將嘗試解決這些沖突。如果無法找到滿足所有依賴項的版本,Gradle 將選擇一個版本并標記為沖突(conflict)。(c)
標記表示該依賴項是由于沖突解決而被強制選擇的版本。
舉個例子:
假設項目 A 依賴于庫 X 的版本 1.0,而項目 B 依賴于庫 X 的版本 2.0。這兩個項目都作為依賴項添加到同一個項目 C 中。現在,項目 C 需要同時滿足項目 A 和項目 B 的依賴。
Gradle 將嘗試解決這個沖突,它會檢查是否有一個版本可以同時滿足項目 A 和項目 B 的依賴。如果存在滿足所有依賴項的版本,Gradle 將選擇該版本,并將其標記為被選中的版本 (*)
。
然而,如果無法找到滿足所有依賴項的版本,Gradle 將不得不做出一個決策。在這種情況下,Gradle 會選擇一個版本,并將其標記為沖突 (c)
。這表示所選的版本是為了解決沖突而被強制選擇的,可能無法完全滿足所有依賴項的要求。
2.8 性能相關命令
2.8.1 使用本地緩存版本離線編譯
./gradlew assembleDebug --offline
也可以在AndroidStudio 側邊欄可視化開啟關閉。差別在于,如果沒開啟離線編譯,每次編譯的時候都會去檢查版本,對于沒指定版本號或者動態版本號的依賴每次都會以最新的版本進行編譯。
2.8.2 構建緩存
./gradlew assembleDebug --build-cache //開啟
./gradlew assembleDebug --no-build-cache //不開啟
2.8.3 配置緩存
./gradlew assembleDebug --configuration-cache //開啟
./gradlew assembleDebug --no-configuration-cache //不開啟
2.8.4 并行構建
./gradlew assembleDebug --parallel //開啟
./gradlew assembleDebug --no-parallel //不開啟
性能相關的這幾個命令執行效果,和直接在 gradle.properties 中配置效果是一樣的。
2.8.5 編譯性能報告
./gradlew assembleDebug --profile
會在項目目錄的 build
> reports
> profile
路徑下生成報告文件
./gradlew assembleDebug --scan
會生成更詳細的在線報告,首次執行會郵箱驗證授權,完成后會輸出一個鏈接。
2.9 動態傳參命令
./gradlew assembleDebug -PisTest=true
build.gradle 中通過如下方式獲取參數值
if(project.hasProperty("isTest")){
// do something
}else{
// do something else
}
通過 hasProperty 來獲取命令行的參數
project.getProperty("isTest")
上面的方式都是判斷參數是否存在,那么怎么獲取參數的值呢?
if(project.hasProperty("isTest")){println("******hasProperty isTest yes******")if(Boolean.valueOf(project.getProperty('isTest')){println("******property isTest true******")}else{println("******property isTest false******")}
}else{println("******hasProperty isTest no******")
}
獲取參數的數據類型需要基本數據類型轉換成對應的類型,即 XXX.valueOf(getProperty('key'))
。通過動態參數,我們可以在打包過程中做一些差異化的構建。
二、依賴管理和版本決議
在我們的開發中,經常會遇到各個模塊中引入了相同的三方庫,但是三方庫版本又各不相同。有時候只是升級了一下某個依賴庫存,結果運行就各種報錯了。這部分課程將介紹一下 Gradle 的依賴管理方式和版本決議機制,弄明白 Gradle 是怎么把三方庫引入到項目中的。在遇到同庫不同版本的時候又是怎樣決定使用哪個版本的。
1、依賴管理
不使用 maven 方式接入三方庫,我們一般都是直接導入 jar 包或者 aar 包。替換版本的時候又重新去導入新的版本的 jar 或者 aar。遇到導入了相同 jar 或者 aar 的時候還出現沖突編不過。如果我們基于 Gradle 來開發項目,則可以依靠 Gradle 比較靈活方便的對依賴庫版本進行管理。下圖是 Gradle 工作的大致示意圖:
構建過程中,Gradle 會先從本地檢索,找不到就挨個從遠端找依賴庫,然后緩存到本地。 我們也可以通過以下方式,開啟離線編譯,對于未指定版本號或者使用動態版本號的依賴使用本地的版本進行編譯
1.1 聲明依賴
1.1.1 配置 maven 和依賴信息
聲明 maven 依賴包含兩部分:
- 倉庫配置 我這里是在 gradle 8.0 的環境下演示的。配置信息在 projetc > settings.gradle 下,低版本配置信息一般在 project > build.gradle 下
pluginManagement {repositories {//指定 maven 倉庫的地址maven { url "https://www.jitpack.io" }google()//maven 官方倉庫地址mavenCentral()//自定義 gitlab 倉庫作為 maven 地址maven {url "https://gitee.com/monkeies/maven/raw/master"}//本地 maven 倉庫地址maven {url uri("/Users/pandaq/WorkSpace/AndroidProjects/Aizhong/Maven/")}//http 地址需要配置 allowInsecureProtocol = truemaven { url 'http://xxx.xxx.xxx/xxx/'allowInsecureProtocol = true}}
}
- 依賴庫配置 依賴庫的配置信息在各個 module 的 build.gradle 下
implementation 'com.airbnb.android:lottie:6.1.0'
1.1.2 依賴類型
- 本地模塊依賴
- 本地二進制文件依賴
- 遠端二進制文件依賴
dependencies {
// Dependency on a local library module
implementation project(':mylibrary')
// Dependency on local binaries
implementation fileTree(dir: 'libs', include: ['*.jar'])
// Dependency on a remote binary
implementation 'com.example.android:app-magic:12.3' }
1.2 遠端倉庫
1.1.1 中我們配置的 repositories ,里面的 url 就是依賴項上川島遠端倉庫的 url,遠端倉庫起一個橋梁的作用,把開發者和依賴庫作者連接起來。開發者、遠端倉庫、依賴庫開發者三者關系大概如下圖所示:
- 左側是我們項目的開發過程,通過聲明依賴庫信息和配置遠端倉庫地址,從而找到我們想要的 Lib;
- 中間為遠端倉庫,包含了豐富的 library/組件/插件;
- 右側是 Lib 組件的開發者,把代碼通過 aar/jar的形式打包到遠端倉庫提供給使用方;
1.3 GAV
GAV 即 groupId、artifactId、version , maven 根據這三個維度的規則確定 Library 的唯一性。我們日常的依賴引入是這樣的:
implementation 'com.airbnb.android:lottie:6.1.0'
完整的內容其實是這樣的:
implementation group: 'com.airbnb.android', name: 'lottie', version: '6.1.0'
打開 maven 搜索對應的 Library,我們可以看到更多依賴庫的相關信息:
在 Maven 依賴方式下可以更清晰的看出一個依賴庫引用方式的結構:
- groupId:依賴庫發布組織的名稱,一般是公司域名倒寫.包名;
- artifactId:項目名稱,如果 groupId 包含了項目名稱,這里就是子項目名稱;
- version:版本號,這個庫的具體版本號;
這里我們已系統設置的 DataReporter 這個 Lib 為例,發布端配置信息如下
1.4 依賴傳遞
Gradle 除了幫我們下載依賴,還提供了依賴傳遞的能力。根據我們的依賴引入方法不同,有著不同的依賴傳遞效果。
依賴方法 | 說明 | 示例 |
---|---|---|
implementation | 編譯時對模塊可用,運行時對模塊的消費者可用 | A 依賴 B,B 依賴 C;在編譯和運行時 B均可用 C的代碼;A 不能編譯時用 C 代碼,但運行時可訪問 C 代碼。 |
api | 編譯和運行時對模塊和模塊的消費者都可用 | A 依賴 B,B 依賴 C;編譯和運行時 A、B 都可以用 C 的代碼 |
compileOnly | 僅編譯時對模塊可用,編譯和運行時對模塊消費者不可用,運行時對所有都不可用 | A 依賴 B,B 依賴 C;僅編譯時 B 可以訪問 C,運行時是沒有 C 的任何代碼的 |
runtimeOnly | 僅在運行時對模塊和其消費者可用 | A 依賴 B,B 依賴 C;A、B都無法調用 C 的代碼,但是 C 的代碼會被打包到 apk 中,一般用于組件化隔離代碼。 |
2、版本決議
既然各個模塊都能引入依賴,并且依賴還具有傳遞性,那么必然存在某兩個或幾個模塊都引入了某個依賴庫。當他們引入版本不一樣的時候問題就來了,最終構建項目時以哪個版本的依賴庫為準呢?
2.1 依賴信息
前面課程已經講過通過./gradlew app:dependencies
這個命令,我們可以輸出項目的依賴樹。通過 build --scan,或者AndroidStudio 的 Gradle 側邊欄 Gradle > app > help > dependencies 也是一樣的效果。
輸出的依賴樹包含了模塊所有的直接依賴和間接依賴信息,從圖中我們可以看到,okhttp 是有4.9.3
和 4.10.0
兩個版本的。圖的 4.9.3 -> 4.10.0
表示 lib
模塊中的版本被拔高到了 4.10.0
,因為 app 中引入了更高的 4.10.0 版本。接下來我們一起來了解一下,gradle 是以怎樣的規則來決定用哪個版本的。
2.2 決議規則
我們直接通過不同的示例來了解 gradle 的版本決議規則:
示例1:同模塊不同版本
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
結論:同模塊引入不同版本,以更高版本為準
示例2:同模塊使用強制關鍵字
//app
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation ('com.squareup.okhttp3:okhttp:4.9.3'){version{structly("4.9.3")//strictly("4.10.0")}
}
結論:低版本中如果用 strictly 強制低版本會報錯,強制高版本會給高版本標識 strictly
示例3:不同同模塊不同版本
1、app 中引入 4.10.0,lib 中引入 4.9.3
//app
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
//lib
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
2、app 中引入 4.9.3,lib 中引入 4.10.0
//app
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
//lib
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
結論:不同模塊引入不同版本,以版本高的為準
示例4:子模塊使用強制關鍵字
1、app 引入4.10.0,lib 中強制 4.9.3
//app
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
//lib
implementation ('com.squareup.okhttp3:okhttp:4.9.3'){version{strictly("4.9.3")}
}
2、app 強制4.9.3,lib 中引入4.10.0
//app
implementation ('com.squareup.okhttp3:okhttp:4.9.3'){version{strictly("4.9.3")}
}
//lib
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
結論:子模塊使用 strictly 強制低版本會報錯,主模塊使用 strictly 可以實現子模塊降版本,可能導致子模塊兼容問題。
總結
- 默認規則總是取高版本覆蓋低版本
- strictly 關鍵字主工程可以實現降低編譯版本
- 同模塊或者子模塊使用 strictly 降版本會直接報錯
2.3 版本號規則
gradle 版本決議時的版本號規則如下表所示:
分類 | 示例 | 決議結果 | 說明 |
---|---|---|---|
全數字,段數不同 | 1.2.3 vs 1.3 | 1.3 | 段數從左到右比較,高的勝 |
全數字,段數相同 | 1.2.3 vs 1.2.4 | 1.2.4 | 段數從左到右比較,高的勝 |
全數字,段數相同,位數不同 | 1.2.10 vs 1.2.3 | 1.2.10 | 段數從左到右比較,高的勝 |
全數字,段數不同 | 1.2.3 vs 1.2.3.0 | 1.2.3.0 | 段數多的勝 |
段數相同,字母比較 | 1.2.a vs 1.2.b | 1.2.b | 字母大勝 |
段數相同,數字與非數字 | 1.2.3 vs 1.2.abc | 1.2.3 | 數字優先于字母 |
另外 gradle 也支持版本號范圍選項,如[1.0,)
、[1.1,2.0)
、latest.release
等
2.4 沖突解決
當項目比較復雜,依賴層級和module較多的時候,很多依賴傳遞就變得不可控了,時常會遇到各種版本依賴沖突。不管采用哪種方式,我們都需要有一個決議機制,保證依賴版本全局的唯一性,大家遵循這個機制進行依賴管理才能盡可能的避免這個問題。
2.4.1 版本管理(提前預防)
在項目實施過程中我們一般有以下方式對依賴版本進行約束:
- 配置統一的 gradle.config 放在云端統一進行維護,所有工程要增加三方依賴都通過這個文件進行配置,這樣可以做到編譯過程各個module三方依賴的版本統一。像我們現在項目中統一配置的 config.gradle。目前看應該是項目級別進行了配置,其實也可以遷移到云端統一管理,多項目共用
- 模塊配置一個公共的 module_build.gradle,里面可以把必須項比如 kotlin 、androidx 這些依賴放在里面,使用模塊再 apply from 的形式引入進去。
2.4.2 強制版本(臨時補救)
項目實施中途遇到沖突了,再去統一版本顯然不現實,那么我們有什么小范圍的臨時補救措施呢:
1、exclude 單獨去掉某個依賴的沖突
//去除com.github.niorgai:StatusBarCompat:2.1.3引用的com.android.support包下內容 implementation('com.github.niorgai:StatusBarCompat:2.1.3') {exclude group: 'com.android.support'
})
//去除module引用的'com.google.code.findbugs:jar305'的相關內容
implementation(project(':downlibrary')) { exclude group: 'com.google.code.findbugs', module: 'jsr305'
}
2、去掉所有 module 中的指定依賴
configurations { implementation.exclude group: 'com.example', module: 'lib'
}
lib 中的依賴變成了 app 中的 4.10.0 版本,并且沒有以來沖突標識
3、強制所有module使用指定版本
//app build.gradle 中配置
configurations.configureEach { resolutionStrategy { force 'com.squareup.okhttp3:okhttp:4.11.0' }
}
app 中版本由 4.10.0 升到了 4.11.0;lib1 版本由 4.9.0 升級到了 4.11.0;lib 版本由 4.10.0 升級到了4.11.0
2.4.3 面向 Bug 編程
開啟版本沖突強檢測模式,此模式下編譯只要有版本沖突就會報錯,再反過去順藤摸瓜解決版本沖突。
configurations.configureEach { resolutionStrategy { failOnVersionConflict() }
}
Android 學習筆錄
Gradle 篇:https://qr18.cn/DzrmMB
Android 性能優化篇:https://qr18.cn/FVlo89
Android Framework底層原理篇:https://qr18.cn/AQpN4J
Android 車載篇:https://qr18.cn/F05ZCM
Android 逆向安全學習筆記:https://qr18.cn/CQ5TcL
Android 音視頻篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(內含Compose):https://qr18.cn/A0gajp
OkHttp 源碼解析筆記:https://qr18.cn/Cw0pBD
Kotlin 篇:https://qr18.cn/CdjtAF
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知識體:https://qr18.cn/CyxarU
Android 核心筆記:https://qr21.cn/CaZQLo
Android 往年面試題錦:https://qr18.cn/CKV8OZ
2023年最新Android 面試題集:https://qr18.cn/CgxrRy
Android 車載開發崗位面試習題:https://qr18.cn/FTlyCJ
音視頻面試題錦:https://qr18.cn/AcV6Ap