版本的統一管理
當我們的工程中有許多module的時候,分開管理編譯版本,minsdk將會是一件很麻煩的事,因為一個library的改動,可能會影響到其他module。這時我們就需要對所有的版本進行統一的管理,管理的方式有兩種:
rootProject
我們可以把一些需要用的欄位都放在project的build.gradle(注意是project的不是module的)中:
ext {
compileSdk = 21
minSdk = 11
targetSdk = 23
support = "23.1.1"
buildTools = "21.0.1"
buildstyle ="debug"
}複製程式碼
這樣,在module的build.gradle中可以進行讀取:
defaultConfig {
applicationId "android.com.testgradle"
minSdkVersion rootProject.ext.minSdk
targetSdkVersion rootProject.ext.targetSdk
versionCode 1
versionName "1.0"
}複製程式碼
gradle.properties
找到工程目錄下的gradle.properties檔案,如果沒有也可以自己建立:
ANDROID_COMPLILE_SDK_VERSION=21
ANDROID_BUILD_SDK_VERSION=21.0.1
ANDROID_TEXT=test複製程式碼
然後在各個module的build.gradle中可以引用:
compileSdkVersion ANDROID_COMPLILE_SDK_VERSION as int
buildToolsVersion ANDROID_BUILD_SDK_VERSION複製程式碼
需要注意的是在gradle.properties中宣告的格式都是string型別,如果如要轉化成int型別,可以用as int 進行強制轉化。
#程式中對buildTypes的區分
##buildTypes是對不同build型別的處理
當你點選執行按鈕的時候會根據build Variant進行對應的方式編譯。
build Variant可以在這裡進行選擇:
library的buildTypes
預設情況下被依賴工程會使用release模式,與上層依賴的app工程選擇的模式無關
需要在build.gradle中進行設定:
defaultPublishConfig "debug"複製程式碼
新增buildTypes
你可以在buildTypes,根據需要新增一個型別,如下程式碼所示:
buildTypes {
debug {
buildConfigField("String","TEXT","\"這個字串來自debug模式\"")
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
stag {
buildConfigField("String","TEXT","\"這個字串來自test模式\"")
minifyEnabled false
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
buildConfigField("String","TEXT","\"這個字串來自release模式\"")
minifyEnabled false
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}複製程式碼
不同模式字元不同
根據上面的程式碼,在不同的buildTypes中,TEXT這個變數是不一樣的,而且根據程式碼可以看出,這個變數是一個String型別,那麼我們在程式檔案中可以這樣通過BuildConfig引用:
t2.setText(BuildConfig.TEXT);複製程式碼
Variant
gradle外掛允許最終生成的包以多個維度進行組合
例如我們可以設定一下幾個維度:
productFlavors {
red {
applicationId 'android.com.red'
versionCode 1
minSdkVersion 21
targetSdkVersion 22
}
blue {
applicationId 'android.com.blue'
}
yellow {
applicationId 'android.com.yellow'
}
}複製程式碼
每個維度中可以設定這個版本的最小sdk限制,以及targetsdkversion
假設我們設定的維度有red blue yellow但是結合之前講過的buildType(假設只有debug和release)
那麼將會出現以下構建:
blueDebug和blueRelease
yellowDebug和yellowRelease
redDebug和redRelease
Gradle會為每一個Variant建立一個任務
對應如下:
gradle assembleBlue 會生成debug和release兩個版本
gradle assembleDebug 會生成blue yellow red三個版本
gradle assembleBlueDebug 會生成bluedebug一個版本
這裡還有一個用處需要提一下:
Gradle在打包android應用之前會將所有的程式碼,資原始檔,包括manifest進行結合,當然library也會提供額外的資源,這些也會進行合併。
字串讀取
如果我們在建立一些設定時,需要動態的去更改內容,可以設定一個變數,然後從本地檔案或者打包的命令列讀取,我們這裡就拿上面提到過的BuildConfig做例子,希望程式中引用的字串是從本地讀取的或從命令列讀取的
從本地檔案中讀取
首先需要在最開始的地方設定一個變數aaa:
然後在buildTypes的debug模式中修改對應的程式碼:
debug {
buildConfigField("String","TEXT","\""+aaa+"\"")
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}複製程式碼
然後在工程目錄下建立一個本地檔案test.properties,並新增內容:
然後回到你剛才定義字串的build.gradle中,新增:
if(rootProject.file('test.properties').exists()){
java.util.Properties properties = new Properties()
properties.load(rootProject.file('test.properties').newDataInputStream())
aaa = properties.getProperty('debug.text')
println("!!!!!"+aaa)
}else {
aaa = "檔案沒找到"
}複製程式碼
即可讀取到你本地檔案的字串
從命令列讀取
如果是從命令列讀入就更加簡單,只需要將上面讀取檔案的程式碼改為:
aaa = new String(System.console().readLine("請輸入字串:"))複製程式碼
編譯命令
首先想看一個工程包含了多少task,需要切到這個工程目錄下:
gradle tasks複製程式碼
會列出所有的tasks:
當然篇幅有限,這裡不貼出所有的任務了,我們只需要知道編譯命令即可,如圖可以看到,如果想編譯debug版本,使用:
assembleDebug複製程式碼
其它同理即可。
如果使用build則回編譯出所有的版本
衝突問題
在執行打包的時候很有可能會出現如上問題,這是由於依賴的jar衝突問題,我們可以分析一下工程結構。
我現在的結構是:
現在調整一下結構:
把jar以module的形式提供就不會出現衝突。
編譯流程
Task任務
執行順序
例如我們新建一個任務:
task umengtest{
println("aaaaaaaaa")
println("bbbbbb")
}複製程式碼
他的執行如下:
它並不是在執行任務的時候執行的,而是在執行任務之前就列印了。
這是由於gradle構建有三個階段:
初始化階段,配置階段,執行階段。
上面的例子實際是列印在了配置階段,換句話說,你不執行這個任務,執行這個工程別的任務也會列印。
例如我再寫一個任務:
task umengtestaa<<{
println("ccc")
println("dddd")
}複製程式碼
這次執行這個任務:
你會發現也列印aaaa這說明這不是在真正的執行階段執行的,為了保證任務的可控性,可以像上面umengtestaa那樣寫加一個<<符號
這樣就可以保證了任務的可控性:
或者使用:
task umengtest{
doLast{
println("aaaaaaaaa")
println("bbbbbb")
}
}複製程式碼
打包任務
有了上面的基礎,下面就可以說一下打包的任務了,根據我們之前的工程,我們有一個app的module和四個library module,我需要列印出一個apk和四個jar,明確了任務,現在可以開始實施了。
開啟工程的build.gradle
def sdk = [
root : 'build/sdk/',
]task dabao( type:Zip) {
dependsOn('cp_main')
def name = 'umeng_test' ;
destinationDir = file('build')
archiveName = name + '.zip'
from('build/sdk') {
into( name )
}
}
task cp_main(type: Copy, dependsOn: ['app:assembleRelease'] ) {
destinationDir = file( sdk.root )
from('app/build/outputs/apk') {
include('app-release.apk')
rename ('app-release.apk','test.apk' )
into('.')
}
from('mylibrary1/build/intermediates/bundles/release') {
include('classes.jar')
rename ('classes.jar','library1.jar' )
into('.')
}
from('mylibrary2/build/intermediates/bundles/release') {
include('classes.jar')
rename ('classes.jar','library2.jar' )
into('.')
}
from('mylibrary3/build/intermediates/bundles/release') {
include('classes.jar')
rename ('classes.jar','library3.jar' )
into('.')
}
from('mylibrary4/build/intermediates/bundles/release') {
include('classes.jar')
rename ('classes.jar','library4.jar' )
into('.') }
}複製程式碼
這時,我們再去找一下工程的build資料夾下可以發現:
打包不同內容的module
打包不同內容的module可以利用之前講過的variant或這個buildtypes來控制,這裡就不說了,不明白的,可以回頭再去看一下結合上面的打包指令碼沒有什麼難度,然而還有一種需求,不是某個變數或者包名的更改,而是兩個版本中兩個檔案的不同,我們可以試一下修改variant的方式來實現,在app的build.gradle中:
productFlavors {
pay {
}
free {
}
}複製程式碼
修改結構目錄:
這樣編譯出來就會有兩個不同型別的apk了
防止打包錯誤
在這裡已經說完了所有與打包相關的東西了,在最後仍然加這一個標題是交給大家如何防止專案開發者打包出錯,或者上傳包出錯後定位問題。
方法就是在打包的時候,生成一個記錄檔案,在這個包中記錄打包時間,和當前git的版本號:
def releaseTime() {
return new Date().format("yyyyMMddHHmmss", TimeZone.getTimeZone("GMT+8"))
}
def getGitVersion() {
return 'git rev-parse --short HEAD'.execute().text.trim()
}
task writefile( ){
File configFile = new File('config.xml');
if (!configFile.exists()){
configFile.createNewFile()
}
FileOutputStream out =new FileOutputStream(configFile)
def result ="編譯時間:"+"${releaseTime()}\n"+"commitid:"+"${getGitVersion()}\n" out.write(result.getBytes())
out.close();
}
task cp_config(type: Copy, dependsOn: ['writefile'] ) {
destinationDir = file( sdk.root )
duplicatesStrategy = 'exclude'
includeEmptyDirs = false
from('.') {
include('config.xml')
into('.')
}
}複製程式碼
以上工程中所用到的所有程式碼,已經上傳github
地址如下:
github.com/mymdeep/And…
如有對groovy語法不清楚的看官,請看一下我的上一篇文章,groovy基礎知識:
www.jianshu.com/p/b58b254d8…
*更多的開發知識,可以關注我的公眾號: