自己流AssetBundleManager

 自己流AssetBundleManagerを作ってました。もっと便利なAssetBundle管理ライブラリはあると思いますが、知識を再確認するために自分で一から作ってみました。
 今回作ったAssetBundleManagerは以下の5つの要求に応えられるようにしました。
 
  • 言語切り替えに対応したい
  • チュートリアルに使う分だけダウンロードしたい
  • マスターデータだけ更新したい
  • 暗号化したい
  • UnityEditor上で素材の更新を素早く確認したい(非同期読み込みを維持しながら)
 

・言語切り替えに対応したい

 日本語版のアプリに英語版のリソースが入らないようにしたい、と思いました。使わないリソースで容量を圧迫したくないです。
 管理を煩雑にしたくないので、ファイル名を工夫するだけで実現できるようにしました。ファイル名に[jp]などのタグを追加するだけでOK。すべてのファイルに書くのが面倒くさければフォルダ名にタグを仕込めば認識されます。
 今回作ったAssetBundleManagerは独自形式のAssetBundleリストを参照して制御を行うようにしています。このAssetBundleリストを切り替えることで言語切替を実現できます。ビルドスクリプトがファイルパスからタグを読み取って日本語版用のAssetBundleリストと英語版用のAssetBundleリストを自動生成するようになっています。
 

チュートリアルに使う分だけダウンロードしたい

 長いダウンロード時間はユーザー離脱の元。最初のダウンロード時間を少しでも短くするために、チュートリアルに使う分だけのAssetBundleをダウンロードする機能があると良いなと思いました。
 これは言語切り替えと同様に[tutorial]といったタグをファイルパスに含めるだけでOKです。チュートリアル用のファイルだけが記載されたAssetBundleリストとすべてのファイルが記載されたAssetBundleリストが作成されます。
 応用で、タイトル画面までに必要なAssetBundleリストを作っておいてアプリに含めるリソースをほぼゼロにする、という使い方も考えられます。
 

・マスターデータだけ更新したい

 各種パラメーターを頻繁に更新してテストすることを考えると、マスターデータ(パラメータなどのデータ)だけ更新できると便利そうです。マスターデータの更新にリソースデータ(画像など)の更新も必須です、というのは避けたいところ。
 これはAssetBundleリストの分割で対応しました。AssetBundleにするデータを置くフォルダを分けておけば、別々にAssetBundleリストを作成できます。AssetBundleを読み込むクラスを複数作ることができるので、それぞれでデータをロードするようにします。
 

・暗号化したい

 ユーザーの端末にAssetBundleを保存して運用するので、簡単に中身を見られないように暗号化が必須です。今回はRijndaelで暗号化しました。
 暗号化キーを取り出す部分は解析対策が一切行われていないので、別途難読化する必要がありそうです。また、速度面も検証されていないので、実際に使用して確認していく必要があります。
 端末内の保存場所ですが、iOS以外はApplication.persistentDataPath、iOSだけはApplication.temporaryCachePathを指定しています。iOSはpersistentDataPathを使用するとiCloudに保存されてしまい、リジェクト対象となってしまうのでtemporaryCachePathを使っています。
 

・UnityEditor上で素材の更新を素早く確認したい(非同期読み込みを維持しながら)

 画像などの素材更新のたびにAssetBundleをビルドしていては時間がかかりすぎてしまいます。これではゲーム内での確認も一手間です。
 そこでResources.LoadAsyncを用いてLocal読み込みモードを作成しました。UnityEditor上で実行すると、まずResources.LoadAsyncでResources直下にファイルの有無が存在するか確認し、無ければAssetBundleの読み込みに移ります。
 非同期読み込みを維持したかったのでAssetDatabase.LoadAssetAtPathでなくResources.LoadAsyncを選択しました。非同期処理がしっかりできていないと処理落ちしてアプリの出来が悪くなるので、UnityEditor上でも非同期で読み込んで確認できるようにしています。
 

・(注意点)ビルドはResourcesを削除してから行う

 Resourcesの下にデータを置いているので、そのままビルドするとすべてのデータがアプリに含まれてしまいます。ビルド専用にCloneした作業フォルダを用意して、削除→ビルドというタスクをJenkinsなどのCIに登録すると良さそうです。
 
 実際に作られたゲームで試すのはこれからなので、不足している機能や不具合はあると思います。現時点でも「そのやり方はパフォーマンス悪いぞ」という箇所はあるでしょう。そこは今後自分で使ってみて色々修正していこうと思います。