概要
GoにはAndroidとiOS向けにアプリケーションやライブラリを出力するgomobileというライブラリがあります。
Goはワンプロセス、マルチスレッド、スレッド間通信を言語レベルで実装しており、スレッドプログラムを安全にかつ、非常に簡単に書ける特徴があり、Unityでのスマフォアプリ開発に利用できればと思い評価しました。
今回の検証では、UnityでGoが動作するかの確認までとし、Goのスレッドの恩恵を受けれるかを評価した内容ではありません。
今回の調査後に下記も書きました
今回の実現方法
gomobileで作成したaar(Android ARchive)とAndroid Studioで作成したaarをUnityのPluginに放り込むことで実現します。
とても黒魔術な香り。
何故このやり方になるかというとgomobileのbindはabstract classが出力される為、
Unityから直接呼び出せなくて一度書き直す必要がありました。
何か他にいい方法あれば教えてください。
gomobileとAndroid StudioとUnityのインストール手順は割愛。
もっとスマートに出来るといいけど、とりあえず今日はハックするとこまで。
gomobileでaar作成
$ mkdir $GOPATH/src/hoge
$ cd $GOPATH/src/hoge
hoge.goを作成
package hoge
func GetInt() int {
return 10
}
$ gomobile bind -target=android .
hoge.aar
が出力される
中身を見るとCPU毎にlibgojni.so
(Shared Library)が出力となっている。
$ unzip -Z1 hoge.aar
AndroidManifest.xml
proguard.txt
classes.jar
jni/armeabi-v7a/libgojni.so
jni/arm64-v8a/libgojni.so
jni/x86/libgojni.so
jni/x86_64/libgojni.so
R.txt
res/
上のclasses.jar
の中身はこのようになっている。
META-INF/MANIFEST.MF
go/LoadJNI.class
go/Seq$1.class
go/Seq$Proxy.class
go/Seq$Ref.class
go/Seq$RefMap.class
go/Seq$RefTracker.class
go/Seq.class
go/Universe$proxyerror.class
go/Universe.class
go/error.class
go/hoge/Hoge.class
Android Studioでaar作成
-
New Project
でAdd No Activiry
を作成
- minSdkVersion=15とした
-
New Module
でAndroid Library
を作成
- Module名は
hogedroid
にした。
- gomobileで作成した
hoge.aar
をlibs
にドラッグ&ドロップする - build.gradleに下記を追記
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile (name: 'hoge', ext:'aar')
}
repositories{
flatDir{
dirs 'libs'
}
}
5 メイン処理の作成
package com.example.manabu.hogedroid;
import go.hoge.Hoge;
public class HogeClass {
public static long get() {
return Hoge.getInt();
}
}
- パスが通っていれば⌘Bで定義にジャンプして
hoge.aar
の中身が見れる
package go.hoge;
import go.Seq;
public abstract class Hoge {
private Hoge() {
}
public static void touch() {
}
private static native void _init();
public static native long getInt();
static {
Seq.touch();
_init();
}
}
Unityから直接abstract呼べたらいいのに。
ここでは、頭文字大文字で書いてたメソッドが小文字になってたりする。
他にもintがlongになっていた。
罠でしかない。
操作箇所にコメントした画像
Gradleからassembleをダブルクリックで実行してaar作成
% unzip -Z1 hogedroid-debug.aar
aapt/
aapt/AndroidManifest.xml
AndroidManifest.xml
classes.jar
R.txt
res/
res/values/
res/values/values.xml
aidl/
assets/
jni/
libs/
Unityに適当なコール処理を書く
-
hoge.aar
とhogedroid-debug.aar
をAssets/Plugins/Android
にドラッグして配置する
using UnityEngine;
using System.Collections;
public class ButtonTest : MonoBehaviour
{
long gnum = 0;
public void TestClick(){
#if UNITY_ANDROID
using (AndroidJavaClass jc = new AndroidJavaClass("com.example.manabu.hogedroid.HogeClass"))
{
Debug.Log(jc);
long num = jc.CallStatic<long>("get");
Debug.Log(num);
gnum += num;
}
#endif
}
void OnGUI(){
GUI.Label (new Rect (0, 0, 100, 30), gnum.ToString());
}
}
うまくビルドできたら動くはず。
あとがき
本当はAppleのTLS1.2対応の話があったので、Golang使ったhttp2+TLS1.2をUnityで動かすネタをやろうと思ったがここまでで結構大変なのでやめた。
Unityは.NET3.5で動いていて、TLS1.0までしか対応してないのでいいネタになると思ったんだけどなぁ。
おまけ:http2 serverとclient
参考: https://golang.org/pkg/net/http/
go v1.6系ならこの書き方でいける
- pemのcommon nameだけ設定するようなの
$ go run /usr/local/go/src/crypto/tls/generate_cert.go --host localhost
package main
import (
"net/http"
"log"
)
func handler(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("This is an example server.\n"))
}
func main(){
http.HandleFunc("/", handler)
log.Printf("About to listen on 10443. Go to https://localhost:10443")
err := http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil)
log.Fatal(err)
}
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"crypto/tls"
)
func main() {
tr := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://localhost:10443/")
if err != nil {
log.Fatal(err)
}
robots, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", robots)
}
ちょこちょこ罠がある
- うちのMacBookProだとgccのビルドに1時間かかった
- Android Studioの謎エラーの調整、ほんと謎だわ
Theme.AppCompat.Light.DarkActionBar
↓
android:Theme.Holo.Light.DarkActionBar
- Gradleからassembleの実行が謎エラーになる時はプロジェクト直下にあるコマンドを叩くとうまくいく
$ ./gradlew assembleRelease`