LoginSignup
30
26

More than 5 years have passed since last update.

Unityのプラグインを作るAndroid/iOS

Last updated at Posted at 2017-08-07

Unityのプラグインを作る

Android編

.aarの作成方法は↓の記事が素晴らしい。
このままAndroidStudioをライブラリをビルドして.aarを作れば良い。

突然仕事でUnity向けのSDKやPluginを作ることになった人向け資料

組み込み方法

作った.aarを Assets/Plugins/Android に置けば使える。

スタティックメソッドの呼び出し方

AndroidJavaClass + CallStatic<戻り値の型>()

Unity(C#)

Scene.cs
AndroidJavaClass cls = new AndroidJavaClass("com.package.PluginTest");
string result = cls.CallStatic<string>("execStaticMethod", "2", 2);

Android(Java)

PluginTest.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#)

Scene.cs
AndroidJavaObject cls = new AndroidJavaObject("com.package.PluginTest"/*, "コンストラクタに引数も渡せる" */);
string result = cls.Call<string>("execMemberMethod", text, 2);

Android(Java)

PluginTest.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#)

Scene.cs
AndroidJavaClass cls = new AndroidJavaClass("com.package.PluginTest");
cls.CallStatic("execDelegateMethod", text, 2, "Canvas", "Delegate");

Scene.cs
    public void Delegate(string message)
    {
        Debug.Log(message);
    }

Android(Java)

PluginTest.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の連携まとめ

組み込み方法

ソース・ファイルをAssets/Plugins/iOSに置けば、iOS Build時のXCodeプロジェクトに組み込まれて使える。
拡張子は .mm がオススメ

C言語でオブジェクト指向

C言語はオブジェクト指向言語ではないので、オブジェクト指向的な実装をするためには、

Object.mm
Obj* Obj_new
{
  return [Obj alloc];
}
void Obj_doSomething(Obj* obj, int value)
{
  [obj doSomething:value];
}

こういう実装にしておけば、こう書ける↓

Object.cs
IntPtr obj = Obj_new();
Obj_doSomething(obj, 2);

型対応表

C# C
int int
float float
string char*
System.IntPtr void*

配列もいけるっぽい↓
[Unity] C#とObjective-Cの連携まとめ

注意

返り値を文字列にするためには、その文字列は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++)

Interface.mm
#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#)

PluginTest.cs
// iOS側で用意したインターフェースの定義
[DllImport("__Internal")]
static extern string PluginTest_execStaticMethod(string text, int multiple);
MainScene.cs
// 呼ぶとき
PluginTest.PluginTest_execStaticMethod(text, multiple);

iOS(Object-C++)

PluginTest.mm
// + が 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#)

PluginTest.cs
[DllImport("__Internal")]
static extern IntPtr PluginTest_new();

[DllImport("__Internal")]
static extern string PluginTest_execMemberMethod(IntPtr p, string text, int multiple);
MainScene.cs
// 呼ぶとき
var p = PluginTest.PluginTest_new();
PluginTest.PluginTest_execMemberMethod(p, text, multiple);

iOS(Object-C++)

PluginTest.mm
// + が 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#)

PluginTest.cs
[DllImport("__Internal")]
static extern void PluginTest_execDelegateMethod(string text, int multiple, string gameobject, string method);
MainScene.cs
// 呼ぶとき
PluginTest.PluginTest_execDelegateMethod(p, text, multiple, "Canvas", "Delegate");

iOS(Object-C)

PluginTest.mm
// 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);
  });
}
30
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
26