3. プログラムサンプル
次に、このサンプルでのコード内容について見ていきます。サンプルはスマートフォン用と、地図表示のできるPC画面用に分かれています。ただし、これは画面サイズを考慮した見やすさから分けているだけなので、これを例えばPCでスマートフォン用の画面を使用し、スマートフォンでPC用画面から地図表示を行うようなことも可能で、これについてもAndroid実機で動作・表示が問題ないことを確認しています。
サンプルではクラウドサーバ側およびWebクライアント側でいくつかのソフトウェア機能が使われていますので、最初に簡単に確認しておきます。
GAE側
Channel API
Channel APIは、Webクライアントとクラウドサーバとの間に継続するコネクションを形成して、ブラウザからのポーリング(リロード)なしで、リアルタイムでサーバからWebクライアントへのサーバプッシュによるデータ送信を行います。Channel APIではサーバ側、クライアント側の両方で、対応するコード記述が必要ですが、gaedirect(gaedirect2.0)を使用することにより、サーバ側のコード記述は必要なくなり、JavaScriptでのクライアント側記述のみで済むようになります。
Channel APIは2010年の12月2日にリリースされており、いわゆるクリスマスリリースでの公開となっています。GAEでは毎年クリスマス前に大きな機能アップリリースを行ってきていますが、このChannel APIもこのなかに含まれるビッグリリースと言ってよいでしょう。
Low-Level API
GAEでのデータストア(Bigtable)アクセス用に使用されるサーバ側のJava APIですが、このAPIによるコード記述もgaedirectを使用することによって必要なくなり、第1回記事で紹介したようなJavaScriptでの簡単なプログラム記述によってBigtableへのアクセス(登録・参照・更新・削除)を行うことができます。
JavaからのBigtableアクセスではこのほかに、JDO(Java Data Objects)やSlim3などがありますが、gaedirectでは唯一ソフトスキーマを適用できる、Low-Level APIを使用しています。
Webクライアント側
Geolocation
GeolocationはHTML5の位置情報取得機能です。これまでは、個々のデバイスが独自の規格で位置情報を取得していたため、位置情報取得を利用するアプリケーション作成では、キャリアが異なるデバイス(スマートフォンや、タブレットPCなど)ごとにそれぞれ固有の記述が必要でした。しかしHTML5のGeolocationを使用すれば、個々のデバイスに依存せずに、同じ記述で位置情報の処理を行うことができるようになります。Geolocationは種々の興味深い機能をもつHTML5のなかでも、トップの人気をもつ機能になっています。
Google Maps API
PC画面ではGeolocationで取得した位置情報をもとに、送信者(遭難者)の位置情報をGoogle Maps上に表示します。Google Maps APIを使えば指定の座標の地図を表示させ、マーカを地図上に設置したり、任意の線を地図上に描くようなこともできます。またデータストアなどと組み合わせ独自の地図情報アプリケーションを作成することもできます(例:http://6.swsgaejpgm10.appspot.com/tsunami.html)。
jQuery
jQueryはJavaScriptの軽量ライブラリです。JavaScriptのライブラリとしては最も人気がありますが、よく知られているものなので詳細は省略します。
3.1 スマートフォン用画面のサンプルコード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewpoint" content="width=device-width"/> <!--(S1)-->
<style type="text/css"> <!--(S2):ここから-->
@CHARSET "UTF-8";
* { margin: 0px; padding: 0px; }
div#container * { margin: 2px; }
input { width: 98%; font-size: 20px; }
input[type="text"] { height: 32px; }
input[type="button"] { height: 40px; }
.error { font-weight: bold; color: #FF4444; }
</style> <!--(S2):ここまで-->
<script type="text/javascript" src='/jslib/gaedirect.js'></script>
<script type="text/javascript" src="/jslib/gears_init.js"></script>
<script type="text/javascript" src='/_ah/channel/jsapi'></script>
<script type="text/javascript" src='/jslib/jquery-1.6.1.min.js'></script>
<title>Channel API テスト</title>
<script type="text/javascript">
var token = "";
var clientId = "";
var socket = "";
var initialized = false;
var connected = false;
var requestToken = false;
$(function(){
if(!navigator.geolocation){ //(S3):ここから
navigator.geolocation = google.gears.factory.create('beta.geolocation');
} //(S3):ここまで
clientId = ""+Math.floor(Math.random()*1000000); //(C1):ここから
token = getToken(clientId);
channel = new goog.appengine.Channel(token);
initialized = true; //(C1):ここまで
socket = channel.open();
$("#status").text("初期化が完了しました。serverからの応答待ちです。");
$("#send").click(function(){ //(1)
if(!connected ){ //(2)
$("#status").text("接続未完了でデータを送信できません");
return;
}
navigator.geolocation.getCurrentPosition( //(3)(S4)
function (pos) { //(S5)
var name = $("#name").val(); //(4)
var tel = $("#tel").val(); //(4)
var lat = pos.coords.latitude; //(4)(S6)
var lon = pos.coords.longitude; //(4)(S7)
var id = "name,tel,lat,lon";
var val = name+"<p>"+tel+"<p>"+lat+"<p>"+lon;
var query = {};
query["kind"] = "geoloc"; //(5)
query["clientId"] = clientId; //(5)
query["id"] = id; //(5)
query["val"] = val; //(5)
var res = postsyn(capi(), query); //(6)
},
function () {
alert("位置情報の取得に失敗しました");
},{
enableHighAccuracy: true
}
);
});
$("#cinit").click(function(){
cInit(clientId);
});
$("#close").click(function(){
if(socket == "" || initialized == false || connected == false){
$("#status").text("まだ接続されていません");
return;
}
cClose(clientId);
socket.close();
socket = "";
initialized = false;
connected = false;
token = "";
clientId = "";
$("#status").text("接続を終了しました");
});
socket.onopen = function(){ //(C2):ここから
connected = true;
$("#status").text("接続が開始されました。データ受信できます。");
} //(C2):ここまで
socket.onmessage = function(msg){ //(C3):ここから
var res = $.parseJSON(msg.data);
$("#name").val(res.name);
$("#tel").val(res.tel);
$("#lat").text(res.lat);
$("#lon").text(res.lon);
$("#date").text(res.date);
$("#msg").val("");
} //(C3):ここまで
socket.onerror = function(err){ //(C4):ここから
$("#status").text("Serverでエラー発生。 内容:"
+ err.description + " エラー:" + err.code);
} //(C4):ここまで
socket.onclose = function(){ //(C5):ここから
$("#status").text("接続が正常に終了しました。");
connected = false;
initialized = false;
} //(C5):ここまで
});
</script>
</head>
<body>
<h2>Channel API&Geolocation</h2>
<div id="status"></div><br/>
<p>
<input type="button" id="send" value="データ送信" />
<input type="button" id="cinit" value=" 初期化 " />
<input type="button" id="close" value="接続終了" />
</p>
<p>姓名と携帯TELを入力後「データ送信」</p>
姓名:<input type="text" id="name">
携帯TEL番号:<input type="text" id="tel">
緯度:<p id="lat"></p>
経度:<p id="lon"></p>
日時:<p id="date"></p>
</body>
</html>
リスト1はスマートフォン用のクライアントサンプルですが、今回はChannel APIなどを組み合わせているため、前回に比べてコード量が多くなっています。
このコードではメインでChannel APIとGeolocationの処理を行い、クラウドサーバとの非同期通信ではgaedirectを、イベント処理やデータ表示ではjQueryを使用しているというのが大まかな内容です。またスマートフォン画面への対応はCSSで行っています。
