偵錯依附元件解決方案錯誤

新增依附元件時,可能會遇到必要的依附元件問題 產生的內容,且不同依附元件版本之間的衝突。 以下說明如何分析依附元件圖表,並修正可能發生的常見問題。

如需修正與自訂建構相關的依附元件解析錯誤相關指引 邏輯,請參閱 自訂依附元件解析策略

檢視模組依附元件

部分直接依附元件可能有自己的依附元件。這就是所謂的遞移依附元件。Gradle 會自動為您收集並新增這類依附元件,讓您不必手動宣告各項遞移依附元件。Gradle 適用的 Android 外掛程式提供的工作會顯示 Gradle 解析特定模組的依附元件清單。

各個模組也會依據建構變數、測試來源集和類別路徑將依附元件分組。以下是應用程式模組偵錯類別變數的執行階段類別路徑,以及編譯檢測設備測試來源集的類別路徑的範例報表。

debugRuntimeClasspath - Dependencies for runtime/packaging
+--- :mylibrary (variant: debug)
+--- com.google.android.material:material:1.0.0@aar
+--- androidx.appcompat:appcompat:1.0.2@aar
+--- androidx.constraintlayout:constraintlayout:1.1.3@aar
+--- androidx.fragment:fragment:1.0.0@aar
+--- androidx.vectordrawable:vectordrawable-animated:1.0.0@aar
+--- androidx.recyclerview:recyclerview:1.0.0@aar
+--- androidx.legacy:legacy-support-core-ui:1.0.0@aar
...

debugAndroidTest
debugAndroidTestCompileClasspath - Dependencies for compilation
+--- androidx.test.ext:junit:1.1.0@aar
+--- androidx.test.espresso:espresso-core:3.1.1@aar
+--- androidx.test:runner:1.1.1@aar
+--- junit:junit:4.12@jar
...

如要執行工作,請依照下列步驟操作:

  1. 依序選取「View」>「Tool Windows」>「Gradle」,或者點選工具視窗列中的「Gradle」圖示
  2. 展開「AppName」>「Tasks」>「Android」,然後按兩下「androidDependencies」。Gradle 執行工作之後,「Run」視窗應該會開啟以顯示輸出內容。

如要進一步瞭解如何在 Gradle 中管理依附元件,請參閱 依附元件管理基本概念

排除遞移依附元件

隨著應用程式的範圍擴大,可包含多種依附元件,包括直接依附元件和遞移依附元件 (應用程式匯入的程式庫所依附的程式庫)。如要不再需要排除遞移依附元件,您可以使用 exclude 關鍵字,如下所示:

Kotlin

dependencies {
    implementation("some-library") {
        exclude(group = "com.example.imgtools", module = "native")
    }
}

Groovy

dependencies {
    implementation('some-library') {
        exclude group: 'com.example.imgtools', module: 'native'
    }
}

從測試設定中排除遞移依附元件

假使您需要從測試中排除某些遞移依附元件,上述的程式碼範例可能無法正常運作。這是因為測試設定 (例如 androidTestImplementation) 會擴充模組的 implementation 設定。也就是說,Gradle 會在 Gradle 解析設定時一律包含 implementation 依附元件。

因此,如要從測試中排除遞移依附元件,您必須在執行時間執行,如下所示:

Kotlin

android.testVariants.all {
    compileConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
    runtimeConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
}

Groovy

android.testVariants.all { variant ->
    variant.getCompileConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
    variant.getRuntimeConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
}

注意:您仍然可以在依附元件區塊中使用 exclude 關鍵字,如「排除遞移依附元件部分中的原始代碼範例所示,以省略特定於測試設定且不包含在其他設定中的遞移依附元件。

修正依附元件解決方案錯誤

在應用程式專案中加入多個依附元件時,這些直接和遞移的依附元件可能會彼此衝突。Android Gradle 外掛程式會試著圓滿地解決這些衝突,但有些衝突可能會導致編譯時間或執行階段錯誤。

為協助您調查哪些依附元件導致錯誤,請查看應用程式的依附元件樹狀結構,找出重複出現或衝突版本的依附元件。

假使您無法辨別重複的依附元件,請嘗試使用 Android Studio 的 UI 搜尋包含重複類別的依附元件,如下所示:

  1. 在選單列中依序選取「Navigate」>「Class」
  2. 在彈出式搜尋對話方塊中,確定已勾選「Include non-project items」旁的方塊。
  3. 輸入建構錯誤中顯示的類別名稱。
  4. 檢查含有類別的依附元件結果。

以下各節說明您可能會遇到的各種依附元件的解決錯誤及修正方式。

修正重複的類別錯誤

假使類別在執行階段類別路徑上多次出現,您會看到如下的錯誤:

Program type already present com.example.MyClass

此錯誤的常見原因如下:

  • 二進位檔依附元件包括一個程式庫,您的應用程式也將其作為直接依附元件包含在內。舉例來說,您的應用程式宣告了程式庫 A 和程式庫 B 的直接依附元件,但程式庫 A 的二進位檔中已包含程式庫 B。
    • 如要解決此問題,請移除程式庫 B 作為直接依附元件。
  • 您的應用程式在同一個程式庫中,儲存本機二進位檔依附元件和遠端二進位檔依附元件。
    • 如要解決此問題,請移除其中一個二進位檔依附元件。

修正類別路徑之間的衝突

Gradle 解析編譯類別路徑時,會先解析執行階段類別路徑,並使用結果來決定要將哪些依附元件版本新增至編譯類別路徑。換句話說,執行階段類別路徑會判斷下游類別路徑中相同依附元件的必要版本號碼。

您應用程式的執行階段類別路徑也會決定 Gradle 需要的應版本號碼,才能比對應用程式的測試 APK 的執行階段類別路徑。圖 1 說明類別路徑的階層結構。

圖 1. 出現在多個類別路徑中的依附元件版本編號必須符合此階層。

當相同依附元件的不同版本出現在多個類路徑中,便可能會發生衝突。舉例來說,當您的應用程式包含使用 implementation 依附元件設定的依附元件版本,而程式庫模組包含使用 runtimeOnly 設定的另一個依附元件版本時,便可能會發生衝突。

解決執行階段中編譯依附元件和編譯時間類別路徑時,Android Gradle 外掛程式 3.3.0 以上版本會嘗試自動修正特定的下游版本衝突。舉例來說,當執行階段類別路徑內含程式庫 A 版本 2.0,而編譯類別路徑內含程式庫 A 版本 1.0,此時外掛程式會自動將編譯類別路徑內的依附元件更新為程式庫 A 版本 2.0,以便防止發生錯誤。

然而,假使執行階段類別路徑包含程式庫 A 版本 1.0,且編譯類別路徑包含程式庫 A 版本 2.0,則外掛程式不會將編譯類別路徑的依附元件降級至程式庫 A 版本 1.0,但您仍然會取得錯誤,如下所示:

Conflict with dependency 'com.example.library:some-lib:2.0' in project 'my-library'.
Resolved versions for runtime classpath (1.0) and compile classpath (2.0) differ.

如要解決這個問題,請按照下列其中一種做法進行:

  • 將所需依附元件版本新增為程式庫模組的 api 依附元件。也就是說,只有您的程式庫模組會宣告依附元件,但應用程式模組也可以遞移地存取其 API。
  • 或者,您可以在這兩種模組中宣告依附元件,但請務必確保每個模組都使用相同版本的依附元件。建議設定全專案的屬性,確保整個專案中各項依附元件的版本保持一致。