Android Gradle依賴經驗總結

 

前言:

比較大的APP項目開發中總是會遇到各種Gradle編譯依賴問題等,這裏根據以往的踩坑經驗做個總結,以方便大家日後能夠更高效率的處理Gradle相關依賴的問題。

 

一、依賴配置

目前 Gradle 版本支持的依賴配置有:

implementation、api、compileOnly、runtimeOnly annotationProcessor

已經廢棄的配置有:compile、provided、apk、providedCompile。

各配置項具體作用如下[括號後面爲對應的已廢棄的配置]

  • implementation  (compile):會添加依賴到編譯路徑,並且會將依賴打包到輸出(aar或apk),但是在編譯時不會將依賴的實現暴露給其他module,也就是隻有在運行時其他module才能訪問這個依賴中的實現。使用這個配置,可以顯著提升構建時間,因爲它可以減少重新編譯的module的數量。建議,儘量使用這個依賴配置。

  • api  (compile):與 compile功能完全一樣,會添加依賴到編譯路徑,並且會將依賴打包到輸出(aar 或a pk)。與 implementation 不同,這個依賴可以傳遞,其他 module 無論在編譯時和運行時都可以訪問這個依賴的實現,也就是會泄漏一些不應該不使用的實現。舉個例子,A 依賴 B,B 依賴 C,如果都是使用 api 配置的話,A 可以直接使用 C 中的類(編譯時和運行時)。而如果是使用 implementation 配置的話,在編譯時,A 無法訪問 C 中的類。

  • compileOnly  (provided):Gradle 把依賴加到編譯路徑,編譯時使用,不會打包到輸出(aar 或 apk)。這可以減少輸出的體積,在只在編譯時需要,在運行時可選的情況,很有用。

  • runtimeOnly  (apk):只在生成apk的時候參與打包,編譯時不會參與,很少用。

  • annotationProcessor  (compile):用於註解處理器的依賴配置。

 

二、依賴類型

依賴類型主要有如下三種:

apply plugin: 'com.android.application'
 
android { ... }
 
dependencies {
    // 【1、本地源碼依賴】Dependency on a local library module
    implementation project(":mylibrary")
 
    // 【2、本地libs目錄jar包等依賴】Dependency on local binaries
    implementation fileTree(dir: 'libs', include: ['*.jar'])
 
    // 【3、遠程Maven倉庫等依賴】Dependency on a remote binary
    implementation 'com.example.android:app-magic:12.3'
}

 

三、排除依賴透傳

1、dependencies中單個依賴排除:

compile('com.hongri.android:accs-huawei:1.1.2@aar') {
        transitive = true
        exclude group: 'com.taobao.android', module: 'accs_sdk_taobao'
}

2、全局配置排除:

configurations {
    compile.exclude module: 'cglib'
    //全局排除原有的tnet jar包與so包分離的配置,統一使用aar包中的內容
    all*.exclude group: 'com.taobao.android', module: 'tnet-jni'
    all*.exclude group: 'com.taobao.android', module: 'tnet-so'
}

3、禁止依賴傳遞:

compile('com.hongri.android:foundation:1.0') {
    transitive = false
}
 
configurations.all {
    transitive = false
}

4、還可以在單個依賴項中使用 @jar 標識符忽略傳遞依賴:

compile 'com.hongri.android:foundation:1.0.0@jar'

 

四、查看依賴樹:

在Terminal 終端輸入以下命令,即可看到項目的依賴關係解析樹:

./gradlew app:dependencies

我們可以在上面的命令中添加一個標識來查看特定構建變體的配置。例如 --configuration releaseCompileClasspath將向我們展示 release 變體的依賴樹。

releaseCompileClasspath - Resolved configuration for compilation for variant: release
+--- com.android.databinding:library:1.3.1
|    +--- com.android.support:support-v4:21.0.3
|    |    \--- com.android.support:support-annotations:21.0.3 -> 27.0.2
|    \--- com.android.databinding:baseLibrary:2.3.0-dev -> 3.0.1
+--- com.android.databinding:baseLibrary:3.0.1
+--- com.android.databinding:adapters:1.3.1
|    +--- com.android.databinding:library:1.3 -> 1.3.1 (*)
|    \--- com.android.databinding:baseLibrary:2.3.0-dev -> 3.0.1
+--- com.android.support.constraint:constraint-layout:1.0.2
|    \--- com.android.support.constraint:constraint-layout-solver:1.0.2
\--- com.android.support:appcompat-v7:27.0.2
     +--- com.android.support:support-annotations:27.0.2
     +--- com.android.support:support-core-utils:27.0.2
     |    +--- com.android.support:support-annotations:27.0.2
     |    \--- com.android.support:support-compat:27.0.2
     |         +--- com.android.support:support-annotations:27.0.2
     |         \--- android.arch.lifecycle:runtime:1.0.3
     |              +--- android.arch.lifecycle:common:1.0.3
     |              \--- android.arch.core:common:1.0.0
     +--- com.android.support:support-fragment:27.0.2
     |    +--- com.android.support:support-compat:27.0.2 (*)
     |    +--- com.android.support:support-core-ui:27.0.2
     |    |    +--- com.android.support:support-annotations:27.0.2
     |    |    \--- com.android.support:support-compat:27.0.2 (*)
     |    +--- com.android.support:support-core-utils:27.0.2 (*)
     |    \--- com.android.support:support-annotations:27.0.2
     +--- com.android.support:support-vector-drawable:27.0.2
     |    +--- com.android.support:support-annotations:27.0.2
     |    \--- com.android.support:support-compat:27.0.2 (*)
     \--- com.android.support:animated-vector-drawable:27.0.2
          +--- com.android.support:support-vector-drawable:27.0.2 (*)
          \--- com.android.support:support-core-ui:27.0.2 (*)

在查找目的之前,理解 Gradle 依賴關係樹的格式很重要。

先來談談以下三個符號,它們的目的僅用於格式化:

  • +- - - 是依賴分支庫的開始。
  • | 標識還是在之前的依賴庫中的依賴,顯示它依賴的庫。
  • \- - - 是依賴庫的末尾。

星號(*) 在依賴庫的末尾,意味着該庫的進一步依賴關係不會顯示,因爲它們已經列在其他某個子依賴樹中。

最重要的標識是 -> :

如果 Gradle 發現多個依賴庫都依賴到同一個庫但是不同版本,那麼它必須做出選擇。畢竟包含同一個庫的不同版本是沒有意義的。在這種情況下,Gradle 默認選擇該庫的最新版本。例如:

| + — — com.android.support:support-v4:21.0.3
| | \ — — com.android.support:support-annotations:21.0.3 -> 27.0.2

 

 

五、強制指定依賴

  • 在dependencies中配置之後呢,一般情況下高的版本會覆蓋舊的低的版本:
implementation 'com.android.support:appcompat-v7:27.0.2'
  • 如果我們想一直使用某個固定版本,那麼可以使用如下的強制依賴實現:
compile('com.hongri.android:foundation:1.0.0') {
    force = true
}
//或者進行全局配置
configurations.all {
    resolutionStrategy {
        force 'com.hongri.android:foundation:1.0.0'
        //或這種寫法
        forcedModules = ['com.hongri.android:foundation:1.0.0']
    }
}

 

六、定義解析策略

1、dependencySubstitution:

dependencySubstitution接收一系列替換規則,允許你通過substitute函數爲項目中的依賴替換爲你希望的依賴項:

// add dependency substitution rules
dependencySubstitution {
   //將該module所有的遠程依賴替換成源碼依賴
   substitute module('org.gradle:api') with project(':api')
   //將該module所有源碼依賴替換成遠程依賴
   substitute project(':util') with module('org.gradle:util:3.0')
}

 

2、eachDependency:

eachDependency允許你在gradle解析配置時爲每個依賴項添加一個替換規則,DependencyResolveDetails類型的參數可以讓你獲取一個requested和使用useVersion()、useTarget()兩個函數指定依賴版本和目標依賴。request中存放了依賴項的groupid、module name以及version,你可以通過這些值來篩選你想要替換的依賴項,再通過useVersion或useTarget指定你想要的依賴。

  • 將group是com.android.support且name不等於multidex的所有module版本指定爲28.0.2:
configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        def requested = details.requested
        if (requested.group == 'com.android.support') {
            if (!requested.name.startsWith("multidex")) {
                details.useVersion '28.0.2'
            }
        }
    }
}
  • 將所有module爲rxjava的依賴,全都指定使用如下版本:‘io.reactivex.rxjava3:rxjava:3.0.0-RC1’:
configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        if (details.requested.name == 'rxjava') {
            //由於useVersion只能指定版本號,不適用於group不同的情況
            details.useTarget group: 'io.reactivex.rxjava3', name: 'rxjava', version: '3.0.0-RC1'
        }
    }
}

 

 

 

參考:

Gradle官網 ResolutionStrategy

配置構建變體

Gradle 的依賴關係處理不當,可能導致你編譯異常

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章