一套代碼打包多個項目這一篇就夠了

最近在做項目制的開發(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權威指南》

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容