Unityのプラグインを作る
Android編
.aarの作成方法は↓の記事が素晴らしい。
このままAndroidStudioをライブラリをビルドして.aarを作れば良い。
突然仕事でUnity向けのSDKやPluginを作ることになった人向け資料
組み込み方法
作った.aarを Assets/Plugins/Android に置けば使える。
スタティックメソッドの呼び出し方
AndroidJavaClass + CallStatic<戻り値の型>()
Unity(C#)
AndroidJavaClass cls = new AndroidJavaClass("com.package.PluginTest");
string result = cls.CallStatic<string>("execStaticMethod", "2", 2);
Android(Java)
public class PluginTest
{
// スタティック関数
public static String execStaticMethod(String str, int multiply)
{
Integer i = Integer.parseInt(str);
String result = String.format("%d", i * multiply);
return result;
}
}
インスタンスメソッドの呼び出し方
AndroidJavaObject + Call<戻り値の型>()
Unity(C#)
AndroidJavaObject cls = new AndroidJavaObject("com.package.PluginTest"/*, "コンストラクタに引数も渡せる" */);
string result = cls.Call<string>("execMemberMethod", text, 2);
Android(Java)
public class PluginTest
{
// メンバー関数
public String execMemberMethod(String str, int multiply)
{
Integer i = Integer.parseInt(str);
String result = String.format("%d", i * multiply);
return result;
}
}
Delegate登録してコールバックを受け取る
com.unity3d.player.UnityPlayer.UnitySendMessage
Unity(C#)
AndroidJavaClass cls = new AndroidJavaClass("com.package.PluginTest");
cls.CallStatic("execDelegateMethod", text, 2, "Canvas", "Delegate");
public void Delegate(string message)
{
Debug.Log(message);
}
Android(Java)
public class PluginTest
{
// デリゲート関数
public static void execDelegateMethod(final String str, final int multiply, final String gameobject, final String method)
{
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(3000);
String result = execStaticMethod(str, multiply);
// 文字列一つしか送れないから、複数の場合はJSONとかに
com.unity3d.player.UnityPlayer.UnitySendMessage(gameobject, method, result);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
iOS編
iOSは
Unity & iOSプラグイン連携
にもあるように、
C# → C → Objective-C(++) → Swift
こういうブリッジになる。
↓ここが一番詳しく書いている
[[Unity] C#とObjective-Cの連携まとめ]
(http://qiita.com/tkyaji/items/74d485a021c75ed10bca)
組み込み方法
ソース・ファイルをAssets/Plugins/iOSに置けば、iOS Build時のXCodeプロジェクトに組み込まれて使える。
拡張子は .mm がオススメ
C言語でオブジェクト指向
C言語はオブジェクト指向言語ではないので、オブジェクト指向的な実装をするためには、
Obj* Obj_new
{
return [Obj alloc];
}
void Obj_doSomething(Obj* obj, int value)
{
[obj doSomething:value];
}
こういう実装にしておけば、こう書ける↓
IntPtr obj = Obj_new();
Obj_doSomething(obj, 2);
型対応表
C# | C |
---|---|
int | int |
float | float |
string | char* |
System.IntPtr | void* |
配列もいけるっぽい↓
[[Unity] C#とObjective-Cの連携まとめ]
(http://qiita.com/tkyaji/items/74d485a021c75ed10bca)
注意
返り値を文字列にするためには、その文字列はmalloc()で確保しておかないといけない。ARCとかauto releaseとかそういう問題ではなく、返り値がstring型だったらUnityがchar* をfree()している。
だから、
return "abc";
とかすると、 "abc"をfree()するので落ちる。
こういう関数を用意しておいて、
const char* mallocString(const char* str)
{
char* ret = (char*)malloc(strlen(str)*4);
strcpy(ret, str);
return ret;
}
return mallocString("abc");
こうするのが正解。(これでもUnityがfree()しているからメモリーリークは起きていないはず)
参考:How to return string from native iOS plugin to unity?
インターフェースを作る
.hに定義しそうなもんだが、.mmに直書きでいける。
iOS(Object-C++)
#import <Foundation/Foundation.h>
#import "PluginTest.h"
#ifdef __cplusplus
extern "C" {
#endif
// スタティック関数
const char* PluginTest_execStaticMethod(const char* str, int mupltiply)
{
return [PluginTest execStaticMethod:str multiply:mupltiply];
}
// インスタンス生成
PluginTest* PluginTest_new()
{
return [PluginTest alloc];
}
// メンバ関数
const char* PluginTest_execMemberMethod(PluginTest* instance, const char* str, int mupltiply)
{
return [instance execMemberMethod:str multiply:mupltiply];
}
// デリゲート
void PluginTest_execDelegateMethod(const char* str, int multiply, const char* gameobject, const char* method) {
[PluginTest execDelegateMethod:str multiply:multiply gameobject:gameobject method:method];
}
#ifdef __cplusplus
}
#endif
スタティックメソッドの呼び出し方
Unity(C#)
// iOS側で用意したインターフェースの定義
[DllImport("__Internal")]
static extern string PluginTest_execStaticMethod(string text, int multiple);
// 呼ぶとき
PluginTest.PluginTest_execStaticMethod(text, multiple);
iOS(Object-C++)
// + が Static関数
+(const char*)execStaticMethod:(const char*)str multiply:(int)multiply
{
int num = atoi(str);
int result = num * multiply;
return mallocString([[NSString stringWithFormat:@"%d", result]UTF8String]);
}
インスタンスメソッドの呼び出し方
Unity(C#)
[DllImport("__Internal")]
static extern IntPtr PluginTest_new();
[DllImport("__Internal")]
static extern string PluginTest_execMemberMethod(IntPtr p, string text, int multiple);
// 呼ぶとき
var p = PluginTest.PluginTest_new();
PluginTest.PluginTest_execMemberMethod(p, text, multiple);
iOS(Object-C++)
// + が Static関数
-(const char*)execMemberMethod:(const char*)str multiply:(int)multiply
{
int num = atoi(str);
int result = num * multiply;
return mallocString([[NSString stringWithFormat:@"%d", result]UTF8String]);
}
Delegate登録してコールバックを受け取る
UnitySendMessageで、ゲームオブエジェクト名・メソッド名を指定して、C#にメッセージを送る。
Unity(C#)
[DllImport("__Internal")]
static extern void PluginTest_execDelegateMethod(string text, int multiple, string gameobject, string method);
// 呼ぶとき
PluginTest.PluginTest_execDelegateMethod(p, text, multiple, "Canvas", "Delegate");
iOS(Object-C)
// Delegateでコールバック
+(void)execDelegateMethod:(const char*)str multiply:(int)multiply gameobject:(const char*)gameobject method:(const char*)method
{
const char* result = [PluginTest execStaticMethod:str multiply:multiply];
const char* go = mallocString(gameobject);
const char* mt = mallocString(method);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NSThread sleepForTimeInterval:3.0];
UnitySendMessage(go, mt, result);
});
}