GoでOSXのアプリを書く #golang


はじめに

タイトルは釣りです。すいません。
YosemiteからAppleScriptの代わりにJavaScriptが使えるようになったらしいです。

JavaScriptで動かせるようになったということは、GopherJSの出番ですね!

GopherJS + Nashorn + JavaFXをやったときみたいに、簡単なサンプルを動かしてみました。

Windowを出す

ひとまず、Windowを出してみます。
上記のQiitaのJXAの記事を参考にしながら、JavaScriptのコードを無心でGo言語に変えていきます。
本気でやるなら(やる人はいないだろうけど)型を作った方がいいとは思うけど、とりあえずinterface{}を使っておきます。

$変数名に使えないので、__を代用しました。
相変わらず、Goのソースの中にjsobjCという他の言語の名前が出てくる気持ち悪い感じになっています。
registerSubclassのあたりなんか、ゾクゾクしますね。
windowWillClose:windowWillCloseって書いててしばらくハマりました。
win.centerと書くとウィンドウが真ん中によるという謎仕様にもハマりました。
関数を呼び出す訳でも、フィールドに値を入れるわけでもなく、単にフィールドにアクセスするだけなのは不思議です。
win.center()とかの方がわかりやすい気がします。

sample.go
package main

import (
    "github.com/gopherjs/gopherjs/js"
)

func main() {

    objC := js.Global.Get("ObjC")
    __ := js.Global.Get("$")
    objC.Call("import", "Cocoa")

    var app js.Object
    objC.Call("registerSubclass", map[string]interface{}{
        "name":       "WinDelegate",
        "superclass": "NSObject",
        "protocols":  []string{"NSWindowDelegate"},
        "methods": map[string]interface{}{
            "windowWillClose:": map[string]interface{}{
                "types": []interface{}{"void", []interface{}{"id"}},
                "implementation": func(notification js.Object) js.Object {
                    return app.Call("terminate", 0)
                },
            },
        },
    })

    styleMask := __.Get("NSTitledWindowMask").Int() |
        __.Get("NSClosableWindowMask").Int() |
        __.Get("NSMiniaturizableWindowMask").Int()

    win := __.Get("NSWindow").Get("alloc").Call("initWithContentRectStyleMaskBackingDefer",
        __.Call("NSMakeRect", 0, 0, 400, 400),
        styleMask,
        __.Get("NSBackingStoreBuffered"),
        false,
    )

    win.Get("center")
    win.Set("title", "Hello Cocoa")
    win.Call("makeKeyAndOrderFront", win)
    win.Set("delegate", __.Get("WinDelegate").Get("alloc").Get("init"))

    app = __.Get("NSApplication").Get("sharedApplication")
    app.Call("setActivationPolicy", __.Get("NSApplicationActivationPolicyRegular"))
    app.Call("activateIgnoringOtherApps", true)
    app.Call("run")

}

動かしてみます。

$ gopherjs build sample.go && osascript -l JavaScript sample.js

Nashornをやった頃より、エラーメッセージがわかりやすくなったので、go buildをかませる必要はないかなと思います。

感想

Nashornの時に、グローバルオブジェクトの対応をしたおかげで、gopehrjsには手を入れずに済みました。
Gopher君の3Dオブジェクトをグリグリやれるところぐらいまでやらないといけなかった気がします。
きっと誰も必要としない記事なんだろうと思います。
ありがとうございました。