おはようございます、五十川です。
先日GmailがGearsに対応してオフラインサポートを開始したのはご存知の通りですが、このとき久しぶりにGearsという名前を聞いたというかたも多いのではないでしょうか。
2007年5月のデベロッパーデーで鳴り物入りで登場したGears(当時の名称はGoogle Gears)でしたが、その後Gearsを積極的にサポートしたという話を聞く機会は決して多くありませんし、実際ウェブを検索しても決して多くの情報が見つかるわけではありません。
先日社内の定例のコードレビューで、他にネタがなかったのでしょうがなくGearsのデモアプリを作ってみたのですが、やはりGearsそのものに対する反応は芳しいものではありませんでした。
ちなみにそのとき作ったデモアプリは、モバイル端末を想定したオフライン対応のフィードリーダーで、データはローカルのSQLiteデータベースに保存され、、その更新はバックグラウンドで行われます。また、データがローカルにあるので、そのデモとして全文のインクリメンタル検索を用意していました(下図)。
なぜGearsはこれまで流行らなかったのか
デベロッパーがGearsでの開発に二の足を踏む理由のひとつは、別途にインストールが必要なブラウザプラグインであるという点でしょう。あるいはGearsの特徴のひとつであるオフラインサポートにしても、決してGearsが唯一無二の選択肢ではありません。
しかし最大の理由は、初期のGearsはそのオフラインサポートがあまりにも喧伝され、しかしこれを有効活用するアイデアが、なかなか思い浮かばないというところであったかと思います。
2008年6月11日付けでInfoQ Japanに掲載されている、“Google Gearsは、Webに機能を付け加えると言う位置づけになったのか?”という記事には、登場から1年経った当時のGearsに対する興味深いコメントが集められています(この記事の翻訳は、現時点で国内唯一のGearsに関する書籍である“Google Gearsスタートガイド”を著された白石俊平さんです)。
しかし、Dare(Obasanjo)は次のように主張する。
この一年間 ... アプリケーションをオフライン利用可能にする、と言う進化や熱意はそれほどなかった ...
Sarah Perezは、同じような主張を展開している。
今日の世界では、インターネット接続から遠く切り離される、と言う事がほとんどない。... 加えて、オフライン利用可能にする事は簡単ではない - それが、Webベースのアプリからデスクトップの世界への移行を行う、Web2.0開発者をあまり見かけない理由である... [そして]オフラインアプリは、オンライン状態ほどには良いサービスを提供できない。
ちなみに初期のGearsには不具合も多かったようです。溝畑考史さんはGears登場直後の2007年7月のブログエントリー“Google Gears を使って Game of Life を作る: その2 - Workerpool について”で、GearsのWorkerPoolについて以下のように書かれています。
(WorkerPoolは)エラーがあるときは、基本的に無言で Firefox ごと落ちます。それが精神的にも良くないし、問題の特定を難しくしています
そんなことされたら自分ならソッコー投げ出してますね。幸い今はこうした点は改善されていますが、もし今でもそうならこんなエントリーを書くこともなかったでしょう。
今やGearsはオフラインサポートのためだけのものではない
現時点でのGearsのバージョンは0.5.xとなっており、バージョン番号が示す通り初期のリリース以降主要なバージョンアップが5度行われ、その都度新しい機能が次々と追加されています。
初期リリース時(バージョン0.1)のAPI
Database | ローカルデータベース(SQLite) |
LocalServer | キャッシュ |
WorkerPool | バックグラウンド処理 |
以降バージョン0.5までで追加されたAPI
HttpRequest | 標準XmlHttpRequestの代替(主にWorkerPool用) |
Timer | 標準Timerの代替(主にWorkerPool用) |
Desktop | デスクトップ操作 |
Geolocation | 位置情報 |
Blob | バイナリ処理 |
このうちオフラインサポートで主に利用するのは初期からあるLocalServerとDatabaseだと思いますが(もちろんDatabaseはオフラインサポートだけに用途が限定されるわけではありませんが)、以降に追加された機能は、いずれもオフラインサポートに直接関わるものではありません。
また、Gears Wikiには今後予定されている/検討中のAPIがリストされており、Canvas、Notification、Audio、Camera、Database2などが挙げられていますが、その名称からも知れる通り、多くはやはりオフラインサポートとは無縁のものです。
これらのAPI群は一見それぞれバラバラな機能の寄せ集めのようですが、共通しているのは、オフラインサポートはもちろん、WorkerPoolによるバックグラウンド処理にしても、もっとわかりやすい例では、Desktop APIのopenFilesによる複数ファイルを選択可能なファイルオープンダイアログにしても、いずれも現在のブラウザの実装のままでは不可能なことを可能にするものであるという点です。
前述のInfoQ Japanの記事には以下の引用があります。
Googleのテクノロジーエバンジェリストを含む、Google Gearsを支持する多くの人たちが、ブラウザを強化しWebに機能を付け加えるものとして(ちょうど、Flashがそうであったように)、Gearsを位置づけるようだんだんと切り替わってきている。
TechCrunchの2008年10月8日の記事“Google Gearsを改めて検討する―狙いはオフライン機能だけではない”は、以下のような挑発的な書き出しで始まっています。
Gearsについては、ウェブ・アプリケーションをオフラインで利用することだけが(あるいは主にそれが)目的だという誤解が広まっているようだ。事実は、 Googleの野望はとてもそんなところに収まってはいない。Gearsのブラウザ拡張機能はそのような誤解をはるかに超えて多機能であり、広範囲な影響を与えるものだ。
ここで述べられているように、現在のGearsが志向しているのは、ブラウザの実装に不足している点を補う機能群の集合体です。さらに言えば、TechCrunchが指摘しているように、デスクトップアプリケーションが不要になる程の機能をブラウザに与えることであり、かつそれを、ブラウザベンダーの意向に左右されずに、あるいはGeolocation APIのように、モバイルキャリアへの配慮なしになし得るものとなることなのです。
今でも魅力的な機能を取り揃えているGearsですが、今後機能がより拡充されていくとやがてはGearsなしのウェブ開発など考えられない時代が来るかもしれません。
Gears入門
さてここまでコードがなくて寂しいので、以下GearsのDatabase APIとWorkerPool APIの簡単なサンプルを紹介しておきます。
Gearsを使う場合のお約束
Gearsを使う場合は初めにgears_init.jsを読み込ませます。これでGearsがインストールされていればwindow.google.gearsが生成されるので、なければインストールされていないと判断してGearsのインストールページへユーザを誘導してください。Gearsのインストールページは、クエリーストリングにパラメータを指定して表示をカスタマイズできます(カスタマイズ例)。
<script type="text/javascript" src="gears_init.js"></script> <script type="text/javascript"> if (!window.google || !google.gears) { var appName = 'Your application name'; var appMsg = 'Your message to users'; var appUrl = 'http://your-application-url'; var appIconUrl = 'http://your-application-icon-url'; location.href = 'http://gears.google.com/?action=install' + '&name=' + encodeURIComponent(appName) + '&message=' + encodeURIComponent(appMsg) + '&return=' + encodeURIComponent(appUrl) + '&icon_src=' + encodeURIComponent(appIconUrl); } </script>
Database API
GearsにはSQLiteが組み込まれており、Database APIによってJavaScriptから操作できるローカルのリレーショナルデータベースが利用できるようになります。以下のように、データベースの操作はお馴染みのSQL文で行います。プレースホルダーを使用する場合は、db.executeの二番目のパラメータにその値を配列で指定します。
var db = google.gears.factory.create('beta.database'); db.open('test-db'); db.execute( 'CREATE TABLE IF NOT EXISTS test_table' + ' (id integer PRIMARY KEY, content text, created_at integer)' ); db.execute( 'INSERT INTO test_table VALUES(NULL, ?, ?)', ['Hello World!', new Date().getTime()] ); var resultSet = db.execute( 'SELECT * FROM test_table' ); while (resultSet.isValidRow()) { console.log(resultSet.fieldByName('content')); resultSet.next(); } resultSet.close();
上は素のGearsのコードですがGears対応のO/Rマッパーも幾つか登場しています。ActiveRecord.jsは名前の通りJavaScriptによるActiveRecordの実装で、GearsのみならずアドビAir、アプタナJaxer、及びiPhoneなどのHTML5のデータストレージ対応プラットフォームに対応しています。
またGearsはアドビAirでも動作しますが、AirベースのGears用SQLite管理ツールが作られています。
WorkerPool API
WorkerPoolはJavaScriptで非同期のバックグラウンド処理を可能にするAPIです。バックグラウンド処理の効果については、マイコミジャーナル掲載の“"重たいJavaScript処理"もこれで解決! - Google Gearsのワーカプールを試す”にあるサンプルプログラムがわかりやすいので、お試しになってみてください。
以下のサンプルでは、ワーカーはワーカープールから送信されたテキストファイルのURL(以下では「fetch-me.txt」)にアクセスし、その内容をローカルデータベースに保存します。
まずワーカープール側のコードです。ワーカーは処理が完了すると、データが保存されているレコードIDとHTTPステータスコードから成るハッシュをワーカープールに送信するのですが、ワーカーとワーカープールがやり取りできるのは文字列だけなので、ハッシュはあらかじめ送信時にシリアライズされており、ワーカープールはeval()で文字列からハッシュを復元しています。2009年2月27日訂正: 現在は文字列以外にもBlobを含むさまざまな型をやり取りすることが可能になっており、またonmessageハンドラでは、第1パラメータ(メッセージ文字列)と第2パラメータ(送信者ID)の利用はdeprecatedで、代わって第3パラメータのメッセージオブジェクトを利用することになっています。以下コードはこれに合わせて修正しました。
var workerPool = google.gears.factory.create('beta.workerpool'); workerPool.onmessage = function(messageText, senderId, messageObject) { var db = google.gears.factory.create('beta.database'); db.open('test_db'); var resultSet = db.execute( 'SELECT * FROM test_table WHERE id = ?', [messageObject.body.rowId] ); if (resultSet.isValidRow()) { console.log(resultSet.fieldByName('content')); } resultSet.close(); }; var url = 'fetch-me.txt'; var worker = workerPool.createWorkerFromUrl('worker.js'); workerPool.sendMessage({url: url}, worker);
以前はワーカーを作成する際は、ワーカーの処理コード(つまり以下のworker.jsの内容)を文字列で指定する必要がありましたが、現在は処理コードを別のJavaScriptファイルに記述し、そのURLをcreateWorkerFromUrlで指定することができます。
以下は上のコード中で指定されている「worker.js」ファイルの内容で、これがこのワーカーの処理内容になります。
google.gears.workerPool.onmessage = function(messageText, senderId, messageObject) { var req = google.gears.factory.create('beta.httprequest'); req.onreadystatechange = function() { if (req.readyState == 4) { var db = google.gears.factory.create('beta.database'); db.open('test_db'); db.execute( 'CREATE TABLE IF NOT EXISTS test_table' + ' (id integer PRIMARY KEY, content text, created_at integer)' ); db.execute( 'INSERT INTO test_table VALUES(NULL, ?, ?)', [req.responseText, new Date().getTime()] ); google.gears.workerPool.sendMessage( {status: req.status, rowId: db.lastInsertRowId}, messageObject.sender ); } }; req.open('GET', messageObject.body.url); req.send(); }
ワーカーはバックグラウンドで動作するためwindowオブジェクトが存在しません。つまり普段常用している多くの機能が、ワーカーのコード中では使えません。そこでGearsでは主にワーカーで使用されることを想定した、こうした機能の代替となるAPIがいくつか提供されています。ここではXmlHttpRequestに代わるGearsのHttpRequest APIを使って、指定されたURLへのリクエストを行っています。また、HttpRequest APIはワーカーで使用されることを前提としているため、XmlHttpRequestに対して、responseXMLが存在しない、同期通信が行えないなどの制約がある一方で、バイナリーデータの送受信などの機能が追加されています。
2009年2月27日訂正: WorkerPoolのサンプルがdeprecatedなコードだったので修正しました。