其使用的基本原理是Gradle的 manifest merger 功能,這個功能的主要用途是可以在運行時替換AndroidManifest.xml裏面的內容,因爲使用不一樣的渠道(或者第三方發佈市場),從而在AndroidManifest.xml寫上不一樣的渠道ID,而避免重複多餘的工做,統一在gradle寫.如在AndroidManifest.xml可能要寫上如下代碼:java
<meta-data android:name="TD_APP_ID" android:value="C3FE75F5BE72B521C04C55B62E4E5D19" /> <meta-data android:name="TD_CHANNEL_ID" android:value="${CHANNEL_NAME}" /> <meta-data android:name="com.amap.api.v2.apikey" android:value="dcc98525f96d4cd62f5d3006e7fea013" /> <meta-data android:name="channelname" android:value="${CHANNEL_NAME}" /> <meta-data android:name="channelid" android:value="${CHANNEL_ID}" />
那麼針對 android:value的值咱們能夠在gradle這樣寫:android
android{ ......... defaultConfig{ ......... manifestPlaceholders = [ CHANNEL_NAME : "官網", CHANNEL_ID : "l79000i4:ts5x38dl:kxi542in:l79000hu"] } }
manifestPlaceholders裏的值能夠有多個用","隔開, 上文提到的android:value的值就是在manifestPlaceholders 定義的值,至關於自定義了一個類型.api
而後使用productFlavors打出各個渠道的包:服務器
android{ .......... productFlavors.all { flavor -> flavor.manifestPlaceholders = [CHANNEL_NAME: name] } productFlavors { home { manifestPlaceholders = [CHANNEL_NAME: "官網", CHANNEL_ID: "l79000i4:ts5x38dl:kxi542in:l79000hu"] } samsung { manifestPlaceholders = [CHANNEL_NAME: "三星應用市場", CHANNEL_ID: "moi000qp:al80ssgp:kxi542in:moi000qj"] } oppo { manifestPlaceholders = [CHANNEL_NAME: "OPPO可可應用市場", CHANNEL_ID: "moi000qq:al80ssgp:kxi542in:moi000qk"] } meizu { manifestPlaceholders = [CHANNEL_NAME: "魅族flyme應用商店", CHANNEL_ID: "moi000qr:al80ssgp:kxi542in:moi000ql"] } } }
productFlavors.all中的寫法代表了各個渠道的CHANNEL_NAME所對應的值是productFlavors 裏面的子項的名字,如三星的samsung 也能夠這樣寫:app
productFlavors { wandoujia {} baidu {} c360 {} uc {} productFlavors.all { flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] } }
productFlavors.all實際上是能夠不用寫的,只不過上文的寫法使用漢字標明瞭各個渠道的意思,一目瞭然.並且各個渠道除了CHANNEL_NAME, 還有CHANNEL_ID因此要添加了一個productFlavors.all
在productFlavors 的各個子項裏能夠自定義其applicationId、versionCode以及versionName等信息,以便打出不一樣包名的apk.測試
批量修改生成的apk文件名gradle
def buildTime() { def date = new Date() def formattedDate = date.format('yyyyMMdd') return formattedDate } android { buildTypes { release { applicationVariants.all { variant -> variant.outputs.each { output -> if (output.outputFile != null && output.outputFile.name.endsWith('.apk') &&'release'.equals(variant.buildType.name)) { def apkFile = new File( output.outputFile.getParent(), "Mymoney_${variant.flavorName}_v${variant.versionName}_${buildTime()}.apk") output.outputFile = apkFile } } } } } }
經過這種方式咱們能夠知道這個apk是哪一個版本的,哪一個渠道的,是哪天打的包等等, 例如生成的Mymoney_baidu_v9.5.2.6_20150330.apk.ui
定義不一樣的通訊方式
在平時Android開發中會有生產和測試環境,在發佈正式版本時能夠經過如下方式:google
android { defaultConfig { buildConfigField("String", "URL_UPDATE", "\"http://api2.okzaijia.com.cn/\"") } productFlavors { google{ buildConfigField("String", "URL_UPDATE", "\"http://api2.okzaijia.com.cn/\"") } baidu{ buildConfigField("String", "URL_UPDATE", "\"http://api2.okzaijia.com.cn/\"") } } }
BuildConfig.java是Android Gradle自動生成的一個java類文件,沒法手動編譯,可是能夠經過Gradle控制,也就是說他是動態可配置的.buildConfigField 一共有3個參數,第一個是數據類型,就是你定義的常量值是一個什麼類型,和Java的類型是對等的,這裏是String。第二個參數是常量名,這裏是 API_SERVER_URL。第三個參數是常量值。如此定義以後,就會在BuildConfig.java中生成一個常量名爲 API_SERVER_URL的常量定義。默認配置的生成是:編碼
public final static String API_SERVER_URL = "http://test.flysnw.org/" 當是baidu和google渠道的時候生成的就是http://www.flysnow.org/了。這個常量能夠在咱們編碼中引用。在咱們進行打包的時候會根據Gradle配置動態替換。
通常渠道版本都是用來發布的,確定用的是生產服務器,因此咱們可使用批處理來搞定這個事情,而不用在一個個渠道里寫這些配置。
productFlavors.all { flavor -> buildConfigField("String", "URL_UPDATE", "\"http://api2.okzaijia.com.cn/\"") }