Play Asset Deliveryとは
参考: Google公式ドキュメント - Play Asset Delivery
旧来はGoogle Playにアップロードするapkには100MBという制限があって、収まりきらないリソースを別途アップロードする Opaque Binary Blob (OBB) という仕組みが存在した。
2021年8月からは Android App Bundle (ABB) という新しい仕組みが必須対応となり、この仕組みにおけるOBBに相当する機能が Play Asset Delivery。
Play Asset Deliveryではアセットパックという単位でリソースを扱う。アセットパックには以下の配信モードを紐付けることができる。
配信モード名 | ダウンロードタイミング | サイズ制限 | ストアのアプリサイズ | 削除可能性 | 注意事項 |
---|---|---|---|---|---|
install-time | アプリインストール時 | 1GB | 含まれる | AABの機能によって1つのapkとしてインストールされるので削除されない | |
fast-follow | インストール直後 | 512MB | 含まれる | アプリの内部ストレージ領域に展開され、削除の可能性がある | アプリ起動時にDLが完了していない可能性がある |
on-demand | リクエスト時 | 512MB | 含まれない | アプリの内部ストレージ領域に展開され、削除の可能性がある |
Android App Bundle (AAB) とは
参考: Google公式ドキュメント - Android App Bundle
従来のapkは1つのファイルの中にx64やarm64といったCPUアーキテクチャ別のバイナリや、hdpiやxhdpiといった画面密度別のリソースなどが全て含まれていた。
これだと不要なデータまで含まれてしまって無駄なので、細かく分割して動的にapkを構成してインストールする仕組みが生み出された。その仕組みに対応したファイル形式がAndroid App Bundle。
イメージとしてはAndroid Developers Blogのgifが分かりやすい。
UnityにおけるAAB、Play Asset Delivery対応
参考: Unity公式ドキュメント - Play Asset Delivery
UnityでもAABおよびPlay Asset Deliveryを利用する仕組みは提供されている。Unity設定に示す項目を設定してビルドするだけでPlay Asset Delivery対応のAABが成果物として出力される。
Unityが内部でどのようなことをしているかはUnityの「Split Application Binary」を用いて、GooglePlay Storeで150MBより大きいアプリケーションを配信するという記事で詳しく調査されています。
仕様
- 対象アセットのサイズが1GB未満の場合、全て1つのアセットパックにまとめて、
install-time
配信モードになる- この場合、追加実装は不要。ストリーミングアセットにアクセスする際の
Application.streamingAssetsPath
で取得できるパスがアセットパックを考慮したものになっている
- この場合、追加実装は不要。ストリーミングアセットにアクセスする際の
- 対象アセットのサイズが1GB以上の場合、ストリーミングアセットで1つ、その他で1つのアセットパックにまとめて、大きい方が
install-time
、小さい方がfast-follow
配信モードになる。- この場合、追加実装が必要。
fast-follow
配信モードはインストール後にDLが開始するけれど、必要なタイミングまでにDLが完了しているとは限らないのでハンドリング処理が必要になる
- この場合、追加実装が必要。
カスタムアセットパックという仕組みを使うことで任意のアセット、任意の配信モードのアセットパックを作ることもできる。
Unity設定
① 出力をapkからaabにする
- File > Build Settings から Build Settingsウィンドウを開く
- PlatformのAndroid設定において、Build App Bundle (Google Play) を有効にする
※ Export Project が有効の場合、Export for App Bundle という項目名に変化している
② ベースモジュールとアセットパックを分割する
- Edit > Project Settings から Project Settingsウィンドウを開き、Playerカテゴリを選択する
- Android タブを開き、Publishing Settings セクションを選択する
- Split Application Binary を有効にする
成果物(aab)に含まれるもの
- ベースモジュール
- プラグイン、スクリプト、アセット、ビルドインデックスが0のシーンの実行ファイル
- アセットパック
- 残りのシーン、リソース、ストリーミングアセットなど
実機上のパス
-
install-time
- apk領域
- jar:file:///data/app/[アプリのID]-[ハッシュ値]/split_[アセットパック名].apk!/assets/[アセットのパス]
-
fast-follow
,on-demand
- 内部ストレージ領域 (Javaの
getFilesDir()
で取得できるパス) - /data/data/[アプリのID]/files/assetpacks/[アセットパック名]/[Bundle Version Code]/[Bundle Version Code]/assets/[アセットパス]
- 内部ストレージ領域 (Javaの
動作確認について
参考: Google公式ドキュメント - アセット配信をテストする
UnityエディタにAndroid実機を繋いでBuild And Runすれば動作確認ができる。
install-time
はアプリのインストールと一緒にインストールされる。
fast-follow
はon-demand
と同様の動作となる (明示的にリクエストしないとDLされない)。
注意事項は下記
- Google Playからではなく外部ストレージからパックを取得するのでネットワークエラーのテストはできない
- Wi-Fi接続を待つテストはできない
- アセットパックのアップデートはサポートされない。事前にアンインストールしたりデータ消去する必要がある
多少手間はかかるけれど、Google Playの内部テストで動作確認するほうがトータルの手間は少ないかもしれない。
Addressable Asset Systemの場合
配置先がローカル (= ストリーミングアセット) になっているグループのAssetBundleが全てアセットパックに含まれる。
ファイルサイズが1GB未満でinstall-time
だけでいいなら特に追加実装は不要。
ファイルサイズが1GB以上になると前述のようにアセットパックが分割されて小さいほうがfast-follow
配信モードになるので追加実装が必要。
※ 追加の実装 = fast-follow
やon-demand
のアセットパックの場合、必要時にDLされていなければDLする処理
追加実装はAddressables公式サンプルから必要なファイルを持ってきて、適宜改変するのが楽。
Warning
Addressables 1.21.1でGenerateLocationListsTask.cs
に入った変更によって、カタログに記載されるInternalIdのセパレータが/
から\
に変わったため、公式サンプルのコードのままでは正常に動作しない。
PlayAssetDeliveryAssetBundleProvider.cs
とPlayAssetDeliveryInitialization.cs
のInternalIdに関する操作のところで、セパレータの置換をしてやれば動作するようになる。
作業手順
Unity設定も必要
- Addressables公式サンプルをクローンする
-
Addressables-Sample/Advanced/Play Asset Delivery/Assets/PlayAssetDelivery
フォルダをAssets
配下にコピーする -
Assets/AddressableAssetsData/AddressableAssetSettings.asset
のインスペクタを開き、Build and Play Mode ScriptにAssets/PlayAssetDelivery/Data/BuildScriptPlayAssetDelivery.asset
を追加する - 同インスペクタのInitialization Objectsに
Assets/PlayAssetDelivery/Data/PlayAssetDeliveryInitializationSettings.asset
を追加する - Addressables Groupsウィンドウにて、Play Asset Deliveryに含めたいグループのインスペクタを開き、Add Schemaボタンを押下して、Play Asset Deliveryを選択して追加する。配信モードを選択できるので任意の設定を行う
- 同インスペクタのAsset Bundle Providerの項目をPlay Asset Delivery Providerに変更する
- Build & LoadPathsの項目をLocalに変更する
- アセットのビルドはDefault Build ScriptではなくPlay Asset Deliveryを用いる
実装調査
ビルドスクリプト
Play Asset Deliveryの実体はBuildScriptPlayAssetDelivery.cs
で、Default Build Scriptの実体であるBuildScriptPackedMode.cs
を継承している。内部の処理も継承元であるBuildScriptPackedModeのビルド処理を実行後にPlay Asset Delivery用の追加処理を実行しているだけなので、プラットフォーム問わず導入後はこちらに切り替えて構わない。
リソースプロバイダ
PlayAssetDeliveryProviderはアセットバンドル用のプロバイダであるAssetBundleProviderを継承している。
Android実機以外のプラットフォームでは親のAssetBundleProviderとして振る舞う。
Android実機ではアセットパックの状況を確認し、必要ならDLしてから親のAssetBundleProviderとして振る舞う。
グループスキーマ
CustomAssetPackSettings.asset
のインスペクタでアセットパックの定義をする。
カスタムアセットパックを定義した場合、必要な[アセットパック名].androidpack
フォルダやbuild.gradle
を自動で生成する。
Play Asset Delivery用のグループスキーマを追加することで、グループごとにどのアセットパックに含めるか指定できる。
Unityの仕様変更
アセットパックの配置仕様がパッチバージョンで変わっているので注意が必要。
リリースノートでは UUM-15109
というIssueIDで表記されている。
2021では3.15から、2022では2.9から、2023では1.0から変更されている。
- 変更前
- [アセットパック名].androidpack/XXX.bundle
- 変更後
- [アセットパック名].androidpack/src/main/assets/XXX.bundle
AABを調べてみる
適当なサンプルプロジェクトをARMv7
とARM64
アーキテクチャ向けにビルドしたTest.aab
を調べてみる。
aabを展開する
Google公式でbundletoolというツールが提供されている。これを使うことでAABファイルを展開できる。
Homebrewでもインストール可能 (Homebrew Formulae - bundletool) なのでMacOSやLinuxの場合はそちらを使うほうが楽かもしれない。
aabからapkセットを生成する
bundletoolのbuild-apksコマンドでaabからapkセットファイルを生成できる。
ビルドしたTest.aab
からTest.apks
を生成するコマンドは以下のようになる。
bundletool build-apks --bundle="./Test.aab" --output="./Test.apks" \
--ks="<keystoreFilePath>" \
--ks-pass="pass:<storePassword>" \
--ks-key-alias="<keyAlias>" \
--key-pass="pass:<keyPassword>"
apkセットを展開する
生成されたapkセット (.apks
) ファイルはただのzipなので拡張子を変えれば展開できる。
splits配下に格納されているのがベースモジュール、asset-slices配下に格納されているのがアセットパック。
ここから端末に合わせて動的に統合されたapkがインストールされる。
apkも展開してみる
apktoolを使うことでapkファイルの展開ができる。
Homebrewでもインストール可能 (Homebrew Formulae - apktool) なのでMacOSやLinuxの場合はそちらを使うほうが楽かもしれない。
apkを展開するコマンドは以下のようになる。
apktool d <apkFilePath>
base-master.apk
の展開結果
- Unityの基本的なアセットやglobal-metadata.dataがassets配下に格納されている
- original配下にはapktoolによってデコードされる前の生のAndroidManifest.xmlが格納されている
- res配下には画面密度別のアプリアイコンやstrings.xmlが格納されている
- smali配下にはapktoolによってJava実行ファイルのclasses.dexをデコードしたsmaliファイルが格納されている
※ .smali
はAndroid Dalvik仮想マシンで使用されるアセンブリ言語であるSmaliで記述されたファイル
base-arm64_v8a.apk
とbase-armeabi_v7a.apk
の展開結果
- lib配下にはそれぞれarm64-v8a向けとarmeabi-v7a向けのネイティブバイナリが格納されている
UnityDataAssetPack-master.apk
の展開結果
- assets配下にAddressablesにてローカル設定にしたアセットバンドルとカタログや設定ファイルが格納されている
aabをGoogle Play Consoleにアップロードしてみる
Google Play Consoleにaabをアップロードすると App Bundle エクスプローラでaabの詳細を確認することができる。
デバイス別のapkセットのDL
デバイス一覧からデバイスごとのapkセットをzip形式でDLすることができる。
試しに10.or E
と3BBTV TBBTV01
のapkセットをDLしてみると、base.apk
とUnityDataAssetPack.apk
は共通でCPUアーキテクチャ別のapkだけが異なるのが確認できた。
10.or E
のapkセット
3BBTV TBBTV01
のapkセット
署名済みのユニバーサルAPKのDL
AABが登場する以前の1つのapkに全端末用のデータが入ったapkファイル形式でDLできる。
aabファイルをbundletoolとApktoolで展開した際に個々のapkに含まれていたファイルが全て1つのapkに格納されているのが確認できた。
Unityは1GB未満ならばinstall-time
になるのが仕様で、それもここで確認できた。
モジュールとアセットパックの確認
配信タブでは機能モジュールとアセットパックが確認できる。
機能モジュールにはbase
という名前のモジュールが1つあり、マスター1つとABI2種類の3つから構成されることが確認できた。
アセットパックにはUnityDataAssetPack
という名前のアセットパックが1つあり、Unityの仕様通りにinstall-time
配信モードであることが確認できた。
アセットパックを複数作った場合
Addressables公式サンプルのPlay Asset Deliveryのサンプルを利用してinstall-time
, fast-follow
, on-demand
それぞれのアセットパックを生成してみた。
aabを展開するとasset-slices配下に3つのアセットパックが格納されているのが確認できた。
またApp Bundle エクスプローラにてそれぞれのアセットパックに配信モードが適切に設定されているのが確認できた。