Unity
dll
UnityEditor

using UnityEditor; を含むDLLを作るときに気をつけること


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の拡張で、自作属性を宣言していました。


PathAttributeDrawer.cs

[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ファイルのエディタ拡張のみのコードなので、全てを囲んでしまいました。


PathAttributeDrawer.cs

#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/PluginsPlugins/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をすると編集時にコード補完が起動しなかったり該当プラットフォームでないときにコメントアウトされてしまうので、個人的にはあまり好きではありません。


さいごに

対策方法を教えてくださったアズマゴローさんありがとうございました!!


おかげさまで仕事が進みます。助かりました。

ここまで読んでくださった皆様もありがとうございました!