見出し画像

Android App Bundle(AAB)が150MBを超えてしまった場合の対応

AABが150MBを超えてしまって、Play Consoleへアップロードできない。
対応方法をググっても、むずかしくてよくわからない。
理解は後回しでいいから、とにかくリリースできるようにしたい。
・・・といった方に喜ばれるかもしれない記事です。

自己紹介

はじめまして。
Unityでゲーム開発をしているpopliner99と言います。
これまでにAndroid向けのゲームを数本リリースしています。いずれもシンプルなゲームです。
noteに記事を書くのは初めてです。
無味乾燥な記事になってしまいましたが、気にせず公開することにします。

記事を書くきっかけ

今回、タイトルのような問題にぶつかって私なりに対応しました。
2021/8/1よりGoogle PlayがAABのみ対応になり(=APK不可=OBB不可)、誰かの役に立つかもと思い、記事にすることにしました。

ゲームをPlay Consoleにアップロードしたら怒られた

まずは問題の契機を。

7月下旬、開発中だった拙作「さえずりクイズ おうちで? バードウォッチング」がようやく完成したので、AABファイルをPlay Consoleにアップロードしたところ、失敗した。以下のようなメッセージがブラウザに表示された。

App Bundle に含まれている設定(ARM64_V8A)で、初期インストールのサイズは 150 MB 以下である必要があります。

ん? よくわからないが・・・AABにファイルサイズの制限があるのか?

UnityでBuildしたAABファイルのサイズを確認すると、220MB強。150MBに対して70MB以上オーバーしている。
ゲームの内容が「鳴き声を聞いて、何の鳥かを当てるクイズゲーム」なので、大量のmp3ファイルを含んでおりそれがAABファイルサイズの肥大化の原因のようだ。

数MBの超過であれば、mp3を編集して再生時間を短くしたり一部の音質を下げることでごまかせたと思うが、ゲームのコンテンツ(クイズゲームなので、設問数)を大幅に削らないと、70MBも減らせない。
設問数をこれ以上減らすとクイズとしての規模が純粋に小さくなってしまうので、今更それはできない。
SNSでGoogle Playへの申請予定日も発表しており、それも翌日に迫っていた。

状況を理解して、冷や汗が出た。

ぇぇえ・・・。いやまて、AABの上限サイズが150MBなんていくら何でも小さすぎる。このゲームよりもはるかにリッチなコンテンツのゲームなんていくらでもあるじゃないか。
たった150MBしか許容できないわけがない。何か対策があるはずだ!

結論としては、AABのサイズが150MBを超えてもPlay Consoleにアップロードする方法はありました。

具体的な対応について、この後説明していきたいと思います。

最も参考にさせていただいたサイト

まず最初に、最も参考にさせていただいたサイトは、以下です。

上記のunagirabbit’s blogさんの記事の冒頭の一節が、「AABが150MBを超えてしまった場合の対応」を最初から最後まで、正確に述べられていると思います。引用させていただきます。

Play Asset Deliveryを利用することで、アプリ内包(BuiltIn)しているAssetBundleをAsset Packとして扱うようにします。
そのAssetBundleはサイズから除外してくれるので150MBを超えててもOKになります。
StreamingAssetsにおいてたものをAssetPackに移動させるイメージです。
このために実装を切り分けるないといけないのは辛い所です。

上記を読んで「ふむふむ」と理解できる方は、以下の私の記事を読み進めるよりもunagirabbit’s blogさんの記事を読む方が早く解決すると思います。

私は"Play Asset Delivery"や"AssetBundle"や"Asset Pack"や"StreamingAssets"といった用語がわからなかったため(全部だ!)、他のサイトで知識を補完し対応しながらunagirabbit’s blogさんの記事で答え合わせをした、という感じです。
私と同様「なるほどわからん」という方でかつ「理解は後でいいからとにかく対応したい」という方は、以下の私の記事を読み進めると、もしかしたらお役に立てるかもしれません。

実際の対応

本題です。
150MBを超えてしまった場合の対応順序としては、大まかに、

 ①Play Asset Deliveryの導入
 ②AssetBundleをBuildする
 ③AssetBundleをAsset Pack扱いにするよう設定する
 ④Asset PackからAssetをロードするように実装を変更する
 ⑤Asset Packを含める形でBuildし、実機でテストする
 ⑥Play ConsoleへのAABのアップロード

となるかと思います。

①Play Asset Deliveryの導入

Play Asset Deliveryについては、公式が詳しいです。

上記に記載されている通り、以下から最新版のプラグインを導入します。

色々なプラグインがあるのですが、とりあえず私は諸事情あり、
google-play-plugins-1.4.0.unitypackage
から、assetdeliveryとcommonとcoreを入れました。appbundleもこのタイミングで入れた気がしますが、失念しました。
2021/8/11現在、google-play-plugins-1.5.0.unitypackageでもよいと思います。試していませんが。

②AssetBundleをBuildする

次に、AABのサイズに含まれないAssetBundle(Asset Pack)を作ります。
これは、AABのサイズに含めたくないAsset(画像や音声など)を、AssetBundleというファイルに追い出す作業です。

実際のAssetBundleファイルの作成(Build)については、以下が詳しかったです。

上記のk7aさんの記事を参考にコーディングすればAssetBundleをBuildできるのですが、つまずいた点がいくつかあります。

1.エディタ拡張を使ってBuildする
Buildは、(あたりまえですが)実行時にはできません。
AssetBundleをBuildするコードは、エディタ拡張を使って実行する必要があると思われます。
私は「エディタ拡張」という概念を知らなかったため、以下の記事を参考にさせていただきました。

私なりの理解を書かせていただくと、

実行モード(プレイモード)を使わずに、コードを実行する。そのコードはメニューから実行できる。

といった感じです。
パッケージをインポートしたときにメニューバーに勝手にアイテムが増えるのは、この機能を使っていたためか~と思いました。
先ほどのGoogleのプラグインをインポートしたことで、メニューバーに[Google]メニューが増えているのも、この機能を使ったものだと思います。

2.AssetBundleの元になったAssetは(Resources配下から)削除する
もともとがAssets/Resources配下のものをロードする実装であったならば、ここから削除しておかないと、AABに二重に含まれることになるため、削除する必要があります。
今考えると「そりゃ当然だろう」って話なのですが。
そしてこれも当然の話なのですが、元のAssetをここから削除すると、もともとResources.Load()でロードする実装としていた場合、動かなくなります。このことについては④で触れます。

余談ですが、色々な記事を拝見させていただくと"AssetGraph"や"AssetBundleBrowser"を使うことも推奨されていました。
ですが、結果的に私は使いませんでした。これ以上新しい概念を頭に入れるとより混乱しそうだったため。

エディタ拡張から呼び出したBuild用スクリプトで、無事にAssetBundleファイルが出力されればOKです。
上記のk7aさんの記事では、AssetBundleをStreamingAssetsに配置したり、AssetBundleからロードする実装についても記述されていますが、今回はこれは不要です。今回は、AssetBundleからではなくAsset Packからロードしたいので。

③AssetBundleをAsset Pack扱いにするよう設定する

AssetBundleをBuildできたら、今度はそれをAsset Pack扱いするように設定します。
具体的な方法は、Googleのチュートリアルがわかりやすいかと思います。

これは、作成したAssetBundleをAABのBuild時にAsset PackとしてAABに含めるための設定、といったものです。
この時、[Delivery Mode]を設定できますが、[Install Time]にしておけばインストール時にこのAssetBundle(Asset Pack)も併せてインストールしてくれます。よって、特に理由がなければ[Install Time]に設定しておけばよいかと考えます。
(インストール時に150MBを超える分をインストールしてくれるのなら、150MB制限の意義が良くわかりません・・・)

④Asset PackからAssetをロードするように実装を変更する

Asset PackからAssetをロードする方法も、Googleのチュートリアルが詳しいです。
このページは、「プラグイン設定アセットパック」と「API設定アセットパック」でフローを切り替えられるのですが、今回は「プラグイン設定アセットパック」でよいかと思います。

基本的には、上記チュートリアルに記載の方法でいいと思うのですが、私は以下のように実装しています。

Start()で以下を1回呼び出す。

bundleRequest = PlayAssetDelivery.RetrieveAssetBundleAsync("sounds");

実際のロード前に、以下を1回呼び出す。

if (assetBundle == null) setBundle = bundleRequest.AssetBundle;

(ロード時に毎回呼ばれるとよくない気がしたので、assetBundleがnullだったらロードするような実装にしました。)

そして実際にロードする箇所は、私はシーンではなく音声データをロードしたかったので、

AudioClip voice = assetBundle.LoadAsset<AudioClip>(name);

のような実装にしています。

assetBundleオブジェクトを使わなくなるタイミング(私の場合は次のシーンのロード時)に、

assetBundle.Unload(false);

を呼んでいます。

このような実装にすると、困ることがあります。
というのも、上記のコマンドは実行モードでは

"Exception: Field currentActivity or type signature not found"

というエラーが吐かれます。実機では動作します。(シミュレータで動作するかどうかは、試していません。)
この事象については、以下のQAが参考になりました。

よって、開発中とリリース用Buildは条件付コンパイルなどで制御し、さらに開発中はAssetsフォルダの下に何らかの形でAssetを置いておかねばならない、ということになります。
私はとりあえず手動で配置/削除の対応しました。もっとスマートな方法があるかもしれませんが。

⑤Asset Packを含める形でBuildし、実機でテストする

AssetBundleの作成、Asset Packの設定、Asset Packからロードする実装ができたので、次はAsset Packを含める形でAABをBuildします。
この場合は、通常の[ファイル] - [ビルド設定...]からのBuildではなく、[Google] - [Build Android App Bundle...]からのBuildになります。

無事Buildできて、またAABのファイルサイズも問題ないことを確認します。この時のファイルサイズは、結局Asset Pack(AssetBundle)を含んだサイズになるので、当初のサイズと大差ないかと思われます。
問題なければ今度は[Google] - [Build And Run]で実機テストを行います。
Googleのチュートリアルでは、以下のようにに記述されています。

これで、実機で期待通りにAssetがロードされれば、Asset Packからのロード機能の実装としては成功かと思います。

なお私が対応した際、実機でアプリを起動しようとすると"Failure to Initialize!"、"Failed to load 'libmain.so'"というようなエラーメッセージがAndroid上に表示され、起動することができませんでした。
これもかなりハマったのですが、最終的には解決しました。
原因をしっかり理解しているわけではないのですが、少なくともPlay Asset Deliveryを使い、かつUnityが特定のバージョンの場合には発生するようです。
私の環境は、Unity 2020.2.7f1 でした。他のどのバージョンが条件を満たすかは分かりません。
この時は、ゴールの見えない状況で「エディタのバージョンアップ」という新要素を持ち込みたくなかったため、何とかバージョンを上げずに対応する方法を探し、以下のQAを見つけました。

上記のスレッドを読み進めると、「推奨しませんが・・・」という条件付きで以下のコメントがありました。以下引用となります。

Note: as a workaround for someone who urgently needs to use Play Asset Delivery with Unity 2020.2, they could modify this plugin's code to always set config.optimizations.uncompressNativeLibraries.enabled=false. I don't really recommend this however, and will check to see if Unity can fix the issue on their end.

結果的に上記のとおり対応したところ、"Failure to Initialize!"を回避することができました。
ただし、上記の記載以外にも少し変な対応が必要です。具体的には以下のような対応をしました。

・"Packages/Google Android App Bundle/Editor/Scripts/Internal/BuildTools/BundletoolHelper.cs"というスクリプトファイルをVisual Studioで開く。(他のエディタでは試していません。)
Assetsフォルダの下ではなく、Packagesフォルダの下にあるスクリプトなので注意。
・BundletoolHelper.csの98行目の
 config.optimizations.uncompressNativeLibraries.enabled = true;
 を、
 config.optimizations.uncompressNativeLibraries.enabled = false;
 にして保存する。
・保存すると、Unity Package Managerが自動的に動いて、trueに戻すはず。
・もう一度falseにして保存します。この時は、Unity Package Managerは起動しないと思われます。
・Windows上で、Unityエディタにタスクを切り替えます。Unityエディタ側でUnity Package Managerが動き始めますが、すぐにVisual Studioにタスクを切り替えます。
 Alt+Tabなどで素早くタスク切り替えするとよいと思います。
・うまくいくと、falseのままになり、そのあとはUnityエディタに戻ってもfalseのままです。
失敗するとtrueに戻ってしまいますが、微妙なタイミングの問題なので、何度か繰り返すと成功するかもしれません。

自分で書いていて思いますが、非常にビミョーな操作です。Macで同様にできるかは分かりません。
また、そもそもUnity Package Managerを有効にさせない方法があるような気がします。
とにかく、trueがfalseになっている隙をついてBuildします。

⑥Play ConsoleへのAABのアップロード

実機で稼働確認が出来たら、Play ConsoleへAsset Pack入りのAABをアップロードします。
これで、最初に挙げた以下のエラー、

App Bundle に含まれている設定(ARM64_V8A)で、初期インストールのサイズは 150 MB 以下である必要があります。

が出なければOKです。

さいごに

以上、「とりあえずAABを150MB超え問題を解決したい」という方には、もしかしたら役に立つかもしれない記事でした。

この記事が気に入ったらサポートをしてみませんか?