以前自分でAndroid用のGPSロガーアプリを作っていたんだけど、収集した位置情報をAndroid内に持っていても特に面白いことが出来なくて悩んでた。
Android版のgoogle latitudeはもちろんサーバーに位置情報が溜まっているので、これを別の自分のサーバーから取得したほうが使い勝手がよい。
作ったもの https://github.com/shokai/google-latitude-logger
■google latitudeから位置情報を取る方法
GData APIからGoogle Latitude APIが使えるが、なんかわけがわからなかったのでgoogle latitude badgeからデータを取ることにした。
Google Latitude公開ロケーションバッジのページにgoogleアカウントにログインした状態で行き、「有効にして最新の現在地情報を表示する」にチェックを入れる。
webサイト用のembedコードから api?user=1234567890 の部分をメモする。
で、 http://www.google.com/latitude/apps/badge/api?user=1234567890&type=json を見ると自分の位置情報が書かれている。
位置情報を取得してMongoDBに保存するコードをlatitude-logger.rbに置いておいた。さくらVPSのサーバーで数分おきに動かして位置情報を保存している。
■保存した位置情報を使う
移動の方角と速度を計算してtwitterに投げるようにしてみた。
俺が元気に活動している様子がわかる。例えば、時速200km以上で西に移動するのが連続していたら新幹線に乗ってるのかなとか、そういう想像ができる。
位置情報をそのまま公開するのは気持ち悪いし危険だし誰も得しないので、何か加工して表示する必要があるのでちょっと抽象的な表現にしてみた。
地理的な知識があれば速度と方角だけでも結構何をしているかわかる。時速20〜40kmで東西に移動しているなら神奈川中央交通のバスに乗っているし、時速80kmぐらいだったら電車で東京に向かっている事が多い。けっこうわかる。
KMLで出力してGoogle Earthに表示してみた。これは先週木曜に学校に行こうとしてバスを乗り過ごして迷子になった時の移動のログ。
KMLファイルはAndroidで開いてもMapに描画されるので、サーバーで定期的に生成されてるようにしてあるからほぼ以前作ったAndroid用GPSロガーと同じ事ができている。
今後は俺が近くに来たら通知するアプリを作って配布しようかと思ったけどあまりうれしくないのでやめた。
iPhone JavaScript Console作った
作った → https://github.com/shokai/iphone-js-console
iPhone用のJavaScript shellのようなもの。FirebugやChromeの開発パネルみたいな感じで使う。
chrome拡張やiPhoneシミュレータでiPhone用のwebページの動作は確認できるが、加速度センサやGeo Location APIなんかは実機で動かさないとデバッグできない。
しかしデバッグをしようにも、iPhone上で大量のalertを出すと気が狂ってしまう。iPhoneで実行中のwebページ上の任意のオブジェクトの中身を、Macから覗いたり値を書き換えたり関数を実行したりするツールが必要だったので作った。
なお、Androidのブラウザにはwebsocketが無いのでこのツールは動かない。Androidではlogcatで
adb logcat | grep "^./browser" --color=autoすればconsole.log、console.errorの出力は見れるので、それで何とか我慢している。
■セットアップ
MacとiPhoneを用意する。MacとiPhoneは同じ無線LANの下に接続して、互いに通信できるようにしておく。
github.com/shokai/iphone-js-consoleからcloneしてくる。
iphone-js-console.jsをhtmlに読み込ませる。JsConsole.startで自分のMacに接続させるようにする。
<script src='iphone-js-console.js' type='text/javascript' />(あらかじめconsoleを起動するMacのIPアドレスは調べておこう)
<script type='text/javascript'>
JsConsole.start('ws://192.168.1.38:8088'); // Addr of Console Server
</script>
Macで、iphone-js-consoleを起動する
./iphone-js-console
iphone-js-consoleの起動時に、rubygemsが足りないという警告がでたら足りないgemをインストールする。
gem install eventmachine em-websocket多分これで足りる。
あとreadlineを使っているけど、Macの最初から入っているreadlineは腐ってた気がするので、brewかportsで入れるといい。(わからなかったら飛ばしても多分良い)
■使う
Macのiphone-js-consoleで
alert(document.title)と打つと、
このようにiPhoneのSafari上でJavaScriptが実行される。
また、iPhoneのSafariの変数を参照することもできる。
> window.navigator.appVersion
<1> "5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"
中身が複雑なオブジェクトは整形されて表示される。
> location
<1>
{"href"=>"http://192.168.1.38:8080/debug-sample.html",
"hash"=>"",
"port"=>"8080",
"protocol"=>"http:",
"origin"=>"http://192.168.1.38:8080",
"pathname"=>"/debug-sample.html",
"hostname"=>"192.168.1.38",
"host"=>"192.168.1.38:8080",
"search"=>""}
もちろん、エラーも出力される。
> homu
<1> "error : Can't find variable: homu"
> 1+2
<1> 3
> 1+
<1> "error : Parse error"
iPhoneのJSで、あらかじめ
console.log(foo);とか書いておけばもちろんMacのiphone-js-consoleにfooの値が表示される。
一度入力したコマンドは、キーボード上下で履歴を呼び出したりできる。
大変便利ですね。
■技術的なこと
iPhoneとiphone-js-consoleの接続にはWebSocketを使っている。EventMachine::WebSocketが便利だった。
iphone-js-consoleからiphoneへ送信された文字列は、そのままiPhone上でevalで実行させている。
iphoneからiphone-js-consoleへのオブジェクトの送信は、iPhone上でJSON.stringifyでシリアライズして送信して、iphone-js-consoleでparseして適当に整形して表示している。
別に難しいことはしていない。
targetはAndroid2.3.4、API 10向けにビルドして試した。
参考:
<uses-permission android:name="android.permission.INTERNET" />
import java.io.*;
import java.util.*;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
HttpClient client = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://localhost:8080");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("message", "ほむ"));
try{
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
HttpResponse res = client.execute(httppost);
ByteArrayOutputStream os = new ByteArrayOutputStream();
res.getEntity().writeTo(os);
Log.v("result", os.toString());
Log.v("status", res.getStatusLine().getStatusCode());
}
catch(Exception e){
e.printStackTrace();
}
リクエストができているかの確認は、EM::HttpServerで見た
gem install eventmachine_httpserver
#!/usr/bin/env ruby
require 'rubygems'
require 'eventmachine'
require 'evma_httpserver'
class Handler < EM::Connection
include EM::HttpServer
def process_http_request
res = EM::DelegatedHttpResponse.new(self)
puts "request_method : #{@http_request_method}"
puts "path_info : #{@http_path_info}"
puts "query_str : #{@http_query_string}"
puts "post_content : #{@http_post_content}"
res.status = 200
res.content = "こんにちは"
res.send_response
end
end
EM::run do
EM::start_server("0.0.0.0", 8080, Handler)
puts "http server start, prot 8080"
end
昨日、男の店主がメルマガで、「急に三田二郎を食べたくなったから昼の営業は休みます」「今神保町で二郎食べたけど、これから用心棒も食べるから夜は19時からになります」と言っていて面白かったから作った。
■インストール
gem install otokonoramen500yen
■使う
gem installすると、otokonoramen500yenというコマンドが使えるようになる。
otokonoramen500yen実行すると、最新のメルマガの日時と本文が表示される。
これでterminalで作業している時に、ブラウザを開かなくても今日営業しているかパッと調べられるので便利です。
■開発者向け情報
一応gemなので、本文と発行日時を取得できるようにしておいた。
例えば、センサーで取得した自身の健康状態と、男のらーめんの営業状態とを連動させた健康促進システムの開発などへの応用が期待できる。
require 'rubygems'
require 'otokonoramen500yen'
o = Otokonoramen500yen.get
puts o.date
puts o.body
puts o.url
2ヶ月ぐらい前に作った。blog書くのめんどくさくて放置してた。
http://glitchtweet.com
俺がやっているような素敵な装飾がついたツイートがだれでもできるwebサービスです。しかも気に入ったのがでるまで何度でもやりなおせる。
iPhoneやAndroidから使うことを想定している。
ライブラリ以外のコードを数えたら、286行しかなかった。
その他は以前作ったテキストに文字装飾を行うglitchtext.jsが500行ぐらい。sinatra、haml、jqueryのおかげでシンプルに書けた。
ソースはここにある
shokai/glitchtweet-web-app – GitHub
以下細かいことなどを書く
■ファイルサイズ
でかい。glitchtext.jsが辞書が巨大すぎて300kb以上ある。けどしょうがないし、まあキャッシュ効くからいいか
■サーバー
さくらVPSのdev.shokai.orgに、virtualhostでglitchtweet.com割り当てて使ってる。
■開発環境
まずglitchtext.jsはv8とRakeで単体でテストをしている。前に書いた。
glitchtweet.comのwebアプリ自体はローカルでwebrickで起動して、chromeの開発パネルでjsなどのデバッグをした。あとはiPhoneとAndroidのsafariのブラウザで開いて、見た目を調整した。
■なるべく画面遷移しない
jquery mobileやjQTouchを使うとネイティブアプリ風に外見で、横にスライドして表示を切り替えるwebアプリを作れるけど
面倒だったので使わなかった。visibleをon/offしてtweetボタンを表示したりしなかったり等している。
なのでviewのテンプレートは1つしかない。
■twitterログイン
生成したglitchテキストはoAuthでログインしてtweetされるが、ユーザ情報管理にDBは使っていない。
cookieにtwitterのoauth tokenとsecretを保存している。
最初の画面でログイン済みかどうかは、haml template上でtokenとsecretがあるかどうかだけで表示を分岐しているので、実際glitchtweet.com側では誰がどんなtweetをしているかは把握していない(しようと思えばできる)
■cookieでsession
sinatraでcookieベースのsessionを使うようにしている。
Rack::Session::Cookieを使う – 橋本詳解に書いた。
glitchtweet.comでは2週間cookieで保存するようにしている。
use Rack::Sessioin::Cookieしたらsinatraのsession関数がcookieを使うようになってくれた。
(これで大丈夫ですよね?)
■ホーム画面アイコン
<link href='http://glitchtweet.com/img/icon.png' rel='apple-touch-icon' />これをheadに書いておくと、iPhoneのホーム画面にブックマーク保存するとアイコンが付く。
Android2.3でもホーム画面にブックマークショートカットを作ったらアイコンが出るようになった。しかも角丸化される。apple-touch-iconって名前なのに処理してくれるAndroidえらい。
■テスト環境にwebrick使うようにした
開発中にSinatra1.2.1が出たのでupdateしたら、thinを使うとhttpリクエスト送った瞬間に問答無用で強制終了するようになった。
webrick使うようにした。
Sinatra1.2.1とthin1.2.10を同時に使うと死ぬ – 橋本詳解
■viewport
@hitoriblogさんに教えてもらった。
適当なhtml/cssを書いていてもiPhoneではそれなりに正しいサイズで表示されるんだけど、Androidではテキストエリアをクリックした瞬間にものすごいズームをされてしまう。
これはviewportをheadに指定しておくとなんとかなる。Androidはデバイスがたくさんあるので、画面サイズが微妙に違うのでwebサービス作ってる人は大変そう。
<meta content='width=device-width, user-scalable=no' name='viewport' />このへんも参考になる。
■shakeイベント
ネイティブアプリではshakeのイベント、つまりiPhone本体を振ったイベントを取得して、undoに使われている。
全く、操作と実行内容の関連付けが最も意味不明な機能だと思う。
でもiOS4.2からsafariでも加速度センサーが使えるようになったので、せっかくだからshakeイベントを取れるjsライブラリを作った。
shokai/js-iphone-shake-event – GitHub
glitchtweet.comでも使っている。tweet後に、もう一度同じソースからglitchしたい時にshakeすると消えた文字が復元される。
これについてはあとで書く。
■iphone-js-console
shokai/iphone-js-console – GitHub
iphone-shake-event.jsを作っている時に、iPhone実機でのデバッグをする為に作った。
パソコンのterminal上でjsを書くと、iPhone上で実行されたり、パソコン上でiPhoneのブラウザ上のjsの値を読み出したりできて便利。
これについてもあとで書く。