読者です 読者をやめる 読者になる 読者になる

TitaniumMobile勉強記

Web系エンジニア向けのキャリアアドバイザーやってましたが現在はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連(Node.js、Titanium)あたり

Google Fusion Tablesと連携する処理試してみた

Titanium.Map使ったサンプル

TitaniumのAdventCalendar@kinofumiさんが紹介してたGoogleFusionTablesですが

  • 元となるデータをCSVデータ等からインポート出来るのはもちろん、Webインターフェース上でも入力できる
  • 座標情報を格納するためのLocationというColumnがあり、地図上に手軽にプロット出来る
  • 開発者向けのAPI&ドキュメントが一応整備されているので、標準機能にないものを拡張できそう

という印象を受けました。

以前http://d.hatena.ne.jp/h5y1m141/20100509/1273410287:title=というので、都内の地ビール買えるお店をまとめたことがあるのですが、こういう情報をまとめつつ、他の人と共有するのに向いてるのかなと思ってちょっと触ってみました(*1)

Google Fusion Tables設定

GoogleFusionTablesの画面のSEE MY TABLESをクリックします
googlefusiontables01

Google Docsの画面にリダイレクトされるので、左側にあるCREATEボタンクリックしてTable(beta)を選択します
googlefusiontables02

Table作成するためのウィザード画面が表示されます。見る限り他の情報もインポートできそうですが今回はCreate empty tableを選択します
googlefusiontables03

選択すると、以下のような画面になるのでこれで初期設定は完了
googlefusiontables04

Titanium Mobileから使うには?

最初OAuthにチャレンジ呆気無く挫折。ClientLoginで認証することに
http://blog.under-the-tree.jp/?p=25:title=

と書かれているようにClientLogin利用できるし、少し前にhttp://d.hatena.ne.jp/h5y1m141/20111129/p1:title=というエントリで触れている認証部分がそのまま流用出来るからそっちを試しました

Google Fusion Tablesから取得できるデータ形式は標準ではCSVのようだったのですが、Titanium Mobile上ではJSON形式の方が処理しやすいと思うので

    // 一部抜粋
    var xhr = Ti.Network.createHTTPClient();
    xhr.setRequestHeader("Authorization",auth);
    var baseUrl= "https://www.google.com/fusiontables/api/query?sql=SELECT+*+FROM+2415682&jsonCallback=callback";
    xhr.open('GET',baseUrl);

という感じで、クエリーパラメータにjsonCallbackを指定してあげるとJSONP形式で値が返ってきます。

JSONPって何なのか、実はこれまで全く知らなかったので、http://d.hatena.ne.jp/jdg/20090902/1251851867:title=などを見て現在勉強中。

そのためコードが汚いですが、ひとまず晒しておくことにします

//app.js
var style = require("ui/style");
var model = require("model/model");
var beer = {};
(function(){
   model.login('YOURGMAIL','YOURPASSWORD',
     function(auth){
       model._get(auth,function (value){
	 eval(value);
       });
     }
   );
}).call(this);
// この部分は本当ならmodel.js内部で処理して、配列containerだけ返す方が役割的にスッキリする
function callback(obj){
  var len = obj.table.rows.length;
  var container = [];
  var win = Ti.UI.createWindow($$.app.win("地ビール"));
  var mapview = Titanium.Map.createView($$.app.mapview);
  for(var i=0;i<len;i++){
    var location = obj.table.rows[i][2].split(",");
    var annotation = Titanium.Map.createAnnotation($$.app.mapAnnotation);
    annotation.latitude = location[0],
    annotation.longitude =location[1],
    annotation.title = obj.table.rows[i][0],
    container.push(annotation);
  }
  mapview.addAnnotations(container);
  win.add(mapview);
  win.open();
}
// model/model.js
exports = {
  login:function(email,password,func){
    var _authToken = null;
    var auth = null;
    var xhr = Ti.Network.createHTTPClient();
    var config = {
      email          : email,
      password       : password,
      login_param :{
	accountType: 'HOSTED_OR_GOOGLE',
	Email : email,
	Passwd : password,
	'Content-Type': "application/x-www-form-urlencoded",
	service        : "reader"
      }
    };
    xhr.open('POST','https://www.google.com/accounts/ClientLogin');
    xhr.onload = function(){
      //AuthKey取得した後にその値をHeaderにセットして認証処理を行う
      var body = xhr.responseText;
      var matches = body.match(/Auth=(.*)/);
      var results = matches[0].split('Auth=');
      var auth_token = results[1];
      if(this.status===200){
	var auth = "GoogleLogin auth=" + auth_token;
	func(auth);
      }else{
	//認証通らない場合の処理
      }
    };
    xhr.send(config.login_param);
  },
  _get:function(auth,func){
    var xhr = Ti.Network.createHTTPClient();
    xhr.setRequestHeader("Authorization",auth);
    var baseUrl= "https://www.google.com/fusiontables/api/query?sql=SELECT+*+FROM+2415682&jsonCallback=callback";
    xhr.open('GET',baseUrl);
    xhr.onload = function(){
      var result = this.responseText;
      Ti.API.info('onload:'+ result);
      func(result);
    };
    xhr.send();
  }

};
// ui/style.js
exports = {
  app : {
    win : function(arg) {
      return {
	title : arg
      };
    },
    view : {
      backgroundColor : "#333333",
      color:'#ffffff'
    },
    label:{
     color:'#89C'
    },
    mapView:{
      mapType: Titanium.Map.STANDARD_TYPE,
      region: {latitude:35.700457, longitude:139.742207, latitudeDelta:0.01, longitudeDelta:0.01},
      animate:true,
      regionFit:true,
      userLocation:true
    },
    mapAnnotation:{
      pincolor:Titanium.Map.ANNOTATION_PURPLE,
      animate:true
    }
  }
};



(*1) 最近 Titanium+JavaScriptでiPhoneアプリ開発カフェという6回シリーズの勉強会をやっていて、4回目以降のお題として位置情報連携するアプリ作るというのをネタにしようと考えているから触ってみたというのが本音