今回はgomobile+unityでGoroutineを実装できるか試した編。
結果は、JAR経由でGomobileで作成したAARは動くことが確認できたが、直接Shared Libraryを動かすまでは行けていない。
cgoで書いたShared LibraryをUnityから直接コールはダメですか?
何となく今回は返り値をstringで実装してみた。
Stringで実装する場合、Unityとcgoでは値の受け渡しの調整が必要になる。
C.CStringでラップするのとC.freeで解放は忘れてはいけない。
しかし、プログラムを実装したがスレッド実行時にハングして終わる結果となる。
コマンド
GOMOBILE=$GOPATH/pkg/gomobile \
GOOS=android \
GOARCH=arm \
NDK=ndk-r12b \
CC=$GOMOBILE/android-${NDK}/arm/bin/arm-linux-androideabi-clang \
CXX=$GOMOBILE/android-${NDK}/arm/bin/arm-linux-androideabi-clang++ \
CGO_CFLAGS="-target armv7a-none-linux-androideabi --sysroot $GOMOBILE/android-${NDK}/arm/sysroot" \
CGO_CPPFLAGS="-target armv7a-none-linux-androideabi --sysroot $GOMOBILE/android-${NDK}/arm/sysroot" \
CGO_LDFLAGS="-target armv7a-none-linux-androideabi --sysroot $GOMOBILE/android-${NDK}/arm/sysroot" \
CGO_ENABLED=1 GOARM=7 go build -pkgdir=$GOMOBILE/pkg_android_arm \
-tags="" -x -buildmode=c-shared \
-o=./hoge/libhoge.so \
hoge.go
cgoで思ったのはgoの書き方からだいぶ変わるのでこの書き方で実装すべきかどうかという点
package main
import (
"fmt"
)
// #include <stdlib.h>
import "C"
import "unsafe"
//export MyFunction
func MyFunction() *C.char {
co := make(chan string)
hello(co)
msg := fmt.Sprintln(<-co, "World")
msg += fmt.Sprintln("Hello", <-co)
msg += fmt.Sprintln(<-co)
p := C.CString(msg)
defer C.free(unsafe.Pointer(p))
return p
}
func hello(yield chan<- string) {
go func() {
yield <- "Hello"
yield <- "Gopher"
yield <- "Hello NDS"
}()
}
func main() {
}
using UnityEngine;
using System.Runtime.InteropServices;
public class ButtonTest : MonoBehaviour {
string msg;
[DllImport("hoge")]
private static extern string MyFunction();
public void TestClick()
{
string str = MyFunction();
Debug.Log(str);
msg = str;
}
void OnGUI(){
GUI.Label (new Rect (0, 0, 300, 300), msg );
}
}
何かお作法があるのだろうか?もう少し勉強してみます。
今後に期待。
Gomobile標準のbindで作ったAARをばらしてShared LibraryだけをUnityで動かす
これはStringの返り値をC.CStringで実装してないので動くはずもないのでスルー。
Gomobileで作成したAARをJAR経由で実行する
このやり方だとGoroutineは動いた。
JAR経由と書いてあるが、AARの内部でclasses.jarが入っており、それをコールしてるということ(ややこしい)
Unity -> AAR -> AAR(Classes.jar -> libgojni.so) の順でコールしている。
package hoge
import (
"fmt"
)
func MyFunction() string {
co := make(chan string)
hello(co)
msg := fmt.Sprintln(<-co, "World")
msg += fmt.Sprintln("Hello", <-co)
msg += fmt.Sprintln(<-co)
return msg
}
func hello(yield chan<- string) {
go func() {
yield <- "Hello"
yield <- "Gopher"
yield <- "Hello NDS"
}()
}
Gomobile標準のbindコマンドでhoge.aar
を出力
$ gomobile bind -target=android .
Android StudioのAndroidLibraryのlibsにhoge.aarをセットする。
package com.example.manabu.hogedroid;
import go.hoge.Hoge;
public class HogeClass {
public static String get(){
return Hoge.myFunction();
}
}
using UnityEngine;
using System.Collections;
public class ButtonTest : MonoBehaviour
{
string msg = "";
public void TestClick(){
#if UNITY_ANDROID
using (AndroidJavaClass jc = new AndroidJavaClass("com.example.manabu.hogedroid.HogeClass"))
{
Debug.Log(jc);
string msg = jc.CallStatic<string>("get");
Debug.Log(msg);
}
#endif
}
void OnGUI(){
GUI.Label (new Rect (0, 0, 100, 30), msg);
}
}
参考までにabstractの中身
package go.hoge;
import go.Seq;
public abstract class Hoge {
private Hoge() {
}
public static void touch() {
}
private static native void _init();
public static native String myFunction();
static {
Seq.touch();
_init();
}
}