2011/04/21

JQueryMobileでらくらくアプリ開発をはじめよう(2)

前回JQueryMobileのサンプルプログラムとしてToDo管理アプリのUIを作るところまで説明しました。
今回は、JavaScript(JQuery)とHTML5のWebStorageを使って実際にToDoを入力し、保存できるところまで
つくりアプリを完成させます。

まずサンプルコードを書く前に、WebStorageについて少し説明します。

HTML5のWebStorageについて

WebStorageはHTML5から新たに搭載された規格で、
Cookieのような働きをします。ローカルストレージという端末ごとの
データ保存領域に(キー、バリュー)の組み合わせを保存できます。

しかし、Cookieと違う点としては、
・CookieはHTTPリクエストを使ってサーバに値を送信するのに対して、
 WebStorageはサーバ通信は必要とせず、ローカルで完結している。
・サイズ制限が無い
・有効期限が無い
・JavaScriptのオブジェクトをそのまま保存できる
などの便利な点があります。

詳しくは第14回HTML5とか勉強会資料:Web Storageが参考になります。

サンプルアプリの作成(データ処理編)
ここから本題のサンプルアプリの作成の話に戻ります。

前回の記事ではUIだけを
作りました。このUIだけ記述したHTMLファイルに今回はJavaScriptのコードを記述して、ToDoデータの画面間での受け渡しと登録されたToDo情報の保存の2つの機能を追加します。

機能追加した時のサンプルアプリのイメージはこんな感じです。


ローカルストレージ領域には次の2種類のデータを保存します。
・list_acountという名前で現在ToDoリストが何個あるかを記憶します。
・text(本文)、date(日付)という変数をToDoが新規登録される度に作成し、これにToDoの情報を記憶していきます。
WebStorageは単純な(キー、バリュー)のペアでしか保存できないので、text1,text2...date1,date2...という
名前で保存していくことで擬似的に配列を表現しています。 
(※ほんとはWeb SQL Storageを使った方がスマートですが、今回は説明簡略化のため、Web Storageで行います)

そして、画面遷移の際に発生する処理は以下の2つです。
・set関数
- 新規ToDo入力画面で入力されたテキストと日付をローカルストレージに保存します。
・load関数 
- ローカルストレージに保存されているテキストと日付を取り出し、リストに反映させます。

ソースコードは以下になります。javascriptの部分(<script>タグに囲まれた部分)以外は基本的に前回と同じです。

<!DOCTYPE html> 
<html lang="ja"> 
    <head>
        <meta charset="utf-8">
            <title>ToDoアプリ</title>
            <meta name="viewport" content="width=320,user-scalable=no" />
            <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.css" />
            <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.min.js"></script>
            <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.js"></script>    
            </head> 
    <body onload="load()">
        
        <div data-role="page" data-theme="b"> 
            
                <div  data-role="header"> 
                    <h1>TODOリスト</h1>
                    <a rel="external" href="add_todo.html" data-role="button" data-icon="plus" data-transition="slide" >追加</a>
                </div> 
                
                <div data-role="content">
            
                    <ul data-role="listview" id="todo_list">
                    </ul>
                    
                </div>
                        
                <div data-role="footer"> 
        
                </div>
        
                <script>
        
                function load(){
                    
                    jQuery.noConflict();
                    
                    //リストの反映
                    var text;
                    var date;
                    
                    //現在の登録件数をlocalStorageから取得
                    var list_acount = localStorage['list_acount'];

                    if(list_acount == null){
                        list_acount = 0;
                    }
                    
                    for(var i=list_acount-1; i>=0; i--){

                        text = localStorage['text' + i];
                        date = localStorage['date' + i];
                        
                        jQuery('#todo_list').append('<li><h2>' + text + '</h2><p>' + date + '</p></li>');
                        
                    }
                    
                    jQuery('#todo_list').listview('refresh');
                    
                }
        
                </script>
                
            </div>

    </body> 
</html>
リスト1:TODO一覧を表示する画面のソースコード(index.html)

<!DOCTYPE html> 
<html lang="ja"> 
    <head>
        <meta charset="utf-8">
            <title>ToDoアプリ</title>
            <meta name="viewport" content="width=320,user-scalable=no" />
            <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.css" />
            <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.min.js"></script>
            <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.js"></script>
            <link href="displaytest4.css" rel="stylesheet" type="text/css" />
            
    </head> 
    <body onload="load()"> 
        
        <div data-role="page" data-theme="b"> 
            
                <div data-role="header"> 
     <h2>ToDoの追加</h2>
                    <a rel="external" href="index.html" data-role="button" data-icon="back" data-transition="slide">戻る</a>
                </div>
                
                <div data-role="content">
            
      <div id="label">TODOを入力してください</div>
                        <div data-role="fieldcontain">
                            <input type="text" id="text" value=""  />
                        </div>

                        <a rel="external" href="index.html" data-role="button" data-icon="check" data-transition="slide" onclick="set()">追加</a>

    </div>
                           
    <div data-role="footer"> 
        
    </div>
    
    <script>
        
    function set(){
            
                    jQuery.noConflict();
            
                    //現在の登録件数をlocalStorageから取得
                    var list_acount = localStorage['list_acount'];
                    
                    if(list_acount == null){
                        list_acount = 0;
                    }

                    var set_text = jQuery('#text').val();
                    var set_date = new Date();

                    //send_textに何か書いてあればlocalStorageに追加する。
                    if(set_text.length > 0){
                        
                        localStorage['text' + list_acount] = set_text;
                        localStorage['date' + list_acount] = set_date;
                        
                        list_acount++;
                                                                                                                                                                                                        
                    }
                    
                    localStorage['list_acount'] = list_acount;
                 
    }
                        
    </script>
        
  </div>
        
    </body> 
</html>
リスト2:新規TODOを追加する画面のソースコード(add_todo.html)

両方のソースに共通する前回との相違点は、8行目でJQueryのライブラリを読み込みのところです。
JavaScriptのライブラリであるJQueryを使う事でDOM操作のコードが非常にシンプルで分かりやすくなります。

具体的なソースコードの説明はまず、リスト2のset関数からしたいと思います。
set関数は新規ToDoのテキストを入力して「追加」ボタンを押したときに呼び出されます。

ここでの処理は以下の4ステップです。

ステップ1(42行目〜47行目):
ローカルストレージのlist_acountから現在登録されているリスト数を取得します。
初回起動時はlist_acountが存在しない(値を取得するとNullが返ってくる)ので0を設定します。

ステップ2(51,52行目):
テキストエリアに入力された値と現在の日時をset_text,set_date変数にそれぞれ代入します。

ステップ3(55行目〜62行目):
set_text,set_dateの値をローカルストレージに保存します。この処理で新たなToDoが1つ
追加されました。このときに保存する変数名は現在のリスト数+1のインデックスを変数名の後ろに付加した形の
名前にすることでリストの追加を実現しています。
(例えば、現在2行ToDoが登録されている場合に新規に追加するとtext3とdata3に保存します)
また、1行追加されたのでlist_acountを+1します。

ステップ4(64行目)
:+1したlist_acountの値をローカルストレージに保存します。

以上の4ステップで新たなToDoを追加することができました。

次にリスト1のload関数の説明をします。
ここでは、ローカルストレージに保存されているすべてのToDoを取り出して、表示する処理をしています。
このload関数はページ(index.html)が読み込まれたときに呼び出されます。
以下の3ステップです。

ステップ1(42行目〜47行目):
ローカルストレージのlist_acountから現在登録されているリスト数を取得します。
さっきのset関数でやったのと同じですね。

ステップ2(49行目〜56行目):
ローカルストレージに保存されているすべてのToDoを取得し、リスト表示させます。54行目で
実際のリストへの追加が行われており、23行目のulタグの子要素として追加されていきます。

ステップ3(58行目):
ステップ2でDOM操作を行ったため、これを反映させる為に最後にリフレッシュをします。

このようにJavaScriptとHTML5のWebStorageを使うことでUIに実際の処理を追加する事ができます。

これでサンプルアプリは完成です。この2つのhtmlを同一階層のフォルダに置いてSafariで読み込むだけで
動作を確認する事もできます。前回も書きましたが、PhoneGapを使ってアプリ化することで、iPhoneやAndroid端末
で動作させる事もできるようになります。

Objective-CやJavaでアプリを作るよりも、かなりシンプルで保守性も高いコードになっていると思います。
このようにJQueryMobileなどのWeb技術をベースとしてアプリをつくるメリットの一つに、
コードがとてもシンプルになり可読性があがることが挙げられると思います。
UIの記述はデザイナーに、実際の処理はプログラマが実装という分業や、複数人でコードを書くとかが
非常に楽になるのではという感じがしています。

今回はこのくらいで次回以降はサンプルを作りながら分かってきたJQueryMobileの癖なんかをちょっとづつ
書いていこうかと思っています。

2011/04/14

JQueryMobileでらくらくアプリ開発をはじめよう(1)

はじめに:JQueryMobileに注目する理由

最近、クロスプラットフォーム・モバイルアプリ開発が注目を集めています。
Webの技術(HTML + CSS + JavaScript)を使ってアプリのUIと動作を記述でき、作ったものは
iPhoneでもiPadでもGallaxy SでもXperiaで動作するというのが特徴です。

さまざまな会社からクロスプラットフォーム・モバイルアプリ開発の為の
フレームワークが提供されていますが、私はその中でもJQueryMobileに注目しています。

JQueryMobile公式ページ
http://jquerymobile.com/

理由としては、
(1) HTMLの記述のみでUI設計ができる
     (Titanium Mobileとかの他フレームワークよりも簡単)
(2) よけいな設定ファイルやフレームワークが吐き出すベースコードがないのがとっつきやすい
(3) DOM操作にとても便利なライブラリであるJQueryとの親和性が高い


という点です。特に使ってみて(1)がとても便利で、少しでもHTMLが分かっている人なら
簡単にUIを作ることができます(CSSを全くいじらなくてもそれなりのUIが作れます。)

例えば、JQuery Mobileにあらかじめ用意されているUIの部品(ボタンやリストなど)
を使ってこんな感じの画面をHMTLの記述で作れてしまいます。

                 (JQuery Mobile Examples -JQM Galleryより引用)


UIをHTMLで記述したら、
データの受け渡し処理などはjavascript、
データの保存はHTML5のWebStorage
を使うという組み合わせで結構なんでも作れちゃいます。


JQueryMobileを覚えると、次のような良いことがあると考えています。

「こういう感じのアプリを作りたいんだけど」っていうイメージを誰かに伝えたい時、
パワーポイントで苦労して資料を作っても、画面遷移が多くなると
イメージが湧きにくいと言われたりということがあるかと思います。

そんな時に、JQueryMobileでは、ささっとUIと遷移だけ作って、端末に入れて
すぐアプリイメージを伝えるということができるのではと考えています。
(しかも、ひとつ作ってしまえば、いろんな端末で見せることが可能です)

そして、そのあとすぐメンバーの意見を反映させて、UIをFIXした後は、
(その間にUIを修正するのもHTMLを変更するだけなのですぐできます)
実際の処理を作って、テストしてとにかく早くリリースするっていうのが可能になります。

Objective-cやJavaは全く使わずに、多端末対応のアプリを素早く作れて、
何よりもソースコードが分かりやすくなると言った点がとても気に入っています。


悪い点もあげておくと、
(1)デバイスを使った処理(例えば、カメラ制御やGPS、加速度センサ)を含むアプリの開発には向いていない
(2)ゲームなどのアニメーションが多いアプリの開発には向いていない
(javascriptやHTML5で作ることは可能ですが、また別の話です)

という点があげられます。上記のような特徴を持つアプリの開発は現状では、Objective-CやJAVAでの
開発のほうが向いているのかもしれません。

JQueryMobileは現在α4版がリリースされています。
今春中に完成版リリース予定とアナウンスされていますので今後の
アップデート次第では上記の悪い点が改善される可能性もあります。

追記:
先日、AdobeからDreamWeaverがJQuery Moblieに対応することが発表されました。
[参考記事]jQuery MobileにDreamweaverが対応。モバイルアプリケーション開発ツールとして本命に急浮上!
ますます注目を集めそうですね。

サンプルアプリの作成(UI編)

じゃあさっそくサンプルアプリを作ってみましょう。

一番始めにつくるサンプルアプリは、
「TODO管理アプリ(簡易ver)」
を作ってみようかと思います。

作成する画面は以下の2つです。
・TODO一覧を表示する画面(図1)
・新規TODOを追加する画面(図2)

今回はこのUI部分だけ作ってみることとします。


図1:TODO一覧を表示する画面


図2:新規TODOを追加する画面

図1の画面でツールバーの「追加」ボタンを押すと図2の画面に遷移して、新たなTODOを入力する
ことができます。
図2で新規TODOを入力して、画面下の「追加」ボタンを押すと、新たなTODOが追加されて、
図1の画面に戻ります。

というような単純なアプリです。

早速コードを紹介します。
図1、図2にそれぞれ対応する形でリスト1,リスト2のような2つのhtmlファイルを作ります。

<!DOCTYPE html> 
<html lang="ja"> 
    <head>
        <title>ToDoアプリ</title>
        <meta name="viewport" content="width=320,user-scalable=no" charset="utf-8"/>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.css" />
        <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.js"></script>    
    </head> 
    <body>
        
        <div data-role="page" data-theme="b"> 
            
                <div  data-role="header"> 
                    <h1>TODOリスト</h1>
                    <a rel="external" href="add_todo.html" data-role="button" data-icon="plus" >追加</a>
                </div> 
                
                
                <div data-role="content">
            
                    <ul data-role="listview" id="todo_list">
                        <li><h2>レポート書く</h2><p>Thu Apr 2011 12:38:16....</p></li>
                        <li><h2>リンゴ買う</h2><p>Thu Apr 2011 12:28:52....</p></li>
                    </ul>
                    
                </div>
                
                                
                <div data-role="footer"> 
        
                </div>
        
            </div>

    </body> 
</html>

リスト1:TODO一覧を表示する画面のソースコード(index.html)

<!DOCTYPE html> 
<html lang="ja"> 
    <head>
        <title>ToDoアプリ</title>
        <meta name="viewport" content="width=320,user-scalable=no" charset="utf-8"/>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.css" />
        <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.js"></script>
    </head> 
    <body> 
        
        <div data-role="page" data-theme="b"> 
            
                <div data-role="header">
                    <h2>ToDoの追加</h2>
                    <a rel="external" href="index.html" data-role="button" data-icon="back">戻る</a>
                </div>
                
                
                <div data-role="content">
                    <div id="label">TODOを入力してください</div>
                    <div data-role="fieldcontain">
                        <input type="text" id="text" value=""  />
                    </div>

                    <a rel="external" href="index.html" data-role="button" data-icon="check">追加</a>
                </div>
                
                <div data-role="footer">
    </div>
  </div>
        
    </body> 
</html>


リスト2:新規TODOを追加する画面のソースコード(add_todo.html)

index.htmlから
簡単にソースコードの説明をしていきます。

まずheadタグ内ではJQueryMobileを使うためにjsファイルとcssファイルをインポートしています。

次にbodyタグの中ですが、始めにここの中がJQueryMobileを使ったUIですよということを表す為に、
<div data-role="page" data-theme="b">というタグを記述します。
ここでdata-themeという属性がありますが、JQueryMobileであらかじめ用意されている
いくつかのUIデザインのテーマ(下記図3のようにaからeまであります)を選択することで、アプリのデザインテーマを
変更することができます。
なお、各部品ごとにテーマを変えるということも可能です。
(ボタンはテーマa、ツールバーはテーマcを使うとかが可能)

図3 選択できるテーマ




デザインテーマを指定したら、実際のUIを記述していきます。
JQueryMobileではHTML5の思想を取り入れ、header部、content部、footer部に
分けて記述します。それぞれdivタグのdata-roleの属性値にheader,content,footerと指定すること切り分け
をおこないます。

このコードと画面との対応ですが、headerが画面上部にあるツールバー(図1ではTODOリストと書いてあり、追加ボタンが表示されている部分です。)に対応し、content部が中央の領域(図1ではリストを表示している部分)、footerは画面下部の領域に対応し、ここにボタンやラベルを表示できます。(図1では使っていません)

ソースを見てもらえれば分かると思いますが、3つに分けられた各部にラベルやボタンをタグで記述するだけで、
UIを設計することができます。

ここで気をつけるのは、ボタンのを表現するのにJQueryMobileではaタグを利用します。aタグのdata-role属性に
buttonと記述するだけで、ボタンの画像が埋め込まれたリンクが自動的に作成されます。
またbutton-icon属性を指定することで、ボタンのアイコンを指定することができます。
どのようなボタンがあるかは、JQueryMobileのリファレンス(日本語)を見ればよくわかります。たくさんのiconが用意されていることが分かります。

次にadd_todo.htmlです。index.htmlと違う点はテキストを入力するinputタグが使われているところぐらいです。
「戻る」ボタン、「追加」ボタンもindex.htmlと同様にaタグで作成されています。

このようにあらかじめ用意されているUIの部品セットを使ってHTMLを記述するだけで、簡単にUIを作れてしまいます。

しかし、これだけでは画面1と2を行き来できるだけで、実際のtodoを登録してリストに反映させることはできません。
はじめにも書きましたが、todoの登録処理の記述はJavascript、データの保持はHTML5のWebStorageを使うことで
実現します。次回の記事はこの部分について書こうと思います。

最後に:マルチデバイスでアプリ化するためのツール「Phone Gap」の紹介

最後に、JQueryMobileで作ったものを端末でアプリとして見せる為の方法を説明します。
今回作ったものはHTMLなので、当然ながらWebサーバ上に置けば動作します。
しかし、適当なサーバを用意するのは割と面倒ですし、mobileSafariの上で動作させるとアプリっぽく見えないとか
電波状況が悪いところでは動作しないというような欠点もあります。

そこで、HTMLをiPhoneやAndroid端末のアプリに自動変換するPhone Gapというツールを使います。

Phone Gap公式ページ
http://www.phonegap.com/

詳しい使い方は次回以降また書こうと思いますが、
本アプリを使うことで簡単にiPhoneアプリに変換することができました。
対応機種は、
・Android
・BlackBerry
・BlackBerry WebWorks (OS 5.0 and higher)
・iPhone
PhoneGap API Documentationより引用)
となっています。

今回紹介したJQueryMobileとPhoneGapを使えば、1度の開発でマルチプラットフォームで動作するアプリが
作れるようになるというのがとても魅力的だと思っています。