AssetBundle使いつつlink.xmlになにか書くのは無意味、、ではなかった!!


概要

Unity 5.3.2p2 WebGLビルドの話題。

link.xml思ってたより意味なくて笑った。俺が間違っていることを望む。

→俺が間違ってた。



前提

目的は最初にロードされるシーンの軽量化。次のような手順で動かしてる。


・Scene Listにはローダーのみのほぼ空っぽのシーンを置く

・Strip Engine CodeをOnにする

・link.xmlに依存を書く

・AssetBundleに依存コードを使っているクラスを使う(Canvasとか


link.xmlにClass情報を記述し、AssetBundleで要素を取得、Instantiateした場合、link.xmlになにを書こうが無駄だった、みたいな話。



手順

link.xmlに特定のオブジェクトのClassId - nameを記述(下記)

<linker>

<assembly fullname="UnityEngine">

<type fullname="UnityEngine.MeshRenderer" preserve="all"/>

<type fullname="UnityEngine.BoxCollider" preserve="all"/>

<type fullname="UnityEngine.MeshFilter" preserve="all"/>

<type fullname="UnityEngine.Canvas" preserve="all"/>

<type fullname="UnityEngine.Sprite" preserve="all"/>

<type fullname="UnityEngine.CanvasRenderer" preserve="all"/>

</assembly>

</linker>


WebGLビルドで、特定のオブジェクト(Canvasなど)をAssetBundleから読み出した際に、link.xmlに対象クラスが入っていても、コードがアタッチされない。


The referenced script on this Behaviour is missing!

というエラーが出る。ちなみにブラウザ上だけ。



本来なら、例えばCanvasなら、デフォルトでコンポーネントに含まれている要素があって、それが展開されるはず、、なんだ。

そいつがmissingになる。


で。解決方法はあって、「同様のオブジェクトを含んだものをビルド時のScene Listに含んでいるシーンのヒエラルキーに持たせる」とか。

たとえそのシーンでは使ってなくてもdisableにしておいても、ようは入れておけばいい。


これだけで全く同じ手順でもmissingが発生しなくなる。


、、、



いや正しいけどさあ

これが正解の一つであることは別にいいんだよ、だって「コンパイル時に使ってないコードは入らない」んだから。

WebGLをはじめとして、UnityはあとからAssetBundleとかでコードを足すことができるプラットフォームでもないし(できるのもあるけど無視する。


link.xmlに期待してたのは、まさにその「コンパイル時には使ってないコードを内包した状態でビルドされ、あとからそれを使用するのを許す」部分だったんだけど。

なんか書き足すとビルド時のjsに内包されてるっぽい増え方するし、やったぜって思ったんだけどさ。


なぜ実行時にmissingになるのさ。



一番マシな解決法が正攻法一発、しかも使ってないリソース足す方法で、なおかつ一番重量を食うっていう、、、ほら、、なんか泣ける。



結局link.xmlに書こうが書かまいが、シーンに入れておかないとAssetBundleからのロード時に無意味になる、、という感じで、

っていうかビルド時に含まれるならもうそれで良くて、、使ってなくても、、


link.xmlになにか書いても意味がなく、link.xmlとは一体、、という疑問がある。



ちなみに

ぶっちゃけUnityEngineのコード全部含んでもDL sizeは5.3MBとかだったんで諦めたよ。

そのうち改善 or 解明されるだろ。


お問い合わせにはすでに出しております。俺は無駄なFUDはしない主義なんで。



ここから追記

Unityにお問い合わせしたところ、自分が作っていたlink.xmlの書式に不足があったことが分かった。


before

<linker>

<assembly fullname="UnityEngine">

<type fullname="UnityEngine.MeshRenderer" preserve="all"/>

<type fullname="UnityEngine.BoxCollider" preserve="all"/>

<type fullname="UnityEngine.MeshFilter" preserve="all"/>

<type fullname="UnityEngine.Canvas" preserve="all"/>

<type fullname="UnityEngine.Sprite" preserve="all"/>

<type fullname="UnityEngine.CanvasRenderer" preserve="all"/>

</assembly>

</linker>



after

<linker>

<assembly fullname="UnityEngine">

<type fullname="UnityEngine.MeshRenderer" preserve="all"/>

<type fullname="UnityEngine.BoxCollider" preserve="all"/>

<type fullname="UnityEngine.MeshFilter" preserve="all"/>

<type fullname="UnityEngine.Canvas" preserve="all"/>

<type fullname="UnityEngine.Sprite" preserve="all"/>

<type fullname="UnityEngine.CanvasRenderer" preserve="all"/>

       </assembly>

<assembly fullname="UnityEngine.UI">

               <type fullname="UnityEngine.CanvasScaler" preserve="all"/>

               <type fullname="UnityEngine.Image" preserve="all"/>

               <type fullname="UnityEngine.Shadow" preserve="all"/>

               <type fullname="UnityEngine.Text" preserve="all"/>

</assembly>

</linker>


不足していたのはこの濃いグレーのとこの記法のUnityEngine.UIで、

なんていうかその、、こういう書き方してある資料にWebGL絡みだけ探してても遭遇できなかったのが辛い。

うーーん、、この、、、解決してよかった、、、



エラーについてわかった事

missingを起こしていた原因は、クラス情報が不足していたから、に他ならん感じ。


エラーには2通りのものがあるというのがわかった。



その1 該当クラスの記述がlink.xmlにないと、Could not produceエラーが出るやつ


例えばlink.xmlにわざと不足を出す(Canvasとか消す)と、

Could not produce class with ID 223.


みたいなエラーがでるタイプ1。



その2 該当クラスの記述がlink.xmlにないと、The referenced script on this Behaviour is missing! エラーが出るやつ


例えばlink.xmlに不足があると、

The referenced script on this Behaviour is missing!


みたいなエラーが出るタイプ2。こちらはIDが出ない。missing + 何がmissingか(Object名かな)が出る



link.xmlに影響されてるエラーが正直タイプ1しか無いと思いこんでいたので、ハマった。

思い込みはよくねーな。



どんな依存をしているかについて

実行時のエラーをもとに依存をわりだしていたんだけど、

よく見たらAssetBundle作った時のmanifestにclassIdが書いてあった。


で、まあ、使うAssetBundleのmanifestを全てぶち抜いてグチャッと混ぜてlink.xmlに正しく書いたらいけたという次第。



ということで

得られた知見としては2つ。


1.dependencyがlink.xmlに書いてないから発生するエラーは一種類じゃ無い。

2.AssetBundle作ったらmanifestには依存ClassIdが書いてあるからとにかく収集すればいい



うまくいった~~よかった。