2010年7月7日水曜日

Google tasks にアクセスするたったひとつの冴えたやりかた。


ごめんなさい。タイトルは書いてみたかっただけです。



もっと冴えたやり方があるかもしれませんし、たった一つではないと思います。

追記2012-3-21
Google側の仕様変更なのか以下の方法は使えなくなりました。
どうもAPIがリリースされた時点で使えなかったようです。
素直にAPIを使うのが吉という感じです。

追記2011-06-18
Googleから公式のAPIがリリースされました。

Developer's Guide (v1): Using the API - Google Tasks API





AndroidのJAVAでGoogleTasksにアクセスしたかったのですが、検索の仕方が悪かったのか、


日本語の情報がまったく見つからなかったので、調べて、書いてみました。



FireFoxの RestTest と LiveHTTPHeaders という拡張を使って調べた結果です。







やり方は単純です。



1.ClientLogin で トークンを取得。



2.色々POSTする。



3.結果をパースして、使う。



です。











1.ClientLogin で トークンを取得。



ClientLoginするときの serviceは、goanna_mobile です。



トークンを使ってPOSTするURLは https://mail.google.com/tasks/r/d です。



トークンを使ってPOSTするとき、Cookie: GTL=と使います。





この3つの情報を探すのに、すごく手間取りました。





詳しくは、こちらです。



http://code.google.com/intl/ja/apis/accounts/docs/AuthForInstalledApps.html











2.色々POSTする。



共通の設定。



HTTPUrlConnectionの設定。FilreFoxから抜き出しました。まだ削れる部分がありそうです。



conn.setRequestProperty("HOST", "mail.google.com");
conn.setRequestProperty("User-Agent", "<アプリの名前>");
conn.setRequestProperty("ACCEPT", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
conn.setRequestProperty("Accept-Language", "ja,en-us;q=0.7,en;q=0.3");
conn.setRequestProperty("Accept-Encoding", "deflate");
conn.setRequestProperty("Connection", "keep-alive");
conn.setRequestProperty("Keep-Alive", "115");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
conn.setRequestProperty("Accept-Charset", "Shift_JIS,utf-8;q=0.7,*;q=0.7");
conn.setRequestProperty("AT", "1");
conn.setRequestProperty("Cookie", "GTL=" + authToken);




一番下の行で1.で取得したTokenを使っています。



レスポンスをgzipで取得することもできるようですが、面倒なのでAccept-Encodingからgzipをのぞいています。







各動作でのPOSTする内容について。



list_idは 11111111111111111111:0:0 と書いています。桁数は合っています。



各タスクのIDの先頭も list_id と同じ値が入っているので同じように書き換えています。



時間を表す部分に矛盾があるかもしれませんが、メモしてあったものを使っているからです。桁数自体は合っています。



action_id の値は、一つのPOSTごとに1ずつ増やしていくと上手くいきました。例であげているのは、適当になっています。



client_versionの値については、詳細不明です。同じクライアントを使っていても、たまに変わっているのですが、古いまま使っても、問題ありませんでした。



メッセージの内容をUTF8でエンコードし、先頭に r= とつけてPOSTします。r= の部分はエンコードしません。



リストの取得以外の場合に"latest_sync_point"が必要です。はじめにリストを取得して、"latest_sync_point"の値を取得するのが良いと思います。



以下に、各動作時にPOSTする内容を列挙していきます。





リストの取得


ゴミ箱に入っていないタスクのみを取得。get_deletedをtrueにすると、ゴミ箱の中のタスクも同時に取得されます。



POST


{"action_list":[{"action_type":"get_all","action_id":"1","list_id":"11111111111111111111:0:0","get_deleted":false}],"client_version":12694550}


Response


{"latest_sync_point":1278435430697000,"response_time":1278435437,"results":
[],"tasks":
[{"id":"11111111111111111111:0:169","last_modified":1278263172434,"name":"
ウィジェットの実装","type":"TASK","deleted":false,"list_id":
["11111111111111111111:0:0"],"completed":false},
{"completed_date":1278435430682,"id":"11111111111111111111:0:168","last_modified":1278435430682,"name":"
掃除する","task_date":"20100707","notes":"ノートです
よ。","type":"TASK","deleted":false,"list_id":
["11111111111111111111:0:0"],"completed":true},
{"id":"11111111111111111111:0:159","last_modified":1277798052273,"name":"","type":"TASK","deleted":false,"list_id":
["11111111111111111111:0:0"],"completed":false}],"user":
{"id":"11111111111111111111","show_tips":false,"auto_clear":false,"mobile_default_list_id":"11111111111111111111:0:0","requested_list_id":"11111111111111111111:0:0","default_list_id":"11111111111111111111:0:0"},"groups":
[],"lists":[{"id":"11111111111111111111:0:0","child_entity":
[{"id":"11111111111111111111:0:169"},
{"id":"11111111111111111111:0:168"},
{"id":"11111111111111111111:0:159"}],"last_modified":1278435400129,"list_metadata":
{"1":2222222222222},"name":"リスト","type":"GROUP"}]}


改行を入れてます。


2つのタスクがあり、2つ目に完了済み、日付設定、ノートありのタスクがあります。



latest_sync_point 最終更新日時(マイクロ秒単位unix time)



response_time 最終取得日時 (ミリ秒単位unix time)



completed_date タスクを完了済みにした日時 (ミリ秒単位unix time)





2つ目のタスクのみを切り出しました。タスク名は"掃除する"で、日付は2010-07-07、ノートの内容は"ノートです"、完了済みになっています。





{"completed_date":1278435430682,"id":"11111111111111111111:0:168","last_modified":1278435430682,"name":" 掃除する","task_date":"20100707","notes":"ノートです よ。","type":"TASK","deleted":false,"list_id": ["11111111111111111111:0:0"],"completed":true}







リストの取得(完了済み)


POST



{"action_list":[{"action_type":"get_all","action_id":"5","list_id":"11111111111111111111:0:0","get_deleted":false,"date_start":"1970-1-1","get_archived":true}],"client_version":12694550}






新規作成

名前無しのタスクをリストの一番上に追加しています。


indexで追加する場所を指定しています。



POST


{"action_list":[{"action_type":"create","action_id":"1","index":0,"entity_delta":{"name":"","creator_id":null,"entity_type":"TASK"},"parent_id":"11111111111111111111:0:0","dest_parent_type":"GROUP","list_id":"11111111111111111111:0:0"}],"client_version":12694550,"current_list_id":"11111111111111111111:0:0","latest_sync_point":1276482255896000}




Response



newidの値が新規作成されたタスクのIDです。


{"latest_sync_point":1276695762607000,"response_time":1276695762,"results":[{"result_type":"new_entity","action_id":1,"new_id":"11111111111111111111:0:92"}]}












タスクの変更


名前、日付、ノート、 完了済みが同様の内容です。



ですが、完了済みを同時に行うことはできないようです。



idで指定したタスクの名前、日付、ノートを変更しています。





POST


{"action_list":[{"action_type":"update","action_id":"2","id":"11111111111111111111:0:88","entity_delta":{"name":"Test08","task_date":"20100614","notes":"Test NOTE"}}],"client_version":12694550,"current_list_id":"11111111111111111111:0:0","latest_sync_point":1276498048979000}




完了済みにするときは、"completed":trueを入れます。上にも書いた通り、なぜかこれだけは、単独でないとエラーが出ました。





Response


{"latest_sync_point":1276699757842000,"response_time":1276699760,"results":[]}




レスポンスの種類は、リスト、新規作成、変更の3種類しかありません。







タスクの削除


これも、変更と同じ書式です。





POST


{"action_list":[{"action_type":"update","action_id":"1","id":"11111111111111111111:0:108","entity_delta":{"deleted":true}}],"client_version":12694550,"current_list_id":"11111111111111111111:0:0","latest_sync_point":1276740340868000}




Response


{"latest_sync_point":1273146284799000,"response_time":1273146284,"results":[]}














以上です。



ツッコミ歓迎です。











追記



一番最初にリストの取得をすることになると思うのですが、そのときに必要なリストIDは



https://mail.google.com/tasks/canvas?pli=1



このURLから取得できます。





さらに追記


アイテムのIDですが


11111111111111111111:0:108


前の部分がアカウントごとのIDで、次がリストのIDで、最後がタスクのIDになっています。


今、存在しているリストの数ではなく、今までに作ったリストの数で順に増えていっています。



さらに追記です。

コメント欄で INSE さんが書いてくれてます。

Thanks INSE !!



タスクを他のリストに移動させる。


{"action_list":[{"action_type":"move","action_id":"1","id":"11111111111111111111:0:6","source_list":"11111111111111111111:0:0","dest_parent":"11111111111111111111:1:2","dest_list":"11111111111111111111:1:0"}],"client_version":12743913,"current_list_id":"11111111111111111111:0:0","latest_sync_point":1290777906645000}

id が対象のタスク。
source_list が元のリスト。
dest_parent が移動先の位置(上の例では、3番目に入ります)。
dest_list が移動先のリスト。





ついでにこちらも。


完了したタスクを表示しない。

{"action_list":[{"action_type":"update_user","action_id":"2","clear_list_ids":["11111111111111111111:0:0"]}],"client_version":12743913,"current_list_id":"11111111111111111111:0:0","latest_sync_point":1290779844183000}