モバイル機器用のオフライン Web アプリケーションを HTML5 を使って作成する

複数のオペレーティング・システムや多種多様なモバイル機器を対象としたアプリケーションの作成は、困難な作業になる場合があります。また、高度なモバイル・アプリケーションに対する需要の高まりから、モバイル機器に搭載するハードウェアへの要求も高くなっています。こうした状況に対処する方法として、Web アプリケーションを提供する方法があります。Web アプリケーションはモバイル機器のプラットフォームの種類に依存せずに実行することができます。また、専用の技術 (例えば iPhone の Cocoa での Objective-C など) を使う必要はなく、一般的な Web 技術を使うことができます。ポイントは、用意するアプリケーションは 1 つのバージョンだけでよいという点です。この場合、アプリケーションの処理は主にサーバーのハードウェア・リソースを使って行われます。この記事では、モバイル機器用の Web アプリケーションを開発する方法について、HTML5 標準を活用した単純なアプリケーションを例に説明します。

Dietmar Krueger, IT Architect, WSO2 Inc

Photo of Dietmar KruegerDietmar Krueger は、IBM Global Business Services のサービス・シリーズの 1 つである Application Innovation Services に従事しています。彼はオブジェクト指向ソフトウェアの開発を 17 年にわたって行ってきており、アジャイル・ソフトウェア開発、軽量アーキテクチャー、動的型付けプログラミング言語に情熱を注いでいます。



2010年 5月 18日

はじめに

モバイル・アプリケーションを Web アプリケーションとして開発することが多くなっています。しかしモバイル機器の場合、クラウド・インフラ上で Web 技術を利用する際に、常時ネットワークに接続できるわけではない点が大きな障害になっています。従来の Web アプリケーションはネットワークを利用できない場合は動作しません。この問題に対する 1 つの解決策として、HTML5 標準 (「参考文献」を参照) に含まれる、以下の 2 つの機能を利用する方法があります。

  • オフラインの Web アプリケーション
  • クライアント・サイドのデータベース・ストレージ

ユーザーは、モバイル機器でクラウドの機能を利用した後、ローカルにデプロイされたアプリケーションでローカル・データベースをオフラインで操作し、再度オンラインに復帰した場合にはクラウドとデータを共有することができます。

この記事では、上記の 2 つの機能を利用する典型的なシナリオでの技術的な詳細について学びます。また、単純な在庫管理アプリケーションのプロトタイプを使用しながら、HTML5 の技術について説明します。

この記事のサンプル・アプリケーションのソース・コードを「ダウンロード」セクションからダウンロードしてください。

概要

図 1 は、このサンプル・アプリケーションのアーキテクチャーの主要なコンポーネントを示しています。

図 1. オフライン Web アプリケーションの主要なコンポーネント
ブロック図の中で、「HTML」というラベルの付いたボックスとユーザーが矢印で結ばれています。「HTML」ボックスは、「CSS」、「Manifest」、「JavaScript」、「DB」というボックスを指しています。また「HTML」ボックスと「JavaScript」ボックスは「Server」ボックスも指しており、「JavaScript」ボックスは「DB」ボックスも指しています。
HTML ページ
HTML ページはアプリケーションの中核であり、モデルの役割を持っています。HTML ページには表示されるデータと (デフォルトの) 描画のための情報が含まれています。このページの HTML 要素は HTML DOM (Document Object Model) ツリーの階層構造として構成されています。ユーザー操作で起動されるイベントにより、従来のリクエスト/レスポンスのサイクルが開始されてページがロードされ、関連する JavaScript 関数が実行されます。

なんと、このアプリケーションは 1 つの HTML ページで構成されており、リクエスト/レスポンスのサイクルで他の HTML ページをロードする必要がありません。すべてのアクションは 1 つのページ上にあります。

JavaScript
JavaScript 要素には、このアプリケーションのコントローラー機能が含まれています。HTML 要素はイベント・ハンドラーによって JavaScript 関数にバインドされています。JavaScript は、アプリケーション (そしてその UI (User Interface) 要素すべて) の HTML DOM ツリーにアクセスすることができ、その DOM ツリーを計算用のデータ入力に使うことができます。その処理の結果は、HTML ページを変更することでユーザーに表示されます。
CSS (Cascading Style Sheet)
CSS (Cascading Style Sheet) は HTML ページの表示方法を記述します。ここでは表示タスクを省略してソリューションを単純化しています。このアプリケーションでは、HTML 要素のデフォルトの描画動作のみが使われます。

モバイル機器用には、Web アプリケーションを使って実際のモバイル機器ネイティブのユーザー・エクスペリエンスに近いエクスペリエンスを提供する、さまざまな JavaScript/CSS ライブラリーやフレームワークがあります (例えば iPhone 用の iUi など)。詳細については「参考文献」を参照してください。ユーザーにとって受け入れやすいものにすることは必要ですが、この方法はプラットフォームに依存するという欠点があります。

データベース
HTML5 標準ではローカル・データベース・ストレージが導入されています。この機能は Apple® の Safari ブラウザーの最新バージョンに実装されています。このブラウザーにはデータベース (SQLite) が組み込まれており、このデータベースには JavaScript で SQL クエリーを処理することで、アクセスすることができます。アプリケーション・モデルのビジネス・データは、このデータベースに保存されます。
マニフェスト
マニフェスト・ファイルは、オフライン Web アプリケーションに必須のデプロイメント記述子コンポーネントです。このファイルには、ロードが必要なすべてのファイルが単純にリストアップされています。

サンプル・アプリケーション

このセクションでは、MyHomeStuff というサンプル・アプリケーションの概要を説明します。このアプリケーションは皆さんの持ち物を記録しておける簡単な在庫管理アプリケーションです。このアプリケーションを iPhone に表示したものが図 2 です。

図 2. iPhone のビュー
「MyHomeStuff」アプリケーションを iPhone で表示した場合のスクリーン・ショット。ビューには太字の見出しが 3 つあり、各見出しの下に情報があります。見出しは、「Overview (概要)」、「Details (詳細)」、「Status (状態)」です。

簡単のため、サーバーとのデータの同期は省略します。図 3 は MyHomeStuff 在庫管理アプリケーションを Palm Pre の Web ブラウザーで表示した場合を示しています。

図 3. Palm Pre のビュー
上の画像と同じスクリーン・ショットですが、この場合は Palm Pre の Web ブラウザーを使っています。

画面の上の方にあるリストは、入力されたすべての項目 (Book (本) や Computer (コンピューター) など) の概要を示しています。

ユーザーがリストの項目を 1 つ選択すると、その項目の詳細 (Id (ID)、Quantity (数量)、Name (名前)) がフォームの真ん中に表示されます。選択された項目の詳細は「update (更新)」ボタンを使って変更することができます。また、「delete (削除)」ボタンを使うことで、選択された項目をアプリケーションから削除することもできます。新しい項目を作成するためには、その項目の数量と名前をフォームに入力してから「create (作成)」ボタンをクリックします。

アプリケーションの状態 (Status) は画面の下の方に表示されます。

HTML の詳細

この HTML ページには、さまざまな宣言や、モバイル用に最適化された表示をするためのメタ・タグ、外部ファイル (マニフェスト・ファイル、JavaScript ファイル、CSS ファイル) への参照、そしてこのアプリケーションの基本構造として欠かせない HTML 要素が含まれています。リスト 1 は HTML コードを示しています。

リスト 1. HTML コード
                <!DOCTYPE HTML>
                <html manifest="MyHomeStuff.manifest">
                <head>
                <meta name="viewport" content="width=device-width; 
                initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
                <title>MyHomeStuff</title>
                <script type="text/javascript" src="MyHomeStuff.js" ></script>
                </head>
                <body onload="onInit()">
                <h3>Overview</h3>
        <ul id="itemData" ></ul>
    <h3>Details</h3>
        <form name="itemForm">
            <label for="id">Id: </label>
            <input type="text" name="id" id="id" size=2 disabled="true"/>
            <label for="amount">Amount: </label>
            <input type="text" name="amount" id="amount" size = 3/>
            <label for="name">Name: </label>
            <input type="text" name="name" id="name" size=16 /> <br>
            <br>
            <input type="button" name="create" value="create"
                onclick="onCreate()" />
            <input type="button" name="update" value="update"
                onclick="onUpdate()" />
            <input type="button" name="delete" value="delete"
        </form>
    <h4>Status</h4>
        <div id="status"></div>
   </body>
</html>

HTML 要素のイベント・ハンドラー属性は、このページが最初にロードされた時 (onload)、またはボタン要素がクリックされた時 (onclick) に、どの JavaScript 関数を実行するかを指定します。

オフライン Web アプリケーションの HTML ページは <!DOCTYPE HTML> タグで始まります。マニフェストはタグの manifest 属性によって <html manifest="MyHomeStuff.manifest"> のように参照されます。

先ほど触れたように、マニフェストはキャッシュへのロードが必要なファイルを指定します。このアプリケーションは 1 つの HTML ファイルと 1つの JavaScript ファイルで構成されています。HTML ファイルはマニフェストへの参照と共に、自動的にアプリケーションのキャッシュに含まれます。マニフェストは以下のもののみを含んでいます。

リスト 2. マニフェスト・ファイル
CACHE MANIFEST

MyHomeStuff.js

JavaScript の詳細

JavaScript コードは以下の 3 つの主なブロックで構成されています。

  • 初期化関数
  • DB (CRUD) 関数とビュー更新関数
  • 簡単なユーティリティー関数

最初のブロックには、アプリケーションを初期化するイベント・ハンドラー (onload) と、データベースの初期化を行う関数が含まれています (リスト 3)。

リスト 3. JavaScript による初期化コード
function onInit(){
    try {
        if (!window.openDatabase) {
            updateStatus("Error: DB not supported");
        }
        else {
            initDB();
            createTables();
            queryAndUpdateOverview();
        }
    } 
    catch (e) {
        if (e == 2) {
            updateStatus("Error: Invalid database version.");
        }
        else {
            updateStatus("Error: Unknown error " + e + ".");
        }
        return;
    }
}

function initDB(){
    var shortName = 'stuffDB';
    var version = '1.0';
    var displayName = 'MyStuffDB';
    var maxSize = 65536; // in bytes
    localDB = window.openDatabase(shortName, version, displayName, maxSize);
}

上記のコードの内容を以下に説明します。

  • onInit 関数はまず、必須の openDatabase 関数があるかどうかをチェックします。この関数がない場合、そのブラウザーはローカル・データベースをサポートしていないことを通知します。
  • initDB 関数は HTML5 ブラウザーのデータベースを開きます。
  • データベースを開くことができると、データベース・テーブルを作成するための SQL DDL を実行します。最後に、既存のレコードにクエリーを実行して HTML ページにデータを追加する関数群が呼び出されます。

2 番目の JavaScript ブロックの各関数には、データベースへのアクセスと表示ロジックのための部分があります。このようにロジックを統合できることが Model 1 アーキテクチャー (「参考文献」を参照) の特徴です (Model 1 アーキテクチャーは単純な Web アプリケーションを作成するための最も容易な方法です)。実際のシナリオでは、モデル、ビュー、コントローラー (MVC) の各部分を明確に分離したアーキテクチャーの方が適切です。

サンプルの「Overview (概要)」リストを作成するためには、イベント・ハンドラー関数から queryAndUpdate 関数を呼び出します。リスト 4 はそのコードを示しています。

リスト 4. JavaScript による Overview のコード
function queryAndUpdateOverview(){

    //remove old table rows
    var dataRows = document.getElementById("itemData").getElementsByClassName("data");
    while (dataRows.length > 0) {
        row = dataRows[0];
        document.getElementById("itemData").removeChild(row);
    };

    //read db data and create new table rows
    var query = "SELECT * FROM items;";
    try {
        localDB.transaction(function(transaction){
        
            transaction.executeSql(query, [], function(transaction, results){
                for (var i = 0; i < results.rows.length; i++) {
                
                    var row = results.rows.item(i);
                    var li = document.createElement("li");
                    li.setAttribute("id", row['id']);
                    li.setAttribute("class", "data");
                    li.setAttribute("onclick", "onSelect(this)");
                    
                    var liText =
                        document.createTextNode(row['amount'] + " x "+ row['name']);
                    li.appendChild(liText);
                    
                    document.getElementById("itemData").appendChild(li);
                }
            }, function(transaction, error){
                updateStatus("Error: " + error.code + "<br>Message: " + error.message);
            });
        });
    } 
    catch (e) {
        updateStatus("Error: Unable to select data from the db " + e + ".");
    }
}

上記のコードの内容を以下に説明します。

  • 古いデータが DOM ツリーから削除されます。
  • すべてのデータ・セットを選択するクエリーが実行されます。
  • クエリーの実行結果に含まれる各データ・セットに対して HTML のリスト要素が 1 つ作成され、その要素がリストに追加されます。
  • クリックに応答する各リスト要素に対し、イベント・ハンドラー (onSelect) が追加されます。

このブロックの関数には、ボタン・バーとリスト に対するイベント・ハンドラー (onUpdateonDeleteonCreateonSelect) も含まれています。リスト 5 は onUpdate のコードを示しています。(onCreate と onDelete は構造が似ているため、ここには示してありません。このサンプル・アプリケーションのすべてのソース・コードは下記の「ダウンロード」セクションからダウンロードすることができます。)

リスト 5. JavaScript による onUpdate のコード
function onUpdate(){
    var id = document.itemForm.id.value;
    var amount = document.itemForm.amount.value;
    var name = document.itemForm.name.value;
    if (amount == "" || name == "") {
        updateStatus("'Amount' and 'Name' are required fields!");
    }
    else {
        var query = "update items set amount=?, name=? where id=?;";
        try {
            localDB.transaction(function(transaction){
                transaction.executeSql(query, [amount, name, id],
                function(transaction, results){
                    if (!results.rowsAffected) {
                        updateStatus("Error: No rows affected");
                    }
                    else {
                        updateForm("", "", "");
                        updateStatus("Updated rows:"
                            + results.rowsAffected);
                        queryAndUpdateOverview();
                    }
                }, errorHandler);
            });
        } 
        catch (e) {
            updateStatus("Error: Unable to perform an UPDATE " + e + ".");
        }
    }
}

上記のコードの内容を以下に説明します。

  • フォームのフィールドの値が読み取られ、検証されます。
  • 値が有効な場合には、更新クエリーが実行されます。
  • クエリーの実行結果は、更新された HTML ページに表示されます。

onSelect 関数はユーザーがリスト要素を選択すると実行されます。このリスト要素のデータは、リスト 6 のコードを使って詳細フォームに追加されます。

リスト 6. JavaScript による onSelect のコード
function onSelect(htmlLIElement){
    var id = htmlLIElement.getAttribute("id");
    query = "SELECT * FROM items where id=?;";
    try {
        localDB.transaction(function(transaction){
        
            transaction.executeSql(query, [id], function(transaction, results){
            
                var row = results.rows.item(0);
                
                updateForm(row['id'], row['amount'], row['name']);
                
            }, function(transaction, error){
                updateStatus("Error: " + error.code + "<br>Message: " + error.message);
            });
        });
    } 
    catch (e) {
        updateStatus("Error: Unable to select data from the db " + e + ".");
    }
}

上記のコードの内容を以下に説明します。

  • 選択された要素の ID が判断されます。
  • SELECT クエリーが実行されます。
  • 読み取られたデータ・セットで、詳細フォームを更新する関数が呼び出されます。

ユーティリティー関数による最後の JavaScript ブロックは、データ・ハンドラーで始まります。これらのデータ・ハンドラーはクエリー用のパラメーターとして必要です。

リスト 7. JavaScript によるハンドラー・コード
errorHandler = function(transaction, error){
    updateStatus("Error: " + error.message);
    return true;
}

nullDataHandler = function(transaction, results){
}

冗長性を避けるために、ユーティリティー関数は、詳細フォーム (updateForm) とステータス・メッセージ (updateStatus) の各フィールドにデータを追加します (リスト 8)。

リスト 8. JavaScript によるユーティリティー関数のコード
function updateForm(id, amount, name){
    document.itemForm.id.value = id;
    document.itemForm.amount.value = amount;
    document.itemForm.name.value = name;
}

function updateStatus(status){
    document.getElementById('status').innerHTML = status;
}

デプロイメント

実際の HTML5 モバイル機器上でサンプル・アプリケーションを実行するために、iPhone 3GS と Palm Pre を使用しました。最新の Safari ブラウザーを使用した場合も動作しました。

このアプリケーションのファイルを下記の「ダウンロード」セクションからダウンロードし、HTTP サーバーにデプロイすることができます。マニフェスト・ファイルは、HTTP サーバーで提供する必要があります (MIME タイプはtext/cache-manifest)。iPhone でアプリケーションを開いた後、ブックマークを保存してからオフラインの機内モードにします。ブックマークを選択するとアプリケーションが起動し、ネットワークに接続されていなくてもアプリケーションが動作します。

まとめ

この記事ではオフライン Web アプリケーションの技術的な面に焦点を当てました。簡単な在庫管理アプリケーションのプロトタイプを使用しながら、ローカルにデプロイされたアプリケーションとローカル・データベースとを使った HTML5 の技術について説明しました。


ダウンロード

内容ファイル名サイズ
Source code for this articleOfflineWebAppSrc.zip3KB

参考文献

学ぶために

  • Safari Client-Side Storage and Offline Applications Programming Guide」(2010年1月20日、Apple Inc.) は HTML5 での JavaScript データベースのサポートについて詳細に解説しています。
  • ABI Research: Cloud computing will transform mobile apps」(2009年、Dusan Belic 著) は、モバイル・アプリケーションの有力なモデルになりつつある Web ベースの技術を解説しています。Web アプリケーションでは 1 つのバージョンのアプリケーション以外は必要ありません。
  • HTML 5 - A vocabulary and associated APIs for HTML and XHTML」(2010年3月4日、W3C ワーキング・ドラフト) は HTML5 に関して最も信頼のおけるソースです。
  • iUi: iPhone User Interface Framework」を読み、iPhone クラスの機器でのWeb アプリケーション開発について学んでください。iUi は JavaScript ライブラリーや CSS、画像などで構成された、iPhone とその互換機や同等機用の高度なモバイル Web アプリケーションを作成するためのフレームワークです。
  • Mobile app dev trends: Making life easier for developers」(2009年7月、John K. Waters 著) は、モバイル領域で Web 開発が使われる傾向が強まっていることを解説しています。
  • Java Web アプリケーションのための Model 1 デザイン・モデルについて学んでください。Model 1 デザイン・モデルでは、リクエストを JSP またはサーブレットに送信すると、その JSP またはサーブレットがリクエストの処理、データの検証、ビジネス・ロジックの処理、レスポンスの生成など、そのリクエストのすべての処理を行います。
  • developerWorks の Web development ゾーンには、Web ベースのソリューションに特化した記事が豊富に用意されています。
  • developerWorks の Technical events and webcasts で最新情報を入手してください。
  • developerWorks On demand demos をご覧ください。初心者を対象とした、製品のインストール方法やセットアップ方法の説明から、経験豊富な開発者のための高度な機能の説明に至るまで、多様な内容が網羅されています。

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

  • 皆さんの目的に最適な方法で IBM 製品を評価してください。製品の試用版をダウンロードする方法、オンラインで製品を試す方法、クラウド環境で製品を使う方法、あるいは SOA Sandbox で数時間を費やし、サービス指向アーキテクチャーの効率的な実装方法を学ぶ方法などがあります。

議論するために

  • My developerWorks で開発者向けのブログ、フォーラム、グループ、ウィキなどを利用しながら、他の developerWorks ユーザーとやり取りしてください。

コメント

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=Web development
ArticleID=495716
ArticleTitle=モバイル機器用のオフライン Web アプリケーションを HTML5 を使って作成する
publish-date=05182010