TVMLKitchen

こんにちは、皆さんAppleTV楽しく使っていますか?私はなんと毎日使っています。なぜなら案件についているからです!

というのは実は(!)冗談で、今このゲームにハマっているからです。

Gameloft Video Game Developer Worldwide

Audiのファミリーカーでマルチプレイに参戦し、速そうなクルマを追い抜かして楽しんでいます。AppleTVのリモコンはハンドルにもなるんですよ!ご存知でしたか?
ちなみにハンドルネームは「練馬最速の男」です。周辺地域でのランキングは7位くらいです。ヨロシクお願いします。

余談はさておき、今日は最近作ったライブラリの紹介をしたいと思います。

github.com

年末にTVMLとネイティブアプリのハイブリッドを実現する方法について発表したのですが、その仕組みを簡単に使えるようにしたものになります。

使い方は簡単で、AppDelegateのdidFinishLaunchingWithOptions でこんなおまじないを唱えるだけで、

Kitchen.prepare(launchOptions)

あとはこのようにどこからでも簡単にTVMLのページを表示することができます。

Kitchen.serve(jsFile: "Sample.xml.js")

上は、アプリのMainBundleのSample.xml.js を読み込む例ですが、MainBundleからでなくても、サーバのURLを指定したり、

Kitchen.serve(urlString: "http://.../Catalog.xml.js")

xml文字列を直接読み込ませたり、

let xmlString = // get XML string
Kitchen.serve(xmlString: xmlString)

いろいろな使い方ができます。

使用上のポイントがいくつかありますので説明します。

UINavigationControllerがTVMLと共有される

まず1つ目は、実装の都合によりnavigationControllerがTVML側と共有になるということです。同じUIWindowにある場合は、navigationControllerは基本的にTVML側と共有になります。

つまりTVML => Native => TVML と遷移した場合は、Remote(AppleTVのリモコン) のMenuボタンでバックすることができるわけです。なんて素敵なんでしょう!

共有のnavigationControllerにアクセスするにはちょっとコツがあって、UINavigationControllerを直接辿れる場合は、いつも通り下記のようにすることができますが、

func showDetailViewController() {
    let vc = DetailViewController()
    navigationController.presentViewController(vc, animated: true, completion: nil)
}

UINavigationControllerのインスタンスが辿れない場合は下記のようにします。

Kitchen.navigationController.presentViewController(vc, animated: true, completion: nil)

actionHandler

もう1つは、TVML側で使用するJavaScriptは、基本的には最初のおまじないの時にしか注入できないということです。つまり、Kitchen.serve(urlString: "http://..../Catalog.xml.js") というような形でTVMLのページを表示したとして、このボタンを押したらどうするということは、ライブラリで独自に提供するactionHandlerの仕組みを利用して、起動時に定義しておく必要があるということです。こんな風に。

    Kitchen.prepare(launchOptions, actionIDHandler:{ actionID in
        switch actionID {
        case "openHogeViewController":
            print("Hoge")
        default:
            print("Hage")
        }
    })

actionIDは、TVML側で次のようにして定義します。

<lockup actionID="openHogeViewController" titleId="1234">
    <img src="${this.BASEURL}music_1.lcr" width="308" height="308" />
    <title class="whiteText">Title 1</title>
</lockup>

これで、actionIDが設定された要素をClickすると、actionHandlerがactionIDの値を引数にして呼び出される、というわけです。

なぜTVMLなのか

TVMLマークアップ言語ですので、HTMLがちょっとかけるくらいのデザイナーの方でもとっつきやすいと思います。簡単なページであればTVMLでサクッと作ってしまえば工数の節約になりますし、後から運用ができるというのも利点だと思います。まああまり複雑な使い方はせず、お知らせやライセンス情報のページを表示する、くらいにしておくのが幸せだと思います。

以上になります。実はデータ構造を渡すだけで複雑なビューも実現してくれるレシピ機能の実装も目論んでいたのですが、そこまでするならNativeでも良さそうなので、一旦途中でやめています。皆さんのコントリビュート、お待ちしています。

追記

ちなみにTVMLKitchen というネーミングは、jpsim氏のSourceKitten を真似しました。美味しそうでしょう?