專案實戰之gradle在實際專案中的使用

小劉哥可愛多發表於2018-05-09

前言

本文作為實戰系列,主要講解gradle在實際專案中的使用,原理部分不會講解太多。本文會用到一些Groovy的知識,如果不瞭解Groovy基礎語法的話可以參考一下主席的文章Groovy基礎Gradle執行時序。當然我也會對使用到的地方做註解說明,就算你不看的話,也行。

1、統一依賴管理

這裡主要是說專案的編譯版本、依賴庫的版本等,這裡參考Google官方的專案,在專案的根目錄單獨建一個version.gradle檔案統一管理版本,這樣做的好處明顯,特別是多module的專案,很方便的做統一版本管理,避免衝突。但是這樣做也會帶來一個壞處,就是你inspection檢查新版本的時候,當有了新版本的話,你是檢查不到的。不過總體來說,利大於弊吧。

來看一看version.gradle檔案裡都有些什麼吧

 // version.gradle檔案
ext{
android = [
        compileSdkVersion: 27,
        minSdkVersion    : 21,
        targetSdkVersion : 27,
        versionName: "1.0.0"
    ]
dependencies = [
        appcompatV7 : 'com.android.support:appcompat-v7:27.1.1',
        design      : 'com.android.support:design:27.1.1',
        constrant :'com.android.support.constraint:constraint-layout:1.0.2'
    ]
}
複製程式碼

這裡作為說明,只寫了幾個最基本的依賴,接下來就是要使用這些配置了。首先在project的build.gradle檔案裡引入

buildscript {
    apply from: 'version.gradle'
    repositories {
        google()
        jcenter()
    }
    …………
}
複製程式碼

然後,在module的gradle裡就可以愉快的使用了。

compileSdkVersion rootProject.ext.android.compileSdkVersion
defaultConfig {
    minSdkVersion rootProject.ext.android.minSdkVersion
    targetSdkVersion rootProject.ext.android.targetSdkVersion
    versionCode getCode()
    versionName rootProject.ext.android.versionName
    …………
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation rootProject.ext.dependencies.appcompatV7
    implementation rootProject.ext.dependencies.constrant
    implementation rootProject.ext.dependencies.design
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'

}
複製程式碼

2、根據versionName 自動生成versionCode

細心的小夥伴可能發現了,上面的versionCode並沒有使用version.gradle裡配置的versionCode,事實上version.gradle裡也並沒有配置versionCode,這裡我是根據產品需求使用versionName自動生成的versionCode。

// 讀取version.gradle裡的versionName 生成versionCode
def getCode() {
    String name = rootProject.ext.android.versionName
    List arr = name.tokenize('.')
    int code1
    int code2
    int code3
    code1 = arr.get(0).toInteger() * 10000
    code2 = arr.get(1).toInteger() * 100
    code3 = arr.get(2).toInteger()
    int code = code1 + code2 + code3
}
複製程式碼

上面就是獲取版本號的方法,採用三段式,每段兩位,可以根據實際需求自己改。另外說明一下,Groovy語法裡,如果自己不寫return語句,會把最後一行計算的code自動return。這樣的話,就不用每次版本升級要修改versionName還要修改versionCode了。注意上面的程式碼是在android的同級領域。

3、優雅的簽名設定

簽名檔案怎麼生成這裡就不說了,需要說明的是為了方便引用,jks簽名檔案我放在了app目錄下,同樣在這個目錄下,建立了一個signing.properties的檔案,檔案內容如下:

// signing.properties 檔案
storePass=123456
alias=key
keyPass=123456
v2SigningEnabled=false
signingFile=key.jks
複製程式碼

就是基本的簽名資訊了,看一下module的gradle裡的使用:

signingConfigs {
    // 定義signConfig並賦值
    signConfig
    File propFile = file('signing.properties')
    if (propFile.exists()) {
        Properties props = new Properties()
        props.load(new FileInputStream(propFile))
        if (props.containsKey('signingFile') && props.containsKey('storePass') &&
                props.containsKey('alias') && props.containsKey('keyPass') && props.containsKey("v2SigningEnabled")) {
            signConfig.storeFile = file(props['signingFile'])
            signConfig.storePassword = props['storePass']
            signConfig.keyAlias = props['alias']
            signConfig.keyPassword = props['keyPass']
            android.signingConfigs.signConfig.v2SigningEnabled = props['v2SigningEnabled']
        } else {
            android.buildTypes.release.signingConfig = null
            android.buildTypes.flavor.signingConfig = null
        }
    } else {
        android.buildTypes.release.signingConfig = null
        android.buildTypes.flavor.signingConfig = null
    }
    print("signingConfigs===========${signConfig}")
}
複製程式碼

就是定義一個signConfig 並給賦值了,很簡單。但是這樣寫就避免了直接在gradle裡暴露簽名資訊了。當然你可以在terminal裡執行一下gradle guild指令來驗證,看一下列印結果是否正確。

配置完以後,直接在buildTypes裡引用就行了。

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

4、自定義BuildConfig

實際開發中伺服器一般有正式環境和生成環境,有時候還會有個後臺開發人員自己本地的伺服器環境,這時候通過自定義buildConfigField來區分配置不同的環境

release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.signConfig
        buildConfigField "boolean","isRelease","true"
        …………
    }
複製程式碼

我們在release的type裡把值設定為true,其他的type設定為fasle,這樣,同步完以後,在BuildConfig類裡會多出一個靜態變數isRelease,這樣在java程式碼裡,就可以根據這個變數來判斷是測試環境還是生產環境了,還可以根據這個變數來控制是否需要日誌輸出等。甚至你都可以直接把測試伺服器地址和生產伺服器地址配置到裡面都行。

buildConfigField 'String','API_SERVER_URL','"http://lxy.v1/"'
複製程式碼

5、不同的版本配置不同的包名和AppName

實際開發中,為了區分測試版和正式版,有時候需要把測試版的包名和app名字設定為不同。其實這樣的需求用gradle分分鐘就可以實現

release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.signConfig
        buildConfigField "boolean","isFlavor","false"
        manifestPlaceholders = [
                APP_NAME           : "release"
        ]
    }

    debug {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.signConfig
        buildConfigField "boolean","isFlavor","false"
        applicationIdSuffix 'debug'
        manifestPlaceholders = [
                APP_NAME           : "debug"
        ]
    }
複製程式碼

如上,在debug版裡,配置了applicationIdSuffix 'debug',這樣打包的話,會在原來的包名後面加上debug,這樣安裝到手機上就是兩個不同的app了,因為包名不同。這樣一個測試機就可以同時測試測試包和正式包了。而且,還設定了manifestPlaceholders佔位符,這樣在menifests檔案裡直接引用就行,就實現了不同的包名和app名字。

// 清單檔案裡引用
android:label="${APP_NAME}"
複製程式碼

這裡有個坑,如果這樣配置過後,如果你專案裡使用有微信支付、分享等的sdk,注意支付、分享後的回撥的類所在的包和正式版分開,否則是收不到回撥的(微信的sdk有時候很蛋疼)。

6、自定義打包apk的檔名

在android的領域裡新增如下程式碼

applicationVariants.all { variant ->
    variant.outputs.all { output ->
        def newApkName
        newApkName = getTime() + defaultConfig.versionName + "-" + defaultConfig.versionCode + ".apk"
        outputFileName = newApkName
    }
}
複製程式碼

getTime()方法在android領域的同級

def getTime() {
     return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}
複製程式碼

7、java8和dataBinding的支援

java8的lambda還是很簡潔的,同樣,dataBinding用起來一樣爽飛

// 當然在android領域裡設定了
 
 dataBinding {
    enabled = true
}

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
複製程式碼

8、自定義jinlibs目錄

現在新建as專案會自動在app目錄下生成一個libs目錄,可以在gradle裡設定jar、so庫等的檔案目錄

sourceSets {
    main {
        jniLibs.srcDirs = ['libs']
    }
}
複製程式碼

9、混淆、多渠道打包等其他配置

混淆配置的話配置在release版本里,注意別忘了新增混淆檔案

minifyEnabled true
zipAlignEnabled true
shrinkResources true
複製程式碼

用gradle打包多渠道的話比較慢,這裡就不講了,個人感覺360多渠道打包挺好用的,推薦一下。

以上是實際專案裡常用的配置,當然還有很多不太常用的配置,如可能需要打包aar到maven,gradle編譯、gradle效能檢測、gradle加速、使用gradle快取,自定義gradle外掛等等,篇幅問題,大家自己學習了……

附上完整的demo地址,如果對你有幫助,麻煩start鼓勵一下!

相關文章