使用 Gradle 對應用進行個性化定製

劉俊發表於2017-07-07

啥也不說了,直接進入主題吧。本篇文章主要根據實際開發中遇到的需求,講解使用 Gradle 對應用的不同版本進行個性化定製。

場景介紹

  1. 一般的應用基本上都有正式服和測試服,這個就不需要多說了。但是有些應用可能還有超管伺服器專供運營人員使用,對應用內的一些內容進行監管,具有一些管理員才有的操作許可權。
  2. 開發過程中釋出測試伺服器的安裝包需要在版本號後面增加版本序號,超管伺服器的包在版本號後面增加管理員文字,線上包則正常顯示版本號。
  3. 每次打包 versionCode 自增,避免發版時忘記手動修改導致老版本不能覆蓋安裝。
  4. 超管包的渠道名為 admin,日常執行的 debug 包渠道名為 test,上線的包使用加固軟體進行多渠道加固。
  5. debug 包和 release 包使用同樣的簽名,避免直接執行的 debug 包因為簽名問題不能使用需要校驗簽名的第三方服務,比如:QQ 登入,微信登入,高德地圖。
  6. debug 包列印日誌資訊,release 包不列印日誌資訊

以上某些場景從我工作以來就一直存在,以前用 eclipse 開發時除了每次都手動去修改一些開關變數也沒啥好辦法,可能是因為當時菜 ╮(╯▽╰)╭(如果你們有什麼好方法的話)。

後來切換到 Android Studio 後使用 Gradle 進行依賴管理已經讓人很是欣喜,既然如此能不能使用 Gradle 將以上問題統統解決,完全自動化呢?答案是:必須的。

解決問題

先上完整的 Gradle 配置。

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "com.imliujun.gradle"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode gitVersionCode()  //獲取 git 的 commit 次數
        versionName rootProject.ext.versionName

        manifestPlaceholders = [UMENG_APP_KEY      : "填你的友盟 APP KEY",
                                UMENG_CHANNEL_VALUE: "預設的渠道名"]
    }

    signingConfigs {
    //在這裡配置相關的簽名資訊
        keyStore {
            storeFile file("test.jks")
            storePassword "111111"
            keyAlias "test"
            keyPassword "111111"
        }
    }

    buildTypes {
        release {
            // 不顯示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"
            signingConfig signingConfigs.keyStore //設定簽名檔案
        }

        debug {
            // 顯示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"
            versionNameSuffix "-debug"  //設定字尾
            signingConfig signingConfigs.keyStore  //設定簽名檔案
            manifestPlaceholders.UMENG_CHANNEL_VALUE = "test" //修改渠道名
        }
    }

    productFlavors {
        offline {
            buildConfigField "String", "DOMAIN_NAME", "\"https://offline.domain.com/\""
            versionName getTestVersionName() //修改 versionName
        }

        online {
            buildConfigField "String", "DOMAIN_NAME", "\"https://online.domain.com/\""
        }

        admin {
            buildConfigField "String", "DOMAIN_NAME", "\"https://admin.domain.com/\""
            versionName rootProject.ext.versionName + "-管理員" //修改 versionName
            manifestPlaceholders.UMENG_CHANNEL_VALUE = "admin" //修改渠道名
        }
    }
}複製程式碼

根目錄下的 build.gradle 檔案進行如下配置,主要是將版本號和測試包的序號抽取出來:

ext {
    versionName = "2.0.2"
    testNum = "0001"
}

def getTestVersionName() {
    return String.format("%s.%s", rootProject.ext.versionName,
            rootProject.ext.testNum)
}

static int gitVersionCode() {
    def count = "git rev-list HEAD --count".execute().text.trim()
    return count.isInteger() ? count.toInteger() : 0
}複製程式碼

下面就根據場景來依次介紹對應的配置程式碼。

1. 配置伺服器版本

這裡建立了三個 flavor,分別是 offline 測試服online 正式服admin 超管服。並且通過 buildConfigField 動態配置伺服器的 URL 常量值到編譯後自動生成的 BuildConfig 類中。

自動生成的 BuildConfig 類
自動生成的 BuildConfig 類

圖中可以看到,不止有 DOMAIN_NAME 常量值,還有一個 FLAVOR 常量。這個 FLAVOR 常量中的值是 offline,代表當前在 offline 這個版本上面。那怎麼切換到其他的伺服器呢?

切換不同的變種版本
切換不同的變種版本

點開左下角的 Build Variants, 可以自由切換當前執行的版本。需要在管理員包中開啟一些高階的功能,可以判斷 FLAVOR 的值是不是 admin,如果是的話就顯示管理員的操作佈局。當然必不可少的要對使用者許可權進行校驗哦。

2. 定製 versionName

大家看上圖 BuildConfig 類中 VERSION_NAME 常量的值為 2.0.2.0001-debug,當前是測試服的 debug 包,所以 versionName 應該是正常的 2.0.2 版本後面拼上當前出包的序號 0001 ,再拼上 debug 的字尾,所以完整的版本號是 2.0.2.0001-debug

看看不同伺服器版本的 VERSION_NAME

  • offlineRelease 版本為 2.0.2.0001
  • offlineDebug 版本為 2.0.2.0001-debug
  • adminRelease 版本為 2.0.2-管理員
  • adminDebug 版本為 2.0.2-管理員-debug
  • onlineRelease 版本為 2.0.2
  • onlineDebug 版本為 2.0.2-debug

如果我們介面需要上傳版本號給伺服器呢?肯定不能直接上傳這些定製化後的 VERSION_NAME,那麼我們在 Gradle 中增加一個 buildConfigField 將原始的版本號存起來就好了。

buildConfigField "String", "versionNumber", "\"${rootProject.ext.versionName}\""複製程式碼

3. versionCode 自增

這裡採用了主流的方式,使用 gitcommit 次數作為 versionCode 的值。不用擔心這個值會超過 int 的上限,你得敲爛多少鍵盤才能提交 2147483648次 commit

static int gitVersionCode() {
    def count = "git rev-list HEAD --count".execute().text.trim()
    return count.isInteger() ? count.toInteger() : 0
 }複製程式碼

4. 個性化渠道名

Gradle 多渠道打包的文章太多了,相關的基礎我就不講了。簡單講下本文相關的配置吧。

通過定義 manifestPlaceholders 鍵值對,在 AndroidManifest.xml 檔案中使用佔位符的方式動態輸入 UMENG_APPKEYUMENG_CHANNEL

然後在 debugbuildType 中修改渠道名為 test,在 adminFlavor 中修改渠道名為 admin。如果選擇 adminDebug 版本,則渠道名為 testbuildType 中的配置會覆蓋掉 Flavor 中的配置。

由於我們線上使用第三方加固,所以多渠道包就交給第三方加固軟體來生成了。

關於多渠道打包我還有兩句話要說,以前使用 Gradle 進行多渠道打包,通過程式碼自定義修改 apk 檔案的輸出路徑,Android Studio 編譯的時候時不時的報一些檔案找不到的錯誤,以前都是通過在 Gradle 檔案中隨便修改一點東西然後重新整理一下 Gradle 檔案來解決。現在我打包不修改輸出路徑,再也沒遇到以前的那些問題了。

建議大家使用 assemble 命令來進行打包,比如我要出一個測試包使用 ./gradlew assembleOfflineRelease 命令,apk 檔案生成在 /build/outputs/apk/ 目錄下。直接執行 assemble 命令是編譯 Build Variants 中的所有包,如果你要編譯指定版本的包,直接在 assemble 命令後面拼上指定的 Build Variant 就好了。

5. debug 包使用 release 簽名

這個問題在 eclipse 時代,可以直接在設定裡面配置 debug 簽名檔案為 release 的簽名檔案。
Android Studio 只需要在 Gradle 中配置就好了。

首先配置簽名檔案的資訊:

signingConfigs {
     //在這裡配置相關的簽名資訊
     keyStore {
         storeFile file("test.jks")
         storePassword "111111"
         keyAlias "test"
         keyPassword "111111"
     }
}複製程式碼

然後在 buildTypes 中設定簽名資訊:

buildTypes {
    release {
        signingConfig signingConfigs.keyStore //設定簽名檔案
    }

    debug {
        signingConfig signingConfigs.keyStore  //設定簽名檔案
    }
}複製程式碼

6. 日誌開關

這個太簡單了,不想單獨列出來。不過上面場景裡面提出來了,就簡單一行程式碼展示吧。

release {
    // 不顯示Log
    buildConfigField "boolean", "LOG_DEBUG", "false"
}

debug {
    // 顯示Log
    buildConfigField "boolean", "LOG_DEBUG", "true"
}複製程式碼

在日誌工具類中使用 BuildConfig 類中的 LOG_DEBUG 常量來判斷當前是否應該輸出日誌。

當然也可以用這個開關來控制開啟嚴格模式等其他只適合在 debug 模式下開啟的設定。

結語

唧唧歪歪說了這麼多,在懂的人眼中自然很簡單,在對 gradle 一點都不瞭解的人眼中就可以直接複製過去用了。當然我是不建議直接複製,畢竟需求稍微一改,你可能就束手無策了。建議大家還是以理解為主,掌握其原理自然一通百通。

相關閱讀

Android Studio 3.0 上 Gradle 改動

使用 Gradle 實現一套程式碼開發多個應用

歡迎關注微信公眾號:大腦好餓,更多幹貨等你來嘗

公眾號:大腦好餓
公眾號:大腦好餓

相關文章