Play Feature Delivery 總覽

Google Play 的應用程式供應模型會使用 Android App Bundle,針對每個使用者的裝置設定產生並提供最佳化的 APK,因此使用者只需下載執行應用程式所需的程式碼和資源。

Play Feature Delivery 使用應用程式套件的進階功能,以便視情況提供或隨選下載應用程式的特定功能。為此,您必須先將這些功能從基礎應用程式隔離,並納入功能模組。

功能模組建構設定

使用 Android Studio 建立新的功能模組時,IDE 會將下列 Gradle 外掛程式套用至模組的 build.gradle 檔案。

// The following applies the dynamic-feature plugin to your feature module.
// The plugin includes the Gradle tasks and properties required to configure and build
// an app bundle that includes your feature module.

plugins {
  id 'com.android.dynamic-feature'
}

標準應用程式外掛程式的許多可用屬性也適用於功能模組。以下各節說明應該與不應納入功能模組建構設定的屬性。

不應納入功能模組建構設定的內容

由於每個功能模組取決於基礎模組,因此也會沿用特定設定。所以您應在功能模組的 build.gradle 檔案中省略下列項目:

  • 簽署設定:應用程式套件是根據您在基礎模組中指定的簽署設定進行簽署。
  • minifyEnabled 屬性:您可以透過基礎模組的建構設定,為整個應用程式專案啟用程式碼縮減功能。因此,您應在功能模組中省略這個屬性。不過,您可以為每個功能模組指定其他 ProGuard 規則
  • versionCodeversionName:建立應用程式套件時,Gradle 會使用基礎模組提供的應用程式版本資訊。您應從功能模組的 build.gradle 檔案中省略這些屬性。

建立與基礎模組的關係

Android Studio 建立功能模組時,為了讓基本模組偵測到該模組,會將 android.dynamicFeatures 屬性新增至基礎模組的 build.gradle 檔案,如下所示:

// In the base module’s build.gradle file.
android {
    ...
    // Specifies feature modules that have a dependency on
    // this base module.
    dynamicFeatures = [":dynamic_feature", ":dynamic_feature2"]
}

此外,Android Studio 也納入基礎模組做為功能模組的依附元件,如下所示:

// In the feature module’s build.gradle file:
...
dependencies {
    ...
    // Declares a dependency on the base module, ':app'.
    implementation project(':app')
}

指定其他 ProGuard 規則

雖然只有基礎模組的建構設定可為應用程式專案啟用程式碼縮減功能,但您可以利用 proguardFiles 屬性,透過各個功能模組提供自訂 ProGuard 規則,如下所示。

android.buildTypes {
     release {
         // You must use the following property to specify additional ProGuard
         // rules for feature modules.
         proguardFiles 'proguard-rules-dynamic-features.pro'
     }
}

請注意,在建構期間,這些 ProGuard 規則會與其他模組 (包括基礎模組) 中的規則合併。因此,雖然每個功能模組可能都會指定一組新規則,但這些規則會套用至應用程式專案中的所有模組。

部署應用程式

在開發支援功能模組的應用程式時,您可以照常為已連結的裝置部署應用程式,方法是從選單列中依序選取「Run」>「Run」(或者點選工具列中的「Run」圖示 )。

如果您的應用程式專案包含一或多個功能模組,可以按照下列步驟修改現有的執行/偵錯設定,選擇要在部署應用程式時納入哪些功能:

  1. 在選單列中,依序選取「Run」>「Edit Configurations」
  2. 在「Run/Debug Configurations」對話方塊的左側面板中,選取所需「Android App」設定。
  3. 在「General」分頁的「Dynamic features to deploy」下方,找到部署應用程式時要納入的各項功能模組,然後勾選旁邊的方塊。
  4. 按一下「OK」

根據預設,Android Studio 不會使用應用程式套件部署應用程式。相反地,IDE 會在裝置中建構並安裝適當的 APK,從而將部署速度最佳化 (而非 APK 的大小)。如要將 Android Studio 設定改為透過建構和部署 APK 與免安裝體驗,而不是透過應用程式套件,請修改執行/偵錯設定

透過功能模組按照使用者的需求提供功能

使用功能模組特有的好處,就是能自訂將應用程式的不同功能下載到搭載 Android 5.0 (API 級別 21) 以上版本的裝置上的方式和時機。舉例來說,如要縮減應用程式的初始下載大小,您可以設定某些功能,讓使用者視需求隨選下載,或僅透過支援特定功能的裝置下載,例如拍照功能或支援擴增實境功能。

儘管在預設情況下,以應用程式套件的形式上傳應用程式即可取得經過高度最佳化的下載內容,但如果要使用更進階的自訂功能提供選項,就必須使用「功能模組」,對應用程式的功能進行額外設定及模組化作業。也就是說,功能模組可提供用於建立模組化功能的建構組塊,讓您能設定各項功能,視使用者的需求進行下載。

假設某個應用程式允許使用者透過線上市集買賣商品。您可以合理地將應用程式的下列各項功能模組化,成為獨立的功能模組:

  • 帳戶登入和建立
  • 瀏覽市集
  • 上架銷售商品
  • 處理付款

下表說明功能模組支援的不同提供選項,以及如何利用這些選項,最佳化此範例市集應用程式的初始下載大小。

提供選項 行為 用途範例 開始使用
安裝時提供 根據預設,若未設定上述任何提供選項,系統會在安裝應用程式時下載功能模組。這項行為至關重要,因為這意味著您可以逐步採用進階提供選項。比如說,您必須先使用 Play Feature Delivery 程式庫完整實作隨選下載程序,才能受益於應用程式功能的模組化作業並啟用隨選提供功能。

此外,應用程式日後也可以要求解除安裝各項功能。因此,假如您只在應用程式安裝期間需要 (安裝之後即不需要) 使用特定功能,可以要求從裝置上移除該項功能,藉此縮減安裝大小。

如果應用程式提供特定的訓練活動,例如有關如何在市集中買賣商品的互動式指南,您可以預設在應用程式安裝時加入該功能。

但是,如要縮減應用程式安裝大小,應用程式可以在使用者完成訓練後要求刪除該功能。

運用未設定進階提供選項的功能模組進行應用程式模組化作業。

如要瞭解如何透過移除使用者不再需要的特定功能模組來縮減應用程式安裝大小,請參閱管理已安裝的模組一文。

隨選提供 允許應用程式視需要要求和下載功能模組。 如果只有 20% 的市集應用程式使用者上架銷售商品,大多數的使用者想要縮減初始下載大小時,建議以隨選下載項目的形式,提供拍照功能 (含商品說明) 和銷售商品上架功能。也就是說,您可設定僅在使用者有意將銷售商品上架到市集時,才下載用於應用程式銷售功能的功能模組。

此外,如果使用者在經過一段時間後不再銷售商品,應用程式可以要求解除安裝該功能,以縮減其安裝大小。

建立功能模組並設定隨選提供。這樣一來,應用程式就能透過 Play Feature Delivery 程式庫來要求下載隨選模組。
條件式提供 可讓您指定特定使用者裝置需求,例如硬體功能、語言代碼和最低 API 級別,藉此判定是否在安裝應用程式時下載相關模組化功能。 如果市集應用程式提供全球服務,您可能需要支援只有在特定區域或當地風行的付款方式。為了縮減應用程式初始下載大小,您可以建立獨立的功能模組,用於處理特定類型的付款方式,並根據使用者登錄的語言代碼,有條件地安裝在使用者的裝置上。 建立功能模組並設定條件式提供
免安裝提供 Google Play 免安裝技術可讓使用者無須在裝置上安裝應用程式,就能與應用程式互動。他們只須透過 Google Play 商店上的「立即體驗」按鈕或您建立的網址,就能體驗應用程式。這種提供內容的方式可讓您更輕鬆地提高應用程式的參與度。

透過免安裝提供,您可運用 Google Play 免安裝技術,讓使用者無須安裝就能立即體驗應用程式的某些功能。

假設遊戲的輕量功能模組中含有遊戲的前幾個關卡。您可以將該模組設定為免安裝即用,讓使用者無須安裝應用程式,就能透過網址連結或「立即體驗」按鈕免安裝體驗遊戲。 建立功能模組並設定免安裝提供。這樣一來,應用程式就能透過 Play Feature Delivery 程式庫來要求下載隨選模組。

請注意,利用功能模組進行應用程式功能模組化作業只是第一步。如要支援 Google Play 免安裝技術,應用程式基礎模組和特定免安裝即用功能的下載大小,都必須符合嚴格的大小限制。詳情請參閱透過縮減應用程式或遊戲大小來啟用免安裝體驗一文。

建立資源的 URI

如果您要透過 URI 存取儲存在某個功能模組中的資源,以下提供利用 Uri.Builder() 產生功能模組資源 URI 的方式:

Kotlin

val uri = Uri.Builder()
                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                .authority(context.getPackageName()) // Look up the resources in the application with its splits loaded
                .appendPath(resources.getResourceTypeName(resId))
                .appendPath(String.format("%s:%s",
                  resources.getResourcePackageName(resId), // Look up the dynamic resource in the split namespace.
                  resources.getResourceEntryName(resId)
                  ))
                .build()

Java

String uri = Uri.Builder()
                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                .authority(context.getPackageName()) // Look up the resources in the application with its splits loaded
                .appendPath(resources.getResourceTypeName(resId))
                .appendPath(String.format("%s:%s",
                  resources.getResourcePackageName(resId), // Look up the dynamic resource in the split namespace.
                  resources.getResourceEntryName(resId)
                  ))
                .build().toString();

資源路徑的每個部分都是在執行階段建構,確保在載入分割 APK 後,才會產生正確的命名空間。

為了說明 URI 的產生方式,先假設您有具備下列名稱的應用程式和功能模組:

  • 應用程式套件名稱:com.example.my_app_package
  • 功能的資源套件名稱:com.example.my_app_package.my_dynamic_feature

如果上述程式碼片段中的 resId 參照功能模組中名為「my_video」的原始檔案資源,則上述的 Uri.Builder() 程式碼會輸出下列內容:

android.resource://com.example.my_app_package/raw/com.example.my_app_package.my_dynamic_feature:my_video

這樣一來,應用程式就能利用此 URI 存取該功能模組的資源。

如要驗證 URI 中的路徑,您可使用 APK 分析工具來檢查功能模組 APK,並判定套件名稱:

APK 分析工具檢查已編譯資源檔案的內容時的螢幕截圖。

圖 2. 使用 APK 分析工具檢查已編譯資源檔案中的套件名稱。

功能模組的注意事項

您可以透過功能模組提升建構速度和工程速度,並廣泛自訂應用程式的功能提供方式,藉此縮減應用程式大小。不過,使用功能模組時,請留意相關限制和極端案件:

  • 透過條件式或隨選提供,在單一裝置上安裝 50 個以上的功能模組後,可能會引發效能問題。基礎模組會自動加入未設定為可移除的安裝時間模組,且在每台裝置上只會計為一個功能模組。
  • 將設為可移除的安裝時提供模組數量限制在 10 個以下。否則,可能會加長應用程式的下載和安裝時間。
  • 只有搭載 Android 5.0 (API 級別 21) 以上版本的裝置,才能隨選下載和安裝功能。若要讓功能適用於較舊的 Android 版本,請在建立功能模組時,啟用「融合」功能。
  • 啟用 SplitCompat,讓應用程式能夠存取隨選提供的已下載功能模組。
  • android:exported 設為 true 時,功能模組不應在資訊清單中指定活動。原因在於,當其他應用程式嘗試啟動活動時,不保證裝置已下載功能模組。此外,應用程式在嘗試存取特定功能的程式碼和資源之前,應先確認已下載該功能。詳情請參閱管理已安裝的模組一文。
  • 由於 Play Feature Delivery 規定您必須使用應用程式套件發布應用程式,因此請務必瞭解應用程式套件的已知問題

功能模組資訊清單參考資料

使用 Android Studio 建立新的功能模組時,IDE 會加入模組所需的大多數資訊清單屬性,以便呈現功能模組的行為模式。此外,建構系統也會在編譯期間插入部分屬性,因此您無須自行指定或修改這些屬性。下表說明重要的功能模組資訊清單屬性。

屬性 說明
<manifest
...
這是一般的 <manifest> 區塊。
xmlns:dist="http://schemas.android.com/apk/distribution" 指定新的 dist: XML 命名空間 (將於下文說明)。
split="split_name" 當 Android Studio 建立應用程式套件時,其中會包含這項屬性。因此,請勿自行加入或修改這項屬性

定義應用程式使用 Play Feature Delivery 程式庫要求隨選模組時會指定的模組名稱。

Gradle 如何判定這項屬性的值:

根據預設,當您透過 Android Studio 建立功能模組時,IDE 會使用您指定的「Module name」,在 Gradle 設定檔中將該模組視為 Gradle 子專案。

當您建立應用程式套件時,Gradle 會使用子專案路徑的最後一個元素,在模組的資訊清單中插入此資訊清單屬性。舉例來說,假設您在 MyAppProject/features/ 目錄中建立新的功能模組,並將「dynamic_feature1」指定為「Module name」,IDE 就會在 settings.gradle 檔案中新增 ':features:dynamic_feature1' 做為子專案。這樣一來,Gradle 就會在建立應用程式套件時,在模組的資訊清單中插入 <manifest split="dynamic_feature1">

android:isFeatureSplit="true | false"> 當 Android Studio 建立應用程式套件時,其中會包含這項屬性。因此,請勿手動加入或修改這項屬性

指定這個模組為功能模組。基礎模組和設定 APK 中的資訊清單可能會省略這個屬性,或是將其設為 false

<dist:module 這個新的 XML 元素會定義相關屬性,判定模組以 APK 的形式包裝和發布的方式。
dist:instant="true | false" 指定是否應透過 Google Play 免安裝技術提供模組,做為免安裝體驗。

如果應用程式包含一或多個免安裝即用的功能模組,您也必須將基礎模組設為免安裝即用。使用 Android Studio 3.5 以上版本時,IDE 會在您建立免安裝即用的功能模組時,為您完成這項操作。

您無法在此 XML 元素設定為 true 的情況下,同時設定 <dist:on-demand/>。不過,您還是可以使用 Play Feature Delivery 程式庫,要求隨選下載免安裝即用的功能模組「做為免安裝體驗」。根據預設,使用者下載並「安裝」應用程式時,裝置會下載並安裝應用程式的免安裝即用功能模組,以及基礎 APK。

dist:title="@string/feature_name" 指定使用者看到的模組標題。例如,裝置要求下載確認時,裝置可能會顯示這個標題。

您必須在基礎模組的 module_root/src/source_set/res/values/strings.xml 檔案中納入這個標題的字串資源。

<dist:fusing dist:include="true | false" />
</dist:module>
指定是否將模組納入適用於搭載 Android 4.4 (API 級別 20) 以下版本的裝置的多個 APK。

此外,當您使用 bundletool 從應用程式套件產生 APK 時,只會在通用 APK 中納入將這個屬性設為 true 的功能模組-這是單體式 APK,內含應用程式支援的所有裝置設定的程式碼和資源。

<dist:delivery> 封裝自訂模組提供的選項,如下所示。請留意,每個功能模組只能設定一種自訂提供選項。
<dist:install-time> 指定應可在安裝期間使用該模組。這是未指定另一種自訂提供選項的功能模組的預設行為。

如要進一步瞭解安裝時的下載作業,請參閱設定安裝時提供功能一文。

這個節點也可以指定條件,限制模組只能下載至符合特定需求的裝置,例如裝置功能、使用者國家/地區或最低 API 級別。詳情請參閱設定條件式提供功能

<dist:removable dist:value="true | false" />

在未設定或設為 false 的情況下,Bundletool 會在透過套件產生分割 APK 時,將安裝時間模組融入基礎模組中。由於融合後產生的分割 APK 數量較少,因此這項設定有助於改善應用程式的效能。

removable 設為 true 時:不會將安裝時間模組融入基礎模組。如果日後想要解除安裝模組,請設為 true。不過,如果將過多模組設為可移除,則可能會延長應用程式的安裝時間。

預設為 false。只有在您想停用功能模組的融合功能時,才需要在資訊清單中設定這個值。

注意:只有使用 Android Gradle 外掛程式 4.2 或透過指令列使用 bundletool v1.0 時,才能使用這項功能。

</dist:install-time>  
<dist:on-demand/> 指定模組是否應以隨選下載的形式提供。也就是說,無法在安裝時使用模組,但應用程式之後可能會要求下載該模組。

如要進一步瞭解隨選下載,請參閱設定隨選提供功能一文。

</dist:delivery>
<application
android:hasCode="true | false">
...
</application>
如果功能模組不會產生任何 DEX 檔案,也就是未包含之後編譯至 DEX 檔案格式的任何程式碼,您必須執行下列操作 (否則可能會發生執行階段錯誤):
  1. 在功能模組的資訊清單中,將 android:hasCode 設為 "false"
  2. 將以下內容新增至「基礎」模組的資訊清單:
    
    <application
      android:hasCode="true"
      tools:replace="android:hasCode">
      ...
    </application>
    

其他資源

若要進一步瞭解如何使用功能模組,請參考下列資源。

網誌文章

影片

服務條款與資料安全性

存取或使用 Play Feature Delivery 程式庫,即表示您同意《Play Core 軟體開發套件服務條款》。存取程式庫前,請先詳閱並瞭解所有適用的條款和政策。

資料安全性

Play Core 程式庫是您的應用程式與 Google Play 商店之間的執行階段介面。因此,在應用程式中使用 Play Core 時,Play 商店會執行自己的程序,包括依據《Google Play 服務條款》的規範處理資料。以下資訊說明 Play Core 程式庫如何處理資料,以處理來自應用程式的特定要求。

其他語言 API

收集到資料的使用情況 已安裝的語言清單
資料收集目的 收集到的資料會用於提供不同語言版本的應用程式,並在應用程式更新後保留已安裝的語言。
資料加密 資料已加密。
資料分享 資料不會轉移給任何第三方。
資料刪除 過了固定的保留期限後,系統會刪除資料。

Play Feature Delivery

收集到資料的使用情況 裝置中繼資料
應用程式版本
資料收集目的 收集到的資料會用於為裝置提供適當的模組,並在更新、備份及還原之後保留已安裝的模組。
資料加密 資料已加密。
資料分享 資料不會轉移給任何第三方。
資料刪除 過了固定的保留期限後,系統會刪除資料。

雖然我們力求盡可能維持公開透明,但您必須全權負責決定如何回應 Google Play 的「資料安全性」專區表單,有關應用程式使用者資料收集、分享和安全性的做法。