Android Studio 採用了 gradle 做為 android 專案的自動化編譯工具後,讓專案的發佈設定也方便了許多,也因此可以更為進階的對進行管理。
本篇將為各位介紹一下,如何善用 gradle 為 keystore 做較為安全的管理,這對一個開發團隊來說,格外重要。
一開始先來看一下,一般在 android studio 專案裡,要編譯成欲發佈的 module 中,其 build.gradle 都會有類似下面這樣的程式碼片段
1 2 3 4 5 6 7 8 9 10 11 12 |
android { signingConfigs { release { storeFile your_keystore_directory storePassword your_keysotre_password keyAlias your_alias_name keyPassword your_alias_password } } ... } |
具體一點來說,在沒有修改預設生成目錄結構的狀況下,這個 module 名稱就是「app」,而我們通常都是將 keystore 的相關資料填寫在 app/build.gradle 中。
這樣的狀況,若是該專案一直都是屬於個人開發的狀況下,那肯定是沒有問題的。但若是團隊開發,或是屬於公司的專案,這樣的設定勢必就會讓所有開發人員都看到該 keystore 的密碼資料。若是再有人將「keystore 的本體檔案」也放在專案目錄中,一起上傳到版本控管工具;甚或是一起包進 APK 檔裡上架,這樣團隊在強調自己很在意用戶安全,那也是很啟人疑竇了。
那該怎麼做呢?
接下來分成三個情境來介紹
- 整個 Android Studio 專案只會產出唯一一個要上架的 APK
- 將 keystore 的資訊獨立
- Android Studio 專案裡包含多個欲產出的 APK
專案僅產出唯一要上架的 APK (有但書)
這樣的狀況設定上較為簡單,在專案根目錄下的 gradle.properties 裡面加入 keystore 的相關資訊,程式格式如下
1 2 3 4 |
KEYSTORE_FILE=<YOUR_DIR>/<KEYSTORE_FILE> KEYSTORE_PASSWORD=<KEYSTORE_PASSWORD> KEYSTORE_ALIAS=<YOUR_ALIAS_NAME> KEYSTORE_ALIAS_PASSWORD=<ALIAS_PASSWORD> |
實際程式碼請參閱 github(only_one_module root) 上的 gradle.properties 。
再來打開 module 的 build.gradle 檔,在其中的 android {…} 片段裡做 signingConfigs 的設定,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
android { signingConfigs { sign { storeFile file(KEYSTORE_FILE) storePassword KEYSTORE_PASSWORD keyAlias KEYSTORE_ALIAS keyPassword KEYSTORE_ALIAS_PASSWORD } } ... buildTypes { release { ... signingConfig signingConfigs.sign } } } |
範例這邊的 Signing 區塊裡定義了一個名為「sign」的簽署設定,實際程式碼請參閱 github(only_one_module/app) 上的 build.gradle。
但書
由於很多時候,開發者團隊是沒有使用到根目錄下的這個 gradle.properties 這個設定檔的,所以可以直接用這個檔案做全域的系統參數宣告。
所以,以安全為由,記得不要將已寫入簽署資料的設定檔案放到版控平台上,讓非產出上架用 APK 的其他成員也能取得。
若是您的專案有用到這個檔案;又或是覺得上述方法的設定雖然簡單,但好像又有可能在晃神的狀況下,不小心將之更新到版控平台上,那就採用下面這樣的方式。
獨立出 keystore 的設定
在專案根目錄中建立一 keystore.properties (檔名任取),內容格式同上,請參照 github(keystore_extra root) 的keystore.properties。
再來是 module 中的 build.gradle 裡的部份程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
android { ... } //rootProject.file(): 取得根目錄中的檔案 def ksFile = rootProject.file('<YOUR_KEYSTORE_PROPERTY_NAME>') def props = new Properties(); if (ksFile.canRead()) { props.load(new FileInputStream(ksFile)) if (props != null) { android.signingConfigs.sign.storeFile file(props['KEYSTORE_FILE']) android.signingConfigs.sign.storePassword props['KEYSTORE_PASSWORD'] android.signingConfigs.sign.keyAlias props['KEYSTORE_ALIAS'] android.signingConfigs.sign.keyPassword props['KEYSTORE_ALIAS_PASSWORD'] } else { println 'some entries in \'keystore.properties\' not found!' } } else { println '\'keystore.properties\' not found!' } |
然後在其中的 android {…} 片段中的 signingConfigs {…} 縮減成如下即可
1 2 3 |
signingConfigs { sign } |
以上完整程式碼請見 github(keystore_extra/app) 的 build.gradle。
專案中會產出多個 APK
這個情境下,原則上就是一個 Android Studio 裡的專案裡,有多個 module 屬性為 com.android.application ,實作方式也是直接延續上述狀況,在不同的 module 裡面建立一個屬於各別的 keystore 屬性檔。
此完整範例在 github(multi_module)專案中,這個專案裡面有兩個 application module – app 以及 app2,其各別的 keystore 屬性檔名為 keystore.properites 與 app2_keystore.properites,裡面的內容也是大同小異。跟前述情境的不同處就在於其中的 build.gradle 裡,取出目錄的方式從
1 |
def ksFile = rootProject.file('<YOUR_KEYSTORE_PROPERTY_NAME>') |
改變為
1 2 |
//file(): 取得這個 module 目錄中的檔案 def ksFile = file('<YOUR_KEYSTORE_PROPERTY_NAME>') |
最後要提醒大家的是,本程式範例在 github 上是個錯誤試範,請各位自行在團隊開發時,務必記得,別將這些 keystore 的屬性檔以及本體全都上傳到版控平台上,甚或是跟著一起包進要上架的 APK 中嘍!
本篇的完整程式碼請見:Github[Android-Mosil-Sample-Gradle-Keystore]