#2019/06/10更新
エディタ内でのみ動かして、ビルドで弾く方法がもう一つ見つかった&こちらのほうが対応が楽なので、
追記していきます。
#はじめに
コード保護などのためにC#スクリプトをDLL化する人向けの記事です。
DLLの中にusing UnityEditor;
を含むスクリプトが書かれており、それが原因でビルドが通らないことがあったので、
備忘録がてらまとめます。
#起きたこと
iOSビルドが通りませんでした。エラーログを見ると
ArgumentException: The Assembly UnityEditor is referenced by Hoge.Hoge
('Assets/Plugins/Hoge.Hoge.dll'). But the dll is not allowed to be included or could not be found.
が出力されていました。(ログは簡略化しています)
Hoge.Hoge内でUnityEditorの参照が必要だけどDLLが見つからないか、ビルドに含めることが認められてなかったよ
という旨のログです。
#原因・考察
これの原因は
Hoge.Hoge.DLL
内でエディタ拡張のコードを書いていたことです。
今回書いていたコードはAttributeの拡張で、自作属性を宣言していました。
[CustomPropertyDrawer(typeof(PathAttribute))]
public class PathAttributeDrawer : PropertyDrawer
//以下略
インスペクタ上にドラッグアンドドロップでフォルダのパスを指定できるエディタ拡張です。
参考:Inspectorにファイルをドラック&ドロップしてパスを設定する
PropertyDrawerがUnityEditor下のコードで、UnityEditorを読み込む必要がありました。
本来ならばエディタ拡張のスクリプトはEditor
ディレクトリに設置するものです。
しかし今回はDLLで包んでいるので、該当コードがPlugins
ディレクトリに存在する扱いになっていました。
Editor
ディレクトリはビルド時は自動的に除外され、ビルドに含まれることはありません。
そのためUnityEditor
を参照するスクリプトを置いてあってもエラーは発生しませんでした。
今回はPlugins
ディレクトリに存在したため、全てのコードがビルドに含まれてしまい、
本来ならば弾かれるべきコードが弾かれず、エラーを吐いてしまいました。
#対策その1
ビルド時に自動的に弾いてくれないので、スクリプト側で自分から弾かれるように
プラットフォーム依存コンパイルで区切りましょう。#defineディレクティブです。
UnityEditorで実行するときだけ走り、ビルドで走らなくするための#defineは
#if UNITY_EDITOR
です。
今回書いたスクリプトは1クラス1ファイルのエディタ拡張のみのコードなので、全てを囲んでしまいました。
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
//中略
#endif
#defineで囲んだことでUnityEditor外の環境ではコードが走らなくなり、
Plugins
ディレクトリに存在してもコンパイルされなくなりました。
これでエラーが出ずにビルドが通るようになりました。
#結論その1
Editor
ディレクトリ以外にエディタ拡張のスクリプトを設置すると、
ビルド時にUnityEditor
の参照が足りなくなりエラーが出て通りません。
DLL化してPlugins
ディレクトリに設置するとき(以外のケースもあるかも?)等、
エディタ拡張コードをEditor
ディレクトリ以外に置くときは、
スクリプト丸ごと#if UNITY_EDITOR
で囲んでコンパイルが走らないようにしましょう。
#対策その2(2019/06/10追記)
ビルド時に自動的に弾くように、特殊フォルダを使いましょう。
Editor
ディレクトリやPlugins
ディレクトリが使えるようです。
(上記リンクでは”PluginsフォルダはAssets直下・単一であるべき(意訳)”と記されていますが、
Unity5から複数Pluginsフォルダが並立しても動くようになりました。
参考:Unity5からは"Assets/Plugins"フォルダは不要)
DLLでエディタ拡張を行う場合、該当コードをどのディレクトリに設置すればいいか謎でしたが、
いじっているうちに法則が見えたので備忘録として記しておきます。
まずDLLは必ずPlugins
フォルダに入れておかないと動きません。
これに例外はありません。サブフォルダ内にあっても問題ありませんが、DLLのルートをたどっていくと必ずどこかでPlugins
になるように設置してください。
次にEditor
フォルダですが、これは
”ビルド時にこの中のコードは自動的にスキップして、コンパイルが通さないでください”と宣言するためのフォルダです。
開発時のエディタ上でのみ機能を追加するもので、ビルドには使用できないものを置いておく場所です。
こちらもサブフォルダ内にあっても問題ありません。
上記2点を踏まえて
”エディタ上でのみ機能するスクリプトを含んだDLL”を設置する場所を考えると
Editor/Plugins
かPlugins/Editor
の2つの候補が出てきます。
この2つのどちらを選択するかですが、そのDLLをどう管理したいかによって分けるといいでしょう。
まずEditor/Plugins
ですがルートディレクトリがEditor
なので、以下全てのフォルダがビルドから弾かれます。
そのためエディタ拡張のDLLのみを配置することになると考えられます。
Plugins/Editor
はルートディレクトリがPlugins
なので、全てのDLLを1フォルダ下にまとめることができます。
とりあえず全てのDLLをPlugins
フォルダに配置して、エディタ拡張に関わるものだけをPlugins/Editor
に配置しなおすことになるでしょう。
自分で作って自分で使うだけで完結するのであればどちらでも構いません。
アセットストアやその他の方法でDLLを含むパッケージを配布する場合はPlugins/Editor
にして、DLLの配置場所が散らばらないようにするといいのではないでしょうか。
#結論その2(2019/06/10追記)
こちらはDLL内で#defineをしなくて済むので、コードの編集時に余計な気を使わなくてもいいという利点があります。
ただ、エディタ拡張のコードのみを含むDLLを別で出力しないといけないという点がデメリットになり得ます。
最終的には好みの問題ですが、#defineをすると編集時にコード補完が起動しなかったり該当プラットフォームでないときにコメントアウトされてしまうので、個人的にはあまり好きではありません。
#さいごに
対策方法を教えてくださったアズマゴローさんありがとうございました!!
using UnityEditor; を要するコードはエディター上でしか使えないんですよね。Editorディレクトリ以下やifで囲うとビルドから除かれます。たまにストアから購入したアセットが考慮してくれてなくてビルドできなくなるパターンがあります。
— アズマゴロー@モンスター合成ハクスラ開発中 (@azumagoro) June 7, 2019
おかげさまで仕事が進みます。助かりました。
ここまで読んでくださった皆様もありがとうございました!