Titanium - JavaScript で iPhone/Android アプリを作る

Titanium MobileJavaScriptiPhone/Android のアプリ (not Webアプリ) を開発できる開発環境。詳しくは Titaniumで始めるモバイルアプリ作成の基礎知識 (1/3):Web技術でネイティブアプリを作れるTitanium(2) - @IT などに解説があります。

少し時間があったので、JavaScript で作るというのがどんな感じか試してみました。作ったアプリは

こんな感じで TableView があり、選択すると WebView でアプリ内ブラウザが立ち上がる、ブラウザはツールバーで「戻る」や「リロード」が可能。あとはタブコントロールがあったり・・・という単純なもの。初期起動画面のサイトリストは、HTTP でローカルに立てたサーバーから JSON で読み込んでいます。

Web上のドキュメントを見ながら2, 3時間試行錯誤で一応の形になりました。

Titanium での開発の実際

Titanium は開発環境ではありますが、IDE がついてくるわけではありません。今回は Emacs + js2-mode.el でゴリゴリ書きました。個人的には、IDE よりこのスタイルの方が好み。

JavaScript 中で、Titanium.UI.createWindow(...) といった API を呼び出して iPhone/Android の UI を組み立てていきます。コードができたら、"Titanium Developer" という開発ツールでビルド。

ビルドが完了するといつもの iPhone エミュレータが立ち上がり、アプリが動きはじめます。ビルドの裏側で何が行われているかまだ把握していないのですが、立ち上がるアプリは JavaScript によるWebアプリではなく、ネイティブUIを持ったネイティブアプリです。

JavaScript で書くコードは、以下のようなコードになります。

app.js が Titanium アプリのエントリポイントになるスクリプトで、アプリを立ち上げるとまずはこのスクリプトが実行されます。

Titanium.UI.setBackgroundColor('#000');
var tabGroup = Titanium.UI.createTabGroup();

var menu = Titanium.UI.createWindow({  
  title :'メニュー',
  backgroundColor :'#fff',
  url : 'menu.js'
});

var tab1 = Titanium.UI.createTab({  
    icon:'KS_nav_ui.png',
    title:'メニュー',
    window:menu
});

var config = Titanium.UI.createWindow({
  title : '設定',
  backgroundColor : '#fff',
  url : 'config.js'
});

var tab2 = Titanium.UI.createTab({  
    icon:'KS_nav_views.png',
    title:'設定',
    window: config
});

tabGroup.addTab(tab1);  
tabGroup.addTab(tab2);  
tabGroup.open();

Window を生成し、タブメニューを組み立てています。これで画面下部のタブメニューが表示されるようになります。各タブをクリックした後に起動するのは url プロパティで指定した menu.js や config.js です。

menu.js は、上記のスクリーンショットGREEFacebook などの一覧が出ているウィンドウを担当する箇所。

var win = Titanium.UI.currentWindow;
var xhr = Titanium.Network.createHTTPClient();

xhr.open('GET', 'http://localhost:3000/menu');
xhr.onload = function () {
  var data = JSON.parse(this.responseText);
  var tv = Titanium.UI.createTableView({ data : data });
  tv.addEventListener('click', function(e) {
    var row = e.rowData;
    var w   = Ti.UI.createWindow();
    var wv  = Ti.UI.createWebView();
        
    var btn_back = Ti.UI.createButton({
      title : '戻る'
    });
    btn_back.addEventListener('click', function () { wv.goBack(); });

    var btn_reload = Ti.UI.createButton({
      systemButton : Ti.UI.iPhone.SystemButton.REFRESH
    });
    btn_reload.addEventListener('click', function () { wv.reload(); });

    wv.url = row.url;
    w.toolbar = [ btn_back, btn_reload ];
    w.add(wv);
    win.tab.open(w);
  });

  win.add(tv);
};
xhr.send();

Titanium.Network.createHTTPClient() で生成した HTTP クライアントで非同期HTTPでJSONを取得し、コールバック中でメニュー (TableView) を組み立てています。テーブルの各項目をクリックすると動的に WebView が生成されて、GREEFacebook がその中に表示される、という具合。

今回は Titanium の組み込みの API だけを使って書いていますが、jQuery などのライブラリを読み込んで使うこともできるそう。

基本的にアプリを作っていく流れはこれだけ。JavaScript を書いては Titanium Developer でビルドしてエミュレータで確認、という感じです。Objective-C 生で書くときに比べてやはり素早く書けるし、コード量も少ない。楽で良いです。各種 API でカメラや位置情報などデバイスが提供する機能もちゃんと使えます。

間に抽象レイヤが入っている分 Objective-C/Java で作るのに比べると細かい制御ができなかったりというところはあるのかもしれません。とはいえ、十分に実用的なアプリを、書き慣れた JavaScript で手軽に(しかもクロスプラットフォームで)作れるというのはなかなかに魅力的・・・というわけで、Titanium++ です。

おまけ

JSON を返すサーバは Mojolisious::Lite で作りました。Mojolicious はこういう Quick Hack の時にも便利。

use utf8;
use Mojolicious::Lite;

app->renderer->default_format('json');

get '/menu' => sub {
    my $self = shift;
    my $menu = [
        {
            title    => 'GREE',
            hasChild => 1,
            url      => 'http://t.gree.jp/',
        },
        {
            title    => 'Google',
            hasChild => 1,
            url      => 'http://google.com/'
        },
        {
            title    => 'Facebook',
            hasChild => 1,
            url      => 'http://touch.facebook.com/',
        },
    ];
    $self->stash(json => $menu);
};

app->start;