最近在做項目制的開發(fā),有一套開發(fā)好的產品原型的代碼,然后根據不同的客戶進行不同的定制開發(fā)。如果一個項目搞一個分支,要多開多個as,還有一個缺點就是如果產品原型的代碼進行了變更和優(yōu)化,所有的項目分支都要將產品修改后果的代碼復制轉移一次,麻煩!
build.gradle可以幫我們解決這個問題。
一.先來講重點,配置變種:
1.在android { } 中增加如下代碼,適用于as建立的項目,eclipse轉換過來的項目需要增加sourceSets {}
? ? // 維度組合,productFlavors中不同種類的dimension可以組合,名字根據實際需要自己取
? ? flavorDimensions "mode", "channel"
? ? productFlavors {
? ? ? ? trunk {
? ? ? ? ? ? // 維度小組名稱
? ? ? ? ? ? dimension "mode"
? ? ? ? ? ? // 修改項目包名,在清單文件中的包名后增加后綴;
? ? ? ? ? ? // 也可以使用applicationId "com.xx.xx" 替換掉默認的包名
? ? ? ? ? ? applicationIdSuffix ".trunk"
? ? ? ? ? ? // 編譯后會自動生成在BuildConfig.java中,代碼中通過使用BuildConfig.IPADRESS獲取后面的值
? ? ? ? ? ? // 參數規(guī)則“String”表示參數類型,也可以是boolean等,"IPADRESS"是常量名稱,最后一個是內容
? ? ? ? ? ? buildConfigField "String", "IPADRESS", "\"192.168.x.xx:8080\""
? ? ? ? ? ? // 還可以增加各種不同的配置,defaultConfig中配置這里都可以用,重復的配置這里的會覆蓋掉defaultConfig
? ? ? ? }
? ? ? ? guiyang {
? ? ? ? ? ? dimension "mode"
? ? ? ? ? ? applicationIdSuffix ".guiyang"
? ? ? ? ? ? buildConfigField "String", "IPADRESS", "\"192.168.x.xx:8082\""
? ? ? ? }
? ? ? ? huawei{
? ? ? ? ? ? dimension "channel"
? ? ? ? ? ? // 給清單文件中的渠道占位符賦值
? ? ? ? ? ? manifestPlaceholders = [CHANNEL_VALUE:"huawei"]
? ? ? ? }
? ? ? ? xiaomi{
? ? ? ? ? ? dimension "channel"
? ? ? ? ? ? manifestPlaceholders = [CHANNEL_VALUE:"xiaomi"]
? ? ? ? }
2.在工程目錄中新增如下目錄
如果productFlavors中沒有main:main為默認目錄,每個組合都會含有main中的代碼;
如果productFlavors中有main:main也相當于一個風味,不會和trunk合并(根據實際需要,trunk既可以是main的擴展也可以和main平級,完全看自己怎么配置)
trunk和guiyang(注意:文件夾名稱要和productFlavors中的名字對應)中放各個定制項目中的差異代碼,其下的目錄結構文件非必須,如果需要修改main中的資源或新增代碼,就在各自項目中增加對應的文件夾和文件,如果沒有修改可以只有個主目錄
trunk/guiyang和main中的文件合并規(guī)則如下:
圖片、音頻、 XML 類型的 Drawable ,layout等資源文件,將會進行文件級的覆蓋
字符串、顏色值、整型等資源以及 AndroidManifest.xml ,將會進行元素級的覆蓋
代碼資源,同一個類, buildTypes 、 productFlavors 、 main 中只能存在一次,否則會有類重復的錯誤
覆蓋等級為:buildTypes > productFlavors > main
3.配置后在as左下角Build Variants中可以看到如下組合,維度組合2*2,每個組合再分debug和release,共8種
選中哪一個就會編譯哪一個,維度數量根據自己需要可以減少,也可以增加
4.依賴庫也可以根據風味進行不同的依賴
編譯用的第三方庫。例如我們的app在某些情況下有地圖功能,有些情況下沒有,如果我們在代碼里控制有沒有這個功能那么它依賴的包還是會打入apk,這樣就會造成大量無用的代碼進入apk中。
現在不同的變種風味有不同的依賴,dependencies {}中可以這樣寫:
compile 'xxx'? // 所有的項目都依賴
trunkCompile 'yyy'? // 只有trunk項目依賴
trunkCompile 'zzz' // 只有trunk項目依賴
guiyangCompile 'yyy' // 只有guiyang項目依賴
implementation也可以這樣用
5.eclipse轉換過來的項目,需要多一步
sourceSets {
? ? ? ? main {
? ? ? ? ? ? manifest.srcFile 'AndroidManifest.xml'
? ? ? ? ? ? java.srcDirs = ['src']
? ? ? ? ? ? resources.srcDirs = ['src']
? ? ? ? ? ? aidl.srcDirs = ['src']
? ? ? ? ? ? renderscript.srcDirs = ['src']
? ? ? ? ? ? res.srcDirs = ['res']
? ? ? ? ? ? assets.srcDirs = ['assets']
? ? ? ? ? ? jniLibs.srcDirs = ['libs']
? ? ? ? }
? ? ? ? trunk {
? ? ? ? ? ? java.srcDirs = ['src-trunk']
? ? ? ? ? ? res.srcDirs = ['res-trunk']
? ? ? ? }
? ? ? ? guiyang{
? ? ? ? ? ? java.srcDirs = ['src-guiyang']
? ? ? ? ? ? res.srcDirs = ['res-guiyang']
? ? ? ? }
}
sourceSets中主要指定代碼目錄,因為eclipse的目錄結構和as不一樣,as自動識別main下面的代碼,需要通過sourceSets將eclipse的目錄和as的目錄進行對應
as中如果有特殊需要,也可以通過這種方式指定目錄
二.重點講完了,下面記一下build.gradle中各個配置的說明
apply plugin: 'com.android.application'
android {
? ? compileSdkVersion 27
? ? // 默認配置,還有很多配置屬性,參照gradle API
? ? // 相當于所有productFlavor的父類,自建productFlavor中沒有的都使用這個里面的,有的就覆蓋
? ? defaultConfig {
? ? ? ? applicationId "com.example.xxx.gradledemo"
? ? ? ? minSdkVersion 14
? ? ? ? targetSdkVersion 27
? ? ? ? versionCode 1
? ? ? ? versionName "1.0"
? ? ? ? testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
? ? }
? ? // 簽名的配置
? ? // productFlavor的屬性,在所有的productFlavor都可以使用,一般用在buildTypes中,覆蓋登記最高
? ? signingConfigs {
? ? ? ? realse { // 這個名字隨意取,在buildTypes中通過signingConfigs. 調用
? ? ? ? ? ? storeFile file("gradle_demo.jks")
? ? ? ? ? ? storePassword "xxxxxx"
? ? ? ? ? ? keyAlias "xxx"
? ? ? ? ? ? keyPassword "xxxxxx"
? ? ? ? }
? ? }
? ? // 相當于一個維度dimension(隱藏有一個debug),和productFlavors中的風味進行組合
? ? buildTypes {
? ? ? ? // 也是一個productFlavor
? ? ? ? // 一般增加這個風味是為了不同的簽名需要,還有很多配置屬性,參照gradle API
? ? ? ? // release,debug中的buildConfigField會覆蓋productFlavors中同名字的
? ? ? ? release {
? ? ? ? ? ? signingConfig signingConfigs.realse
? ? ? ? ? ? buildConfigField "boolean", "ISSHOW", "false"
? ? ? ? ? ? // 是否減小apk體積,打開混淆
? ? ? ? ? ? minifyEnabled true
? ? ? ? ? ? // 混淆文件的配置文件,getDefaultProguardFile('proguard-android.txt')是默認的,在SDK的tools/proguard目錄下可以找到
? ? ? ? ? ? // proguard-rules.pro是自定義
? ? ? ? ? ? proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
? ? ? ? }
? ? }
? ? // 設置java的編譯版本,通常是為了使用某些版本中的一些語言新特性
? ? // 一般不用設置
? ? /*compileOptions {
? ? ? ? sourceCompatibility JavaVersion.VERSION_1_8
? ? ? ? targetCompatibility JavaVersion.VERSION_1_8
? ? }*/
? ? // 編譯時加速,lint檢查有錯誤時繼續(xù)打包,不影響使用,最好是把lint錯誤全部修改
? ? // 還有很多配置屬性,參照gradle API
? ? /*lintOptions {
? ? ? ? abortOnError false // 如果發(fā)現錯誤,lint是否停止打包
? ? }*/
? ? // 維度組合,productFlavors中不同種類的dimension可以組合,名字根據實際需要自己取
? ? flavorDimensions "mode", "channel"
? ? productFlavors {
? ? ? ? // 一個productFlavor
? ? ? ? trunk {
? ? ? ? ? ? // 維度小組名稱
? ? ? ? ? ? dimension "mode"
? ? ? ? ? ? // 修改項目包名,在清單文件中的包名后增加后綴;
? ? ? ? ? ? // 也可以使用applicationId "com.xx.xx" 替換掉默認的包名
? ? ? ? ? ? applicationIdSuffix ".trunk"
? ? ? ? ? ? // 編譯后會自動生成在BuildConfig.java中,代碼中通過使用BuildConfig.IPADRESS獲取后面的值
? ? ? ? ? ? // 參數規(guī)則“String”表示參數類型,也可以是boolean等,"IPADRESS"是常量名稱,最后一個是內容
? ? ? ? ? ? buildConfigField "String", "IPADRESS", "\"192.168.3.23:8080\""
? ? ? ? ? ? // 還可以增加各種不同的配置,defaultConfig中配置這里都可以用,重復的配置這里的會覆蓋掉defaultConfig
? ? ? ? }
? ? ? ? guiyang {
? ? ? ? ? ? dimension "mode"
? ? ? ? ? ? applicationIdSuffix ".guiyang"
? ? ? ? ? ? buildConfigField "String", "IPADRESS", "\"192.168.8.47:8082\""
? ? ? ? }
? ? ? ? huawei{
? ? ? ? ? ? dimension "channel"
? ? ? ? ? ? // 給清單文件中的渠道占位符賦值
? ? ? ? ? ? manifestPlaceholders = [CHANNEL_VALUE:"huawei"]
? ? ? ? }
? ? ? ? xiaomi{
? ? ? ? ? ? dimension "channel"
? ? ? ? ? ? manifestPlaceholders = [CHANNEL_VALUE:"xiaomi"]
? ? ? ? }
? ? }
? ? /*sourceSets {
? ? ? ? trunk {
? ? ? ? ? ? res.srcDirs = ['src/trunk/res']
? ? ? ? ? ? manifest.srcFile 'src/trunk/AndroidManifest.xml'
? ? ? ? }
? ? ? ? guiyang {
? ? ? ? ? ? res.srcDirs = ['src/guiyang/res']
? ? ? ? ? ? manifest.srcFile 'src/guiyang/AndroidManifest.xml'
? ? ? ? }
? ? }*/
}
dependencies {
? ? implementation fileTree(dir: 'libs', include: ['*.jar'])
? ? implementation 'com.android.support:appcompat-v7:27.1.1'
? ? implementation 'com.android.support.constraint:constraint-layout:1.1.3'
? ? 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'
}
buildConfigField配置的數據在BuildConfig.java中,由as自動生成
在這個目錄下面
三.build.gradle中的一些參數使用公用資源文件,主要是一些編譯版本和jar包版本,modle和主工程都要用到的需要統(tǒng)一的
1.可以在根目錄的build.gradle文件中增加ext{ },或者新建一個.gradle文件,然后引入到根目錄的build.gradle
根目錄下build.gradle 增加
ext {
? ? CompileSdkVersion = 27
? ? BuildToolsVersion = "27.0.3"
? ? MinSdkVersion = 14
? ? TargetSdkVersion = 27
}
主工程和modle的build.gradle中這樣使用
android {
? ? compileSdkVersion rootProject.ext.compileSdkVersion
? ? buildToolsVersion rootProject.ext.buildToolsVersion
? ? defaultConfig {
? ? ? ? applicationId "com.example.xxx.gradledemo"
? ? ? ? minSdkVersion rootProject.ext.minSdkVersion
? ? ? ? targetSdkVersion rootProject.ext.targetSdkVersion
? ? ? ? versionCode 1
? ? ? ? versionName "1.0"
? ? ? ? testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
? ? }
或者在任意地方新建xxx.gradle,然后引入到根目錄下build.gradle(在根目錄中增加 apply from : 'xxx.gradle',需要根據xxx.gradle路徑寫)
ext{
? ? // 可以直接用
? ? /*compileSdkVersion = 27
? ? buildToolsVersion = "27.0.3"
? ? minSdkVersion = 14
? ? targetSdkVersion = 27*/
? ? // 也可以外面套一層
? ? android = [
? ? ? ? ? ? compileSdkVersion : 27,
? ? ? ? ? ? buildToolsVersion : "27.0.3",
? ? ? ? ? ? minSdkVersion : 14,
? ? ? ? ? ? targetSdkVersion : 27
? ? ]
? ? dependencies = [
? ? ? ? ? ? appcompatV7 : 'com.android.support:appcompat-v7:27.1.1',
? ? ? ? ? ? constraintVersion : 'com.android.support.constraint:constraint-layout:1.1.3'
? ? ]
}
主工程和modle的build.gradle中這樣使用
android {
? ? compileSdkVersion rootProject.ext.android.compileSdkVersion
? ? buildToolsVersion rootProject.ext.android.buildToolsVersion
? ? defaultConfig {
? ? ? ? applicationId "com.example.zhangchi.gradledemo"
? ? ? ? minSdkVersion rootProject.ext.android.minSdkVersion
? ? ? ? targetSdkVersion rootProject.ext.android.targetSdkVersion
? ? ? ? versionCode 1
? ? ? ? versionName "1.0"
? ? ? ? testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
? ? }
? ? dependencies {
? ? ? ? implementation fileTree(dir: 'libs', include: ['*.jar'])
? ? ? ? implementation rootProject.ext.dependencies.appcompatV7
? ? ? ? implementation rootProject.ext.dependencies.constraintVersion
? ? ? ? testImplementation 'junit:junit:4.12'
? ? }
}
2.可以在gradle.properties中增加(一般放敏感信息,比如打包用的簽名信息)
? ? 在gradle.properties中添加敏感數據
#簽名文件寫實際路徑
STOREFILE=../gradle_demo.jks?
STOREPASSWORD=xxxxxx
KEYALIAS=xxx
KEYPASSWORD=xxxxxx
主工程的build.gradle中這樣使用
realse {
? ? ? ? ? ? storeFile file(STOREFILE)
? ? ? ? ? ? storePassword STOREPASSWORD
? ? ? ? ? ? keyAlias KEYALIAS
? ? ? ? ? ? keyPassword KEYPASSWORD
? ? ? ? }
四.gradle命令打包
1.Gradle配置(配不配置都行)
下載地址http://services.gradle.org/distributions/
下載你所需要的gradle版本,帶all的,gradle-4.5-all.zip
下載后解壓到你想要的目錄
設置環(huán)境變量
新建系統(tǒng)變量:GRADLE_HOME,值為grdle路徑
設置后測試是否配置成功
在as的Terminal工具欄中:
使用gradlew命令使用的是項目使用的gradle版本,使用gradle命令使用的是環(huán)境變量中配的gradle版本
多變種使用命令打包的命令:gradlew assembleGuiyangHuaweiRelease
gradle assemble維度組合名稱(每個風味首字母大寫)buildType下面的名字(首字母大寫)
注:本篇博客純屬個人筆記,如果錯誤之處,還望幫忙指正,謝謝!
? ? ? 如果想了解的更詳細,可以讀一本書籍《Android Gradle權威指南》