LoginSignup
2
4

More than 5 years have passed since last update.

GomobileからAARを作ってUnityで動かしてみた

Last updated at Posted at 2016-09-09

概要

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を作成

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作成

  1. New ProjectAdd No Activiryを作成
    • minSdkVersion=15とした
  2. New ModuleAndroid Libraryを作成
    • Module名はhogedroidにした。
  3. gomobileで作成したhoge.aarlibsにドラッグ&ドロップする
  4. build.gradleに下記を追記
build.gradle(hogedroid)
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile (name: 'hoge', ext:'aar')
}

repositories{
    flatDir{
        dirs 'libs'
    }
}

5 メイン処理の作成

HogeClass.java

package com.example.manabu.hogedroid;
import go.hoge.Hoge;

public class HogeClass {

    public static long get() {
        return Hoge.getInt();
    }

}
  • パスが通っていれば⌘Bで定義にジャンプしてhoge.aarの中身が見れる
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.aarhogedroid-debug.aarAssets/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 
httpServer.go
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)
}
httpClient.go
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`
2
4
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
2
4