Unity にはアセットバンドル (asset bundle) と呼ばれる仕組みがあります。これは、特定のアセット群をひとつのファイルに固めて、アプリに含めない外部ファイルとして出力するというものです。この仕組みを使うと、コンテンツの追加ダウンロードの機能などが簡単に実装できます。

アセットバンドルは便利な仕組みですが、残念ながらいくつかの不便な点もあります。そのひとつは、Unity のバージョン間における互換性が保証されない、というものです。

(※これはモバイル (iOS/Android) に存在する制約であり、デスクトップ版では少し緩いものとなっています。今回のエントリでは主にモバイルにおける事情を解説します。)

アセットバンドルの仕組み

詳しい話へ入る前に、アセットバンドルの仕組みについて簡単に説明しておきましょう。

デスクトップ版の Unity におけるアセットバンドルとは、次の2つの要素から構成されています。

  • タイプツリー情報
  • データ本体

タイプツリーとは、アセットバンドルに含まれるデータがどのようなタイプ(型)によって構成されているのかを表す情報です。この情報を利用すれば、データレイアウトが変化しても正常にデータを読み込むことができます。これによりデスクトップ版の Unity ではアセットバンドルの下位互換性が実現されているのです。

タイプツリー方式のデメリット

このタイプツリー情報はデータレイアウトに柔軟性を生み出しますが、代償も伴います。読み込み時にタイプツリーの違いを検証し、データレイアウトを更新しなくてはならないのです。

この処理は、データの規模によっては非常に高負荷となりえます。また、テンポラリのメモリ領域も必要とされます。これはモバイルプラットフォームにおいては手痛い出費です。

モバイル版の特殊仕様(昔)

そこで Unity のモバイル版では、タイプツリーの情報を省略することにしました。アセットバンドル側のデータレイアウトと、ランタム側のデータレイアウトが同一であることを前提として、ストレートにデータを読み込めるようにしたのです。

ただしこれを実現するには、「アセットバンドル側のデータレイアウトと、ランタム側のデータレイアウトが同一であること」を確実に保証しなければなりません。

過去のバージョンの Unity においては、「アセットバンドルを構築した Unity のバージョンと、ランタイムをビルドした Unity のバージョンが異なっている場合、データレイアウトが一致しない可能性がある」として、これをエラーとして扱うようにしていました。両者のバージョンが少しでも異なっていたら読み込めないという仕様にしていたのです。

これはちょっと厳し過ぎますよね。

モバイル版の特殊仕様(今)

最近の Unity のリリース傾向を分析してみると、マイナーバージョンアップにおいてデータレイアウトの変更が生じる可能性はかなり低いことが分かってきました。例えば Unity 3.5.0 と 3.5.1 においては、ほとんどのアセットバンドルにおいて同一のデータレイアウトとなるでしょう。

そこで Unity 3.5 以降においては、アセットバンドル内にタイプツリーのハッシュ値を格納するようにし、そのハッシュ値で比較を行うように改良しました。実際にデータレイアウトが異なる場合のみエラーを返すようにしたのです。

まとめ

まとめると、現状のモバイル版 Unity におけるアセットバンドルのバージョン間互換性は、以下のようになっています。

  • アセットバンドルに含まれるタイプツリーのハッシュ値がランタイム側と一致すれば、バージョンの違いに関わらずロードできる。
  • マイナーバージョンアップ(a.b.c の c の数値が変化するバージョンアップ)においては、ほとんどの場合タイプツリーのハッシュ値は一致する。

以上の仕様を前提とすると、「マイナーバージョンアップにおいてはアセットバンドルの引き継ぎがほぼ可能である」と言えます。Unity のバージョンアップを行う際には、移行先のバージョンのランタイムにおいて、今までに構築したアセットバンドルがすべて読み込めるかどうか確かめるような自動テストを実施するとよいでしょう。

補足

スクリプトはプロパティの構成が変更されたとき、それに伴いタイプツリーも変化します。

Keijiro Takahashi (Unity Technologies Japan)