AngularJSとChrome Appsで東京アメッシュアプリ作った

冬休みにTokyo Ameという東京アメッシュのChrome Appsを作ったけど、ブログに書くの忘れてた。Chrome AppsなのでChromeからインストールしてデスクトップで使える。iOS/AndroidはChrome Appsがサポートされていないので対象外。

インストールは ここ から。

Tokyo Ame

東京アメッシュの非公式アプリはいくつかあったけど参戦して作ってしまった。動機としては「雨があまり降っていないときに帰社したい」という自分の要求があって、東京アメッシュのサイトで毎回拡大マップにして会社付近に地図を移動するのが面倒だったので、前回の表示位置を保存して引き継いでくれるだけものが欲しくなった。

さらにChromeしか考慮しなくていいこと、機能としては小さいことからAngularJSの勉強という目的でも作った。今更AngularJSってのは微妙だったが小さなアプリだし一回作ったらほとんど機能追加しなくていいアプリということで採用した。

以下、開発の感想文。

ソースコードはGitHubにアップ。
makotokw/crx-tokyo-ame

AngularJSとの格闘

昨年AngularJS勉強会に参加したんだけど、今回作ってみてすぐに本質は何も学んでいないことに気がついた。勉強会ではJavascriptを使わなくても出来ることは学んだけどいざアプリをつくろうとするとそういうわけにもいかず、まるでiOSでStoryBoardしか学んでいないような状態だった。

Javascriptの実装についてはAngularJS本家のドキュメントや本を読んで勉強した。局所的な仕様はわかるがアプリとしてどうやって設計するかがよくわからず、作法を理解して実装しようとしたので大分時間がかかった。例えばファイル階層どうするかだけでも大分悩んでいた。時間的にみると大体AngularJSの勉強8:アプリの開発2みたいな割合。

ある程度ドキュメント読んで基本がわかった後にGoogle Drive とかAngularJSで実装されたアプリを読むと理解が深まった。(Build Apps with AngularJS)

最終的にTokyo AmeアプリではModelクラス的なものは用意せず、データはただのObjectで持ってカテゴライズした機能をServiceで定義して使うようにした。

Chrome Extension

最初Chrome Extensionでつくろうとしていた。特にChromeのAPIは必要なかったのでYeoman generator for AngularJSを使ってただのhtml5アプリとして作ってそれをChrome ExtensionのPopupページに移植するという形をとった。

しかし、出来たChrome Extensionをいざ使ってみると、毎回ポップアップを開いて画像のロードを待つのが苦痛になった。すぐにChrome Appsに移植した。

Chrome Appsが別人

Chrome Appsは俺が知っているChrome Appsではなくなっていた。初期のChrome Appsは外部のWebのURLを単にパッケージすることも出来たけど、最早それは過去の産物でPackaged Appsはレガシー扱いになっていた。

今回使ったChrome AppsのManifest Version 2のものはどちらかというとNW.js(node-webkit)atom-shellのようなデスクトップアプリを作るツールになっていた。

今回はデスクトップアプリとして常駐するのが要求に適していたのでChrome Appsが良かった。

新Chrome Appsの洗礼

同じManifest Version 2同士だからChrome ExtensionをChrome Appsにするのはそれほど苦労しないだろうと思っていたが少し甘かった。

Chrome Extensionに限ったことではなくhtml5アプリをChrome Appsにするにはいくつかハマるポイントがある。今回ハマッたのは以下の二つ。

  • localStorageの扱い
  • CSPの扱い

localStorageの扱い

Chrome Appsでは window.localStorageが使えない というのが最初の洗礼だった。chrome.storageを使う必要がある。これはオプションによってGoogleアカウントで保存データを共有できるなどの機能もあるがクラウドに送信することも考慮して読み書きが 非同期 になっている。window.localStorageは同期なので変更が必要になった。

今回はマップの状態の保存が重要な機能だったのでoption.jsをAngularのServiceで定義していたのが幸いしてそこで吸収することができた。非同期処理が終わったらメッセージを投げてControllerで更新するという形。

window.localStorageの呼び出しが散らばっているとChrome Appsへの移行は大変になる。

CSPの扱い

Content Security Policyで画像が表示されなかった。ログにエラーが出ていたので「はいはいCSP、CSP」と思って設定しようとしたら Chrome AppsではContent Security Policyが変更できない というのが次の洗礼だった。(Content Security Policy)

その変更できないデフォルトのCSP設定では動画の参照は許されているが、外部の画像の参照が許されていない。

これはImage要素における制限なので回避策としてはXMLHttpRequestで画像URLのデータを取得してImage要素に渡すか、WebViewを使うというものがある。(Referencing external resources)

画像を重ねるなど制御が必要なので前者を選択した。XMLHttpRequestでデータを取得するためアプリ側で雨情報の画像データをキャッシュ管理できるようになったのでそこは良かった面ではあった。

苦労はしたが

結果としてはAngularJSとChrome Appとの格闘に大部分の時間を費やし、アプリケーション本体に注力することはできなかった。まあそれは初見では仕方がないことなので苦労した分、次回使う際には役に立ってくれるだろう。

Webの技術でデスクトップアプリを作る際にChrome AppsがNW.jsやatom-shellに並んで選択肢になるということを知れたのは大きかった。

Chrome Appsは制約もいろいろあるがStoreで公開できたり、アップデートが容易な部分は魅力でもあるので機能が少なければ十分選択肢になってくると思う。あと、試してないけどChromeOSでも動くのかな。