Android Gradle使用總結

来源:http://www.cnblogs.com/zhaoyanjun/archive/2017/09/27/7603640.html
-Advertisement-
Play Games

轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/77678577 本文出自 "【趙彥軍的博客】" 其他 "Groovy 使用完全解析 http://blog.csdn.net/zhaoyanjun6/article/details/7 ...


轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/77678577
本文出自【趙彥軍的博客】

其他

Groovy 使用完全解析 http://blog.csdn.net/zhaoyanjun6/article/details/70313790

Android Gradle

Android項目使用 Gradle 作為構建框架,Gradle 又是以Groovy為腳本語言。所以學習Gradle之前需要先熟悉Groovy腳本語言。

Groovy是基於Java語言的腳本語言,所以它的語法和Java非常相似,但是具有比java更好的靈活性。下麵就列舉一些和Java的主要區別。

Android Gradle 的 Project 和 Tasks

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

Android Gradle 構建生命周期

每次構建的執行本質上執行一系列的Task。某些Task可能依賴其他Task。哪些沒有依賴的Task總會被最先執行,而且每個Task只會被執行一遍。每次構建的依賴關係是在構建的配置階段確定的。每次構建分為3個階段:

  • Initialization: 初始化階段

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

所以這個文件裡面的內容經常是:

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

這是告訴Gradle這些項目需要編譯,所以我們引入一些開源的項目的時候,需要在這裡填上對應的項目名稱,來告訴Gradle這些項目需要參與構建。

  • Configuration:配置階段

這個階段,通過執行構建腳本來為每個project創建並配置Task。配置階段會去載入所有參與構建的項目的build.gradle文件,會將每個build.gradle文件實例化為一個Gradle的project對象。然後分析project之間的依賴關係,下載依賴文件,分析project下的task之間的依賴關係。

  • 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
        }
    }
}

依賴管理

1、依賴 jcenter 包

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

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

2、依賴本地 module

 compile project(':YibaAnalytics')
 

3、依賴 jar 包

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

這裡寫圖片描述

4、依賴 aar 包

  • 1、把 aar 包放到 libs 目錄下
  • 2、在 build.gradle 中添加依賴

repositories {
    flatDir {
        dirs 'libs'
    }
}

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

如圖所示:

這裡寫圖片描述

5、自定義依賴包目錄

當我們的 aar 包需要被多個 module 依賴時,我們就不能把 aar 包放在單一的 module 中,我們可以在項目的根目錄創建一個目錄,比如叫 aar 目錄,然後把我們的 aar 包放進去,如圖所示:

這裡寫圖片描述

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


 flatDir {
     dirs '../aar'
}

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

如圖所示:

這裡寫圖片描述

然後就可以添加依賴了,如下所示:


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

6、依賴配置

有些時候,你可能需要和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 的任務;
如果同時執行 task1、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 命令

  • 1、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

  • 2、gradlew task : 查看所有的 task

參考資料

Android 利用Gradle實現差異化構建

楊海 Android目錄結構


個人微信號:zhaoyanjun125 , 歡迎關註


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、webstrom 11.0.3下載地址1:http://pan.baidu.com/s/1kVQjcwf 密碼:uggr 下載地址2:http://pan.baidu.com/s/1kVQjcwf,點擊DOWNLOAD即可下載 2、webstrom11激活 選擇“license server” ...
  • 網頁title旁邊的小圖片設置,圖片格式必須是.ico ...
  • 一、jQuery 中的常用函數 1) $.map(Array,fn); 對數組中的每個元素,都用fn進行處理,fn將處理後的結果返回,最後得到一個數組 2) $.each(Array,fn); 對數組中的每個元素,調用fn這個函數進行處理,但是,沒有返回值,比上例更常用 二、jQuery 對象和Do ...
  • 最近在前端開發中,遇到一個JavaScript 的問題。 用Chrome,Firefox,運行結果正常。但是在IE裡面確出現了"對象不支持find屬性或方法"的錯誤. 看了下官方文檔才發現他是不支持IE的。https://developer.mozilla.org/en-US/docs/Web/Ja ...
  • 轉自博客園: 現在有一個數據,需要你渲染出對應的列表出來: var data = [ {"id":1}, {"id":2}, {"id":3}, {"id":4}, ]; var str="<ul>"; data.forEach(function(v,i){ str+="<li><span>"+v. ...
  • XMLHttpRequest對象 一、XMLHttpRequest對象 1.Ajax能夠是實現非同步傳輸,所依賴的就是JavaScript中的XMLHttpRequest 2.XMLHttpRequest對象是XMLHttp組件的對象,它是一個抽象對象,允許腳本從伺服器獲取返回的eXML數據或將數據發 ...
  • Https系列會在下麵幾篇文章中分別作介紹: 一:https的簡單介紹及SSL證書的生成二:https的SSL證書在伺服器端的部署,基於tomcat,spring boot三:讓伺服器同時支持http、https,基於spring boot四:https的SSL證書在Android端基於okhttp ...
  • 本文介紹了Android下三種獲取FPS的方法,在調試及優化Android性能時可做參考。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...