零散知識點總結(1) Gradle 使用配置總結

澤毛發表於2017-12-21

零散知識點總結(1)   Gradle 使用配置總結

一、統一管理依賴版本

1.1 在根目錄下,新建config.gradle檔案

ext {

    android = [
            compileSdkVersion: 23,
            buildToolsVersion: "23.0.3",
            applicationId: "com.example.lizejun.repogradle",
            minSdkVersion: 14,
            targetSdkVersion: 23,
            versionCode: 1,
            versionName: "1.0",
            testInstrumentationRunner: "android.support.test.runner.AndroidJUnitRunner"
    ]

    dependencies = [
            "support-v4"  : 'com.android.support:support-v4:23.2.0',
            "support-v7"  : 'com.android.support:appcompat-v7:23.2.0'
    ]

}
複製程式碼

android用來管理SDK版本、版本號等,dependencies用來管理依賴庫的版本,它們都是一個陣列,用逗號來分割,陣列的每個元素都是key:value的格式。

1.2 在根目錄下的build.gradle,新增:

apply from: "config.gradle"
複製程式碼

1.3 在根目錄下的各個Module或者Library中的build.gradle檔案中,引用對應的key

android {
    compileSdkVersion rootProject.ext.android.compileSdkVersion
    buildToolsVersion rootProject.ext.android.buildToolsVersion
    defaultConfig {
        applicationId rootProject.ext.android.applicationId
        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
        testInstrumentationRunner rootProject.ext.android.testInstrumentationRunner
    }
}

dependencies {
    compile rootProject.ext.dependencies["support-v7"]
}
複製程式碼

二、檢視依賴關係

2.1 工具檢視

依賴樹的檢視可以通過Android Studio的外掛Gradle View來檢視:

Gradle View.png
重啟之後,點選View -> Tool Windows -> Gradle View,之後會在最下方生成一個視窗,我們通過這個視窗就可以看到對應專案的依賴關係:
Gradle View Result.png

2.2 命令檢視

除此之外,我們也可以使用以下的命令:

./gradlew -q app:dependencies
複製程式碼

同樣可以獲得類似的結果:

命令.png
注意上圖,如果標記了(*),那麼表示這個依賴被忽略了,這是因為其他頂級依賴中也依賴了這個傳遞的依賴,Gradle會自動分析下載最合適的依賴。

三、識別符號

由於多個頂級依賴當中,可能包含了相同的子依賴,但是它們的版本不同,這時候為了選擇合適的版本,那麼就需要使用一些必要的操作符來管理子依賴。

3.1 Transitive

預設為true,表示gradle自動新增子依賴項,形成一個多層樹形結構;設定為false,則需要手動新增每個依賴項。

3.1.1 統一指定Transitive

configurations.all {
    transitive = false
}

dependencies {
    compile rootProject.ext.dependencies["support-v7"]
}
複製程式碼

最終得到的結果是,可以看到前面的子依賴項都沒有了:

2017-02-09 15:27:38螢幕截圖.png

3.1.2 單獨指定Transitive

dependencies {
    compile ('com.android.support:appcompat-v7:23.2.0') {
        transitive = false
    }
}

複製程式碼

3.2 Force

用來表示強制設定某個模組的版本:

configurations.all {
    resolutionStrategy {
        force 'com.android.support:support-v4:23.1.0'
    }
}
複製程式碼

之後列印,發現其依賴的包版本變成了23.1.0

Force.png

3.3 exclude

該識別符號用來設定不編譯指定的模組

3.3.1 全域性配置某個模組

configurations {
    all *.exclude group : 'com.android.support', module: 'support-v4'
}
複製程式碼

此時的依賴關係為:

2017-02-09 15:54:02螢幕截圖.png
當然,exclude後的引數有groupmodule,可以分別單獨使用,會排除所有匹配項。

3.3.2 單獨給某個模組exclude

    compile ('com.android.support:appcompat-v7:23.2.0') {
        exclude group : 'com.android.support', module: 'support-v4'
    }
複製程式碼

也會和上面獲得相同的結果

四、版本衝突

4.1 相同配置下的版本衝突

同一配置下,某個模組的不同版本同時被依賴時,預設使用最新版,Gradle同步時不會報錯。

五、Gradle詳解

基本配置:AS中的Android專案通常至少包含兩個build.gradle,一個是Project範圍的,另一個是Module範圍的,由於一個Project可以有多個Module,所以每個Module下都會對應一個build.gradle

5.1 Project下的build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply from: "config.gradle"

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.1'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
複製程式碼
  • buildscript下的repositoriesgradle指令碼自身需要的資源,
  • allprojects下的repositories是專案所有模組需要的資源。

5.2 模組的build.gradle

//宣告外掛,表明這是一個Android程式;如果是庫,那麼應當是com.android.library
apply plugin: 'com.android.application'
//Android構建過程需要配置的引數
android {
    //編譯版本
    compileSdkVersion rootProject.ext.android.compileSdkVersion
    //buildTool版本
    buildToolsVersion rootProject.ext.android.buildToolsVersion
    //預設配置,同時應用到debug和release版本上
    defaultConfig {
        applicationId rootProject.ext.android.applicationId
        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
        testInstrumentationRunner rootProject.ext.android.testInstrumentationRunner
    }
    //配置debug和release版本的一些引數,例如混淆,簽名配置等
    buildTypes {
        //release版本
        release {
            minifyEnabled false //是否開啟混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' //混淆檔案位置
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile rootProject.ext.dependencies["support-v7"]
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    testCompile 'junit:junit:4.12'
}
複製程式碼

下面對Android構建過程中需要配置的引數做一些解釋:

  • compileSdkVersion:告訴gradle用那個Android SDK的版本編譯你的應用,修改它不會改變執行時的行為,因為它不會被包含進入最終的APK中;因此,推薦使用最新的SDK編譯;如果使用Suppport Library,那麼compileSdkVersion必須要大於等於它的大版本號。
  • minSdkVersion:應用最低可執行的要求;它必須要大於等於你所依賴的庫的minSdkVersion
  • targetSdkVersionAndroid提供向前相容的重要依據。(targetSdkVersion is the main way Android provides forward compatibility) 因為隨著Android系統的升級,某個api或者模組的行為有可能發生改變,但是為了保證老APK的行為和以前相容,只要APKtargetSdkVersion不變,那麼即使這個APK安裝在新的Android系統上,那麼行為還是保持老的系統上的行為。 系統在呼叫某個api或者模組的時候,會先檢查呼叫的APKtargetSdkVersion,來決定執行什麼行為。

minSdkVersiontargetSdkVersion最終會被包含進入最終的APK檔案中,如果你檢視生成的AndroidManifest.xml,那麼會發現:

<uses-sdk android:targetSdkVersion="23" android:minSdkVersion="7" />
複製程式碼

所以,我們一般遵循的規則是:

minSdkVersion (lowest possible) <= targetSdkVersion == compileSdkVersion (latest SDK)
複製程式碼

5.3 gradle相關檔案

  • gradle.properties 配置檔案,可以定義一些常量供build.gradle使用,比如可以配置簽名相關資訊,例如keystore位置、密碼、keyalias等。
  • settings.gradle 用來配置多模組的,如果你的專案有兩個模組BrowserScannerSDK,那麼就需要:
include ':Browser'
include ':ScannerSDK'
project(':ScannerSDK').projectDir = new File(settingsDir, './ScannerSDK/')
複製程式碼
  • gradle資料夾 裡面有兩個檔案,gradle-wrapper.jargradle-wrapper.properties,後者當中指定了gradle的版本。
distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
複製程式碼
  • gradlewgradlew.bat 分別是Linuxwindows下的批處理檔案,它們的作用是根據gradle-wrapper.properties檔案中的distributionUrl下載對應的gradle版本,這樣即使環境沒有安裝gradle也可以編譯。

5.4 gradle倉庫

gradle有三種倉庫:maven/ivy/flat本地

maven{
    url  "..."
}
ivy{
    url  "..."
}
flatDir{
    dirs 'xxx'
}
複製程式碼

有些倉庫取了別名:

repositories{
    mavenCentral()
    jcenter()
    mavenLocal()
}
複製程式碼

5.5 gradle任務

通過以下指令,可以看到支援的任務:

./gradlew tasks
複製程式碼

Task1.png

Task2.png

六、常見問題

6.1 匯入本地Jar

匯入單個jar檔案:

compile files('libs/xxx.jar')
複製程式碼

匯入libs的多個jar檔案:

compile fileTree(dir: 'libs', include: ['*.jar'])
複製程式碼

6.2 匯入maven

compile 'groupId:artifactId:version'
複製程式碼

6.3 匯入Project

在匯入之前,需要在settings.gradle中把模組包含進來,例如前面的ScannerSDK模組:

compile project(':ScannerSDK')
複製程式碼

6.4 宣告第三方maven

如果專案中需要的一些庫檔案不再中央倉庫中,而是在某個特定地址裡,那麼就需要在Project中的build.gradle中的allprojects結點下或者直接配到某個模組中:

allprojects {
    repositories {
        maven {
            url '地址'
        }
    }
}
複製程式碼

6.5 依賴第三方aar

compile 'com.aaa.xxx:core:1.0.1@aar'
複製程式碼

6.6 將庫匯出為aar

首先,你的專案必須是一個庫專案,之後在build.gradle中進行配置:

apply plugin : 'com.android.library'
複製程式碼

之後,進入到該專案中,執行gradle命令:

./gradlew assembleRelease
複製程式碼

生成的aar放在/build/output/aar檔案當中

6.7 引用本地aar

首先,將aar檔案拷貝到對應目錄下,然後在該模組的build.gradle中宣告flat倉庫:

repositories{
   flatDir{
      dirs '以build.gradle為根目錄的相對路徑'
   }
}
複製程式碼

之後,在dependencies結點下依賴該aar模組:

dependencies{
    compile (name:'xxx',ext:'aar')
}
複製程式碼

七、多版本打包

在此之前,我們先了解幾個基本的概念:

  • buildTypes構建型別Android StudioGradle元件預設提供了debugrelease兩個預設配置,這裡主要用於是否需要混淆,是否除錯。
  • productFlavors產品渠道,在實際釋出中,根據不同渠道,可能需要使用不同的包名,甚至是不同的程式碼。
  • buildVaiants:每個buildTypesproductFlavors組成一個buildvariant

以上我們討論的buildTypesproductFlavors可以通過每個Module中的build.gradleandroid標籤來配置。

下面,我們先看一下不同的productFlavors,分別用來支援讀取不同的檔案和替換不同的字串。

7.1 引用不同的程式碼

我們首先在app/src目錄下新建兩個目錄,分別對應兩個Flavor,再在其中建立相同名字的檔案Constant.java,對裡面的某個常量賦予不同的值。

Flavor.png

  • constantFlavor1
package com.example.lizejun.repogradle;

public class Constant {
    public static final String NAME = "flavor1";
}
複製程式碼
  • constantFlavor2
package com.example.lizejun.repogradle;

public class Constant {
    public static final String NAME = "flavor2";
}
複製程式碼

我們的app下的build.gradle中的android標籤下新增如下幾行程式碼,讓兩個Flavor分別引用不同的Constant檔案:

    sourceSets {
        constantFlavor1 {
            java.srcDirs =  ['src/constantFlavor1', 'src/constantFlavor1/java', 'src/constantFlavor1/java/']
        }
        constantFlavor2 {
            java.srcDirs =  ['src/constantFlavor2', 'src/constantFlavor2/java', 'src/constantFlavor2/java/']
        }
    }

    productFlavors {
        constantFlavor1 {}
        constantFlavor2 {}
    }
複製程式碼

之後我們進行打包,可以得到以下不同安裝包,這兩個apk如果在其中引用的了NAME,那麼它會得到不同的值:

2017-02-10 16:15:51螢幕截圖.png

7.2 自定義buildConfig

如果我們只需要定義一些簡單的值,那麼我們可以用buildConfig類:

    productFlavors {
        constantFlavor1 {
            buildConfigField "boolean", "BOOLEAN_VALUE", "true"
        }
        constantFlavor2 {
            buildConfigField "boolean", "BOOLEAN_VALUE", "false"
        }
    }
複製程式碼

7.3 佔位符

    productFlavors {
        constantFlavor1 {
            buildConfigField "boolean", "BOOLEAN_VALUE", "true"
            manifestPlaceholders = [label:"constantFlavor1"]
        }
        constantFlavor2 {
            buildConfigField "boolean", "BOOLEAN_VALUE", "false"
            manifestPlaceholders = [label:"constantFlavor2"]
        }
    }
複製程式碼

之後,我們再在AndroidManifest.xml中引用它:

android:label="${label}"
複製程式碼

7.4 簽名配置

首先是在android標籤下,我們使用signingConfigs來配置不同的簽名型別

    signingConfigs {
        eng {
            keyAlias 'androiddebugkey'
            keyPassword 'android'
            storeFile file('debug.keystore')
            storePassword 'android'
        }
        prd {
            keyAlias 'androiddebugkey'
            keyPassword 'android'
            storeFile file('debug.keystore')
            storePassword 'android'
        }
    }
複製程式碼

之後,再在buildTypes的各個分支中引用對應的簽名配置:

    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.eng
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.prd
        }
    }
複製程式碼

7.5 依賴

有時候,我們需要在不同的buildTypes下,引用不同的依賴,例如記憶體洩露的檢測工具,我們希望在debug版本時檢查記憶體洩露,並在發生時在桌面上生成圖示,但是在release版本上我們並不希望這麼做,這時候我們可以這麼寫:

debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
複製程式碼

這樣,release版本就不會在桌面生成記憶體洩露的圖示。


更多文章,歡迎訪問我的 Android 知識梳理系列:

相關文章