PhoneGapで手軽にiPhone/Androidアプリを作ろう

第3回PhoneGapを支えるAPIたちjQuery Mobileでメモ帳アプリ

前回はHello, Worldアプリケーションの作成とビルド、PhoneGap:Buildの使い方を紹介しました。今回はPhoneGapを支える各種APIの紹介と、jQuery Mobileを用いたメモ帳アプリを実際に作成してみるところまでを紹介していきたいと思います。

PhoneGap APIの紹介

それではPhoneGap APIといくつかのメソッド・オブジェクトをチェックしてみましょう。

Accelerometer(モーションセンサ)

デバイスのモーションセンサにアクセスし、端末がどの方向に動いたかの情報を取得します。対応しているおもなプラットフォームはAndroid、BlackBerry WebWorks(OS 5.0以上⁠⁠、iOSの3種です。

accelerometer.getCurrentAcceleration
X/Y/Z軸の傾きとタイムスタンプを取得します
accelerometer.watchAcceleration
指定した時間間隔におけるX/Y/Z軸の加速度とタイムスタンプを取得します
accelerometer.clearWatch
accelerometer.watchAccelerationで使用するwatchIDを指定し、加速度情報の監視を中止します

Camera(カメラ)

デバイスのデフォルトカメラアプリケーションにアクセスし、イメージデータを取得します。カメラを使って写真を撮るか、デバイスのフォトアルバムからファイルを取得します。イメージデータはBase64エンコードされた文字列か、イメージファイルが格納されているパスのURIとして取得することが可能です。対応しているおもなプラットフォームはAndroid、BlackBerry WebWorks(OS 5.0以上⁠⁠、iOSの3種です。

camera.getPicture
デバイスのデフォルトカメラアプリケーションか、アルバム内よりイメージデータを取得します。写真の撮影を行うと、カメラアプリケーションは終了して元のアプリケーションに戻ります
図1 navigator.camera.getPictureのオプション「sourceType」に"navigator.camera.PictureSourceType.PHOTOLIBRARY"を指定した場合、デバイスのフォトアルバムが開く
図1 navigator.camera.getPictureのオプション「sourceType」

Capture(マイク録音/カメラ撮影)

HTML5のCapture APIを利用してデバイスのマイクやカメラにアクセスし、録音・写真/動画の撮影を行います。対応しているおもなプラットフォームはAndroid、BlackBerry WebWorks(OS 5.0以上⁠⁠、iOSの3種です。

Capture
キャプチャオブジェクト。navigator.deviceに割り当てられ、グローバルスコープを持っています。capture.captureAudioで録音を、capture.captureImageで写真撮影を、capture.captureVideoで動画撮影を行います
ConfigurationData
デバイスがサポートしているメディアキャプチャのパラメータ一式をカプセル化します
MediaFile
メディアファイルに関するプロパティをカプセル化します
MediaFileData
メディアファイルに関するフォーマット情報をカプセル化します
図2 navigator.device.capture.captureAudio()でレコーダーアプリを起動
図2 navigator.device.capture.captureAudio()でレコーダーアプリを起動

Compass(コンパス)

デバイスが向いている方向を取得します。対応しているおもなプラットフォームはAndroid、iOSの2種です。

compass.getCurrentHeading
現在のコンパスの向きを検出します。方角は0から359.99の範囲の数値として返ります
compass.watchHeading
指定した時間間隔におけるコンパスの向きを検出します
compass.clearWatch
compass.watchHeadingで使用するwatchIDを指定し、コンパスの監視を中止します
図3 iPhone実機でコンパスの向きを取得
図3 iPhone実機でコンパスの向きを取得

Connection(回線情報)

デバイスが利用している回線情報(Ethernet、WiFi、2G、3G、4G)を取得します。対応しているおもなプラットフォームはAndroid、BlackBerry WebWorks(OS 5.0以上⁠⁠、iOSの3種です。

connection.type
デバイスのネットワーク接続の状態、接続の種類を取得します
図4 prettyPrint.jsでconnectionオブジェクトを展開。WiFi接続の場合は"wifi"と返る
図4 prettyPrint.jsでconnectionオブジェクトを展開。WiFi接続の場合

Contacts(電話帳)

デバイスの電話帳(連絡先)データベースにアクセスし、新しい連絡先や既存の連絡先情報を取得します。取り扱い可能な項目は次のとおりです。

id固有のID
displayName名称
name個人名に関するオブジェクト
nicknameニックネーム
phoneNumbers電話番号
emailsメールアドレス
addresses住所
imsIMアドレス
organizations組織名
birthday誕生日
noteメモ
photos写真
categoriesカテゴリ
urlsURL

対応しているおもなプラットフォームはAndroid、BlackBerry WebWorks(OS 5.0以上⁠⁠、iOSの3種です。プラットフォームやバージョンごとに取得できる情報が異なるので注意が必要です。

contacts.create
Contactオブジェクトを作成します。作成したContactオブジェクトはデバイスに保存されません。デバイスに保存するには、Contact.saveメソッドを使用します
contacts.find
電話帳データベースにアクセスし、Contactオブジェクトを取得します。
図5 prettyPrint.jsでcontacts.find()の返り値を展開
図5 prettyPrint.jsでcontacts.find()の返り値を展開

マルチバイトの文字列を取り扱うときは、<meta>タグで文字コードを明示しておきましょう。

Device(デバイス)

各種デバイスのハードウェアおよびソフトウェア情報を取得します。Device APIについては、第2回の記事をご参照ください。

Events(イベント)

PhoneGapがサポートするイベントハンドラです。対応しているおもなプラットフォームはAndroid、BlackBerry WebWorks(OS 5.0以上⁠⁠、iOSの3種です。一部のイベントは、Androidでのみ拾うことができます。

backbuttonAndroidの「戻るボタン」が押された際に発火します
devicereadyPhoneGapライブラリのロードが完了した際に発火します
menubuttonAndroidの「メニューボタン」が押された際に発火します
pausePhoneGapアプリケーションがバックグラウンドに移動した際に発火します
resumePhoneGapアプリケーションがバックグラウンドから復帰した際に発火します
searchbuttonAndroidの「検索ボタン」が押された際に発火します
onlinePhoneGapアプリケーションがオンライン状態(インターネットに接続された)になった際に発火します
offlinePhoneGapアプリケーションがオフライン状態(インターネットから切断された)になった際に発火します

File(ファイルシステム)

デバイスのファイルシステムに読み書きを行います。対応しているおもなプラットフォームはAndroid、BlackBerry WebWorks(OS 5.0以上⁠⁠、iOSの3種です。

FileReader
ファイルの読み込みを行うオブジェクトです。ファイルはテキスト形式またはBase64エンコードされた文字列として読み込まれます
FileWriter
ファイルの書き込みを行うオブジェクトです。ファイルポインタの位置とlengthを指定することができるので、ファイルのどの位置からも書き込みができます
FileTransfer
ファイルをサーバにPOSTアップロードする際に使用します

Geolocation(GPS)

デバイスのGPSセンサにアクセスし、緯度経度の情報を取得します。IPアドレスやRFID、WiFi、Bluetooth、MACアドレス、基地局のIDなどのソースからも現在位置を推測します。このAPIはW3C Geo location API Specificationに準拠しています。W3C Geo location APIをサポートしているデバイスは、PhoneGapの実装を使わずにビルトインの機能がそのまま利用されます。対応しているおもなプラットフォームはAndroid、BlackBerry WebWorks(OS 5.0以上⁠⁠、iOSの3種です。

geolocation.getCurrentPosition
デバイスの現在位置をPositionオブジェクトとして取得します
geolocation.watchPosition
デバイスの現在位置を監視します
geolocation.clearWatch
geolocation.watchPositionで使用するwatchIDを指定し、現在位置の監視を中止します
図6 prettyPrint.jsでgeolocation.getCurrentPosition()の返り値を展開
図6 prettyPrint.jsでgeolocation.getCurrentPosition()の返り値を展開

Media(メディア)

デバイスの音楽を再生したり、録音を行います。Media APIはW3Cの仕様要件を満たしておらず、便宜のために提供されているAPIです。将来的には最新のW3C仕様に合わせるとともに、現在のAPIは非推奨となる可能性もあります。録音といった操作はCapture APIで行った方がよいかも知れません。対応しているおもなプラットフォームはAndroid、iOSの2種です。

media.getCurrentPosition
オーディオファイル内の現在の再生位置を取得します
media.getDuration
オーディオファイルの再生時間を取得します
media.startRecord
オーディオファイルに録音を開始します
図7 サンプルプログラムを使った録音の模様。こちらはCapture APIと違いレコーダーアプリが起動しない
図7 サンプルプログラムを使った録音の模様。こちらはCapture APIと違いレコーダーアプリが起動しない

Notification(通知)

映像、音、バイブレーションを使って通知を行います。対応しているおもなプラットフォームはAndroid、BlackBerry WebWorks(OS 5.0以上⁠⁠、iOSの3種です。一部、BlackBerry(OS4.6)に対応しているものもあります。

notification.alert
アラートまたはダイアログボックスを表示します
notification.confirm
確認のダイアログボックスを表示します
notification.beep
ビープ音を鳴らします
notification.vibrate
指定した時間分バイブレーションを行います
図8 notification.alert()でアラートを表示。JavaScriptのalert()と違い、タイトルやボタンのラベルも変更可能
図8 notification.alert()でアラートを表示。JavaScriptのalert()と違い、タイトルやボタンのラベルも変更可能

Storage

デバイスのストレージにアクセスします。このAPIはW3C Web SQL DatabaseおよびW3C Web Storageに準拠しています。Geolocationと同様、W3C APIをサポートしているデバイスは、PhoneGapの実装を使わずにビルトインの機能がそのまま利用されます。対応しているおもなプラットフォームはAndroid、BlackBerry WebWorks(OS 5.0以上⁠⁠、iOSの3種です。

openDatabase
Databaseオブジェクトを作成し、SQLiteデータベースを作成します

Storage APIを使ったメモ帳アプリケーションを作成

PhoneGapのStorage APIとjQuery Mobileを用いて、簡単なメモ帳アプリケーションを作成してみましょう。今回実装するメモ帳の要件は次のとおりです。

  • メモの追加、編集、削除、全削除が行える
  • 画面数は「登録したメモを確認する一覧画面」「メモを編集する画面」の2画面
  • jQuery Mobileを利用して、index.html1ファイルで完結させる
  • メモ帳のデータはlocalStorage上に保存するものとする

第1回で紹介した手順で新しいプロジェクトを作成します。プロジェクト名は「PhoneGapMemo」としました。wwwディレクトリにjQuery Mobileの成果物一式(js、css、画像ファイル)をデプロイします。

図9 wwwディレクトリ以下に展開したファイル
図9 wwwディレクトリ以下に展開したファイル

Xcodeを開き、www/index.htmlを編集します。

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <link rel="stylesheet" href="jquery.mobile-1.0b2.min.css" />
    <script type="text/javascript" charset="utf-8" src="jquery-1.6.2.min.js"></script>
    <script type="text/javascript" charset="utf-8" src="jquery.mobile-1.0b2.min.js"></script>
    <script type="text/javascript" charset="utf-8" src="phonegap-1.0.0.js"></script>
    <script type="text/javascript" charset="utf-8">
    <!--
           
    function onBodyLoad()
    {       
        document.addEventListener("deviceready",onDeviceReady,false);
    }
    
    function onDeviceReady()
    {

        var key;

        // 起動時にlocalStorageに保存されているメモを一覧に書き出し
        for ( var i=0; i< window.localStorage.length ; i++ )
        {
            key = window.localStorage.key(i);
            $('#memoList').append('<li><a href="#edit" id="' + key + '" class="edit" /></li>');
            $('#' + key ).text( window.localStorage.getItem(key) );
        }
        $('#memoList').listview('refresh');
        
        // メモを新規に作成
        $('#new').live
        (
            'click',
            function()
            {
                var new_memo_id = 'memo_' + (window.localStorage.length + 1);
                window.localStorage.setItem(new_memo_id, '');
                $('#editMemo').attr('name', new_memo_id);
                $('#editMemo').val('');
                $('#memoList').append('<li><a href="#edit" id="' + new_memo_id + '" class="editMemo" /></li>');
                $('#memoList').listview('refresh');
            }
        );
        
        // メモを編集
        $('.edit').live
        (
            'click', 
            function()
            {
                $('#editMemo').attr('name', this.id);
                $('#editMemo').val(window.localStorage.getItem(this.id));
            }
        ); 
                
        // テキストエリアを監視し、変更がおこなわれると localStorage に保存をおこなう
        $('#editMemo').live
        (
            'change',
            function()
            {
                window.localStorage.setItem(this.name, this.value);
                $('#' + this.name ).text( this.value );
            }
        );
        
        // メモを削除
        $('#delete').live
        (
            'click',
            function()
            {
                navigator.notification.confirm
                (
                    'メモを削除します',
                    function(button)
                    {
                        if ( 1 === button )
                        {
                            $('#' + String($('#editMemo').attr('name')) ).parent().parent().remove();
                            window.localStorage.removeItem($('#editMemo').attr('name'));
                            location.href='#home';
                        }
                    },
                    'メモの削除',
                    'OK,キャンセル'
                );
            }
        );
        
        // メモを全削除
        $('#drop').live
        (
            'click',
            function()
            {
                navigator.notification.confirm
                (
                    'メモをすべて削除します',
                    function(button)
                    {
                        if ( 1 === button )
                        {
                            window.localStorage.clear();
                            $('#memoList').empty();
                        }
                    },
                    'メモの全削除',
                    'OK,キャンセル'
                );
            }
        );
        
    }
    
    -->
    </script>
  </head>
  <body onload="onBodyLoad()">
    <div id="home" data-role="page">
        <div data-role="header" data-theme="b"> 
            <h1>PhoneGap Memo</h1>
            <a id="new" href="#edit" data-role="button" data-icon="plus" class="ui-btn-right">New</a>
        </div> 
        <div data-role="content">
            <ul id="memoList" data-role="listview" data-theme="g">
            </ul>
        </div>
        <div data-role="footer" data-position="fixed" data-theme="b" class="id-bar">
            <a id="drop" href="javascript:void(0)" data-role="button" data-icon="delete">All delete</a>
        </div> 
    </div>
    
    <div id="edit" data-role="page">
        <div data-role="header" data-theme="b">
            <a id="back" href="#home" data-direction="reverse" data-role="button" data-icon="arrow-l">Back</a>
            <h1>Editing</h1> 
            <a id="delete" href="javascript:void(0)" data-direction="reverse" data-role="button" data-icon="delete">Delete</a>
        </div> 
        <div data-role="content">
            <textarea placeholder="Hello, PhoneGap!" id="editMemo" rows="8" style="height:100%;"></textarea>
        </div>
    </div>
  </body>
</html>

これをシミュレータで実行してみましょう。

図10 iPhoneシミュレータでPhoneGapMemoを起動
図10 iPhoneシミュレータでPhoneGapMemoを起動

アプリケーションを起動すると、メモの一覧画面が表示されます。起動時にまずlocalStorageにアクセスし、保存されている値をforループ文中のgetItem()ですべて取得、#memoListにappend()しています。

一覧画面右上の"New"をタップするとlocalStorageのサイズをチェックし、memo_(サイズ+1)という名前のキーに空欄の文字列をsetItem()で保存します。編集画面のテキストエリアを初期化したあと、一覧画面に行の追加処理を行い編集画面に遷移します。メモの行をタップすると、同様にテキストエリアを初期化後、編集画面に遷移します。

図11 メモの編集画面
図11 メモの編集画面

編集画面にはメモを入力するためのテキストエリアが配置されています。jQuery Mobileでテキストエリアを配置すると、エリア内に入力された文字列の長さによって高さが自動的に調整されます。テキストエリアではchangeイベントを監視しており、変更されるとlocalStorageに保存を行います。

図12 いくつかメモを登録
図12 いくつかメモを登録

編集画面右上の"Delete"をタップすると、そのメモをremoveItem()でlocalStorageから削除します。JavaScriptのconfirm()ではなく、PhoneGap APIのnotification.confirm()を用いることで、各種ラベルのカスタマイズができます。ボタン押下の返り値は数値で返ります。1番目のボタン「OK」をタップしたなら1が、2番目のボタン「キャンセル」をタップしたなら2が返ります。

一覧画面の最下部、"All Delete"をタップすると、localStorage.clear()を行い、localStorage上すべてのキーとアイテムを削除します。

図13 メモの全削除確認
図13 メモの全削除確認

Androidエミュレータでも動作を確認してみましょう。環境によってはEclipseのデフォルト文字コードがSJISになっているので、適宜UTF-8に修正してください。

図14 AndroidエミュレータでPhoneGapMemoを起動
図14 AndroidエミュレータでPhoneGapMemoを起動

Webアプリを実装する要領でデバイスのネイティブ機能にアクセスできるため、慣れてくればWebアプリと同等の開発スピードでスマートフォンアプリの開発が行えるようになります。今回はjQuery Mobileを利用しましたが、ここ数年でさまざまなスマートフォン向けJSライブラリが登場し、開発者の選択肢も広がってきています。Sencha Touch / jQTouchWink ToolkitbaseJSといったJSフレームワークを活用することで、さらなる開発効率の向上が見込めるのではないでしょうか。

「PhoneGapで手軽にiPhone/Androidアプリを作ろう」次回最終回は、カメラを使ったアプリの作成と、作成したPhoneGapアプリケーションをiPhone/iPad実機にインストールするところまでを紹介していきます。

おすすめ記事

記事・ニュース一覧