テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】Unityの内部APIを確認する方法、呼び出す方法

Unityを触っている上で、この機能はどのように実装されているのかや、公開されていないAPIを呼び出したい事があります。

その辺りの話です。

Unityの中のAPIを確認する

アセンブリブラウザでUnityエディタの中のコードを確認します。

MonodevelopでSolutionの項目からReferencesを開きます。この中には開いているプロジェクトがアクセス・参照しているライブラリ一覧が表示されています。

f:id:tsubaki_t1:20150923121100p:plain

UnityEditorの内部APIを確認したい場合は、UnityEditor.dllをダブルクリックしプロジェクト内部を開きます。
これでライブラリの持つクラス一覧が表示されます。privateなAPIも表示したい場合は、VisibilityをAll membersに設定します。

f:id:tsubaki_t1:20150923121220p:plain

f:id:tsubaki_t1:20150923121325p:plain

あとは右上の検索からキーワードを入力して検索すれば、APIがどのようにして実装されているか確認する事が出来ます。
例えば機能の記事ではSceneViewの内部を確認してAPIを使用しました。

f:id:tsubaki_t1:20150923121732g:plain

tsubakit1.hateblo.jp

なお確認できるのはMono上で動作するAPIまでです。

Unityの内部APIを呼び出す

内部APIや構造を確認したので、今度は呼び出す方法です。privateやinternalのAPIを呼び出すには、Reflectionの機能を活用します。

 

型を取得する

まずはクラスの型を取得します。クラスの型がpublicである場合は簡単に、以下のコードで取得することが出来ます。

 var type = typeof(Transform);

 しかし、クラス名が分かっていてもアクセス出来ない(internalやprivateな)クラスの場合は、アセンブリから取得する必要があります。ので、呼び出すアセンブリと型(フルネーム)から取得します。

var sceneViewType = Types.GetType ("UnityEditor.SceneView", "UnityEditor.dll");

 

メソッドを呼び出す

次は先ほど取得した型からメソッドを呼び出してみます。

まずは先ほど取得したTypeよりMethodを取得します。今回はSceneViewのShowを取得します。

var shoeMethod = sceneViewType.GetMethod("Show");

しかし実際にはShowはオーバーロードしているメソッドなので、欲しい引数のメソッドが一発で引けるとは限りません。オーバーロードしてるメソッドは次のように記述します。

MethodInfo shoeMethod = null;
MethodInfo[] sceneViewMethods = sceneViewType.GetMethods ();
foreach (var method in sceneViewMethods) {
	if( method.Name == "Show" && method.GetParameters().Length == 0 ){
		shoeMethod = method;
		break;
	}
}

 これで呼び出すメソッドの定義は取得できました。後はメソッドにメソッドを呼び出すインスタンスを添えて呼び出します。下のコードではシーンビューのインスタンスを既に取得しているとして…こんな感じで呼び出します。最後のnullは引数が無いのでnullです。引数がある場合は配列で渡します。

 shoeMethod.Invoke (window, null);

 なおprivateやstatic、インスタンスの有無等でGetMethodの呼び方が若干異なります。例えばprivateなインスタンスの場合は、以下のようにBindingFlagsを設定して呼び出します。

 sceneViewType.GetMethods (BindingFlags.NonPublic | BindingFlags.Instance)

 

本来アクセス出来ない変数を取得する

本来呼び出せない変数・privateな変数に対してアクセスします。

やり方は先ほどのMethodと同じような感じです。今回はm_Camera(シーンビューの使っているカメラ。cameraプロパティで同じ物が取得できる)に対してアクセスしてみようと思います

var cameraField = sceneViewType.GetField ("m_Camera", BindingFlags.NonPublic | BindingFlags.Instance);
System.Object camera = cameraField.GetValue (window);

 ソースコード

gist.github.com

補足

今回の内容に関しては、Unity公式イベントのUnite 2015「エディター拡張マニアクス 2015」 http://japan.unity3d.com/unite/unite2015/files/DAY2_1400_room2_Ando.pdf で紹介された内容を参考に書いてます。

正直、この行為はUnity利用規約 2.5 に違反してると思いますが、公式イベントで紹介してるので多分C#までなら問題無いんじゃないかと。

 

ちなみに内部コードは結構簡単に変わるうえに変更通知は無い&ScriptUpdaterが効かないので、アセットに使う場合はそれなりの覚悟を以て使いのが良いです。

参考

http://japan.unity3d.com/unite/unite2015/files/DAY2_1400_room2_Ando.pdf

いつもの日記帳:C# Reflectionでフィールドにアクセス - livedoor Blog(ブログ)

ジェネリックメソッドをリフレクションで取得する方法 (System.Reflection, MethodInfo, MakeGenericMethod, IsGenericMethod, IsGenericMethodDefinition) - いろいろ備忘録日記

[Unite 2015 TOKYO]エディター拡張マニアクス 2015 from Unity Technologies Japan G.K. on Vimeo.