Android SDK 相依項目問題解決方案

在共用套件或其他一些套件以資料庫為相依項目時,如果相依對象是不同且互不相容的共用套件版本,便會發生相依項目問題。Gradle 可減輕 Android 開發人員的工作負擔,只需在 build.gradle 中加入相依項目,所需的資料庫就會無縫地納入組建當中。但是,當兩個相依項目的相依對象是同一資料庫的不同版本時,會發生什麼情況?

如果兩個相依項目屬於相同配置,即同為應用程式配置,Gradle 能夠自動解析相依關係。例如,Android 版 Audience Network SDK 的相依項目為 「exoplayer」資料庫。如果需要加入不同版本的「exoplayer」資料庫,Gradle 將選擇納入最高的版本。但是如果兩個相依項目屬於不同配置,即分別屬應用程式和測試配置,Gradle 便會擲回錯誤。我們將於下文講解不同的衝突和解決方案。

必要條件

確保您在開始操作前,已經先行參閱 Audience Network 新手指南Android 新手指南

相依項目衝突

1:來自相同配置的相依項目共用資料庫

2:來自不同配置的相依項目共用資料庫

相依項目衝突解決方案

1:讓 Gradle 為您解析相依項目

2:排除相依項目的特定版本

3:在 Gradle 中明確地定義出現衝突的資料庫

4:資料庫的強制解決方案



相依項目衝突

1:來自相同配置的相依項目共用資料庫

請參考以下範例。以下程式碼的兩個相依項目均採用相同的配置,並在資料庫「org.hamcrest:hamcrest-core」中有內部相依項目。由於兩個相依項目在內部使用同一個資料庫的不同版本,系統會在組建中納入較高的版本。Gradle 同步的輸出內容將清楚列明,其在最終組建中將 hamcrest 資料庫版本由 1.1 版自動升級至 1.3 版

// Depends on version 1.3 of org.hamcrest:hamcrest-core
androidTestImplementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19'  

2:來自不同配置的相依項目共用資料庫

如果兩個相依項目屬於不同配置,即分別屬應用程式和測試配置,Gradle 便會擲回錯誤。請參考下列程式碼片段。第一個相依項目屬於應用程式配置,而第二個相依項目則屬於測試配置。因此,當建立專案時,系統將失敗並出現異常情況。

進行儀器測試時,主 APK 和測試 APK 將共用相同的類別路徑。如果主 APK 和測試 APK 使用相同的資料庫(例如 Guava),但版本不同,Gradle 將無法建立專案。如果 Gradle 未有發現這一點,您的應用程式在測試時和正常運行時的表現會有所不同,包括在其中一個情況下當機。

// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19' 

相依項目衝突解決方案

1:讓 Gradle 為您解析

這是最簡單的方法,但僅限於各相依項目屬於相同配置的情況。例如,您的模組明確地以 ExoPlayer 的特定版本為相依項目。然而,Audience Network SDK 已納入 ExoPlayer 的另一版本。系統預設會將最高版本納入組建中。在以下的程式碼片段中,Gradle 同步的輸出內容將清楚列明,其在最終組建中將 ExoPlayer 資料庫版本由 r2.4.2 版自動升級至 2.7.3 版

implementation 'com.google.android.exoplayer:exoplayer-core:2.7.3'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.7.3'
...
// audience-network-sdk depends on exoplayer-core:r2.4.2 and exoplayer-dash:r2.4.2
implementation 'com.facebook.android:audience-network-sdk:4.28.1' 

2:排除相依項目的特定版本

在大多數情況下,開發人員或會想控制最終組建中所包含的資料庫版本。您可配置 build.gradle 以做到這一點。例如,如果開發人員想以較低版本的 ExoPlayer r2.4.0,而非 Audience Network SDK 中的 r2.4.2,則您可以在宣告「audience-network-sdk」相依項目時排除此模組。排除標籤也適用於各相依項目屬於不同配置的情況。

在實際專案中,許多相依項目會採用同一資料庫的不同版本。在這種情況下,您需要為每個相依項目分別提供排除標籤,以便納入該資料庫的預期版本。

情景 1:各相依項目屬於同一配置
implementation 'com.google.android.exoplayer:exoplayer-core:r2.4.0'
implementation 'com.google.android.exoplayer:exoplayer-dash:r2.4.0'
...
// audience-network-sdk depends on exoplayer-core:r2.4.2 and exoplayer-dash:r2.4.2
implementation ('com.facebook.android:audience-network-sdk:4.28.1') {
    exclude group: 'com.google.android.exoplayer', module:'exoplayer-core'
    exclude group: 'com.google.android.exoplayer', module:'exoplayer-dash'
}
情景 2:各相依項目屬於不同配置
// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation ('org.mockito:mockito-core:1.10.19'){
    exclude group: 'org.hamcrest', module:'hamcrest-core'
}

3:在 Gradle 中明確地定義出現衝突的資料庫

當屬於不同配置的相依項目發生衝突時,這是較簡潔的解決方法。在這種情況下,我們需要明確指出在為任何一種配置而設的最終組建中,我們希望納入哪個資料庫版本。

這是能夠解決衝突的更簡潔方法,但缺點是在更新 junitmockito 等實際相依項目的同時,開發人員也需要更新出現衝突的資料庫。

// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19' 
// Explictly mention that include version 1.3 of org.hamcrest:hamcrest-core
androidTestCompile 'org.hamcrest:hamcrest-core:1.3' 

4:資料庫的強制解決方案

這是解決衝突的另一種方法,也就是不針對單一配置來宣告,而是強制為所有配置執行此解決方案。在以下範例中,您可以將自己的「resolutionStrategy」加入模組層級的 build.gradle,以便其強制納入套件的指定版本,不論各相依項目的配置是相同還是不同亦然。

使用此方法時請格外小心。在第一個範例中,如果 audience-network-sdk 已更新,而且這些資料庫已更新 exoplayer-core 和 exoplayer-dash 資料庫的版本,則我們仍然會強制使用早期版本。雖然這種情況也適合採用第二種解決方案,但是在此方法中,我們會為所有配置強制設定相依項目版本,而不只是針對單一配置。

情景 1:各相依項目屬於同一配置
android {
    configurations.all {
        resolutionStrategy.force 'com.google.android.exoplayer:exoplayer-core:r2.4.0'
        resolutionStrategy.force 'com.google.android.exoplayer:exoplayer-dash:r2.4.0'
    }
}
情景 2:各相依項目屬於不同配置
android {
    configurations.all {
        resolutionStrategy.force 'org.hamcrest:hamcrest-core:1.1'
    }
}

後續步驟

更多資源

新手指南

Audience Network 入門技術指南

API 參考資料

Facebook iOS SDK 參考資料