Android Gradle使用總結

Android Gradle

Android項目使用 Gradle 做爲構建框架,Gradle 又是以Groovy爲腳本語言。因此學習Gradle以前須要先熟悉Groovy腳本語言。html

Groovy是基於Java語言的腳本語言,因此它的語法和Java很是類似,可是具備比java更好的靈活性。下面就列舉一些和Java的主要區別。java

Android Gradle 的 Project 和 Tasks

這個Gradle中最重要的兩個概念。每次構建(build)至少由一個project構成,一個project 由一到多個task構成。項目結構中的每一個build.gradle文件表明一個project,在這編譯腳本文件中能夠定義一系列的task;task 本質上又是由一組被順序執行的Action`對象構成,Action實際上是一段代碼塊,相似於Java中的方法。android

Android Gradle 構建生命週期

每次構建的執行本質上執行一系列的Task。某些Task可能依賴其餘Task。哪些沒有依賴的Task總會被最早執行,並且每一個Task只會被執行一遍。每次構建的依賴關係是在構建的配置階段肯定的。每次構建分爲3個階段:c++

  • Initialization: 初始化階段

這是建立Project階段,構建工具根據每一個build.gradle文件建立出一個Project實例。初始化階段會執行項目根目錄下的settings.gradle文件,來分析哪些項目參與構建。git

因此這個文件裏面的內容常常是:github

include ':app'
include ':libraries:someProject'

這是告訴Gradle這些項目須要編譯,因此咱們引入一些開源的項目的時候,須要在這裏填上對應的項目名稱,來告訴Gradle這些項目須要參與構建。面試

  • Configuration:配置階段

這個階段,經過執行構建腳原本爲每一個project建立並配置Task。配置階段會去加載全部參與構建的項目的build.gradle文件,會將每一個build.gradle文件實例化爲一個Gradle的project對象。而後分析project之間的依賴關係,下載依賴文件,分析project下的task之間的依賴關係。sql

  • Execution:執行階段

這是Task真正被執行的階段,Gradle會根據依賴關係決定哪些Task須要被執行,以及執行的前後順序。
task是Gradle中的最小執行單元,咱們全部的構建,編譯,打包,debug,test等都是執行了某一個task,一個project能夠有多個task,task之間能夠互相依賴。例如我有兩個task,taskA和taskB,指定taskA依賴taskB,而後執行taskA,這時會先去執行taskB,taskB執行完畢後在執行taskA。小程序

說到這可能會有疑問,我翻遍了build.gradle也沒看見一個task長啥樣,有一種被欺騙的趕腳!性能優化

其實不是,你點擊AndroidStudio右側的一個Gradle按鈕,會打開一個面板,內容差很少是這樣的:

這裏寫圖片描述

裏面的每個條目都是一個task,那這些task是哪來的呢?

一個是根目錄下的 build.gradle 中的

dependencies {
        classpath 'com.android.tools.build:gradle:2.2.2'
    }

一個是 app 目錄下的 build.gradle 中的

apply plugin: 'com.android.application'

這兩段代碼決定的。也就是說,Gradle提供了一個框架,這個框架有一些運行的機制可讓你完成編譯,可是至於怎麼編譯是由插件決定的。還好Google已經給咱們寫好了Android對應的Gradle工具,咱們使用就能夠了。

根目錄下的build.gradle中dependencies {classpath 'com.android.tools.build:gradle:2.2.2'}是Android Gradle編譯插件的版本。

app目錄下的build.gradle中的apply plugin: 'com.android.application'是引入了Android的應用構建項目,還有com.android.library和com.android.test用來構建library和測試。

全部Android構建須要執行的task都封裝在工具裏,若是你有一些特殊需求的話,也能夠本身寫一些task。那麼對於開發一個Android應用來講,最關鍵的部分就是如何來用AndroidGradle的插件了。

認知Gradle Wrapper

Android Studio中默認會使用 Gradle Wrapper 而不是直接使用Gradle。命令也是使用gradlew而不是gradle。這是由於gradle針對特定的開發環境的構建腳本,新的gradle可能不能兼容舊版的構建環境。爲了解決這個問題,使用Gradle Wrapper 來間接使用 gradle。至關於在外邊包裹了一箇中間層。對開發者來講,直接使用Gradlew 便可,不須要關心 gradle的版本變化。Gradle Wrapper 會負責下載合適的的gradle版原本構建項目。

Android 三個文件重要的 gradle 文件

Gradle項目有3個重要的文件須要深刻理解:項目根目錄的 build.gradle , settings.gradle 和模塊目錄的 build.gradle 。

  • 1.settings.gradle 文件會在構建的 initialization 階段被執行,它用於告訴構建系統哪些模塊須要包含到構建過程當中。對於單模塊項目, settings.gradle 文件不是必需的。對於多模塊項目,若是沒有該文件,構建系統就不能知道該用到哪些模塊。

  • 2.項目根目錄的 build.gradle 文件用來配置針對全部模塊的一些屬性。它默認包含2個代碼塊:buildscript{...}和allprojects{...}。前者用於配置構建腳本所用到的代碼庫和依賴關係,後者用於定義全部模塊須要用到的一些公共屬性。

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

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

buildscript:定義了 Android 編譯工具的類路徑。repositories中, jCenter是一個著名的 Maven 倉庫。

allprojects:中定義的屬性會被應用到全部 moudle 中,可是爲了保證每一個項目的獨立性,咱們通常不會在這裏面操做太多共有的東西。

  • 3.模塊級配置文件 build.gradle 針對每一個moudle 的配置,若是這裏的定義的選項和頂層 build.gradle定義的相同。它有3個重要的代碼塊:plugin,android 和 dependencies。

定製項目屬性(project properties)

在項目根目錄的build.gradle配置文件中,咱們能夠定製適用於全部模塊的屬性,經過ext 代碼塊來實現。以下所示:

ext {
    compileSdkVersion = 22
    buildToolsVersion = "22.0.1"
}

而後咱們能夠在模塊目錄的build.gradle配置文件中引用這些屬性,引用語法爲rootProject.ext.{屬性名}。以下:

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
}

Android studio gradle Task

這裏寫圖片描述

//構建
gradlew app:clean    //移除全部的編譯輸出文件,好比apk

gradlew app:build   //構建 app module ,構建任務,至關於同時執行了check任務和assemble任務

//檢測
gradlew app:check   //執行lint檢測編譯。

//打包
gradlew app:assemble //能夠編譯出release包和debug包,可使用gradlew assembleRelease或者gradlew assembleDebug來單獨編譯一種包

gradlew app:assembleRelease  //app module 打 release 包

gradlew app:assembleDebug  //app module 打 debug 包

//安裝,卸載

gradlew app:installDebug  //安裝 app 的 debug 包到手機上

gradlew app:uninstallDebug  //卸載手機上 app 的 debug 包

gradlew app:uninstallRelease  //卸載手機上 app 的 release 包

gradlew app:uninstallAll  //卸載手機上全部 app 的包

這些都是基本的命令,在實際項目中會根據不一樣的配置,會對這些task 設置不一樣的依賴。好比 默認的 assmeble 會依賴 assembleDebug 和assembleRelease,若是直接執行assmeble,最後會編譯debug,和release 的全部版本出來。若是咱們只須要編譯debug 版本,咱們能夠運行assembleDebug。

除此以外還有一些經常使用的新增的其餘命令,好比 install命令,會將編譯後的apk 安裝到鏈接的設備。

lint 檢測

  • 忽略編譯器的 lint 檢查
android {

  lintOptions {
      abortOnError false
  }
  
}

buildTypes 定義了編譯類型

android{

  buildTypes {
        release {
            minifyEnabled true  //打開混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            minifyEnabled false //關閉混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
 }

productFlavors 多渠道打包

AndroidManifest.xml 裏設置動態渠道變量

<meta-data
    android:name="UMENG_CHANNEL"
    android:value="${UMENG_CHANNEL_VALUE}" />

在 build.gradle 設置 productFlavors , 這裏假定咱們須要打包的渠道爲酷安市場、360、小米、百度、豌豆莢。

android {  

    productFlavors {
        kuan {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "kuan"]
        }
        xiaomi {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
        }
        qh360 {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "qh360"]
        }
        baidu {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
        }
        wandoujia {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
        }
    } 
     
}

或者批量修改

android {  

    productFlavors {
        kuan {}
        xiaomi {}
        qh360 {}
        baidu {}
        wandoujia {}
    }  

    productFlavors.all { 
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] 
    }
}

這樣在打包的時候就能夠選擇渠道了

這裏寫圖片描述

或者用命令打包 ,好比:

gradlew assembleWandoujiaRelease  //豌豆莢 release 包

gradlew assembleWandoujiaDebug //豌豆莢 debug 包

Signing 簽名

在 android 標籤下添加 signingConfigs 標籤,以下:

android {
    signingConfigs {
        config {
            keyAlias 'yiba'
            keyPassword '123456'
            storeFile file('C:/work/Key.jks')
            storePassword '1234567'
        }
    }
 }

能夠在 release 和 debug 包中定義簽名,以下:

android {
    signingConfigs {
        config {
            keyAlias 'yiba'
            keyPassword '123456'
            storeFile file('C:/work/Key.jks')
            storePassword '1234567'
        }
    }
 
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.config
        }
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.config
        }
    }
}

依賴管理

一、依賴 jcenter 包

每一個庫名稱包含三個元素:組名:庫名稱:版本號

compile 'com.android.support:appcompat-v7:25.0.0'

二、依賴本地 module

compile project(':YibaAnalytics')

三、依賴 jar 包

  • 一、把 jar 包放在 libs 目錄下
  • 二、在 build.gradle 中添加依賴
dependencies {
   compile files('libs/YibaAnalytics5.jar')
}

這裏寫圖片描述

四、依賴 aar 包

  • 一、把 aar 包放到 libs 目錄下
  • 二、在 build.gradle 中添加依賴
repositories {
    flatDir {
        dirs 'libs'
    }
}

dependencies {
    compile(name:'YibaAnalytics-release', ext:'aar')
}

如圖所示:

這裏寫圖片描述

五、自定義依賴包目錄

當咱們的 aar 包須要被多個 module 依賴時,咱們就不能把 aar 包放在單一的 module 中,咱們能夠在項目的根目錄建立一個目錄,好比叫 aar 目錄,而後把咱們的 aar 包放進去,如圖所示:

這裏寫圖片描述

在項目的根目錄的 build.gradle 的 allprojects 標籤下的 repositories 添加 :

flatDir {
     dirs '../aar'
}

../aar 表示根目錄下的 aar 文件夾。

如圖所示:

這裏寫圖片描述

而後就能夠添加依賴了,以下所示:

compile(name:'YibaAnalytics-release', ext:'aar')

六、依賴配置

有些時候,你可能須要和sdk協調工做。爲了能順利編譯你的代碼,你須要添加SDK到你的編譯環境。你不須要將sdk包含在你的APK中,由於它早已經存在於設備中,因此配置來啦,咱們會有5個不一樣的配置:

  • compile
  • apk
  • provided
  • testCompile
  • androidTestCompile

compile是默認的那個,其含義是包含全部的依賴包,即在APK裏,compile的依賴會存在。

apk的意思是apk中存在,可是不會加入編譯中,這個貌似用的比較少。

provided的意思是提供編譯支持,可是不會寫入apk。

native包(so包)

用c或者c++寫的library會被叫作so包,Android插件默認狀況下支持native包,你須要把.so文件放在對應的文件夾中:

這裏寫圖片描述

注意

jniLibs 目錄應該和 Java 目錄在同一級

defaultConfig 詳解

defaultConfig 對應的是 ProductFlavor 類。

resConfigs : 過濾語言

若是你的app中僅支持1,2種語言,可是可能引用的lib庫包含多種其餘語言的strings資源,這個時候咱們能夠經過resConfig指定咱們須要的strings資源。

android {

    defaultConfig {
        applicationId "com.yiba.sharewe.lite.activity"
        minSdkVersion 14
        targetSdkVersion 24
        versionCode 46
        versionName "1.74"
        resConfigs 'en', 'zh-rCN' ,'es'  //本次打包,只把 en(英文)、zh-rCN(中文簡體)、es(西班牙語)打進保內,其餘語言忽略
    }
}

resConfigs : 過濾 drawable文件夾的資源

通常狀況下,咱們打完包,res 下面的資源如圖所示:

這裏寫圖片描述

如今加上資源過濾規則:

android {
  
    defaultConfig {
        applicationId "com.wifi.analytics"
        minSdkVersion 9
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        resConfigs "hdpi"  //打包的時候只保留 drawable-xhdpi 文件夾裏面的資源
    }

}

此次咱們打包效果以下:

這裏寫圖片描述

buildTypes 詳解

官方文檔

buildTypes{}對應的是 BuildType 類

繼承關係

BuildType 繼承 DefaultBuildType ; DefaultBuildType 繼承 BaseConfigImpl ;

BaseConfigImpl
    --- DefaultBuildType 
          --- BuildType

buildTypes的屬性:

name:build type的名字

applicationIdSuffix:應用id後綴

versionNameSuffix:版本名稱後綴

debuggable:是否生成一個debug的apk

minifyEnabled:是否混淆

proguardFiles:混淆文件

signingConfig:簽名配置

manifestPlaceholders:清單佔位符

shrinkResources:是否去除未利用的資源,默認false,表示不去除。

zipAlignEnable:是否使用zipalign工具壓縮。

multiDexEnabled:是否拆成多個Dex

multiDexKeepFile:指定文本文件編譯進主Dex文件中

multiDexKeepProguard:指定混淆文件編譯進主Dex文件中

buildType的方法:

1.buildConfigField(type,name,value):添加一個變量生成BuildConfig類。

2.consumeProguardFile(proguardFile):添加一個混淆文件進arr包。

3.consumeProguardFile(proguardFiles):添加混淆文件進arr包。

4.externalNativeBuild(action):配置本地的build選項。

5.initWith:複製這個build類型的全部屬性。

6.proguardFile(proguardFile):添加一個新的混淆配置文件。

7.proguradFiles(files):添加新的混淆文件

8.resValue(type,name,value):添加一個新的生成資源

9.setProguardFiles(proguardFileIterable):設置一個混淆配置文件。

initWith :複製屬性

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.wifi.analytics"
        minSdkVersion 9
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        myType {
            initWith debug  //徹底複製 debug 的全部屬性‘
            minifyEnabled true //自定義打開混淆
        }
    }
}

applicationIdSuffix 、versionNameSuffix :添加後綴

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.wifi.analytics"
        minSdkVersion 9
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            applicationIdSuffix "zhao"  //applicationId 追加後綴名 zhao
            versionNameSuffix "debug"  //versionName 追加後綴名 debug1.0
        }
    }

效果圖,以下:

這裏寫圖片描述

buildConfigField: 自定義屬性

在 build.gradle 文件中定義 buildConfigField 屬性

android {
  
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            buildConfigField "String", "API_ENV", "\"http://yiba.com\""  //自定義String屬性
        }
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            buildConfigField "String", "API_ENV", "\"http://yiba.com\""  //自定義String屬性
        }
    }
}

而後點擊同步按鈕,而後就能夠在 build 目錄看到 debug 和 release 信息。

debug 環境下的 BuildConfig 以下:
這裏寫圖片描述

release 環境下的 BuildConfig 以下:

這裏寫圖片描述

固然咱們也能夠在代碼中獲取自定義的值:

//獲取變量值
String API = BuildConfig.API_ENV ;

上面演示了自定義 String 變量,也能夠 自定義 int 、boolean

android {
  
    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            buildConfigField "String", "API_ENV", "\"http://www.baidu.com\"" //自定義 String 值
            buildConfigField "Boolean", "openLog", "true" //自定義 boolean 值
            buildConfigField "int", "age", "10"   //自定義 int 值
        }
    }
}

Gradle 實現差別化構建

情景1

LeakCanary 是 square 公司出品的一個檢測內存泄漏的開源庫。

GitHub : https://github.com/square/leakcanary

咱們通常這樣集成

dependencies {
    compile 'com.squareup.leakcanary:leakcanary-android:1.5.2'
}

而後咱們在 Application 類中初始化:

public class MyApplication extends Application {
    
    @Override
    public void onCreate() {
        super.onCreate();
      
        LeakCanary.install(this);
    }
}

可是這樣集成有一個弊端,就是 debug 和 release 包都會把 LeakCanary 的源碼打進去,若是咱們在 release 包中不把 LeakCanary 源碼打進去,怎麼辦? 還好 LeakCanary 給咱們提供了一個方法,方法以下:

dependencies {

 //打 debug 包
 debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'

 //打 release 包
 releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'

}

leakcanary-android-no-op 是一個空殼,裏面有2個空類,因此就能夠避免把 LeakCanary 源碼打進 release 包。可是這種方式有個缺陷,若是一些開源庫沒有提供 releaseCompile 庫,那咱們改怎麼辦了?下面的情景2 就會講到解決方案。

情景2

Stetho 是 Faceboo k開源的Andorid調試工具。當你的應用集成Stetho時,開發者能夠訪問Chrome,在Chrome Developer Tools中查看應用佈局,網絡請求,sqlite,preference 等等。

官網:http://facebook.github.io/stetho/

從官網能夠看到 stetho 沒有提供 releaseCompile 包 , 情景1 的方案就不能用了。新的思路集成方案以下:

dependencies {
    debugCompile 'com.facebook.stetho:stetho:1.5.0'
}

在 src 目錄下建立 debug 目錄、release 目錄 ,而後分別在 debug 目錄 和 release 目錄 建立 java 目錄 , 在 java 目錄中建立包名,好比: com.app , 以下圖所示:

這裏寫圖片描述

debug 目錄下建立 SDKManage 類 ,以下 :

public class SDKManager {

    public static void init(Context context) {
        //初始化 Stetho
        Stetho.initializeWithDefaults(context);
    }
}

release 目錄下建立 SDKManage 類 ,以下 :

public class SDKManager {

    public static void init(Context context) { 
        //這是一個空方法,目的是不引入 Stetho 源碼
    }

}

在住項目中的 MyApplication 類,而且完成 Stetho 的初始化,以下:

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        SDKManager.init(this);
    }
}

這樣咱們便完成了簡單的差別化構建, 打出來的 release 包就沒有 Stetho 源碼。

SourceSet

SourceSet 簡介

SourceSet 能夠定義項目結構,也能夠修改項目結構。Java插件默認實現了兩個SourceSet,main 和 test。每一個 SourceSet 都提供了一系列的屬性,經過這些屬性,能夠定義該 SourceSet 所包含的源文件。好比,java.srcDirs,resources.srcDirs 。Java 插件中定義的其餘任務,就根據 main 和 test 的這兩個 SourceSet 的定義來尋找產品代碼和測試代碼等。

SourceSet 定義源碼目錄

在 Android 項目中,咱們能夠在 src/main/java 目錄新建 Java 文件,以下圖所示:

這裏寫圖片描述

如今咱們在 src 目錄下,新建 test1 目錄 ,發現不能在 test1 目錄中新建 Java 文件,以下圖所示:

這裏寫圖片描述

爲何在 test1 目錄不能新建 Java 文件,由於 Gradle 中 SourceSet 默認定義的源碼文件路徑是src/main/java , 其餘的文件下下面的源碼咱們天然沒法訪問。解決這個問題也很簡單,咱們須要在 SourceSet 中增長一個源碼路徑便可。以下所示:

android {
  
    sourceSets {
        main {
            java {
                srcDir 'src/test1' //指定源碼目錄
            }
        }
    }
}

而後同步一下,就能夠在 test1 目錄中新建 Java 文件了。以下圖所示:

這裏寫圖片描述

固然咱們也能夠同時指定多個源碼目錄,好比同時指定 test1 , test2 , test3 爲源碼目錄。

android {
 
    sourceSets {
        main {
            java {
                srcDir 'src/test1' //指定 test1 爲源碼目錄
                srcDir 'src/test2' //指定 test2 爲源碼目錄
                srcDir 'src/test3' //指定 test3 爲源碼目錄
            }
        }
    }
}

或者 這樣寫 :

android {
    sourceSets {
        main {
            java.srcDirs( 'src/test1' , 'src/test2' ,'src/test3' )
        }
    }
}

效果以下圖所示:

這裏寫圖片描述

SourceSet 定義資源目錄

定義 test1 目錄 Java 源代碼路徑、res 資源目錄。目錄結構以下圖所示:

這裏寫圖片描述

android {

    sourceSets {
        main {
            java.srcDirs('src/test1/java')  //定義java 源代碼
            res.srcDirs('src/test1/res')    //定義資源目錄(layout , drawable,values)
        }
    }
}

SourceSet 實現 layout 分包

對於一個大項目來講,頁面太多,佈局文件就不少,有時在衆多佈局文件中找某個模塊的佈局文件,非常痛苦,爲了解決這個問題,咱們能夠在建立多個 layout 目錄,不一樣模塊的佈局文件放在不一樣的 layout 目錄中,這樣查找起來,就容易不少。

例子:

好比咱們的項目中,有兩個模塊分別爲:登陸、註冊。

  • 第一步:把項目中 layout 文件夾更名字爲 layouts

  • 第二步:在 layouts 目錄下,分別建立 login 、register 目錄 。

  • 第三步:分別在 login 、register 目錄下建立 layout 目錄。注意這一步是必須的,不然會報錯。

  • 第四步:把 登陸佈局文件、註冊佈局文件 分別放在 第三步建立的對應的 layout 目錄下。

效果圖以下:

這裏寫圖片描述

SourceSet 實現以下:

android {
   
    sourceSets {
        main {
            res.srcDirs 'src/main/res/layouts/login'  //定義登陸佈局目錄
            res.srcDirs 'src/main/res/layouts/register'  //定義註冊佈局目錄
        }
    }
}

SourceSet 定義 AndroidManifest 文件

指定 test1 目錄下的 AndroidManifest 文件。項目結構以下圖所示:

這裏寫圖片描述

代碼以下:

android {

    sourceSets {
        main {
            manifest.srcFile 'src/test1/AndroidManifest.xml'
        }
    }
}

在組件化開發中, 咱們須要針對 debug 與 release 模式下, 指定不一樣的 Manifest 文件, 代碼以下:

android {
    def appDebug = false;
    
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            appDebug = false;
        }

        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            appDebug = false;
        }
    }

    sourceSets {
        main {
            if (appDebug) {
                manifest.srcFile 'src/test1/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
            }
        }
    }
}

SourceSet 定義 assets 目錄

Android Studio 項目目錄中,assets 默認目錄以下:

這裏寫圖片描述

如何從新定義 assets 目錄 。在項目的根目錄下建立 assets 目錄,以下圖所示:

這裏寫圖片描述

sourceSets 定義代碼以下:

android {

    sourceSets {
        main {
            assets.srcDirs = ['assets']
        }
    }
}

SourceSet 定義其餘資源

android {

    sourceSets {
        main {
            jniLibs.srcDirs  //定義 jni 目錄
            aidl.srcDirs  //定義 aidl 目錄
        }
    }
}

applicationVariants

定義 versionName 、VersionCode

在打包的時候分 debug 、release 版本 , 須要控制 versionName

android {

     applicationVariants.all { variant ->
        def flavor = variant.mergedFlavor
        def versionName = flavor.versionName
        if (variant.buildType.isDebuggable()) {
            versionName += "_debug"  //debug 名字
        } else {
            versionName += "_release" //release 名字
        }
        flavor.versionName = versionName
    }

}

定義 APK 包的名字

apply plugin: 'com.android.application'

android {

    defaultConfig {
        applicationId "android.plugin"
        minSdkVersion 14
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    //定義渠道
    productFlavors {
        xiaomi {
            //小米
        }
        wandoujia {
            // 豌豆莢
        }
    }

    //打包命名
    applicationVariants.all {
        variant ->
            variant.outputs.each {
                output ->

                    //定義一個新的apk 名字。
                    // 新名字 = app 名字+ 渠道號 + 構建類型 + 版本號 + 當前構建時間
                    def apkName = "appName_${variant.flavorName}_${buildType.name}_v${variant.versionName}_${getTime()}.apk";
                    output.outputFile = new File(output.outputFile.parent, apkName);
            }
    }

}

//獲取當前時間
def getTime() {
    String today = new Date().format('YY年MM月dd日HH時mm分')
    return today
}

效果圖以下:

這裏寫圖片描述

Task

定義 task

//定義任務1
task task1<<{
    println 'task1'
}

//定義任務2
task task2<<{
    println 'task2'
}

mustRunAfter 定義 task 執行順序

//task2 的執行順訊在 task1 以後
task2.mustRunAfter task1
  • 測試1 : gradlew task1

效果以下:

:app:task1
task1
  • 測試2 : gradlew task2

效果以下:

:app:task2
task2
  • 測試3 : gradlew task1 task2

效果以下:

:app:task1
task1
:app:task2
task2
  • 測試4 : gradlew task2 task1

效果以下:

:app:task1
task1
:app:task2
task2

結論

若是單獨執行 task1 就只會執行 task1 的任務;單獨執行 task2 就只會執行 task2 的任務;
若是同時執行 task一、task2 , 必定會先執行 task1 , 等 task1 執行完後,就會執行 task2 內容。

擴展

上面 mustRunAfter 咱們還有一種寫法,以下圖所示:

task2 {}.mustRunAfter task1

這個寫法的效果和 mustRunAfter 是同樣的,固然咱們還能夠在 花括號裏面寫一些任務,好比 :

task2 {
    println '我最早執行'
}.mustRunAfter task1

下面作個測試,測試命令以下:

gradlew task2 task1

效果以下:

我最早執行

:app:task1
task1
:app:task2
task2

dependsOn 定義 task 依賴

task2 任務依賴於 task1 ,執行 task2 就會先執行 task1

task2.dependsOn task1

測試:

gradlew task2

效果以下:

:app:task1
task1
:app:task2
task2

經常使用 Gradlew 命令

  • 一、gradlew -v : 查看版本號
------------------------------------------------------------
Gradle 3.3
------------------------------------------------------------

Build time:   2017-01-03 15:31:04 UTC
Revision:     075893a3d0798c0c1f322899b41ceca82e4e134b

Groovy:       2.4.7
Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM:          1.8.0_112 (Oracle Corporation 25.112-b15)
OS:           Windows 10 10.0 amd64
  • 二、gradlew task : 查看全部的 task

最後給你們分享一份很是系統和全面的Android進階技術大綱及進階資料,及面試題集

想學習更多Android知識,請加入Android技術開發企鵝交流 7520 16839

進羣與大牛們一塊兒討論,還可獲取Android高級架構資料、源碼、筆記、視頻

包括 高級UI、Gradle、RxJava、小程序、Hybrid、移動架構、React Native、性能優化等全面的Android高級實踐技術講解性能優化架構思惟導圖,和BATJ面試題及答案!

羣裏免費分享給有須要的朋友,但願可以幫助一些在這個行業發展迷茫的,或者想系統深刻提高以及困於瓶頸的朋友,在網上博客論壇等地方少花些時間找資料,把有限的時間,真正花在學習上,因此我在這免費分享一些架構資料及給你們。但願在這些資料中都有你須要的內容。

相關文章
相關標籤/搜索