Titanium Mobileで作る! iPhone/Androidアプリ

第14回 iPhoneサンプルアプリをAndroidに対応させる

この記事を読むのに必要な時間:およそ 4 分

今回は実際に今まで作成してきたiPhone向けのTwitterクライアントを,Androidでも動作するように変更していきます。同時にiPhoneとAndroid向けのアプリが同じコードで生成できるるようにしてみます。今回はエレガントな解法ではないのですが,OSごとに表示を分ける必要がある部分ではif文で分岐させることで対応させていきます。

TwitterAPIを対応させる

では早速コードの変更を行っていきましょう。まずはTwitter APIを呼び出すコードをAndroidに対応させます。TwitterのOAuthインターフェースは最近HTMLが変更になっていて,古いHTMLを対象にしたコードでは動作しません。Androidに対応すると同時にこのHTMLの変更についても追従します。と,偉そうに書きましたが,いままでのサンプルで利用しているtm_twitter_apiを作成されている@mogyaさんがつい先日ライブラリの更新をされたので,実際にはライブラリを更新するだけでもこの点については解決してしまいます。著者のgithubから最新のサンプルアプリをダウンロードするか,mogyaさんのtm_twitte_apiを最新にして対応してください。サンプルアプリで利用しているtwitter_api.jsは著者が改編を加えているので,特に必要がなければサンプルアプリを最新にして対応してください。Android対応のために行われている変更についての細かな検証は最後に付録しますので,興味のある方はそちらを御覧ください。

/lib問題

TwitterAPIについてはライブラリを新しくすることで対応できるのですが,そもそもライブラリがResorcesディレクトリに作られたlib以下にあるとAndroidでは正しくincludeできないというバグが存在します。Androidでは Ti.include('lib/twitter_api.js') というinclude指定がなぜか,Ti.include('lib/lib/twitter_api.js') という指定に勝手に解釈されます。いろいろな解決法があるのですが,筆者の場合はlibディレクトリ以下にさらにlibディレクトリを作り,新しく作った(深い位置にあるほうの)libディレクトリから,元のlibディレクトリにあるファイルに向けてシンボリックリンクを張ることで対処しています。ちなみに,Resources/lib/libがResources/libを指すようなシンボリックリンクを作成するとビルドに失敗しますので,lib以下のファイル一つ一つに対して,lib/libからシンボリックリンクを作る必要があります。そのほかの方法については,前述の@mogyaさんのblogなどをご覧になってください。

TabGroupにひと工夫

前回の記事でも書いていますが,AndroidでのTabGroupはTabBarが消せないなどの問題もあって使い勝手がよくありません。そこでTabGroupの利用をやめてしまいたいのですが,この後に使うmenuボタンの機能がTabGroupなしでは動作しなかったので,TabBarを無理やり消すことにします。かなり汚い実装になりますが,Tiatnium側で改善されるまでは仕方がなさそうです。

app.jsの変更

var js_file;
if (Titanium.Platform.osname !== 'android') {
    js_file = 'table_view.js';
} else {
    js_file = 'dummy.js';
}

var win1 = Titanium.UI.createWindow({
    url: js_file,
    title:'Tab 1',
    backgroundColor:'#fff'
});

TabGroupを利用してwindowを開くのは今までと同じですが,Androidの時だけ,dummy.jsを開くようにしています。

そして,dummy.jsの実装は次のようになっています。

var win = Ti.UI.currentWindow;

Ti.API.debug(win.activity);
var win1 = Titanium.UI.createWindow({
    url: 'table_view.js',
    title:'Tab 1',
    backgroundColor:'#fff'
});

Ti.UI.currentTab.open(win1);

こうするとtable_view.jsを全画面に表示し,あたかもTabBarが存在しないように見せることができます。そしてTabGroupを利用していないと使用することができない,menuボタンの利用が可能になります。

menuボタンを使おう

AndroidではNavigationBarが無くなっているので,NavigationBarに設置していた新しいMessageを作成するボタンや検索ボタンが当然表示できません。そこで,NavigationBarのボタンに実装していた機能を,Android端末のmenuキーに割り当ててしまいます。menuボタンが利用できるというのはAndroidがiPhoneとは大きく違う点です。

menuボタンのコード

if (Titanium.Platform.osname !== 'android') {
    var messageButton = Ti.UI.createButton(
        {
                systemButton: Titanium.UI.iPhone.SystemButton.ADD
        }
    );
    messageButton.addEventListener(
        'click',
        function () {
            var messageWindow = Ti.UI.createWindow(
                {
                    url: 'message_window.js',
                    title: 'message',
                    backgroundColor: '#fff'
                }
            );
            Ti.UI.currentTab.open(messageWindow);
        }
    );
    win1.rightNavButton = messageButton;
} else {
    win1.activity.onCreateOptionsMenu = function(e) { //(A)
        var menu = e.menu;
        var menuItem1 = menu.add({ title: "Message",itemId:1 }); //(B)
        menuItem1.addEventListener(
            "click",
            function(e) {
                var messageWindow = Ti.UI.createWindow(
                    {
                        url: 'message_window.js',
                        title: 'message',
                        backgroundColor: '#fff'
                    }
                );
                Ti.UI.currentTab.open(messageWindow);
            }
        );
        var menuItem2 = menu.add({ title: "Search",itemId:2 });
        menuItem2.addEventListener(
            "click",
            function(e) {
                search.show();
            }
        );
    };
}

これがmenuボタンに機能を割り当てるコードになります。elseの前までが今まで通りのiOS向けの実装で,それより後ろ側が今回新しく実装したandroid向けのmenuボタンを利用するためのコードです。これによりiOSで利用するときはNavigationBarのボタンが利用され,Androidの時は端末のmenuキーを利用するようになります。

ちょっと今までとは違ったコードになっていて分かりづらいので,少し詳しく解説します。AndroidではTi.UI.Windowオブジェクトにactiveityというパラメータが増えています。activityというのはAndroidに特有の概念で,Ti.UI.Windowとほとんど同じとようなものと考えることができます。詳しく知るにはAndoridのアーキテクチャを知る必要があるので,世界を目指せ!Androidアプリ開発入門などを参考にしてください。ここでは,Android固有のwindowの機能というくらいに捉えておいてください。

このactivityには,独自のイベントがいくつも定義されており,そのなかのひとつにonCreateOptionsMenuというイベントがあるので,このイベントリスナを(コード中の(A)部分で)定義しています。このイベントリスナに渡ってくるイベントオブジェクトeには,e.menuというオブジェクトがあり,Androidのmenuを操作することができます。このmunuオブジェクトのaddメソッドにtitleとitemIdを渡すと,menuItemオブジェクトが作成され,返り値として取得できます(コード中の(B)部分)⁠menuIdはmenuの項目ごとに違っている必要があります。

このmenuItemオブジェクトにaddEventListenerでイベントリスナを追加することで,ボタンが押されたときの動作を実装することができます。ここでは,新しくmessage_windos.jsに実装されているwindowを開くようにしています。

著者プロフィール

倉井龍太郎(くらいりゅうたろう)

株式会社はてな アプリケーションエンジニア。

スマートフォンアプリからSQLチューニングまで幅広く格闘中。好きな言語はRuby。

URLhttp://d.hatena.ne.jp/r_kurain/
Twitter@kurain

コメント

コメントの記入