モックアップという意味を持つ Maqetta: 第 3 回 Maqetta でデザインした UI プロトタイプを PhoneGap でデプロイする

PhoneGap を使用して、Maqetta でデザインした UI プロトタイプをあらゆるモバイル端末にデプロイする

Maqetta について紹介するこの連載では、これまで、Dojo と Dojo Mobile ツールキットの機能を使用してインタラクティブなモバイル UI プロトタイプを作成し、その機能を強化する方法を説明してきました。ブラウザー内で Maqetta を使用して作業をすることで、一切コーディングせずにリアルなプロトタイプを作成した後、そのプロトタイプの機能とフローをカスタム JavaScript コードで拡張しました。今回は Maqetta に PhoneGap を組み合わせて、新しいモバイル UI プロトタイプを作成し、実際の端末にデプロイします。

Tony Erwin, Software Engineer, IBM

Tony Erwin - author photoTony Erwin は、IBM Emerging Internet Technologies グループに所属するソフトウェア・エンジニアで、Maqetta 開発チームの主力メンバーです。1998年に IBM に入社して以来、さまざまな技術とツールキットを使用して広範な UI デザインと開発経験を積んでいます。IBM に入社する前は、インディアナ大学でコンピューター・サイエンスの修士号、ローズハルマン工科大学でコンピューター・サイエンスの学士号を取得しました。



2013年 7月 04日

はじめに

この連載について

この連載では、Maqetta を使用して HTML5 によるユーザー・インターフェースのプロトタイプを作成する方法を紹介します。

  • 第 1 回では、リッチ・モバイル・アプリのプロトタイプを作成する手順を通して、Maqetta の主な機能について学びます。
  • 第 2 回では、第 1 回で作成したプロトタイプ・アプリを次のレベルに拡張するために、JavaScript でカスタム・コードを作成してインタラクティブな機能を追加します。
  • 第 3 回では、PhoneGap を使用して、Maqetta で生成されたモバイル・プロトタイプを実際の端末にすぐにデプロイできるネイティブ・アプリに変身させます。

developerWorks の Tony のブログで Maqetta の使い方を詳しく学んでください。

Maqetta と PhoneGap を組み合わせると、モバイル・アプリのプロトタイプ作成、開発、デプロイを迅速に行える強力なプラットフォームになります。連載の最終回となるこの記事では、新しいアプリのプロトタイプを一から作成し、Maqetta によるモバイル・アプリを実装してデプロイするまでを説明します。この記事のサンプル・アプリとして使用するのは、ユーザーが自分の現在地を地図上で確認できるモバイル GPS ロケーター・アプリです。最初に、Maqetta のページ・エディターで UI プロトタイプを作成しますが、(第 1 回と同様に) 一切コーディングは行いません。次に、(第 2 回と同じく) 作成したプロトタイプをさらにインタラクティブな機能で強化する JavaScript コードを追加します。その後、JavaScript に新しい層を追加して、PhoneGap の Geolocation API が提供する機能を使用できるようにします。

プロトタイプの開発が完了した後は、Google Chrome の Ripple Emulator 拡張機能で位置情報機能をテストしてから、Adobe PhoneGap Build サービスを使用して Maqetta で作成した GPS ロケーターをネイティブ・アプリに変身させます。そして最後に、Android SDK に含まれる Android エミュレーターで GPS ロケーターの機能をテストして記事を締めくくります。

現在の知識を基に作成してください

この連載を第 1 回から読んでいれば、GPS ロケーターのプロトタイプを作成して機能を強化することは、簡単な上に、Maqetta について学んだ基礎を固める絶好の機会にもなるはずです。Maqetta にモバイル・アプリがすでに用意されていて、そのアプリを PhoneGap でビルドしてモバイル端末にデプロイしたいというだけなら、「PhoneGap へのアプリのエクスポート」まで読み飛ばしていただいても構いません。


GPS ロケーターのプロトタイプの作成

最初のステップでは、GPS ロケーターの UI プロトタイプを作成します。この GPS ロケーターでは、ユーザーが自分の地理的な位置を地図上で確認することができます。また、地図のスタイルを切り替えることや、現在地の緯度と経度を確認すること、さらにはボタンを押して新しい位置へと表示を更新することもできます。

第 1 回と同様に、まずは Maqetta 内に新規プロジェクトを作成した上で、HTML ファイルを作成するところから始めます。

  1. Maqetta.org の Maqetta サーバーにログインします (このステップは、読者が Maqetta の Webサイトでユーザーとして登録済みであることを前提とします)。
  2. 新規プロジェクトを作成するために、「Create (作成)」 > 「Project... (プロジェクト...)」の順にメニュー・オプションを選択します。プロジェクト名として「gpsLocator」と入力してから、「Create (作成)」ボタンをクリックします。
  3. 今度は新規プロジェクト内に新しいモバイル・アプリを作成するために、「Create (作成)」 > 「Mobile Application... (モバイル・アプリケーション...)」の順にメニュー・オプションを選択します。ファイル名として「index.html」(PhoneGap では、この名前にする必要があります) と入力してから、「Create (作成)」ボタンをクリックします。

ビューの作成

UI をデザインする最初のステップは、ビューを作成することです。このサンプル・アプリの場合、Dojo Mobile の ScrollableView ウィジェットを使用してビューを実装します。

  1. ウィジェット・パレットの「Views (ビュー)」セクションにある ScrollableView ウィジェットを、Maqetta の端末シルエットの中央にドラッグ・アンド・ドロップします (ウィジェットが見つからない場合は、ウィジェット・パレットの最上部にある検索ボックスにウィジェットの名前を入力して検索することができます)。
  2. プロパティー・パレットで、新規ビューの IDmainView に変更します。

分割されたタブ・バーの追加

  1. 次に、ユーザーが表示する地図のタイプを変更するために使用する、分割されたタブ・バーを作成します。
  2. ウィジェット・パレットの「Controls (コントロール)」 > 「Toolbars, ButtonBars (ツールバー、ボタン・バー)」セクションにある TabBar ウィジェットを、現在のビューの一番上にドラッグ・アンド・ドロップします
  3. テキスト・ボックスの値を「Road, Satellite, Hybrid (道路, 衛星, 同時表示)」に変更してから (図 1 を参照)、「OK」をクリックします。
    図 1. TabBar ウィジェットの作成
    TabBar ウィジェットの作成
  4. プロパティー・パレットの「Widget (ウィジェット)」セクションで、barTypesegmentedControl に変更し、fixedtop に変更します (図 2 を参照)。
    図 2. TabBar のプロパティー
    TabBar のプロパティー
  5. TabBar の最初のボタン (「Road (道路)」というラベルが付いたボタン) を選択します。プロパティー・パレットで、IDroadButton に変更し、icon1 属性と icon2 属性のアイコン文字列を削除します (図 3 を参照)。
    図 3. TabBarButton のプロパティー
    TabBarButton のプロパティー
  6. TabBar の 2 番目のボタン (「Satellite (衛星)」というラベルが付いたボタン) を選択します。プロパティー・パレットで、IDsatelliteButton に変更し、icon1 属性と icon2 属性のアイコン文字列を削除します。
  7. TabBar の 3 番目のボタン (「Hybrid (同時表示)」というラベルが付いたボタン) を選択します。プロパティー・パレットで、IDhybridButton に変更し、icon1 属性と icon2 属性のアイコン文字列を削除します。

以上のステップが完了すると、タブ・バーは図 4 に示すスクリーン・ショットのような表示になります。

図 4. 完成した TabBar
完成した TabBar のスクリーン・ショット

地図ディスプレイの作成

今度は、GPS ロケーターの地図のプレースホルダー・コンポーネントをセットアップします。最終的に、この地図にはアプリのユーザーの現在地を表示します。

  1. ウィジェット・パレットの「Containers (コンテナー)」 > 「Dojo」セクションにある RoundRect ウィジェットを、現在のビューの TabBar の直下にドラッグ・アンド・ドロップします
  2. ウィジェット・パレットの「HTML」セクションを開きます。ここにはいくつかのサブセクションが含まれていて、それらのセクションに、Maqetta がデザイナーのために多数の HTML5 要素を用意しています (図 5 を参照)。
    図 5. HTML ウィジェット
    Maqetta のウィジェット・パレットに含まれる HTML ウィジェット
  3. 「Images, Media, Iframes (画像、メディア、インラインフレーム)」サブセクションから <img> ウィジェットを RoundRect ウィジェットにドラッグ・アンド・ドロップして、長方形のウィジェットの子要素にします。
  4. 「Select a source (ソースの選択)」ダイアログが表示されたら、「File URL (ファイル URL)」フィールドに、リスト 1 に記載する URL をコピー・アンド・ペーストして「OK」をクリックします。この URL により、Google Static Maps API を使用して、米国の IBM 本社を中心とした地図が取得されます。
    リスト 1. 地図の URL (1 行の URL としてコピー・アンド・ペーストしてください)
    http://maps.googleapis.com/maps/api/staticmap?
    markers=41.108556,-73.720729&zoom=13&size=284x216
    &sensor=false&scale=2
  5. プロパティー・パレットの「Layout (レイアウト)」セクションで、width 属性を 100% に、height 属性を44% に変更します。
  6. <img>IDmapImg に変更します。

これらのステップを完了すると、地図の画像は図 6 のような表示になります。

図 6. 地図の画像
地図の画像のスクリーン・ショット

緯度と経度の追加

地図に反映されている現在地の緯度と経度を表示するためのウィジェットも追加する必要があります。

  1. ウィジェット・パレットの「Lists (リスト)」セクションにある RoundRectList を、ビューの RoundRect ウィジェットの下にドラッグ・アンド・ドロップします。1 行目に「Latitude (緯度)」と入力し、2 行目に「Longitude (経度)」と入力してから (図 7 を参照)、「OK」をクリックします。
    図 7. RoundRectList
    緯度と経度を表示するための RoundRectList
  2. 最初のリスト項目 (「Latitude (緯度)」というラベルが付いた項目) を選択します。プロパティー・パレットの「Widget (ウィジェット)」セクションで、IDlatitudeListItem に変更し、rightText を「41.108556」(先ほど入力した URL に含まれていた、地図の画像の緯度の値) に変更します。この作業を完了すると、リスト項目は図 8 のような表示になります。
    図 8. 緯度のリスト項目
    緯度を表示するリスト項目
  3. 今度は 2 番目のリスト項目 (「Longitude (経度)」というラベルが付いた項目) を選択します。項目の IDlongitudeListItem に変更し、rightText を「73.720729」(地図の画像の URL に含まれていた経度) に変更します。

位置の更新

最後に、ボタンを追加してビューを完成させます。ユーザーはこのボタンを使用して、地図上の自分の位置を更新します。

  1. ウィジェット・パレットの「Containers (コンテナー)」 > 「Dojo」セクションにある RoundRect を、ビューの RoundRectList の下にドラッグ・アンド・ドロップします
  2. その RoundRect 上に、ウィジェット・パレットの「Controls (コントロール)」 > 「Buttons (ボタン)」セクションにある Button をドラッグ・アンド・ドロップします テキスト・ボックスに「Update Location (位置情報更新)」と入力してから (図 9 を参照)、「OK」をクリックします。
    図 9. 位置情報更新ボタンの追加
    位置情報を更新するための新規ボタンの作成
  3. プロパティー・パレットで、新規ボタンの IDupdateLocationButton に変更します。

プロトタイプのプレビュー表示

ここまでで、一切コーディングをすることなく見事なモックアップができあがりました。ライブ・プレビューを実行して、作成したモックアップを確認してください。第 1 回と第 2 回で説明したように、Maqetta によるプロトタイプのライブ・プレビューを実行するには、Maqetta ツールバーで「Preview in Browser (ブラウザーでプレビュー)」アイコンをクリックします。GPS ロケーターでライブ・プレビューを実行すると、図 10 のスクリーン・ショットに示すような内容の新しいブラウザー・タブが表示されます。

図 10. GPS ロケーター・アプリのライブ・プレビュー
GPS ロケーターのプロトタイプのスクリーン・ショット

このサンプル・プロトタイプと同じようになっていれば、少なくとも潜在的ユーザーからフィードバックを受けるには十分です。ただし、この UI の操作には以下の問題があることに注意してください。

  • 初期状態の位置 (地図上の位置情報) がハード・コーディングされていて、ユーザーの実際の位置とはまったく関係ないものになっています。
  • 「Road (道路)」「Satellite (衛星)」「Hybrid (同時表示)」のどのボタンをクリックしても、地図のタイプは変更されません。
  • 「Update Location (位置情報更新)」ボタンをクリックしても緯度と経度のリスト項目は変更されず、地図に表示される座標も変更されません。
  • 端末のシルエットの向きを変えると、地図が歪んで表示されます。これは、Google に送信される URL にサイズがハード・コーディングされている一方、<img> 要素のサイズは端末の向きに応じて変更されるためです。

これらの制約を修正して GPS ロケーターのプロトタイプの対話性を改善するために、これから連載の第 2 回で行ったように、カスタム JavaScript コードを追加します。


JavaScript によるアプリの機能強化

UI の対話性を強化するためのカスタム JavaScript コードを、Maqetta によるプロトタイプの app.js ファイルに追加する作業を (おそらく第 2 回で) 経験していれば、その経験で得た知識の大半をこのセクションのステップで確認することができます。このセクションでは、app.js ファイルに個々の JavaScript コード・スニペットをコピー・アンド・ペーストしながら作業を進めます。これらのコード・スニペットによってアプリに追加される機能強化の多くはテストして確認できるため、作業を進めながら適宜、アプリの変更をプレビュー表示するように促します。手っ取り早い方法を選ぶ場合には、app.js の最終版をダウンロードして、Maqetta ワークスペース内のファイルと置き換えるだけでも構いません。

必要なモジュール

第 2 回と同じく、必要となる Dojo モジュールを指定することから始めます。これらのモジュールを指定するには、app.jsリスト 2 に記載するコードで置き換えてください (app.js を開くには、「Files (ファイル)」パレットでこのファイルをダブルクリックします)。

リスト 2. Dojo モジュールの指定
/*
 * This file is provided for custom JavaScript logic that your HTML files might need.
 * Maqetta includes this JavaScript file by default within HTML pages authored in 
 * Maqetta.
 */
require(["dojo/ready", 
        "dojo/dom", 
        "dojo/dom-style", 
        "dijit/registry", 
        "dojo/on", 
        "dojo/aspect"], 
function(ready, dom, domStyle, registry, on, aspect){
     ready(function(){
        // logic that requires that Dojo is fully initialized should go here

     });
});

上記のコードによって、以下のモジュールがロードされます。

ウィジェットの参照

次に、コード内で操作するすべてのウィジェットへの参照を取得する必要があります。リスト 3 に示されているように、Dojo ウィジェットを参照するには registry.byId を使用し、DOM 要素 (地図を格納する <img> 要素) を参照するには dom.byId を使用します。また、if ブロックを挿入して、すべてのウィジェットが見つかることを確認します。見つからないウィジェットがある場合には、問題を発見して修正しやすくするために、アラート・メッセージを表示します。

リスト 3. ウィジェットの参照
        /* *******************************************
         * Get a reference to all the widgets and DOM
         * elements we need,
         *********************************************/
        var mainView = registry.byId("mainView");
        var roadButton = registry.byId("roadButton");
        var satelliteButton = registry.byId("satelliteButton");
        var hybridButton = registry.byId("hybridButton");
        var updateLocationButton = registry.byId("updateLocationButton"); 
        var latitudeListItem = registry.byId("latitudeListItem");
        var longitudeListItem = registry.byId("longitudeListItem");
        var mapImg = dom.byId("mapImg");
       
        // Make sure we found all of the widgets
        if (!mainView ||
            !roadButton || 
            !satelliteButton || 
            !hybridButton || 
            !updateLocationButton || 
            !latitudeListItem || 
            !longitudeListItem || 
            !mapImg) {
            
            // Trace out an error to make it easier to figure out
            // which widget(s) could not be found
            alert("could not find at least one of the widgets:\n" + 
                "\t mainView = " +  mainView + ",\n" + 
                "\t roadButton = " +  roadButton + ",\n" + 
                "\t satelliteButton = " +  satelliteButton + ",\n" +
                "\t hybridButton = " +  hybridButton + ",\n" +
                "\t updateLocationButton = " +  updateLocationButton + ",\n" +
                "\t latitudeListItem = " +  latitudeListItem + ",\n" +
                "\t longitudeListItem = " +  longitudeListItem + ",\n" +
                "\t mapImg = " +  mapImg);
                
            // return, so don't run any other JavaScript
            return;
        }

このコードは、app.js ファイルの ready 関数のすぐ内側にコピー・アンド・ペーストすることができます。その後、ファイルを保存してアプリをプレビュー表示し、すべてのウィジェットが見つかることを確認します。

地図データのプレースホルダーの追加

続いてリスト 4 で、mapData という名前の変数を定義します。この変数は、URL (地図を取得するときに使用) を作成するために必要な地図データのプレースホルダーとなります。最初はこのプレーホルダーにデフォルト・データを取り込みますが、ユーザーがアプリを操作するときには、デフォルト・データを変更し、プレースホルダーを使用してページ上にウィジェットを取り込むことになります。お気付きかもしれませんが、latitudelongitudeundefined に設定されています。これは、初期状態でのユーザーの位置がまだ不明であるためです。とりあえず、このままのコードを app.js ファイルに追加してください。注意する点として、プレビュー表示ではプロトタイプの動作に変化はありません。

リスト 4. 地図データ
        /* ****************************************************
         * Initialize our placeholder for all of the map data
         * we want to pass to Google.
         ******************************************************/
        var mapData = {
            latitude: undefined,
            longitude: undefined,
            zoom: 13,
            width: 284, 
            height: 216, 
            sensor: false,
            scale: 2,
            mapType: "roadmap"
        }

地図 URL の作成

次に、getMapUrl という名前の関数を定義します。これは、Google Static Maps API を使用して URL を作成する関数です (リスト 5 を参照)。getMapUrl 関数は、特定の URL の必須パラメーターを入力するために mapData を使用します。この関数は、URL を作成する前に、ユーザーの緯度と経度が設定されているかどうかを調べます。設定されていない場合は、位置座標をデフォルトで 0, 0 に設定し (ズーム・レベルは 1)、ズームアウトした世界地図を取得するための URL を作成します。この設定により、ディスプレイにはユーザーの実際の位置がまだ認識されていないことが示されます。

リスト 5. 地図の URL の作成
        /* ****************************************************
         * Function to build the Google url for the map we
         * want to retrieve. It fills in the url parameters
         * based on data in our "mapData" variable.
         ******************************************************/
        var getMapUrl = function() {
            // If we don't have a valid latitude/longitude, set up
            // parms to get a world map centered at 0, 0 with zoom
            // level of 1.
            var latitude = mapData.latitude ? mapData.latitude : 0;
            var longitude = mapData.longitude ? mapData.longitude : 0;
            var zoom = mapData.latitude ? mapData.zoom : 1;

            // Build the url
            var url = 
                "http://maps.googleapis.com/maps/api/staticmap?" + 
                "markers=" + latitude + "," + longitude + "&" +
                "zoom=" + zoom + "&" +
                "size=" + mapData.width + "x" + mapData.height + "&" + 
                "sensor=" + mapData.sensor + "&" +
                "scale=" + mapData.scale + "&" +
                "maptype=" + mapData.mapType;  

            return url;
        };

まだこの関数を呼び出していないので、app.js にこの関数を追加しても、プロトタイプの動作に変化はありません。

ウィジェットの更新

ここで、updateWidgets という名前の関数を組み込みます (リスト 6 を参照)。この関数を呼び出すと、ページ上のウィジェットのコンテンツが最新の内容に更新されます。この関数は、最初に getMapUrl を呼び出し、その結果の URL を mapImgsrc に設定します。次に、mapData の緯度と経度の値で latitudeListItemlongitudeListItem を更新します。緯度と経度がまだ設定されていなければ、それぞれのリスト項目にはプレースホルダー (「--」) が表示されます。

リスト 6. ウィジェットを更新する関数
        /* ****************************************************
         * Function to updateWidgets on the page based on the
         * current mapData.
         ******************************************************/
        var updateWidgets = function() {
            //Get the map URL and update the image
            var url = getMapUrl();
            mapImg.src = url;

            //Update the latitude on the display
            var latitudeString = 
                    mapData.latitude ? mapData.latitude.toFixed(6) : "--";
            latitudeListItem.set("rightText", latitudeString);

            //Update the longitude on the display
            var longitudeString = 
                    mapData.longitude ? mapData.longitude.toFixed(6) : "--";
            longitudeListItem.set("rightText", longitudeString);
        };

上記のコード・スニペットを追加して app.js を更新します。ただし、この場合もプレビューの動作に変化はありません。

地図のタイプのボタン・ハンドラー

現時点でこのプロトタイプに残っている制約の 1 つは、「Road (道路)」「Satellite (衛星)」「Hybrid (同時表示)」のどのボタンをクリックしても、何の効果もないことです。この問題は、プロトタイプの JavaScript に追加した変更により、簡単に修正できるようになっています。リスト 7 では、3 つのボタンのいずれかがクリックされると呼び出される関数を登録します。続いて各ハンドラーで、mapDatamapType を適切な値に設定します。そして最後に、前のセクションで説明した updateWidgets 関数を呼び出します。

リスト 7. ボタン・ハンドラー
        /* ****************************************************
         * Handle buttons in segmented tab control
         ******************************************************/
        // Change the mapType and update widgets when roadButton is clicked
        on(roadButton, "click", function() {
            mapData.mapType = "roadmap";
            updateWidgets();
        });

        // Change the mapType and update widgets when satelliteButton is clicked
        on(satelliteButton, "click", function() {
            mapData.mapType = "satellite";
            updateWidgets();
        });

        // Change the mapType and update widgets when hybridButton is clicked
        on(hybridButton, "click", function() {
            mapData.mapType = "hybrid";
            updateWidgets();
        });

リスト 7 のコードで app.js を更新すると、今度はプロトタイプの動作に明らかな変化が現われるはずです。初期ディスプレイには、同じく米国の IBM 本社の地図が表示されますが (これについては、この後すぐに修正します)。3 つのボタンのどれをクリックしたとしても、クリックされたボタンの mapType を使用して新しい地図の URL が作成されます。ユーザーの現在地の緯度と経度はまだ設定していないため、URL はズームアウトされた世界地図を自動的に取得します。一例として、図 11「Satellite (衛星)」ボタンをクリックした場合の世界地図を示します。「latitude (緯度)」「longitude (経度)」のリスト項目にも、プレースホルダー (「--」) が取り込まれていることに注目してください。

図 11. 地図のタイプの変更
3 つのビューに対応する地図のタイプの変更

画像のサイズの変更

元のプロトタイプには、(例えば、端末のタイプや向きが変更されたことによって) mapImg のサイズが変更されると、地図の画像が歪んでしまうという制約もあります。これは、地図を取得するために使用する URL には、画像の高さと幅をピクセル単位で指定する必要があるからです。当然ながら、すべての端末とその向きに対応する画像の高さと幅の値がわかるわけではありません。その場合、どのようにしてこの問題を修正すればよいのでしょうか?

リスト 8 に、1 つのソリューションを示します。このソリューションでは aspect.after を使用することにより、mainViewresize 関数が呼び出された後に、ある関数が実行されるようにします。その関数の中で、domStyle.get を使用して mapImg の幅と高さの計算結果を取得し、これらの更新後の値を mapData に戻します。その後、updateWidgets を呼び出すことで、最終的に新しい URL が作成されて mapImg に設定されるという仕組みです。

リスト 8. サイズ変更イベントの処理
        /* ****************************************************
         * Let's monitor changes in the dimensions of our 
         * mainView (such that might occur during a change in 
         * orientation). This will allow us to get the new 
         * dimensions of our mapImg and allow us to make a 
         * new request for the right sized map.
         ******************************************************/
        aspect.after(mainView, "resize", function() {
            // Update map data based on actual width/height of mapImg
            mapData.width = Math.round(domStyle.get(mapImg, "width")); 
            mapData.height = Math.round(domStyle.get(mapImg, "height"));

            // mapData has been changed, so update the widgets
            updateWidgets();
        });

ここで app.js を更新して、アプリをプレビュー表示してください。前もって初期サイズの変更が行われているため、直ちに updateWidgets が呼び出されて、すぐに世界地図が表示されます。端末の向きを変えると、地図の画像が適切なサイズでリロードされることから、画像に歪みはなくなっています。ただし、向きを変更した後は、スクロールしないと「Update (更新)」ボタンが表示されません。この問題は、サイズ変更ハンドラーを改良して、スクロールしなくてもすべてが画面に収まるように mapImg の高さを変更することで修正できます。

図 12. よりシームレスな向きの変更
リロードされて歪みなく表示されている地図の画像

以上で、カスタム JavaScript コードを使用してプロトタイプを更新し、主要な機能のいくつかでユーザー入力に対する応答がもっと良くなるようにしました。ここまでのところで行ったすべての作業は、連載の第 1 回と第 2 回で学んだ内容を反映したものです。次のセクションでは、PhoneGap API を使えるようにするための新しい機能の導入に取り掛かります。


PhoneGap と Maqetta

GPS ロケーターの重要な機能は、地図上に表示される場所を、ユーザーの実際の位置情報に基づいて更新できることです。このプロトタイプは最終的に、PhoneGap を使用してビルドされたネイティブ・モバイル・アプリに変身させることになります。アプリが端末でネイティブに実行されていれば、PhoneGap のすべての API にアクセスすることができます。これらの API によって、共通 JavaScript 層を介してモバイル端末のネイティブ・サービス (位置情報、加速度計、カメラなど) にアクセスできるようになります。具体的に言うと、私たちが使用することになるのは、PhoneGap の Geolocation API です。この API は W3C Geolocation API 仕様に準拠しており、Maqetta でサポートされているデスクトップ・ブラウザー (Chrome、Firefox、Safari) はすべて、この仕様を実装しています。したがって、コーディングするときに、PhoneGap が存在しないとしても Maqetta プレビューアーでユーザーの実際の位置情報にアクセスできるというわけです。

この背景情報を念頭に、リスト 9 に記載する updateCurrentPosition 関数について見ていきましょう。最初に行う処理は、「Update Location (位置情報更新)」ボタンを無効にすることです。その理由は、GPS を利用して端末の位置情報を取得するには時間がかかる場合があり、その間にユーザーがボタンを何回もクリックすることがないようにするためです。次に、Geolocation API から navigator.geolocation.getCurrentPosition を呼び出します。この関数は非同期で動作することから、位置情報が確定すると呼び出される関数を渡す必要があります。この例で渡す関数は、onGetPositionSuccess です (さらに、エラーが発生した場合に呼び出される onGetPositionError も渡しています)。

onGetPositionSuccess が呼び出されるときには、ユーザーの位置情報に関するあらゆる情報を保有する Position オブジェクトが渡されます。このオブジェクトには、緯度と経度の他に、高度、方位、速度などの情報も格納されます。ここでは単純に、mapData に含まれる latitude 変数と longitude 変数を更新してから、updateWidgets を呼び出してディスプレイを最新の表示に更新します。また、ユーザーが別の要求を行っても安全な状態になっているため、「Update Location (位置情報更新)」ボタンを再び有効にします。

updateCurrentPosition を呼び出すコードは (まだ) 用意していないので、以下のコードで app.js を更新しても、アプリのプレビューの動作に変化は現われません。

リスト 9. 地図が示す場所の情報の取得
        /* ****************************************************
         * Callback function when GPS successfully acquired from
         * PhoneGap API (specified in "updateCurrentPosition"
         * function below). It accepts a `Position` object, which 
         * contains the current GPS coordinates/
         ******************************************************/
        var onGetPositionSuccess = function(position) {
            mapData.latitude = position.coords.latitude;
            mapData.longitude = position.coords.longitude;

            // mapData has been changed, so update the widgets
            updateWidgets();

            // Re-enable updateLocationButton
            updateLocationButton.set("disabled", false);
        };

        /* ****************************************************
         * Callback function when GPS acquisition fails using
         * PhoneGap API (specified in "updateCurrentPosition"
         * function below). It accepts a PositionError object
         * containing information on the failure.
         ******************************************************/
        var onGetPositionError = function(error) {
            //Show an alert with the error
            alert('geolocation failure! code: ' + error.code    + '\n' +
                   'message: ' + error.message + '\n');

            // Re-enable updateLocationButton
            updateLocationButton.set("disabled", false);
        }

        /* ****************************************************
         * Function used to get the new GPS position based on 
         * the environment we're running in (PhoneGap or not).
         * Widgets will be updated one the GPS position is 
         * acquired.
         ******************************************************/
        var updateCurrentPosition = function() {
            if(navigator.geolocation && navigator.geolocation.getCurrentPosition){
                // Disable update location button while we're getting location
                updateLocationButton.set("disabled", true);

                // Geolocation services are available so request the 
                // position. The geolocation API is asynchronous, so 
                // we have to rely on a callback function.
                navigator.geolocation.getCurrentPosition(
                    onGetPositionSuccess, //function to call when GPS location acquired
                    onGetPositionError, //function to call if location cannot be acquired
                    { enableHighAccuracy: true }); //added for Android simulator quirk
            } else {
                // We don't have geolocation services, so show an alert
                alert("Geolocation services are not available!");
            }
        };

位置情報更新ボタン・ハンドラー

これから、「Update Location (位置情報更新)」ボタンのクリックに比較的簡単に応答するためのセットアップを行います。リスト 10 で登録するハンドラーは、前のセクションの updateCurrentPosition 関数を呼び出すだけのものです。

リスト 10. 位置情報更新ボタンの処理
        /* ****************************************************
         * Initiate update of the current position when 
         * updateLocationButton is clicked
         ******************************************************/
        on(updateLocationButton, "click", function() {
            updateCurrentPosition();
        });

この時点で、app.js を更新して、アプリをプレビュー表示することができます。今回は、「Update Location (位置情報更新)」ボタンをクリックするとボタンがグレイ・アウトされ、ブラウザーがユーザーに対し、アプリに位置情報へのアクセスを許可するかどうかを尋ねるプロンプトを出します。

図 13. 位置情報更新に対するブラウザーのプロンプト
位置情報更新に対するブラウザーのプロンプトを示すスクリーン・ショット

プロンプトに対し、ユーザーが位置情報を共有することを選択すると、onGetPositionSuccess コールバック関数の非同期呼び出しが行われ、取得された位置情報でディスプレイ上の情報が更新されます (図 14 を参照)。さらに、「Update Location (位置情報更新)」ボタンが再び有効になります。

図 14. Maqetta によるプレビューでの更新された位置情報
更新された位置情報を表示する、Maqetta によるプレビュー

端末の初期化

プロトタイプの機能の大半は実装しましたが、まだ重要な機能が 1 つ欠けています。それは、ユーザーが「Update Location (位置情報更新)」ボタンを押さなくても、ユーザーの位置を初期化できるようにすることです。ユーザーの現在地を取得するには、PhoneGap の API を呼び出せるようにする必要があります。ただし、PhoneGap の API を安全に呼び出すには、端末が「レディー」状態であることを知る必要があります。私たちが目標としているのは、このアプリをモバイル端末でネイティブに実行できるようにすることですが、デザインおよびプロトタイプの作成作業を容易にするために、Maqetta のプレビューアーでも引き続きアプリを実行できるようにしたいと思います。

Maqetta のプレビューアーで目にしたように、ブラウザー環境はデフォルトでレディー状態になっているため、Geolocation API をすぐに呼び出すことができます。ただし、PhoneGap 環境でアプリを実行する場合には、端末がレディー状態であることを合図する特殊なイベントをリッスンする必要があります。そこで、このセクションの残りでは、以下の動作を可能にする JavaScript コードを作成することに焦点を絞って取り組みます。

  1. PhoneGap が存在するかどうかをチェックする
  2. その確認結果を使用して、端末がレディー状態であるかどうかをチェックする
  3. 端末がレディー状態になったら、ユーザーの位置を初期化する

端末のレディー状態と初期化

まずは、初期化を容易にするための 2 つの関数を定義します (リスト 11 を参照)。1 つ目の beforeDeviceReady 関数は、ウィジェットをセットアップして、「Update Location (位置情報更新)」ボタンを無効にします。この関数は、端末がレディー状態になる前に、最初のステップとして呼び出します。2 つ目の onDeviceReady 関数を呼び出すのは、端末がレディー状態であると判断した直後です。onDeviceReady 関数は updateCurrentPosition を呼び出して、ユーザーに代わって自動的に位置情報を取得します。この 2 つの関数を app.js に追加してください。ただし、プレビュー表示に変化はありません。

リスト 11. 初期化関数
        /* ****************************************************
         * Function to do some initialization prior to the device 
         * being ready.
         ******************************************************/
        var beforeDeviceReady = function() {
            // Update widgets with the default values
            updateWidgets();

            // updateLocationButton disabled until device ready
            updateLocationButton.set("disabled", true);
        }

        /* ****************************************************
         * Function to be called when the device is ready and
         * we can safely try to get location, etc.
         ******************************************************/
        var onDeviceReady = function() {
            // Get the initial position
            updateCurrentPosition();
        }

次に定義する isPhoneGap 関数は、現在の環境が PhoneGap 環境であるかどうかをテストするのに役立ちます (リスト 12 を参照)。どの環境が使用されているのかがわかれば、レディー状態を判断するのに最善の方法を決定することができます。あいにく、環境をチェックする最善の方法については意見が分かれていて、絶対に確実な手法となると、かなり複雑になってきますが、このプロトタイプの場合には、以下の実装で十分有効です。以下の関数を app.js に追加してください。ただし、次のスニペットを追加するまでは、プレビュー表示に変化はありません。

リスト 12. PhoneGap 環境であるかどうかのチェック
        /* ****************************************************
         * Function used to determine if we're in a PhoneGap
         * environment or not. Unfortunately, there's not
         * not a consensus on the best way for doing this 
         * (e.g., see this discussion at StackOverflow: 
         * http://bit.ly/Wvmmcw ). And, our situation is 
         * is complicated by our desire to run
         * in Ripple on the desktop. So, I think this code
         * is a reasonable compromise for a prototype.
         * 
         ******************************************************/
        var isPhoneGap = function() {
            var result = 
              // Check for PhoneGap/Cordova works in Ripple, but not 
              // reliable until deviceready
              window.PhoneGap || 
              window.Cordova || 
              // check for browser is more reliable, but will mean if go to 
              // preview URL from mobile browser, this test will pass and it
              // will think you want to use PhoneGap.
              navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry)/);

              return result;
        }

リスト 13 では、上記のリストおよびその前のリストに記載した関数を使用しています。最初に、初期化ステップとして beforeDeviceReady を呼び出します。次に、PhoneGap を使用中の場合には、PhoneGap の deviceready イベントのリスナーを登録します。このイベントが発生するということは、PhoneGap の API の呼び出しを安全に開始できるということなので、このイベントが発生すると onDeviceReady 関数が呼び出されます。現在の環境が PhoneGap 環境でない場合 (例えば、Maqetta プレビューアーを使用中の場合)、端末はデフォルトでレディー状態となっているため、すぐに onDeviceReady を呼び出すことができます。

リスト 13. ページの初期化
        /* ****************************************************
         * Bootstrapping -- call beforeDeviceReady and then 
         * cause onDeviceReady to be called depending on the 
         * environment we're in.
         ******************************************************/
        beforeDeviceReady();
        if (isPhoneGap()) {
            // We're running on with PhoneGap, so register for deviceready. 
            document.addEventListener("deviceready", onDeviceReady, false);
        } else {
            // We're in a desktop browser, so our device is automatically "ready"
            onDeviceReady(); 
        }

app.jsリスト 13 のコードで更新した後は、アプリのプレビュー表示に現在の位置が表示されるようになります。読者の皆さんは、PhoneGap への分岐にしても、「Update Location (位置情報更新)」機能にしても、どのようにテストできるのか疑問に思っていることでしょう。次のセクションで、Ripple Emulator がこの両方の疑問に答えます。


Ripple Emulator

Ripple Emulator (この記事を執筆している時点ではベータ版) は、PhoneGap の API のサブセットをエミュレートするブラウザー環境を提供する Google Chrome の拡張機能です。これから、Ripple Emulator を使用して、Geolocation API の呼び出しをテストするとともに、アプリで deviceready イベントを使用するテストを行います。

以下の手順に従って、Ripple Emulator をセットアップします。

  1. Google Chrome を使用して http://emulate.phonegap.com/ にアクセスします。
  2. 今まで一度も Ripple を使用したことがない場合は、Ripple Emulator をインストールすることをお勧めします (図 14 を参照)。インストールを開始するには、「Get Ripple Emulator (Ripple Emulator を入手)」ボタンをクリックします。
    図 15. Ripple Emulator のインストール
    Google Chrome の Ripple Emulator インストール・ウィンドウ
  3. Chrome ウェブストアが表示されるので、そこで「Add to Chrome (CHROME に追加)」ボタンをクリックします。
  4. http://emulate.phonegap.com/ をリロードすると、エミュレート対象の URL を入力するためのフォームが表示されます (図 16 を参照)。
    図 16. インストール済みの Ripple (URL を入力)
    エミュレート対象の URL を入力するオンライン・フォーム

GPS ロケーターのテスト

  1. Ripple Emulator が起動されたので、早速アプリのテストを開始します。
  2. GPS ロケーターの URL を入力して、Return キーを押します。URL を入手するには、Maqetta プレビューの「Previewing (プレビュー中)」ラベルの隣に示されているリンクをコピー・アンド・ペーストします。以下のような URL になっているはずですが、使用しているユーザー ID によって異なります。http://app.maqetta.org/maqetta/user/XYZ/ws/workspace/gpsLocator/index.html
  3. Ripple が起動されると、シミュレートされたモバイル端末で GPS ロケーター・アプリが実行され、カナダのオンタリオ州ウォータールーを中心とした地図が表示されます (図 17 を参照)。ウォータールーは Ripple Emulator がデフォルトで設定している場所です。したがって、この地図が表示されれば、deviceready が正常に起動し、updateCurrentPosition 内のコードが正常に PhoneGap の navigator.geolocation.getCurrentPosition 関数を呼び出したことになります。
    図 17. Ripple での GPS ロケーターの初の実行
    シミュレートされたモバイル端末で実行中の GPS ロケーター・アプリを示すスクリーン・ショット
  4. プレビュー表示に使用する端末を変更するには、Ripple の左上隅にある「Devices (端末)」を開きます。デフォルトの設定は、「Generic – WVGA (480x800) (汎用 – WVGA (480x800))」になっているので、選択項目を「iPhone 4/4S」に変更します (図 18 を参照)。
    図 18. Ripple の端末設定の変更
    Ripple プレビューの端末設定の変更
  5. Ripple にレンダリングされた端末のサイズは、Maqetta によるプレビューでのサイズとまったく同じになっているはずです (図 19 を参照)。
    図 19. Ripple で iPhone 用にレンダリングされた GPS ロケーター
    iPhone にレンダリングされる場合の GPS ロケーター・アプリ
  6. Ripple の右側にある「Geo Location (ジオ・ロケーション)」セクションを開きます。図 20 に示されているように、PhoneGap の API に対して提供されている、端末の位置情報に関する詳細情報を確認することができます。プロトタイプの地図の中心が、Ripple の「Geo Location (ジオ・ロケーション)」タブの地図と同じ位置に置かれていることに注目してください。アプリが緯度と経度としてレポートしている値も一致します。
    図 20. Ripple の位置情報タブ
    Ripple での端末の位置情報の確認
  7. 「Geo Location (ジオ・ロケーション)」タブの設定をいろいろと試してみてください。地図を新しい位置にスライドさせたり、緯度と経度に明示的な値を入力したりすることができます。更新した後、アプリの「Update Location (位置情報更新)」ボタンをクリックして、アプリの動作を確認します。図 21 では、米国ミネソタ州ロチェスターの IBM 施設がある場所 (緯度 = 44.058633、経度 = -92.507393) に地図の位置が更新されています。
    図 21. Ripple Emulator から更新された位置情報
    更新された端末の位置情報を示すスクリーン・ショット

PhoneGap へのアプリのエクスポート

アプリが動作していること (そしてアプリが PhoneGap の API を使用していること) を確認できたので、次は Adobe PhoneGap Build サービスでアプリをビルドする作業に移ります。最初のステップでは Maqetta からプロジェクトをエクスポートしますが、その前に、以下のことを確認してください (これらのステップは、今後 Maqetta プロジェクトを PhoneGap にエクスポートする際のチェックリストとして記載しています)。

  1. メインの HTML ファイルの名前が index.html になっていること、そしてこのファイルがプロジェクトのルート・ディレクトリーにあることを確認します。PhoneGap でビルドするあらゆる Maqetta プロジェクトでは、このファイル名が必要条件となります。
  2. (GPS ロケーターでの場合と同じく) PhoneGap の API を使用している場合は、index.html 内で phonegap.js を読み込む必要があります。これにより、PhoneGap の API に必要な JavaScript が組み込まれます。まず、HTML ソースを表示して (Maqetta ツールバーの「Source (ソース)」ボタンを使用することを思い出してください)、app.js を読み込む行 (26 行目あたりです) の直前にリスト 14 に記載する行を追加します。その後、HTML ファイルを保存します。
    リスト 14. index.html 内での phonegap.js の読み込み
    <script stype="text/javascript" src="phonegap.js"></script>
  3. phonegap.js を読み込んではいるものの、PhoneGap の JavaScript リソースは Maqetta プロジェクトの中に含まれるわけではありません (その必要もありません)。これらのリソースは、PhoneGap でビルドした後のネイティブ・アプリにパッケージ化されたリソース・セットとして組み込まれます。
  4. index.html を保存してから、Maqetta ツールバーで「Design (デザイン)」ボタンをクリックしてデザイン・モードに戻ってください。

Maqetta からの project zip のエクスポート

次は、Maqetta からプロジェクトを zip ファイルとしてダウンロードします。この zip ファイルを、PhoneGap のビルド・サービスに提供することになります。

  1. Maqetta の「Files (ファイル)」パレットで、ツールバーにある「Download Entire Workspace (ワークスペース全体のダウンロード)」アイコンをクリックします。これにより、「Download (ダウンロード)」ダイアログが呼び出されます (図 22 を参照)。zip ファイル名は、プロジェクト名に基づいてデフォルト設定されます。
  2. gridxclipartshapes ライブラリーは使用しないため、これらのライブラリーのチェック・ボックスをクリアします。これにより、zip ファイルのサイズが小さくなります。
    図 22. Maqetta からのプロジェクトのダウンロード
    Maqetta の「Download (ダウンロード)」ダイアログを示すスクリーン・ショット
  3. 「Download (ダウンロード)」ボタンをクリックします。これで、プロジェクトのリソースが含まれる zip ファイルがファイルシステムにダウンロードされます。

PhoneGap によるプロトタイプのビルド

いよいよ、プロトタイプをネイティブ・アプリとしてビルドするプロセスを開始します。ビルドには、Adobe PhoneGap Build サービスを使用します。まず、https://build.phonegap.com/ にアクセスしてください。ここでは、PhoneGap に初めてサインインするという前提となっています。

  1. 「Get started! (使い始める!)」ボタンをクリックします。
  2. 料金を支払わずに試してみたいだけであれば、「Completely Free (完全無料)」をクリックします。この場合、一度に 1 つのプライベート・アプリをビルド/管理することができます。
  3. Adobe ID または GitHub のクレデンシャルを使用してログインします。
  4. ログインすると、図 23 に示すような画面が表示されます。「private (プライベート)」タブが選択されていることを確認してから、「Upload a zip file (zip ファイルをアップロード)」ボタンをクリックします。
    図 23. PhoneGap によるビルド
    PhoneGap によるビルド画面のスクリーン・ショット
  5. ファイル選択ダイアログが表示されるので、このダイアログで、Maqetta からダウンロードした zip ファイル (例えば、gpsLocator.zip) を選択します。
  6. ファイルのアップロードが完了すると、図 24 のようなページが表示されます。このページで、アプリに関する情報を入力してアプリをビルドすることができます。アプリの名前には、「Maqetta Locator (Maqetta ロケーター)」といった名前を入力します。「Sample GPS locator prototyped in Maqetta (Maqetta で作成したサンプル GPS ロケーターのプロトタイプ)」などの説明を入力することもできます。私たちは明らかにプロトタイプの作成をしているため、「Enable debugging (デバッグを有効にする)」オプションにチェック・マークを付けておくのが賢明です (デバッガーを使用する方法については、この記事では説明しません)。
    図 24. PhoneGap のアプリ・パネル
    アプリをビルドするための PhoneGap の画面
  7. 「Ready to build (ビルドの準備完了)」ボタンをクリックします。すると、Adobe PhoneGap Build サービスが、さまざまなプラットフォームを対象としたネイティブ・アプリのビルド・プロセスを開始します。
  8. ビルドが完了すると、アプリのパネルに一連のボタン (端末ごとに 1 つ) が表示されます。これらのボタンを使用することで、結果をダウンロードすることができます (図 25 を参照)。赤で表示されたボタンは、その特定の端末のビルドが正常に完了しなかったことを示します。赤いボタンをクリックすると、詳細な情報を表示することができます。iOS と Blackberry に対しては、いずれもビルドが失敗することに注意してください (前者の理由は、開発者キーを提供しなかったためで、後者の理由は、ファイル数が多すぎるためです)。この 2 つの端末を対象としたアプリの更新については、この記事では説明しません。
    図 25. ビルドの完了
    複数の端末用に完了したビルドを示すスクリーン・ショット
  9. Maqetta でアプリを変更した場合は、新しい zip ファイルをダウンロードしてから PhoneGap で「Update code (コードを更新)」ボタンをクリックすることで、新しいビルドを実行することができます。

Android エミュレーター

実際の端末にアクセスすることなく PhoneGap の出力をテストする 1 つの方法は、Android SDK に含まれる Android エミュレーターを使用することです。実際に自分で試してみたい場合は、以下のステップに従って Android Virtual Device を作成し、そこにアプリをインストールしてください。

  1. システムに ADT (Android Developer Tools) バンドルをダウンロードしてインストールする手順に従います。このバンドルには、Android SDK、Android プラットフォーム・ツール、そして ADT プラグインがインストールされた Eclipse IDE が含まれています。
  2. ADT バンドルのインストールが完了したら、バンドルに付属の Eclipse IDE を起動します。
  3. Eclipse で「Window (ウィンドウ)」 > 「Android Virtual Device Manager (Android 仮想デバイス・マネージャー)」の順にメニュー・オプションを選択します。
  4. 表示されたダイアログで、新しいデバイスを作成するために「New... (新規…)」ボタンをクリックします。
  5. 「Create (作成)」ダイアログ (図 26 を参照) で、デバイスの名前 (例えば、「myVirtualDevice」) を入力し、デバイスを選択し (私は「Nexus S」を選択しました)、ターゲット・プラットフォームを Android 4.2 に設定してから「OK」をクリックします。
    図 26. 仮想デバイスの作成
    新しい仮想デバイスを作成するためのダイアログのスクリーン・ショット
  6. ダイアログが消えて、Android 仮想デバイスの表に新規デバイスが表示されるようになるはずです。このデバイスを選択して、「Start... (開始…)」ボタンをクリックします。次のダイアログでは、「Launch (起動)」をクリックします。これで、Android エミュレーターが起動されます。

アプリのデプロイ

Android エミュレーターが実行中の状態になったので、アプリをデプロイしてテストすることができます。

  1. PhoneGap のビルド・ページで、Android 用アプリをダウンロードするボタンをクリックします。これにより、MaqettaLocator-debug.apk のような名前の .apk ファイルがファイルシステムに保存されます。
  2. .apk ファイルを入手した後は、このファイルを仮想デバイスにインストールすることができます。それには、コマンドラインから Android Debug Bridge (adb) コマンドを実行します。この例の場合、以下のようなコマンドを使用します。
    <sdk>/platform-tools/adb install <path_to_apk>/MaqettaLocator-debug.apk
  3. このコマンドが正常に実行されると、コンソールに「成功」を示すメッセージが表示されます。その後は、エミュレーターにインストールされた他のすべてのアプリに並んで、アプリがアイコンとして表示されます (図 27 の「Maqetta Locator」アプリのアイコンを見てください)。
  4. アプリは、そのアイコンをダブルクリックするだけで起動します。
    図 27. PhoneGap の Android エミュレーターを起動時の画面に表示されたアプリ
    PhoneGap の Android エミュレーターを起動時の画面に表示されたアプリ

Android エミュレーターでの位置情報の設定

図 28 に示されているように、Android エミュレーターでアプリを起動すると、ズームアウトされた世界時図が表示されます。これは、エミュレーター内では地理的な位置情報を最初は利用できないためです。

図 28. Android エミュレーターに表示された、位置情報を設定する前の GPS ロケーター
位置が設定されていない GPS ロケーターのスクリーン・ショット

この状況を変更するには、Android エミュレーターに地理的な位置情報を設定して認識させる必要があります。

  1. コマンドラインから、以下のコマンドでエミュレーター・コンソールに接続します。
    telnet localhost 5554

    Windows を使用している場合、デフォルトでは、おそらく telnet が有効にされていないことに注意してください。
  2. geo コマンドを使用して、緯度と経度を設定します。例えば、アプリの起動後の画面にブルックリン・ブリッジの場所が表示されるようにする場合は、以下のコマンドを使用します。
    geo fix -73.99665 40.705921

上記の緯度と経度を設定した後は、ブルックリン・ブリッジを中心とした地図が表示されるはずです。表示されない場合は、「Update Location (位置情報更新)」ボタンをクリックする必要があります。図 29 に、位置情報が更新された後 (および「Hybrid (同時表示)」ボタンをクリックして地図のタイプを変更した後)、エミュレーターで実行中のアプリを示します。

図 29. 位置が設定された後のロケーター・アプリ
ブリックリン・ブリッジを現在地として表示しているアプリのスクリーン・ショット

以上で、GPS ロケーターがネイティブ Android アプリとして機能することを見事に検証できました!


体重管理アプリの再考

Maqetta から GPS ロケーターをエクスポートして、PhoneGap でビルドし、モバイル端末/エミュレーターにデプロイするために採ったステップは、どの Maqetta モバイル・プロトタイプにも有効です。一例として、図 30 に PhoneGap でビルドした後、Android エミュレーター内で実行している体重管理アプリのプロトタイプ (第 1 回と第 2 回で開発) を示します。

図 30. Android エミュレーターでの体重管理アプリ
Android エミュレーターで実行中の体重管理アプリのスクリーン・ショット

Maqetta の連載のまとめ

この全 3 回からなる連載では、Maqetta を使用して、2 つの異なるモバイル・アプリのプロトタイプを短時間で作成しました。そのプロセスでは、何とか多くの基礎をカバーしたので、Maqetta をかなり詳しく紹介できていたことを願います。2 つのサンプル・アプリについては、どちらもコーディングを一切せずに、それなりに妥当なプロトタイプを作成することから始め、カスタム JavaScript コードを追加してインタラクティブな機能を拡張しました。この最後の記事では、Maqetta と PhoneGap を組み合わせ、GPS ロケーター・アプリのプロトタイプをネイティブ・アプリに変換し、Android エミュレーターを使用してテストしました。

Maqetta についてさらに詳しく学ぶには、まずは「参考文献」セクションに記載してあるリンクを調べることをお勧めします。また、Tony のブログも読んでください。さらに、この記事で説明したステップバイステップの手順は、今後 Maqetta によるモバイル・アプリを開発して、PhoneGap でデプロイする際のガイドとして利用できることをお忘れなく。

謝辞

この連載記事を慎重にレビューして建設的なフィードバックを提供してくださった Maqetta チーム (Jon Ferraiolo 氏、Javier Pedemonte 氏、Adam Peller 氏、Bill Reed 氏) に深く感謝いたします。


ダウンロード

内容ファイル名サイズ
Final source of the custom appmaqetta_part3.zip5KB

参考文献

学ぶために

製品や技術を入手するために

議論するために

  • Maqetta ユーザー・グループに加わってください。Maqetta を使用してデスクトップ/モバイル用 UI を作成している他のデザイナーや開発者と情報を交換できます。
  • developerWorks コミュニティーに加わってください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者によるブログ、フォーラム、グループ、Wiki を調べることができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Mobile development, Open source, Web development
ArticleID=935516
ArticleTitle=モックアップという意味を持つ Maqetta: 第 3 回 Maqetta でデザインした UI プロトタイプを PhoneGap でデプロイする
publish-date=07042013