# Android App Bundle > 整理文章作者:歐文 [TOC] --- ### 自 2021 年 8 月起,在 Google Play 新發布的所有應用程式都必須採用`Android App Bundle` `Android App Bundle`(aab)是Android推出的新格式,它與APK非常相同,但是它將程式、架構及資源分開,在安裝時針對裝置重新組成Apk,達到降低Apk容量目的,但是使用者無法對aab直接安裝。 ![](https://i.imgur.com/TXwTGCY.gif) --- ## 注意事項: 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觀看。 ![](https://i.imgur.com/5dUlNOv.png) ![](https://i.imgur.com/6mCEg4K.png) ### 實際發版流程會是以下圖示。 ![](https://i.imgur.com/KYzHAxe.png) 在加殼時會偵測APK是否被二次打包,判斷因素之一會使用SigningKey Hash是否更改為判斷基準,因此須重新上傳簽署金鑰 ### 置換後發版流程會是以下圖示。 ![](https://i.imgur.com/tFLF0RU.png) 這樣就能確保使用者安裝的APK與自己當初上傳打包的Key是同一把。 --- ## Android App Bundle 格式 ![](https://i.imgur.com/VXMGsZS.png) aab架構如圖所示,Google Play 會針對下載的設備重組全新的APK安裝檔,達到不必要的資源被放入安裝檔。 --- ## 動態模組配置 - **~~變數太多不建議使用~~** ![](https://i.imgur.com/ZyFAw5T.png) 動態功能模組允許您將某些功能和資源與應用程式的基本模組分開,並將它們包含在您的應用程式包中。通過動態交付,使用者可以在安裝了應用程式的基本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=)