Android 模組化過程中的多渠道編譯

你的專案在模組化,業務程式碼抽到了獨立的library中

你的library程式碼中需要透過BuildConfig。FLAVOR區分業務,例如: if (BuildConfig。FLAVOR。equals(“weipos”)) { // weipos related source } else { // }

首先,我先把目前的解決方案放出來。

目前專案中,我們有很多渠道,這裡主要關注一下專案中接入的POS機渠道 - iboxpay、sunmi、weipos,在我們的業務程式碼中,需要根據不同的flavor去區分實現不同的功能。

在主工程的build。gradle檔案中,我們定義瞭如下幾種flavor:

productFlavors { def customFlavors = getCustomFlavors() if (customFlavors instanceof List) { customFlavors。each { flavor -> “$flavor”{ } } } full { buildConfigField“boolean”,“POS”,“false” buildConfigField“String”,“DEVICE_TYPE”,“\”android\“” } iboxpay { buildConfigField“boolean”,“POS”,“true” buildConfigField“String”,“DEVICE_TYPE”,“\”android-iboxpay\“” } sunmi { buildConfigField“boolean”,“POS”,“true” buildConfigField“String”,“DEVICE_TYPE”,“\”android-sunmi\“” } weipos { buildConfigField“boolean”,“POS”,“true” buildConfigField“String”,“DEVICE_TYPE”,“\”android-weipos\“” }}

為了區分POS機業務和普通業務,需要在編譯時根據具體的 task name 去區分,例如task是assembleSumiDebug,則groupPosPrefix 的值是Sunmi,buildTypePrefix 的值是Debug, 只要groupPosPrefix 的值是我定義的flavor裡的Iboxpay,Sunmi,Weipos,那麼groupPos的值就是”pos”,否則就是空字串。

注意:這裡要注意大小寫的問題,Sunmi不能用sunmi去替代。

// global variablesext{ buildType = “” groupPos=“”}//start parametersprintln “Start parameters:tasks=” + gradle。startParameter。getTaskNames();gradle。startParameter。getTaskNames()。each { task-> def taskParts = splitCamelCase(task。split(“:”)。last()); def groupPosPrefix = taskParts[taskParts。size() - 2]; def buildTypePrefix = taskParts[taskParts。size() - 1]; if (“Debug”。startsWith(buildTypePrefix)) { buildType = ‘debug’; } else if (“Release”。startsWith(buildTypePrefix)) { buildType = ‘release’; } else { return; // do not process tasks that are not ending with proper build type。 } if (“Iboxpay”。startsWith(groupPosPrefix)) { groupPos = ‘pos’; } else if (“Sunmi”。startsWith(groupPosPrefix)) { groupPos = ‘pos’; } else if (“Weipos”。startsWith(groupPosPrefix)) { groupPos = “pos” } else { groupPos = “” }}def splitCamelCase(String word) { def result = [] int nextStart = 0; for (int i = 1; i < word。length(); i++) { if(word。charAt(i)。isUpperCase()) { result。add(word。substring(nextStart, i)); nextStart = i; } } result。add(word。substring(nextStart)); return result;}dependencies { if (groupPos ==“pos”) { iboxpayCompile project(‘:pos_iboxpay’) iboxpayCompile project(path:‘:wsc_goods’,configuration:‘iboxpayRelease’) sunmiCompile project(‘:pos_sunmi’) sunmiCompile project(path:‘:wsc_goods’,configuration:‘sunmiRelease’) weiposCompile project(‘:pos_wei’) weiposCompile project(path:‘:wsc_goods’,configuration:‘weiposRelease’) } else { compile project(path:‘:wsc_goods’,configuration:‘fullRelease’) }

這樣透過groupPos這個變數,就能很自由的去控制普通業務和POS業務跟其他module的依賴關係,很容易實現普通業務和POS機業務在編譯上的分離。

舉個栗子

這個例子是商品module,在這個library中,它的build。gradle裡也需要定義跟app的gradle中一樣的ProductFlavor:

productFlavors { full { buildConfigField“boolean”,“POS”,“false” buildConfigField“String”,“DEVICE_TYPE”,“\”android\“” } iboxpay { buildConfigField“boolean”,“POS”,“true” buildConfigField“String”,“DEVICE_TYPE”,“\”android-iboxpay\“” } sunmi { buildConfigField“boolean”,“POS”,“true” buildConfigField“String”,“DEVICE_TYPE”,“\”android-sunmi\“” } weipos { buildConfigField“boolean”,“POS”,“true” buildConfigField“String”,“DEVICE_TYPE”,“\”android-weipos\“” }}

寫完這些flavor了,不要忘記加上 publishNonDefault true 這麼一句話哦,否則會找不到對應的configuration。

android { publicNonDefault true}

可能有小夥伴問我為什麼沒有customFlavor了,這裡說明一下:baidu,wandoujia等自定義的渠道使用的業務程式碼跟full這個flavor是一樣的,所以不需要再次在module的build。gradle裡去定義了。

當app的build。gradle和商品library的build。gradle都配置如上的時候,在terminal裡執行。/gradlew assembleDebug,就能順利的打包出full、sunmi、iboxpay、weipos這四個渠道的apk。

總結

整個解決方案到此算是講解完了,這裡放幾個小知識點:

如何知道自己的專案中有哪些task?

在AS中開啟terminal,輸入。/gradlew tasks,build成功後會打印出所有的task

Build Variant 是什麼?

Build Type + Product Flavor = Build Variant

flavor 是sunmi,build type是debug ,則build variant是sunmiDebug

當專案中有了flavor後,會有更多的task被建立?

yes,

如下幾種會被建立

assembleassembleassemble

library publish 是什麼?

例如下面的依賴

dependencies { flavor1Compile project(path: ‘:lib1’, configuration: ‘flavor1Release’)}

在編譯 lib1 的時候,預設打包 flavor1Release 版本