轉(zhuǎn)發(fā)自:https://www.jishudog.com/9037/html
官方參考:https://developer.android.com/studio/build/build-variants
一、新增渠道
使用AndroidStudio配合gradle呻袭,可以很方便的輸出多個(gè)渠道包贯被,只需要在app Module下的build.gradle中傅事,對(duì)productFlavors領(lǐng)域進(jìn)行配置即可,假設(shè)我當(dāng)前開發(fā)的項(xiàng)目央拖,需要上線不同的地區(qū),一個(gè)是國內(nèi)版,一個(gè)美國版哎迄,還有一個(gè)免費(fèi)版,那么gradle可以這么配:
android {
productFlavors {
china { // 中國版
}
america { // 美國版
}
free { // 免費(fèi)版
}
}
}
以上多渠道配置完成后隆圆,在Android Studio的Build Variants標(biāo)簽中漱挚,就會(huì)有不同渠道變體供我們選擇了。當(dāng)我們想使用AS直接運(yùn)行某個(gè)渠道的app時(shí)渺氧,就需要先在Build Variants標(biāo)簽中選擇好變體旨涝,再點(diǎn)擊”運(yùn)行”按鈕運(yùn)行項(xiàng)目。
在productFlavors中還可以配置包名(applicationId)侣背、版本號(hào)(versionCode)白华、版本名(versionName)、icon贩耐、應(yīng)用名 等等弧腥,舉個(gè)例子:
free {
applicationId 'com.lqr.demo.free'
versionCode 32
versionName '1.3.2'
manifestPlaceholders = [
app_icon: "@drawable/ic_launcher",
app_name: "菜雞【免費(fèi)版】",
]
}
注意:
這里配置的包名是applicationId,而不是清單文件里的packageName潮太,applicationId與packageName是不一樣的管搪。
我們常說,一部Android設(shè)備上不能同時(shí)安裝2個(gè)相同包名的app消别,指的是applicationId不能一樣抛蚤。
applicationId與packageName的區(qū)別可查閱:《ApplicationId versus PackageName》
如果工程要求不同渠道共存,或者對(duì)版本號(hào)寻狂、icon岁经、應(yīng)用名等有定制需求的話,那么這個(gè)多渠道配置就顯得非常有用了蛇券。其中缀壤,app_icon、app_name是放在manifestPlaceholders的纠亚,這個(gè)其實(shí)是在對(duì)AndroidManifest.xml中的占位符進(jìn)行變量修改塘慕,也就是說,要定制icon或者應(yīng)用名的話蒂胞,還需要對(duì)清單文件做些小修改才行(增加一些占位符)图呢,如:
<application
xmlns:tools="http://schemas.android.com/tools"
android:icon="${app_icon}"
android:label="${app_name}"
android:theme="@style/AppTheme"
android:largeHeap="true"
tools:replace="android:label">
...
</application>
二、生成渠道變量
在新增渠道之后,我們可以對(duì)這些渠道進(jìn)行一起更多的配置蛤织,假設(shè)項(xiàng)目代碼需要根據(jù)不同的渠道赴叹,賦予不同的數(shù)據(jù),當(dāng)然你可以選擇在java代碼中通過判斷當(dāng)前渠道名指蚜,配合switch來設(shè)置靜態(tài)常量乞巧,但其實(shí)不用那么煩瑣,而且有些靜態(tài)數(shù)據(jù)通過類似config.gradle或config.properties這類配置文件來配置有比較好摊鸡,那么gradle中的applicationVariants完全可以幫助到我們绽媒,以下面的配置Demo為例進(jìn)行說明:
// 多渠道相關(guān)設(shè)置
applicationVariants.all { variant ->
buildConfigField("String", "PROUDCT", ""newapp"")
buildConfigField("String[]", "DNSS", "{"http://119.29.29.29","http://8.8.8.8","http://114.114.114.114"}")
if (variant.flavorName == 'china') {
buildConfigField("String", "DNS", ""http://119.29.29.29"")
} else if (variant.flavorName == 'america') {
buildConfigField("String", "DNS", ""http://8.8.8.8"")
} else if (variant.flavorName == 'free') {
buildConfigField("String", "DNS", ""http://114.114.114.114"")
}
}
通過gradle中提供的buildConfigField(),AndroidStudio會(huì)在執(zhí)行腳本初始化時(shí)免猾,根據(jù)當(dāng)前所選變體將對(duì)于的配置轉(zhuǎn)變?yōu)锽uildConfig.java中的一個(gè)個(gè)靜態(tài)常量:
當(dāng)我切換其他變體時(shí)是辕,BuildConfig中的DNS也會(huì)跟著一起改變,這樣掸刊,我們?cè)诠こ檀a中免糕,就不需要去判斷當(dāng)前渠道名來為某些靜態(tài)常量賦值了。這里只是舉例了使用buildConfigField()來生成String和String[]常量忧侧,當(dāng)然也可以用來生成其它類型的常量數(shù)據(jù)石窑,有興趣的話,可以百度了解下蚓炬。
三松逊、變體的使用
上面提到了變體,那么變體是什么肯夏?可以這樣理解经宏,變體是由【Build Type】和【Product Flavor】組合而成的,組合情況有【Build Type】*【Product Flavor】種驯击,舉個(gè)例子烁兰,有如下2種構(gòu)建類型,并配置了2種渠道:
Build Type:release debug
Product Flavor:china free
那么最終會(huì)有四種 Build Variant 組成:
chinaRelease chinaDebug freeRelease freeDebug
變體在復(fù)雜多渠道工程中是相當(dāng)有用的徊都,可以做到資源文件合并以及代碼整合沪斟,這里的合并與整合怎么理解?我們使用Android Studio進(jìn)行項(xiàng)目開發(fā)時(shí)暇矫,會(huì)把代碼文件與資源文件都存放在app/src目錄下主之,通常是main下會(huì)有java、res李根、assets來區(qū)分存放代碼文件和資源文件槽奕,你可以把main看作是默認(rèn)渠道工程文件目錄,也就是說main下存放在代碼文件和資源文件對(duì)所有渠道來說都是共同持有的房轿。
那么粤攒,一旦出來了某些代碼文件或者資源文件是個(gè)別渠道專屬時(shí)所森,應(yīng)該怎么辦呢?因?yàn)閙ain是共有的琼讽,所以理想狀態(tài)下必峰,我們并不會(huì)把這類”不通用”的文件放在main下(這樣做不會(huì)出錯(cuò)洪唐,但是做法很low钻蹬,會(huì)增大apk包體積),Android Studio為變體做了很好的支持凭需,我們可以在app/src下问欠,創(chuàng)建一個(gè)以渠道名命名的目錄,用于存放這類個(gè)別渠道專屬的代碼文件和資源文件粒蜈,如:
可以看到顺献,當(dāng)我選擇freeDebug變體時(shí),app/src/free下的目錄高亮了枯怖,說明它們被Android Studio識(shí)別注整,在運(yùn)行工程時(shí),Android Studio會(huì)將free和main下的所有資源文件進(jìn)行合并度硝,將代碼文件進(jìn)行整合肿轨。同理,如果我選擇的是chinaDebug變體蕊程,那么app/src/china下目錄就會(huì)高亮椒袍。知道如何創(chuàng)建變體目錄后,下面就開始進(jìn)行資源合并與代碼整合了藻茂。
1驹暑、資源合并
資源文件有哪些?我們可以這樣認(rèn)為:
資源文件 = res下的所有文件 + AndroidManifest.xml
變體的資源合并功能簡直是”神器”一般的存在辨赐,可以解決很多業(yè)務(wù)需求优俘,如不同渠道顯示的icon不同,應(yīng)用名不同等等掀序。Android Studio在對(duì)變體目錄和main目錄進(jìn)行資源合并時(shí)帆焕,會(huì)遵守這樣的規(guī)則,假設(shè)當(dāng)前選中的變體是freeDebug:
- 某資源在free下有森枪,在main中沒有视搏,那么在打包時(shí),會(huì)將該資源直接合并到main資源中县袱。
- 某資源在free下有浑娜,在main中也有,那么在打包時(shí)式散,會(huì)以free為主筋遭,將free中資源替換掉main中資源。
針對(duì)上述2個(gè)規(guī)則,這里以string.xml為例進(jìn)行說明漓滔,main下的string.xml是:
<resources>
<string name="app_name">Demo</string>
<string name="app_author">Lin</string>
</resources>
free下的string.xml是:
<resources>
<string name="error_append">發(fā)生錯(cuò)誤</string>
<string name="app_author">Lqr</string>
</resources>
那么最終打出的apk包里的string.xml是:
<resources>
<string name="app_name">Demo</string>
<string name="error_append">發(fā)生錯(cuò)誤</string>
<string name="app_author">Lqr</string>
</resources>
除了字符串合并外编饺,還有圖片(drawable、mipmap)响驴、布局(layout)透且、清單文件(AndroidManifest.xml)的合并,具體可以自己嘗試一下豁鲤。其中秽誊,清單文件的合并需要提醒一點(diǎn),如果渠道目錄下的AndroidManifest.xml與main下的AndroidManifest.xml擁有相同的節(jié)點(diǎn)屬性琳骡,但屬性值不同時(shí)锅论,那么就需要對(duì)main下的AndroidManifest.xml進(jìn)行修改了,具體修改要根據(jù)編譯時(shí)報(bào)錯(cuò)來處理楣号,所以最易,報(bào)錯(cuò)時(shí)不要慌,根據(jù)錯(cuò)誤提示修改就是了炫狱。
注意:布局(layout)文件的合并是對(duì)整個(gè)文件進(jìn)行替換的~藻懒。
2、代碼整合
代碼文件毕荐,顧名思義就是指java目錄下的.java文件了束析,為什么代碼叫整合,而資源卻是合并呢憎亚?因?yàn)榇a文件是沒辦法合并的员寇,只能是整合,整合是什么意思第美?假設(shè)當(dāng)前選中的變體是freeDebug蝶锋,有一個(gè)java文件是Test.java,這個(gè)Test.java要么只存在free/java下什往,要么只存在于main/java下扳缕,如:
可以看到,一切正常别威,Test.java被AndroidStudio識(shí)別躯舔,但如果此時(shí)在main/java下也存在Test.java,那么Android Studio就會(huì)報(bào)錯(cuò)了:
代碼整合是一個(gè)比較頭痛的事省古,因?yàn)槿绻闶窃谇滥夸沠ree下去引用main下的類粥庄,那么是完全沒有問題的,但如果反過來豺妓,在main下去引用free下的專屬類時(shí)惜互,情況就會(huì)變得很糟糕布讹,當(dāng)你切換其他變體時(shí)(如,切換成chinaDebug)训堆,這時(shí)工程就會(huì)報(bào)錯(cuò)了描验,因?yàn)樽凅w切換,Test.java是free專屬的坑鱼,在chinaDebug變體下膘流,free不會(huì)被識(shí)別,于是main就找不到對(duì)應(yīng)的類了姑躲。
選擇freeDebug變體時(shí)睡扬,正常引用Test.java:
選擇chinaDebug變體時(shí),找不到Test.java(只找到j(luò)unit下的Test.java):
所以黍析,對(duì)于代碼整合,需要我們?cè)陂_發(fā)過程中慎重考慮屎开,多想想如何將渠道目錄與main目錄進(jìn)行解耦阐枣。比如可以使用Arouter來解耦main與渠道目錄下所有的Activity、Fragment奄抽,將類引用轉(zhuǎn)換為字符串引用蔼两,全部將由Arouter來管理,又或者通過反射來處理逞度,等等额划,這里順帶記錄一下,我項(xiàng)目中使用ARouter來判斷Activity档泽、Fragment是否存在俊戳,和獲取的相關(guān)方法:
/**
* 獲取到目標(biāo)Delegate(僅僅支持Fragment)
*/
public <T extends CommonDelegate> T getTargetDelegate(String path) {
return (T) ARouter.getInstance().build(path).navigation();
}
/**
* 獲取到目標(biāo)類class(支持Activity、Fragment)
*/
public Class<?> getTargetClass(String path) {
Postcard postcard = ARouter.getInstance().build(path);
LogisticsCenter.completion(postcard);
return postcard.getDestination();
}
3馆匿、其他
前面只說到了res和java這2個(gè)目錄抑胎,那么assets呢,它是屬于哪種渐北?很可惜阿逃,assets雖然是資源,但它不是合并赃蛛,而是整合恃锉,也就是說,assets文件的處理方式跟java文件的處理方式是一樣的呕臂,不能在渠道目錄和main目錄下同時(shí)存在相同的assets文件破托,這將對(duì)某些需求實(shí)現(xiàn)造成阻礙,舉個(gè)例子诵闭,假設(shè)china與free使用的assets資源是一樣的炼团,而america單獨(dú)使用自己的assets資源澎嚣,并且這些assets資源文件名都是一樣的,那這時(shí)要怎么辦呢瘟芝?給每個(gè)渠道都放一份各自的assets資源嗎易桃?這種做法可行,但很low锌俱,原因如下:
- 復(fù)用性差:都說了china與free使用的資源是一樣的晤郑,從整個(gè)工程的角度來看,一個(gè)工程里放了2份一模一樣的assets資源文件贸宏,如果我有10個(gè)渠道造寝,其中9個(gè)渠道使用的assets資源是一樣的要怎么辦,copy9次吭练?
- 維護(hù)成本高:在開發(fā)行業(yè)里诫龙,需求變動(dòng)是很常見的事,產(chǎn)品經(jīng)理會(huì)時(shí)不時(shí)改下需求鲫咽,所以签赃,叫你改assets資源文件也是很有可能的,如果你采用每個(gè)渠道都放一份分尸,那么當(dāng)assets資源需要修改時(shí)锦聊,你就需要將每個(gè)渠道的assets目錄資源替換一遍。記得箩绍,是每次修改都要替換一遍孔庭。
正確的解決方案是使用sourceSets,對(duì)于sourceSets的使用材蛛,放到下一節(jié)去說明圆到。
四、sourceSets
強(qiáng)大的gradle仰税,通過sourceSets可以讓開發(fā)者能夠自定義項(xiàng)目結(jié)構(gòu)构资,如自定義assets目錄、java目錄陨簇、res目錄吐绵,而且還可以是多個(gè),但要知道的是河绽,sourceSets并不會(huì)破壞變體的合并規(guī)則己单,它們是分開的,sourceSets只是起到了“擴(kuò)充”的作用耙饰。這里先擺一下sourceSets的常規(guī)使用:
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
}
1纹笼、復(fù)用assets資源
對(duì)于多渠道共用同一套assets資源文件這個(gè)問題,結(jié)合sourceSets苟跪,我們可以這么處理廷痘,步驟如下:
- 把共用的assets資源存放到一個(gè)渠道目錄下蔓涧,如free/assets。
- 修改sourceSets規(guī)則笋额,強(qiáng)制指定china渠道的assets目錄為free/assets元暴。
sourceSets {
china {
sourceSet.assets.srcDirs = ['src/free/assets']
}
}
這樣配置以后,如果下次需要統(tǒng)一修改china與free的assets資源文件時(shí)兄猩,你就只需要把free/assets目錄下的資源文件替換掉就好了茉盏。雖然這種寫法已經(jīng)滿足前面說的需求了,但是還不夠枢冤,還可以再優(yōu)化一下鸠姨,假設(shè)你有20個(gè)渠道,都使用同一套assets資源的話淹真,按前面的寫法你就要寫19遍sourceSets配置了讶迁。
sourceSets {
china {
sourceSet.assets.srcDirs = ['src/free/assets']
}
a{
sourceSet.assets.srcDirs = ['src/free/assets']
}
b{
sourceSet.assets.srcDirs = ['src/free/assets']
}
...
}
可以想像,在這個(gè)gradle文件中趟咆,光sourceSets配置就會(huì)有多長添瓷,你可能會(huì)說,一個(gè)項(xiàng)目怎么會(huì)有這么多渠道值纱,不好意思,本人所處公司的業(yè)務(wù)需求就有20+個(gè)渠道的情況坯汤,話不多說虐唠,下面就來看看怎么優(yōu)化好這段配置,如果你有學(xué)習(xí)過gradle惰聂,就應(yīng)該知道疆偿,gradle是一種腳本,腳本是可以像寫代碼一樣寫邏輯的搓幌,那么上面的配置就可以轉(zhuǎn)化為一個(gè)if-else代碼片段:
sourceSets {
sourceSets.all { sourceSet ->
// println("sourceSet.name = ${sourceSet.name}")
if (sourceSet.name.contains('Debug') || sourceSet.name.contains('Release')) {
if (sourceSet.name.contains("china")
|| sourceSet.name.contains("a")
|| sourceSet.name.contains("b")
|| ...) {
sourceSet.assets.srcDirs = ['src/free/assets']
}
}
}
}
現(xiàn)在你可能會(huì)覺得這樣寫好像精簡不了多少杆故,不過一旦你的業(yè)務(wù)復(fù)雜起來,像這樣用代碼的邏輯思維來處理配置溉愁,相信這會(huì)是一種不錯(cuò)的選擇处铛。
有興趣的可以打印下sourceSet.name;if的寫法不一定要用contains()拐揭,也可以用其他的判斷方式撤蟆,具體看開發(fā)者自己決定。
2堂污、修改程序主入口
對(duì)于sourceSets的使用家肯,除了針對(duì)修改assets以外,java文件盟猖、res資源文件讨衣、清單文件等等都是可以用同樣的方式進(jìn)行“擴(kuò)充”的换棚,比如不同渠道共用一套java代碼邏輯,那么我們可以把這套代碼單獨(dú)抽取出來存放在一個(gè)其他目錄下反镇,然后使用sourceSets對(duì)其進(jìn)行添加固蚤。這里就以我親身經(jīng)歷來說明,我是如何通過sourceSets對(duì)于java和清單文件進(jìn)行指定愿险,并且完美解決此類”變態(tài)”需求的颇蜡。
1)背景
新的app項(xiàng)目開發(fā)完成,現(xiàn)在需要將項(xiàng)目定制化后上線辆亏,項(xiàng)目整體采用 1個(gè)Activity + n個(gè)Fragment架構(gòu)风秤,這個(gè)Activity便是程序主入口,因?yàn)槲覀儺a(chǎn)品是做機(jī)頂盒app開發(fā)扮叨,產(chǎn)品開發(fā)完成后缤弦,需要上線到盒子運(yùn)營商(局方)的應(yīng)用商店,然后通過盒子推薦位(EPG)啟動(dòng)我們開發(fā)的app彻磁,因此上線后碍沐,需要提供app的包名和類名給到局方,假設(shè)新app的包名和類名分別如下:
包名:com.lqr.newapp
類名:com.lqr.newapp.MainActivity
2)需求
把新app的包名和類名改成跟舊app的一樣衷蜓,因?yàn)榫址侥沁叢幌霌Q~~假設(shè)舊app的包名和類名如下:
包名:com.lqr.oldapp
類名:com.lqr.oldapp.MainActivity
3)問題
修改包名很簡單累提,但是修改入口類名就很麻煩了,如果我在該渠道目錄下新增一個(gè)com.lqr.oldapp.MainActivity磁浇,并在其清單文件中進(jìn)行注冊(cè)斋陪,那么,在打包時(shí)置吓,渠道目錄下的AndroidManifest.xml會(huì)與main目錄下的AndroidManifest.xml進(jìn)行合并无虚。
而main目錄下的AndroidManifest.xml中已經(jīng)注冊(cè)了com.lqr.newapp.MainActivity,這樣就會(huì)導(dǎo)致衍锚,最終輸出apk包中的清單文件會(huì)有2個(gè)入口類友题。
是的,這樣的產(chǎn)品交付出去戴质,確實(shí)也可以應(yīng)付掉局方的需求度宦,但是,一旦盒子安裝了這個(gè)app置森,那么盒子Launcher上可能會(huì)同時(shí)出現(xiàn)2個(gè)入口icon斗埂,到時(shí)又是一頓折騰,畢竟app上線流程比較麻煩凫海,我們最好是保證產(chǎn)品就一個(gè)入口呛凶。
4)分析
因?yàn)樽凅w的資源合并規(guī)則,只要渠道目錄和main目錄下都存在AndroidManifest.xml行贪,那么最終apk包里的清單文件合并出來的就會(huì)是2個(gè)文件的融合漾稀,所以模闲,不能在這2個(gè)清單文件中分別注冊(cè)入口≌负矗可以抽出2個(gè)不同入口的AndroidManifest.xml存放到其他目錄尸折,main下的AndroidManifest.xml只注冊(cè)通用組件即可。
5)操作:
a. 抽離MainActivity(oldapp)
在app目錄下殷蛇,創(chuàng)建一個(gè)support/entry目錄(名字隨意)实夹,用于存放入口相關(guān)功能的代碼及資源文件,將com.lqr.oldapp.MainActivity放到support/entry/java目錄下粒梦。
b. 抽離AndroidManifest.xml
在support目錄下亮航,創(chuàng)建manifest(名字隨意),用于存放各渠道對(duì)應(yīng)的AndroidManifest.xml匀们,如:
其中newapp目錄下的AndroidManifest.xml:
<application>
<activity android:name="com.lqr.newapp.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
oldapp目錄下的AndroidManifest.xml:
<application>
<activity android:name="com.lqr.oldapp.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
c. 配置sourceSets
經(jīng)過上面2步后缴淋,oldapp的MainActivity與各自的主入口注冊(cè)清單文件就被抽離出去了,接下來就是使用sourceSets泄朴,根據(jù)不同的渠道名重抖,指定java與清單文件即可:
sourceSets {
sourceSets.all { sourceSet ->
// project.logger.log(LogLevel.ERROR, "sourceSet.name = " + sourceSet.name)
if (sourceSet.name.contains('Debug') || sourceSet.name.contains('Release')) {
if (sourceSet.name.contains("china")) {
sourceSet.java.srcDirs = ['support/entry/java']
sourceSet.manifest.srcFile 'support/manifest/oldapp/AndroidManifest.xml'
} else {
sourceSet.manifest.srcFile 'support/manifest/newapp/AndroidManifest.xml'
}
}
}
}
至此,最終打出的apk包中的AndroidManifest.xml中就只會(huì)保留一個(gè)主入口了祖灰,完美解決了局方要求钟沛。
3、解疑
Q:為什么要把oldapp的MainActivity也抽出去局扶?
A:因?yàn)閛ldapp的MainActivity不單只是china這個(gè)渠道需要用到讹剔,后續(xù)還會(huì)被其它渠道使用,為了后續(xù)復(fù)用考慮详民,于是就把MainActivity抽離出來。
Q:為什么sourceSets中要判斷sourceSet.name是否包含Debug或Release陌兑?
A:如果你有打印過sourceSet.name的話沈跨,你一定會(huì)發(fā)現(xiàn)輸出的結(jié)果不單單只是那幾個(gè)變體名,還有androidTest兔综、test饿凛、main等等這些,但我們僅僅只是想對(duì)工程變體(chinaDebug软驰、chinaRelease涧窒、freeDebug、freeRelease)指定java目錄和清單文件而已锭亏,如果對(duì)test纠吴、main這類“東西”也指定的話,結(jié)果并不是我們想要的慧瘤,所以戴已,一定要確保source配置的是我們想要指定的變體固该,而非其他。
Q:sourceSets與變體合并的關(guān)系究竟如何糖儡?
A:以java源碼目錄為例伐坏,默認(rèn)AS工程的java源碼目錄是【src/main/java】,在gradle中通過sourceSets指定了另一個(gè)目錄握联,比如【support/entry/java】桦沉,那么打包時(shí),AS會(huì)認(rèn)為這2個(gè)目錄均是有效的java目錄金闽,所以纯露,sourceSets指定的java目錄僅僅只是對(duì)原來的擴(kuò)充,而非替換呐矾。還是以java源碼目錄為例苔埋,如果你的項(xiàng)目配置了多渠道,在不考慮sourceSets的情況下蜒犯,項(xiàng)目在打包時(shí)组橄,因?yàn)樽凅w合并的特性,有效的java目錄也是有2個(gè)罚随,分別是【src/main/java】和【src/渠道名/java】玉工,變體的合并規(guī)則不會(huì)因?yàn)閟ourceSets的配置而改變,如果將上述2種情況一起考慮上的話淘菩,那么最終打包時(shí)遵班,有效的java目錄則是3個(gè),分別是【src/main/java】潮改、【src/渠道名/java】狭郑、 【support/entry/java】。
五汇在、渠道依賴
我們知道翰萨,要在gradle中添加第三方庫依賴的話,需要在dependencies領(lǐng)域進(jìn)行配置糕殉,常見的configuration有provided(compileOnly)亩鬼、compile(api)、implementation等等阿蝶,它們的區(qū)別請(qǐng)自行百度查閱了解雳锋,針對(duì)【Build Type】、【Product Flavor】羡洁、【Build Variant】玷过,這些configuration也會(huì)出現(xiàn)一些組合,如:
a. 構(gòu)建類型組合
debugCompile // 所有的debug變體都依賴
releaseCompile // 所有的release變體都依賴
b. 多渠道組合
chinaCompile // china渠道依賴
americaCompile // america渠道依賴
freeCompile // free渠道依賴
c. 變體組合
chinaDebugCompile // chinaDebug變體依賴
chinaReleaseCompile // chinaRelease變體依賴
americaDebugCompile // americaDebug變體依賴
americaReleaseCompile // americaRelease變體依賴
freeDebugCompile // freeDebug變體依賴
freeReleaseCompile // freeRelease變體依賴
1、常規(guī)方式配置渠道依賴
通過上述組合就可以輕松配置好各種情況下的依賴了冶匹,如:
// autofittextview
compile 'me.grantland:autofittextview:0.2.+'
// leakcanary
debugCompile "com.squareup.leakcanary:leakcanary-android:1.6.1"
debugCompile "com.squareup.leakcanary:leakcanary-support-fragment:1.6.1"
releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:1.6.1"
// gson
chinaCompile 'com.google.code.gson:gson:2.6.2'
americaCompile 'com.google.code.gson:gson:2.6.2'
freeCompile 'com.google.code.gson:gson:2.5.2'
2习劫、代碼方式配置渠道依賴
雖然官方給出的多種組合依賴可以解決幾乎所有的依賴問題,但實(shí)際上嚼隘,當(dāng)渠道有很多很多時(shí)诽里,整個(gè)gradle文件將變得冗長臃腫,你能想像20多個(gè)渠道中只有1個(gè)渠道依賴的gson版本不同的情況嗎飞蛹?所以谤狡,這時(shí)候就需要考慮一下,充分利用好gradle作為腳本的特性卧檐,使用代碼方式來進(jìn)行渠道依賴:
dependencies {
gradle.startParameter.getTaskNames().each { task ->
// project.logger.log(LogLevel.ERROR, "lqr print task : " + task)
if (task.contains('free')) {
compile 'com.google.code.gson:gson:2.5.2'
} else {
compile 'com.google.code.gson:gson:2.6.2'
}
}
}
另外墓懂,還有一種方式是我之前項(xiàng)目中使用過的,但這種方式不支持依賴遠(yuǎn)程倉庫組件霉囚,這里也記錄一下:
dependencies {
// 配置 插件化庫 依賴
applicationVariants.all { variant ->
if (variant.flavorName == 'china')
||variant.flavorName == 'america') {
dependencies.add("${variant.flavorName}Compile", project(':DroidPluginFix'))
} else {
dependencies.add("${variant.flavorName}Compile", project(':DroidPlugin'))
}
}
}
要知道捕仔,以下寫法是正確的,但就是不生效:
dependencies.add("${variant.flavorName}Compile", 'com.google.code.gson:gson:2.6.2')
DroidPluginFix是最新官方適配了Android7盈罐、8的DroidPlugin榜跌,而DroidPlugin則沒有適配,因?yàn)闅v史原因盅粪,需要對(duì)不同的渠道依賴不同的DroidPlugin版本钓葫。