LuaからObjC/Javaと連携する

C++でObjC/Java連携しようとすると、グルーコードを書いたりPluginXを使ったりする方法がありますが、記述量や設定が複雑になりがちです。開発言語にLuaを使っている場合これらの複雑な部分は既に書かれており、Luaからから呼び出せるインターフェースも提供されています。

## ObjC
LuaからObjCのメソッドを呼び出すにはluaocを使います。例えば本家のテストコードは次のようになっています。

```objc:LuaObjectCBridgeTest.h
@interface LuaObjectCBridgeTest : NSObject

...

+ (int)  addTwoNumbers:(NSDictionary *)dict;

...

@end
```

```objc++:LuaObjectCBridgeTest.mm
+ (int)  addTwoNumbers:(NSDictionary *)dict
{
    int num1 = [[dict objectForKey:@"num1"] intValue];
    int num2 = [[dict objectForKey:@"num2"] intValue];
    
    return num1 + num2;
}
```

```lua:LuaBridgeTest.lua
local targetPlatform = cc.Application:getInstance():getTargetPlatform()

...

if (cc.PLATFORM_OS_IPHONE == targetPlatform) or (cc.PLATFORM_OS_IPAD == targetPlatform) or (cc.PLATFORM_OS_MAC == targetPlatform) then
    local args = { num1 = 2 , num2 = 3 }
    local luaoc = require "cocos.cocos2d.luaoc"
    local className = "LuaObjectCBridgeTest"
    local ok,ret  = luaoc.callStaticMethod(className,"addTwoNumbers",args)
    if not ok then
        Director:getInstance():resume()
    else
        print("The ret is:", ret)
    end
end
```

ObjCで定義したaddTwoNumbersをluaoc.callStaticMethodで呼び出しています。引数はluaのオブジェクトがNSDictionaryに、戻り値は呼び出しの成功と値が返ってきます。

引数には関数を渡すこともでき、ObjCから呼び出せます。

```objc++
#include "CCLuaBridge.h"

...

+ (void)callbackLua:(NSDictionary *)dict;
{
    int scriptHandler = [[dict objectForKey:@"scriptHandler"] intValue];
    LuaBridge::pushLuaFunctionById(scriptHandler);
    LuaStack *stack = LuaBridge::getStack();
    stack->pushString("success");
    stack->executeFunction(1);
    LuaBridge::releaseLuaFunctionById(scriptHandler);
}
```

```lua
local function callback(param)
    if "success" == param then
        print("object c call back success")
    end
end
luaoc.callStaticMethod(className,"callbackLua", {scriptHandler = callback } )
```

引数にluaの関数を渡した場合ObjC側では数値が渡ってくるので、その数値を使って関数を呼び出します。使い終わった関数はreleaseLuaFunctionByIdで解放しないとメモリに残ったままになってしまうので注意が必要です。

## Java
Javaの場合もObjCと同じように、luajを使います。

```java:LuaJavaBridgeTest.java
package com.cocos2dx.sample.LuaJavaBridgeTest;

import org.cocos2dx.lib.Cocos2dxLuaJavaBridge;

public class LuaJavaBridgeTest
{	
	public static int addTwoNumbers(final int num1,final int num2){
		return num1 + num2;
	}

...

}
```

```lua:LuaBridgeTest.lua
if (cc.PLATFORM_OS_ANDROID == targetPlatform) then
    local args = { 2 , 3}
    local sigs = "(II)I"
    local luaj = require "cocos.cocos2d.luaj"
    local className = "com/cocos2dx/sample/LuaJavaBridgeTest/LuaJavaBridgeTest"
    local ok,ret  = luaj.callStaticMethod(className,"addTwoNumbers",args,sigs)
    if not ok then
        print("luaj error:", ret)
    else
        print("The ret is:", ret)
    end

...

end
```

Javaの場合パッケージ名も含めた本名でクラスを指定します。また、メソッドの引数と戻り値の型を表す文字列を指定する必要があり、整数はI、文字列はLjava/lang/String;などを`(引数)戻り値`というフォーマットで渡します。省略した場合luajが引数を見て決めますが、Javaで定義されているシグネチャと違う場合エラーになるので明示する方が安全です。

コールバックもObjCとほぼ同じです。

```java
public static void callbackLua(final String tipInfo,final int luaFunc){
	Cocos2dxLuaJavaBridge.callLuaFunctionWithString(luaFunc, "success");
	Cocos2dxLuaJavaBridge.releaseLuaFunction(luaFunc);
}
```

```lua
local function callbackLua(param)
    if "success" == param then
        print("java call back success")
    end
end
local args = { "callbacklua", callbackLua }
local sigs = "(Ljava/lang/String;I)V"
local ok = luaj.callStaticMethod(className,"callbackLua",args,sigs)
if not ok then
    print("call callback error")
end
```