# Android App Bundle
> 整理文章作者:歐文
[TOC]
---
### 自 2021 年 8 月起,在 Google Play 新發布的所有應用程式都必須採用`Android App Bundle`
`Android App Bundle`(aab)是Android推出的新格式,它與APK非常相同,但是它將程式、架構及資源分開,在安裝時針對裝置重新組成Apk,達到降低Apk容量目的,但是使用者無法對aab直接安裝。

---
## 注意事項:
1. 建置環境須`Android Studio 3.2+`
2. 設備無法直接安裝aab檔案
3. 要安裝aab須透過command line使用bundletool安裝
4. 必須註冊 Google Play 應用程式簽署功能(App Signing)
5. `App Signing`發版出去的APK `Fingerprint Hash` 會不同,須去Google Play Console 確認Hash值,否則會被加殼方認定二次打包的APK,請參考["Google Play 打包APK"](#Google-Play-打包APK)。
6. 因為APK是透過動態模組,所以須注意`Dexguard`或`Arxan`偵測是否能正常發揮
7. GuardSquare 須使用Dexguard 9
8. Android App Bundles 不支援 APK expansion (*.obb) files,替代方式請參考第9項
9. aab組出的APK超過150MB須透過`Play Asset Delivery`或 `Play Feature Delivery`擴充
10. aab分割重組APK,只支援Android 5以上,之下的版本都會下載最原始未分割APK。
11. 因為APK是透過aab重組,因此多國語系須注意`enableSplit` 設定,否則會根據設備系統語言下載字串檔,使用者更換語言須重新安裝才能顯示該語言,有以下兩種解決辦法。
### 關閉語系分割
```
android {
...
bundle {
language {
// Specifies that the app bundle should not support
// configuration APKs for language resources. These
// resources are instead packaged with each base and
// dynamic feature APK.
enableSplit = false
}
abi {
...
}
density{
...
}
}
}
```
### 不關閉語系分割,可以透過動態模組配置加載語言包
``` Kotlin
// Creates a request to download and install additional language resources.
val request = SplitInstallRequest.newBuilder()
// Uses the addLanguage() method to include French language resources in the request.
// Note that country codes are ignored. That is, if your app
// includes resources for “fr-FR” and “fr-CA”, resources for both
// country codes are downloaded when requesting resources for "fr".
.addLanguage(Locale.forLanguageTag("zh_TW")
.build()
// Submits the request to install the additional language resources.
splitInstallManager.startInstall(request)
```
---
## Google Play 打包APK
當APP 註冊 Google Play 應用程式簽署功能,會有上傳Key及簽署Key 兩把Key會是不同,可至Google Play Console觀看。


### 實際發版流程會是以下圖示。

在加殼時會偵測APK是否被二次打包,判斷因素之一會使用SigningKey Hash是否更改為判斷基準,因此須重新上傳簽署金鑰
### 置換後發版流程會是以下圖示。

這樣就能確保使用者安裝的APK與自己當初上傳打包的Key是同一把。
---
## Android App Bundle 格式

aab架構如圖所示,Google Play 會針對下載的設備重組全新的APK安裝檔,達到不必要的資源被放入安裝檔。
---
## 動態模組配置 - **~~變數太多不建議使用~~**

動態功能模組允許您將某些功能和資源與應用程式的基本模組分開,並將它們包含在您的應用程式包中。通過動態交付,使用者可以在安裝了應用程式的基本APK後,在需要時下載和安裝這些元件。
>功能模組(Feature APK)是透過動態加載,所以無法引用到基本模組(Base APK)裡的資源(Resource),這是因為Google Play在生成APK時已經將原本的模組資源與基本模組合併關聯,因此動態加載進來的並無此關聯。
Android 8 (API 26)以下加載完須重新啟動APP。
## Android 平台上發佈應用程式必須採取以下步驟之差異:
### APK
- 步驟 1:在 Android Studio 等 IDE 中編寫應用程式的所有程式碼。
- 步驟 2:建置為 Android 的應用程式格式 APK。建置 APK 時,須以應用程式簽署金鑰進行數位簽署,將是附加到應用程式**“專屬憑證”**,並確保持續更新應用程式時,在更新前Android 一律會先確認更新的**專屬憑證**是否符合裝置上應用程式的。
- 步驟 3:透過 Google Play 管理中心將已簽署 APK 上傳,一切準備就緒後,就可以將應用程式發佈開放使用者安裝。
- 步驟 4:當使用者安裝應用程式,Google Play 就會將您上傳的已簽署 APK 原封不動地發佈至使用者的裝置上。
### Android App Bundle
- 步驟 1:在 Android Studio 等 IDE 中編寫應用程式的所有程式碼
- 步驟 2:建置為新的 Android 應用程式格式 Android App Bundle。仍須簽署應用程式,讓 Google Play 驗證您的應用程式開發人員身分。
- 步驟 3:請先加入 Google Play 應用程式簽署計劃,或準備發佈新應用程式,只要在上傳應用程式時按一下就能加入。
加入計劃後,Play 會將您用於**簽署應用程式套件的金鑰指定為「上傳金鑰」,**這個金鑰只會用於安全識別身分,如果您遺失了金鑰,只要與 Google 聯絡,驗證您的身分並重設金鑰即可。
**(**針對現有應用程式,您則必須前往該應用程式在 Play 管理中心的應用程式簽署部分,然後將應用程式簽署金鑰轉移至 Google Play。**)**
- 步驟 4:您將應用程式套件上傳至 Google Play 後,Play 會加以處理,**並針對所有可能的裝置設定和您支援的語言,產生以應用程式簽署金鑰簽署的分割 APK。**
分割 APK 是一項於 Android 5.0 推出的 Android 平台功能**,**只要每個**分割 APK 皆以同樣的金鑰簽署**,Android 平台就會將它們視為單一應用程式。**您可以將分割 APK 想成 APK 的「零件」:**要執行應用程式時,裝置會將所有必要的**零件」集結起來組成「完整」的應用程式。**
- 步驟 5:當有使用者安裝應用程式,**Play 會發佈基準 APK (也就是每部裝置共通的所有程式碼)、語言分割 APK (針對該使用者的常用語言),以及裝置設定分割 APK (包含針對各裝置螢幕大小和 CPU 架構的分割 APK)**。
裝置只會取得需要的內容,不會浪費任何空間。如要讓裝置接受更新,每個版本的分割 APK 都必須用和原始應用程式安裝檔相同的應用程式簽署金鑰進行簽署。
- 更多參考:
[https://docs.google.com/document/d/e/2PACX-1vRlKvEnPkBorwar-iK0xnpLmKXjhqQB-WmQL6B93uhyzk3ELsPkoFSUDRcHjmLsccmWhKTg2wkBOOJL/pub](https://docs.google.com/document/d/e/2PACX-1vRlKvEnPkBorwar-iK0xnpLmKXjhqQB-WmQL6B93uhyzk3ELsPkoFSUDRcHjmLsccmWhKTg2wkBOOJL/pub)
[Use Play App Signing](https://support.google.com/googleplay/android-developer/answer/9842756?visit_id=637611476105555515-704147332&rd=1#zippy=)