天天看點

史上最全Android build.gradle配置詳解

Android Studio是采用gradle來建構項目的,gradle是基于groovy語言的,如果隻是用它建構普通Android項目的話,是可以不去學groovy的。當我們建立一個Android項目時會包含兩個Android build.gradle配置詳解檔案,如下圖:

史上最全Android build.gradle配置詳解

build.gradle位置.png

一、Project的build.gradle檔案:

對應的build.gradle代碼如下:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {//這裡是gradle腳本執行所需依賴,分别是對應的maven庫和插件
    
    repositories {
        google()//從Android Studio3.0後新增了google()配置,可以引用google上的開源項目
        jcenter()//是一個類似于github的代碼托管倉庫,聲明了jcenter()配置,可以輕松引用 jcenter上的開源項目
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0'此處是android的插件gradle,gradle是一個強大的項目建構工具
        

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {//這裡是項目本身需要的依賴,比如項目所需的maven庫
    repositories {
        google()
        jcenter()
    }
}

// 運作gradle clean時,執行此處定義的task任務。
// 該任務繼承自Delete,删除根目錄中的build目錄。
// 相當于執行Delete.delete(rootProject.buildDir)。
// gradle使用groovy語言,調用method時可以不用加()。
task clean(type: Delete) {
    delete rootProject.buildDir
}      
  • buildscript{}閉包裡是gradle腳本執行所需依賴,分别是對應的maven庫和插件。
  • allprojects{}閉包裡是項目本身需要的依賴,比如項目所需的maven庫。
  • task clean(type: Delete){}是運作gradle clean時,執行此處定義的task任務,該任務繼承自Delete,删除根目錄中的build目錄。其中buildscript包含repositories閉包和dependencies閉包。

repositories{}閉包:配置遠端倉庫

該閉包中聲明了jcenter()和google()的配置,其中jcenter是一個代碼托管倉庫,上面托管了很多Android開源項目,在這裡配置了jcenter後我們可以在項目中友善引用jcenter上的開源項目,從Android Studio3.0後新增了google()配置,可以引用google上的開源項目。

dependencies{}閉包:配置建構工具

該閉包使用classpath聲明了一個Gradle插件,由于Gradle并不隻是用來建構Android項目,是以此處引入相關插件來建構Android項目,其中'3.0.0'為該插件的版本号,可以根據最新的版本号來調整。

二、Module的build.gradle檔案:

從檔案内容可以看出,主要分為三大部分,如下圖所示:

史上最全Android build.gradle配置詳解

Module的build.gradle.png

1、apply plugin:

// 聲明是Android程式,
//com.android.application 表示這是一個應用程式子產品
//com.android.library 辨別這是一個庫子產品
//而這差別:前者可以直接運作,後着是依附别的應用程式運作
apply plugin: 'com.android.application'      

檔案中第一行使用apply plugin表示應用了一個插件,該插件一般有兩種值可選:

  • 'com.android.application',表示該子產品為應用程式子產品,可以直接運作,打包得到的是.apk檔案
  • 'com.android.library',表示該子產品為庫子產品,隻能作為代碼庫依附于别的應用程式子產品來運作,打包得到的是.aar檔案

2、android{}閉包:

這個閉包主要為了配置項目建構的各種屬性:

2.1、添加signingConfigs{}閉包:

signingConfigs {// 自動化打包配置
        release {// 線上環境
            keyAlias 'test'
            keyPassword '123456'
            storeFile file('test.keystore')
            storePassword '123456'
        }
        debug {// 開發環境
            keyAlias 'test'
            keyPassword '123456'
            storeFile file('test.keystore')
            storePassword '123456'
        }
    }      

可以手動添加簽名配置,也可以通過Project Structure 選中app,點選Singing添加,具體步驟如下圖所示:

史上最全Android build.gradle配置詳解

配置Singing.png

簽名配置完成後可以友善帶簽名打包,在module的Build Variants中有兩個Type,分别是debug和release,可以選擇任意一個類型進行打包,并且他們會利用各自配置的Key進行打包,執行 Run app或者Build->Build apk就會自動在module name/app/build/outputs/apk路徑下生成Apk檔案。另一種打包方式是Build->Generate Signed APK填寫簽名資訊生成Apk。

2.2、compileSdkVersion:設定編譯時用的Android版本

2.3、buildToolsVersion:設定編譯時使用的建構工具的版本,Android Studio3.0後去除此項配置

2.4、defaultConfig{}閉包:

compileSdkVersion 27//設定編譯時用的Android版本
    defaultConfig {
        applicationId "com.billy.myapplication"//項目的包名
        minSdkVersion 16//項目最低相容的版本
        targetSdkVersion 27//項目的目标版本
        versionCode 1//版本号
        versionName "1.0"//版本名稱
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"//表明要使用AndroidJUnitRunner進行單元測試
    }      
  • applicationId:指定了項目的包名。
  • minSdkVersion:指定項目最低相容的版本,如果裝置小于這個版本或者大于maxSdkVersion(一般不用)将無法安裝這個應用,這裡指定為16,表示最低相容到Android 4.1系統。
  • targetSdkVersion:指定項目的目标版本,表示在該目标版本上已經做過充分測試,系統會為該應用啟動一些對應該目标系統的最新功能特性,Android系統平台的行為變更,隻有targetSdkVersion的屬性值被設定為大于或等于該系統平台的API版本時,才會生效。例如,若指定targetSdkVersion值為22,則表示該程式最高隻在Android5.1版本上做過充分測試,在Android6.0系統上(對應targetSdkVersion為23)擁有的新特性如系統運作時權限等功能就不會被啟用。
  • versionCode:表示版本号,一般每次打包上線時該值隻能增加,打包後看不見。
  • versionName:表示版本名稱,展示在應用市場上。
  • testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"表明要使用AndroidJUnitRunner進行單元測試。

2.5、 buildTypes{}閉包:

這個閉包主要指定生成安裝檔案的主要配置,一般包含兩個子閉包,一個是debug閉包,用于指定生成測試版安裝檔案的配置,可以忽略不寫;另一個是release閉包,用于指定生成正式版安裝檔案的配置。兩者能配置的參數相同,最大的差別預設屬性配置不一樣,兩種模式支援的屬性配置如下圖:

史上最全Android build.gradle配置詳解

buildTypes配置.png

buildTypes {// 生産/測試環境配置
        release {// 生産環境
            buildConfigField("boolean", "LOG_DEBUG", "false")//配置Log日志
            buildConfigField("String", "URL_PERFIX", "\"https://release.cn/\"")// 配置URL字首
            minifyEnabled false//是否對代碼進行混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的規則檔案
            signingConfig signingConfigs.release//設定簽名資訊
            pseudoLocalesEnabled false//是否在APK中生成僞語言環境,幫助國際化的東西,一般使用的不多
            zipAlignEnabled true//是否對APK包執行ZIP對齊優化,減小zip體積,增加運作效率
            applicationIdSuffix 'test'//在applicationId 中添加了一個字尾,一般使用的不多
            versionNameSuffix 'test'//在applicationId 中添加了一個字尾,一般使用的不多
        }
        debug {// 測試環境
            buildConfigField("boolean", "LOG_DEBUG", "true")//配置Log日志
            buildConfigField("String", "URL_PERFIX", "\"https://test.com/\"")// 配置URL字首
            minifyEnabled false//是否對代碼進行混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的規則檔案
            signingConfig signingConfigs.debug//設定簽名資訊
            debuggable false//是否支援斷點調試
            jniDebuggable false//是否可以調試NDK代碼
            renderscriptDebuggable false//是否開啟渲染腳本就是一些c寫的渲染方法
            zipAlignEnabled true//是否對APK包執行ZIP對齊優化,減小zip體積,增加運作效率
            pseudoLocalesEnabled false//是否在APK中生成僞語言環境,幫助國際化的東西,一般使用的不多
            applicationIdSuffix 'test'//在applicationId 中添加了一個字尾,一般使用的不多
            versionNameSuffix 'test'//在applicationId 中添加了一個字尾,一般使用的不多
        }
    }      

release{}閉包和debug{}閉包兩者能配置的參數相同,最大的差別預設屬性配置不一樣:

  • minifyEnabled:表明是否對代碼進行混淆,true表示對代碼進行混淆,false表示對代碼不進行混淆,預設的是false。
  • proguardFiles:指定混淆的規則檔案,這裡指定了proguard-android.txt檔案和proguard-rules.pro檔案兩個檔案,proguard-android.txt檔案為預設的混淆檔案,裡面定義了一些通用的混淆規則。proguard-rules.pro檔案位于目前項目的根目錄下,可以在該檔案中定義一些項目特有的混淆規則。
  • buildConfigField:用于解決Beta版本服務和Release版本服務位址不同或者一些Log列印需求控制的。例如:配置buildConfigField("boolean", "LOG_DEBUG", "true"),這個方法接收三個非空的參數,第一個:确定值的類型,第二個:指定key的名字,第三個:傳值,調用的時候BuildConfig.LOG_DEBUG即可調用。
  • debuggable:表示是否支援斷點調試,release預設為false,debug預設為true。
  • jniDebuggable:表示是否可以調試NDK代碼,使用lldb進行c和c++代碼調試,release預設為false
  • signingConfig:設定簽名資訊,通過signingConfigs.release或者signingConfigs.debug,配置相應的簽名,但是添加此配置前必須先添加signingConfigs閉包,添加相應的簽名資訊。
  • renderscriptDebuggable:表示是否開啟渲染腳本就是一些c寫的渲染方法,預設為false。
  • renderscriptOptimLevel:表示渲染等級,預設是3。
  • pseudoLocalesEnabled:是否在APK中生成僞語言環境,幫助國際化的東西,一般使用的不多。
  • applicationIdSuffix:和defaultConfig中配置是一的,這裡是在applicationId 中添加了一個字尾,一般使用的不多。
  • versionNameSuffix:表示添加版本名稱的字尾,一般使用的不多。
  • zipAlignEnabled:表示是否對APK包執行ZIP對齊優化,減小zip體積,增加運作效率,release和debug預設都為true。

2.6、sourceSets{}閉包:配置目錄指向

sourceSets {//目錄指向配置
        main {
            jniLibs.srcDirs = ['libs']//指定lib庫目錄
        }
    }      

配置 jniLibs.srcDirs = ['libs'],可以在Android studio的Android視圖下生成jniLibs檔案夾,可以友善我們存放jar包和庫檔案,其中Android視圖下的jniLibs和project視圖下的libs指向同一檔案夾(app→libs),如下圖所示:

史上最全Android build.gradle配置詳解

jniLibs.png

2.7、packagingOptions{}閉包:打包時的相關配置

當項目中依賴的第三方庫越來越多時,有可能會出現兩個依賴庫中存在同一個(名稱)檔案。如果這樣,Gradle在打包時就會提示錯誤(警告)。那麼就可以根據提示,然後使用以下方法将重複的檔案剔除,比較常用的是通過exclude去除重複的檔案,例如:

packagingOptions{
        //pickFirsts做用是 當有重複檔案時 打包會報錯 這樣配置會使用第一個比對的檔案打包進入apk
        // 表示當apk中有重複的META-INF目錄下有重複的LICENSE檔案時  隻用第一個 這樣打包就不會報錯
        pickFirsts = ['META-INF/LICENSE']

        //merges何必 當出現重複檔案時 合并重複的檔案 然後打包入apk
        //這個是有預設值得 merges = [] 這樣會把默預設值去掉  是以我們用下面這種方式 在預設值後添加
        merge 'META-INF/LICENSE'

        //這個是在同時使用butterknife、dagger2做的一個處理。同理,遇到類似的問題,隻要根據gradle的提示,做類似處理即可。
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }      

2.8、productFlavors{}閉包:多個管道配置

這個配置是經常會使用到的,通常在适配多個管道的時候,需要為特定的管道做部分特殊的處理,比如設定不同的包名、應用名等。場景:當我們使用友盟統計時,通常需要設定一個管道ID,那麼我們就可以利用productFlavors來生成對應管道資訊的包,如:

android {  
    productFlavors {
        wandoujia {
            //豌豆莢管道包配置
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
            //manifestPlaceholders的使用在後續章節(AndroidManifest裡的占位符)中介紹
        }
        xiaomi {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
            applicationId "com.wiky.gradle.xiaomi" //配置包名

        }
        _360 {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "_360"]
        }
        //...
    }  
}      

當然也有更簡潔的方式:

android {  
    productFlavors {
        wandoujia {}
        xiaomi {}
        _360 {}
       //...
    }  

    productFlavors.all { 
        //批量修改,類似一個循序周遊
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] 
    }
}      

配置完之後,在指令行視窗中(Terminal)中輸入gradlew assembleRelease(windows)即可開始打包,在Mac系統中對應指令應該是./gradlew assembleRelease。當然,如果想要debug版本的包,将指令中assembleRelease改為assembleDebug即可。最後生成的包還是在app/build/outputs/apk中,預設命名格式如app-wandoujia-release-unsigned.apk,在module的Build Variants中可以選擇相應的管道。

注:Android Studio3.0需在主app的build.gradle裡面的

defaultConfig {
 targetSdkVersion:***
 minSdkVersion :***
 versionCode:***
 versionName :***
 //版本名後面添加一句話,意思就是flavor dimension 它的次元就是該版本号,這樣次元就是都是統一的了
 flavorDimensions "versionCode"
 }      

2.9、lintOptions{}閉包:代碼掃描分析

Lint 是Android Studio 提供的 代碼掃描分析工具,它可以幫助我們發現代碼結構/品質問題,同時提供一些解決方案,而且這個過程不需要我們手寫測試用例。

Lint 發現的每個問題都有描述資訊和等級(和測試發現 bug 很相似),我們可以很友善地定位問題,同時按照嚴重程度進行解決。

//程式在編譯的時候會檢查lint,有任何錯誤提示會停止build,我們可以關閉這個開關
    lintOptions {
        abortOnError false //即使報錯也不會停止打包
        checkReleaseBuilds false  //打包release版本的時候進行檢測
    }      
dependencies {//項目的依賴關系
    implementation fileTree(include: ['*.jar'], dir: 'libs')//本地jar包依賴
    implementation 'com.android.support:appcompat-v7:27.1.1'//遠端依賴
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    testImplementation 'junit:junit:4.12'//聲明測試用例庫
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}      
  • implementation fileTree(include: ['*.jar'], dir: 'libs'):implementation fileTree是一個本地依賴聲明,表示将libs目錄下所有.jar字尾的檔案都添加到項目的建構路徑當中。
  • implementation 'com.android.support:appcompat-v7:27.1.1':implementation語句為 遠端依賴聲明,'com.android.support:appcompat-v7:27.1.1'為一個标準的遠端依賴庫格式,其中com.android.support為域名部分,用于區分不同公司的庫;appcompat-v7為元件名稱,用于區分同一個公司的不同庫;27.1.1為版本号,用于區分同一個庫的不同版本。加上這句聲明後,Gradle在建構項目時會先檢查一下本地是否已經緩存過該庫,若沒有緩存則自動聯網下載下傳,下載下傳後自動添加到項目的建構路徑中去。
  • testImplementation和androidTestImplementation:表示聲明測試用例庫。

Module完整的build.gradle配置如下:

// 聲明是Android程式,
//com.android.application 表示這是一個應用程式子產品
//com.android.library 辨別這是一個庫子產品
//而這差別:前者可以直接運作,後着是依附别的應用程式運作
apply plugin: 'com.android.application'

android {
    signingConfigs {// 自動化打包配置
        release {// 線上環境
            keyAlias 'test'
            keyPassword '123456'
            storeFile file('test.jks')
            storePassword '123456'
        }
        debug {// 開發環境
            keyAlias 'test'
            keyPassword '123456'
            storeFile file('test.jks')
            storePassword '123456'
        }
    }
    compileSdkVersion 27//設定編譯時用的Android版本
    defaultConfig {
        applicationId "com.billy.myapplication"//項目的包名
        minSdkVersion 16//項目最低相容的版本
        targetSdkVersion 27//項目的目标版本
        versionCode 1//版本号
        versionName "1.0"//版本名稱
        flavorDimensions "versionCode"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"//表明要使用AndroidJUnitRunner進行單元測試
    }
    buildTypes {// 生産/測試環境配置
        release {// 生産環境
            buildConfigField("boolean", "LOG_DEBUG", "false")//配置Log日志
            buildConfigField("String", "URL_PERFIX", "\"https://release.cn/\"")// 配置URL字首
            minifyEnabled false//是否對代碼進行混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的規則檔案
            signingConfig signingConfigs.release//設定簽名資訊
            pseudoLocalesEnabled false//是否在APK中生成僞語言環境,幫助國際化的東西,一般使用的不多
            zipAlignEnabled true//是否對APK包執行ZIP對齊優化,減小zip體積,增加運作效率
            applicationIdSuffix 'test'//在applicationId 中添加了一個字尾,一般使用的不多
            versionNameSuffix 'test'//在applicationId 中添加了一個字尾,一般使用的不多
        }
        debug {// 測試環境
            buildConfigField("boolean", "LOG_DEBUG", "true")//配置Log日志
            buildConfigField("String", "URL_PERFIX", "\"https://test.com/\"")// 配置URL字首
            minifyEnabled false//是否對代碼進行混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的規則檔案
            signingConfig signingConfigs.debug//設定簽名資訊
            debuggable false//是否支援斷點調試
            jniDebuggable false//是否可以調試NDK代碼
            renderscriptDebuggable false//是否開啟渲染腳本就是一些c寫的渲染方法
            zipAlignEnabled true//是否對APK包執行ZIP對齊優化,減小zip體積,增加運作效率
            pseudoLocalesEnabled false//是否在APK中生成僞語言環境,幫助國際化的東西,一般使用的不多
            applicationIdSuffix 'test'//在applicationId 中添加了一個字尾,一般使用的不多
            versionNameSuffix 'test'//在applicationId 中添加了一個字尾,一般使用的不多
        }
    }

    sourceSets {//目錄指向配置
        main {
            jniLibs.srcDirs = ['libs']//指定lib庫目錄
        }
    }

    packagingOptions{//打包時的相關配置
        //pickFirsts做用是 當有重複檔案時 打包會報錯 這樣配置會使用第一個比對的檔案打包進入apk
        // 表示當apk中有重複的META-INF目錄下有重複的LICENSE檔案時  隻用第一個 這樣打包就不會報錯
        pickFirsts = ['META-INF/LICENSE']

        //merges何必 當出現重複檔案時 合并重複的檔案 然後打包入apk
        //這個是有預設值得 merges = [] 這樣會把默預設值去掉  是以我們用下面這種方式 在預設值後添加
        merge 'META-INF/LICENSE'

        //這個是在同時使用butterknife、dagger2做的一個處理。同理,遇到類似的問題,隻要根據gradle的提示,做類似處理即可。
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }

    productFlavors {
        wandoujia {}
        xiaomi {}
        _360 {}
    }

    productFlavors.all {
            //批量修改,類似一個循序周遊
        flavor -> flavor.manifestPlaceholders = [IFLYTEK_CHANNEL: name]
    }

    //程式在編譯的時候會檢查lint,有任何錯誤提示會停止build,我們可以關閉這個開關
    lintOptions {
        abortOnError false
        //即使報錯也不會停止打包
        checkReleaseBuilds false
        //打包release版本的時候進行檢測
    }

}

dependencies {
    //項目的依賴關系
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    //本地jar包依賴
    implementation 'com.android.support:appcompat-v7:27.1.1'
    //遠端依賴
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    testImplementation 'junit:junit:4.12'
    //聲明測試用例庫
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}