MF99 coding 💻

keep learning; keep coding;

使用 Android Studio 中的 Build variants (productFlavors)

Android Studio 真的是越玩越好玩~ 之前開始研究了一些 build.gradle 裡面的基本功能,像是設定、修改 default config 等。

但是有時候常常在實務開發上,同時可能會需要 build 好幾個不同版本,最簡單的就是 debug / release 版本,或是有連接 Server 的應用可能又會有連接到不同 Server 的版本(internal test / public test / public release 等)

以前的作法,通常會是拉出一個 config 然後利用 flag 的方式去動態切換。然後在 source control server 上只能放一個最常用的版本。要 release 的時候在去一個個改。

但是這樣會有幾個問題:

  1. Server 上只能放一個版本,不一定每個人都知道每個不同版本到底要怎麼切 flag
  2. Build 的時候只要漏改一個 flag,可能 build 出來的東西就會有問題

這時候 Android Studio 提供的 Build variants 或是 product flavors 就很有用了!

所謂的 Build variants,就是讓你能夠把你的產品做 release 的分類,像是:

Variants 敘述 內容
dev Internal release 內部測試版,所有的 api 連結到內部 Server
RC Public beta 公開測試版,裡面含有一些追蹤、記錄或是會印出一些 debug log
PUB Public release 公開發行版,移除了 debug message log

這時候你就可以開啟 build.gradle 然後加入這幾個 productFlavors

註:以下所講的 build.gradle,都是針對 Module 的部分,而不是 Project 的)

android {
    ...
    defaultConfig {
        ...
        }

    productFlavors {
        dev {
        }
        RC {
        }
        PUB {
        }
    }
    ...
}

加進去之後並且 Sync 完之後(基本上有改到 build.gradle Studio 都會要你 Sync project) 你就可以在左下角的 Build Variants 裡面看到有多了幾個選項:

  • devDebug
  • devRelease
  • RCDebug
  • RCRelease
  • PUBDebug
  • PUBRelease

基本上每一個 Variant 他會幫你產生兩組,一組是 Debug,一組是 Release 版。 至於這兩版的差異,其實最明顯的就差在 Sign Key,Debug 的版本基本上就是 sign Test Key,所以在開發時就可以用 Debug 版本就可以,也比較方便。 至於 Release 版,他就會要你選擇 Release Key,並且要輸入密碼,建議是在如果要 release 給別人或是上架的時候再用就可以。

但是還沒結束~ 目前為止你只是新增了這三組 Variants,但是還沒有任何差異。 這邊提供了兩個實用的功能,讓你能夠在 Source code 裡面自動去切換跟這幾個 Variant 相關的 config

defaultConfig {
    ...
    resValue "string", "app_label", "default_name"
    buildConfigField "boolean", "IS_INTERNAL", "true"
    ...
}
productFlavors {
    dev {
        versionName "My App_dev"
        resValue "string", "app_label", "DEV_APP"
    }
    RC {
        versionName "My App_RC"
        resValue "string", "app_label", "RC_APP"
        buildConfigField "boolean", "IS_INTERNAL", "false"
    }
    PUB {
        versionName "My App"
        buildConfigField "boolean", "IS_INTERNAL", "false"  
    }
}

這邊可以看到,除了可以在不同的 Variant 裡面定義不同的 versionName 之外,在 defaultConfig 跟 productFlavors 裡面分別新增了兩個東西 :

resValue "string", "app_label", "default_name"

以及

buildConfigField "boolean", "IS_INTERNAL", "false"

resValue:會在產出的 resource 裡面新增一組 R.string.app_label 然後內容是 default_name buildConfigField:則是會在 BuildConfig 裡面新增一組 IS_INTERNAL 的 flag,值是 false

實際應用的方式如下:

public static String getServerHost(){
    if(BuildConfig.IS_INTERNAL)
        return "http://internal-server.net";
    else
        return "https://public-server.net";
}
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">           
    ...
    <TextView
        android:id="@+id/some_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_label"
    />        
    ...  
  
</RelativeLayout>

看到這邊應該就差不多知道該怎麼玩了~

註:如果在 Variant 裡面沒有定義的話,就會使用 defaultConfig 裡面的值,所以記得在 defaultConfig 也要新增!

而且 buildConfigField 不只有 boolean 可以用,基本型態(int / double / boolean)甚至是字串(String)都可以用! 在加上某些 XML 裡面只能吃到 resource 的方式也都可以這樣玩!

這樣以後就只要把 build.gradle 改好後,上傳到 Source control Server,這樣以後不管任何人只要在 Build Release APK 的時候選擇 Variant,其他的設定就會一次到位了!

還有一些進階一點的玩法,像是不同版本使用不同的 resource (同名不同檔案!)之類(有點類似 Android framework 裡面的 Overlay 功能)~ 可以參考這篇文章 Mastering "Product Flavors" on Android