【Unity】Assets/Plugins はもう不要？→必要（な場合もある）

# はじめに

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">移動できないUnityアセットはアセットの審査でリジェクトされてほしい。あと勝手に<br><br>・Assets/Scripts<br>・Assets/Plugins<br><br>とかに入ってくるのも同様。</p>&mdash; su10@ハイパーカジュアルゲーム開発 (@su10_dev) <a href="https://twitter.com/su10_dev/status/1278196260449599489?ref_src=twsrc%5Etfw">July 1, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">&gt;・Assets/Scripts<br><br>これは論外で、Assets/{アセット名とか}/ にすべき。<br><br>&gt;・Assets/Plugins<br><br>これは Assets/{アセット名とか}/Plugins にすべきで、これ守ってないやつを毎回直すの面倒。<br><br>これらを守ってくれないと後から消したくなったときに苦痛（git revertはあるけど改造する場合もあるし）</p>&mdash; su10@ハイパーカジュアルゲーム開発 (@su10_dev) <a href="https://twitter.com/su10_dev/status/1278197632834265089?ref_src=twsrc%5Etfw">July 1, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

これをつぶやいてから「いや、 `Assets/Plugins` はUnityの制限があるからしょうがなくない？」みたいなご指摘をいくつかいただいたので調べました（調べる前は「 `Plugins` は `Resources` と同じでどこにあっても・複数あっても同じ」という認識）。

結論から言うとUnityの仕様で `Assets/Plugins` に配置しないといけない場合がまだあったので諦めるしかない__場合もある__（Unityなんとかしてくれ😂）という話でした。

# マニュアル記載の `Assets/Plugins` の挙動

マニュアルのいろんなページに散らばってるのですが、以下のそれぞれで `Assets/Plugins` に関する挙動が説明されています。

* [特殊なフォルダー名](https://docs.unity3d.com/ja/2018.4/Manual/SpecialFolders.html)

>Plug-ins
>
>プラグイン をプロジェクトに追加して Unity の機能を拡張することができます。プラグインは、通常は C/C++ で作成されたネイティブの DLL です。それらは、サードパーティのコードライブラリ、システムコール、その他の Unity ビルトイン機能にアクセスできます。Unity が検出できるように、プラグインは常に Plugins というフォルダーに配置してください。
>
>1 つの Plugins フォルダーのみを持つことができ、プロジェクトのルートに配置する必要があります。Assets フォルダー内に直接配置します。
>
>このフォルダーがスクリプトのコンパイルに与える影響の詳細については、特殊フォルダーとスクリプトのコンパイル順 を、異なるターゲットプラットフォームのプラグインの管理については Plugin インスペクター を参照してください。

* [特殊フォルダーとスクリプトのコンパイル順](https://docs.unity3d.com/ja/2018.4/Manual/ScriptCompileOrderFolders.html)

>定義済みのアセンブリ
>
>Unityは、プロジェクトフォルダー構造内のスクリプトファイルの場所に基づいて、4 つの異なるフェーズでスクリプトをコンパイルします。各フェーズのために、別々の CSharp プロジェクトファイル (.csproj) と事前定義されたアセンブリが作成されます。任意のフェーズに適当なスクリプトがない場合、Unity は対応するプロジェクトファイルやアセンブリを作成しません。
>
>スクリプトが、異なるフェーズでコンパイルされた (つまり、別のアセンブリにある) クラスを参照する場合、コンパイル順はとても重要です。基本的なルールは、現在のフェーズ の後に コンパイルされたものは参照できないということです。現在のフェーズ、またはそれ以前のフェーズでコンパイルされたものは、すべて参照可能です。
>
>コンパイルの各フェーズは下記のとおりです。

| フェーズ | アセンブリ名 | スクリプトファイル |
|--:|:--|:--|
| 1 | Assembly-CSharp-firstpass | Standard Assets、Pro Standard Assets、Plugins という名のフォルダー内のランタイムスクリプト |
| 2 | Assembly-CSharp-Editor-firstpass | Standard Assets、Pro Standard Assets、Plugins という名の最上位フォルダー内のあらゆる場所にある Editor という名のフォルダー内のエディタースクリプト |
| 3 | Assembly-CSharp | Editor という名のフォルダーに入っていないすべてのスクリプト |
| 4 | Assembly-CSharp-Editor | Editor という名のフォルダー内にある残りのすべてのスクリプト |

* [プラグインインスペクター]()

![](https://docs.unity3d.com/ja/2018.4/uploads/Main/PluginInspector.png)
_（↑Pathは `Assets/MyPlugin/MyPlugin.dll` になってる）_

>デフォルト設定
>
>Unity は、プラグインが置かれたフォルダーに応じて、プラグインファイルのインポート設定のデフォルトを設定します。

| フォルダー | デフォルト設定 |
|:--|:--|
| （省略） | （省略） |
| Assets/Plugins/iOS | プラグインは iOS でのみ互換性があると判断されます。 |
| （省略） | （省略） |

---

Unityのマニュアルではないですが、こんなブログ記事もありました。

* [Unity5からは"Assets/Plugins"フォルダは不要](http://anchan828.hatenablog.jp/entry/2014/10/04/004326)（けいごのなんとか）

>Pluginsフォルダがありますけど名残というかわかりやすいようにしているだけです。Pluginsフォルダは必要ありません。

---

というわけで、 `Assets/Plugins` の仕様としては

* ネイティブプラグインはここに入れる必要がある
* コンパイルの順番に関係する（そもそも含まれるDLLに違いが出る）

の２点っぽいことがわかったので検証していきます。

若干古い気もしますがUnity2018.4.0f1にて行いました。

# ネイティブプラグイン置き場として必須？

これについては先述の

>プラグインは、通常は C/C++ で作成されたネイティブの DLL です。それらは、サードパーティのコードライブラリ、システムコール、その他の Unity ビルトイン機能にアクセスできます。Unity が検出できるように、プラグインは常に Plugins というフォルダーに配置してください。

を疑う形になりますが一応確認しておきます。インポート設定とファイルの配置を変えてiOS用にビルドしてみました。

## `Assets/Foo/` 以下で `Any Platform` の場合

マニュアルが正しければ含まれないはず。
<img width="753" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27863/df9ddd80-6c95-439d-7ba3-035d8f7797a3.png">
↓結果
<img width="273" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27863/d15e683c-d34e-b061-119d-e7af86aa46e2.png">

含まれました（！）

## `Assets/Plugins/iOS` 以下でいずれのプラットフォームにも含めない設定にした場合
<img width="754" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27863/c37ff114-afc1-67f5-16ab-471817fe4452.png">
↓結果
<img width="277" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27863/2559d158-5a0c-8481-9dcd-81b2de8ca482.png">

含まれてません。

＊　＊　＊

というわけで、マニュアルのスクショを見てもそうであるように、ネイティブプラグインファイルが `Assets/Plugins` 以下である必要はなさそうです（インスペクタからの設定に依存する）。

# コンパイルの順番に関係する？

配置場所によって含まれるDLLが違うということで、スクリプトを `Assets/Foo/Plugins/` と `Assets/Plugins/` にそれぞれ配置して、含まれるDLLを調べました。

<img width="757" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27863/30aacb16-19e7-c9e4-c983-dcee0243fd8f.png">

<img width="757" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27863/ce6db110-b48c-9a73-346d-f0d9a7e2a8ca.png">

一応それぞれの `*.csproj` を覗いてみましたがインスペクタに表示されたDLL側にちゃんと含まれてました。あと当然 `Assets/Foo/Plugins` から `Assets/Foo/` にスクリプトを移動しても結果は変わりませんでした。

＊　＊　＊

というわけで、 `Assets/Plugins/` とそれ以外にスクリプトを配置した場合とでは違いがあることがわかりました。

# まとめ

結論としては

* ネイティブプラグインの置き場所として `Assets/Plugins` 以下でなければならない制限はもうない
* スクリプトが `Assets/Plugins` 以下だとコンパイル順に影響する
    * `Assets/Plugins/` 以下なら `Assembly-CSharp-firstpass.dll` に含まれる
    * つまり最初にコンパイルされる

ということになりました。

正直後者のメリットというかそうしなければならない理由が思い浮かばず、アセット作者の方々は前者のことを知らずに今でも惰性で `Assets/Plugins` 以下に入れてる場合が多いんじゃないかなと思いました（今だと `asmdef` でなんとかなるのでは？🤔）。

それと、[【Unity】アプリに含めるアセットを抑えて、アプリサイズを小さくする](http://tsubakit1.hateblo.jp/entry/2016/08/18/230707#StreamingAssetsとPluginsはそのまま含まれる)（テラシュールブログ）によると

>StreamingAssetsやPlugins/iOSやPlugins/Androidに含めたファイルは、そのまま含まれます。

とのことなので、もし `Assets/Plugins` に展開されるアセットがデモとかサンプルに画像を含みまくってたらビルド後のサイズが膨れそうなのでやめてほしいです（未検証）。

＊　＊　＊

いろいろ書いてきましたがアセットを実際に作ってる方のほうが詳しいと思うので、間違い等あればご指摘ください。

あとコンパイル順に関して「 `Assembly-CSharp-firstpass.dll` じゃないとダメなんだぜ」というのがあればぜひ教えて下さい。