銀色うつ時間

思い出すたび何か胸につっかえてるだけ

Progressive Web Appsについて

ドワンゴ Advent Calendar 2015 4日目の記事です。最近ちらほら耳にする、Progressive Web Appsというものについて。

Progressive Web Appsとは

Progressive Web Appsは、モバイルWebを開発する上での1つの標榜である、という認識でよさそう。Alex Russell氏がブログで提唱したのが始まりで、先日行われたChrome Dev Summitのkeynoteでも取り上げられている。

medium.com

www.youtube.com

Progressive Web Apps自体は特に何か新しい技術を指すわけではなく、既存の技術の組み合わせに対して名前をつけただけのいわばマーケティングワードみたいなもので、つまるところ「◯◯と☓☓を組み合わせて作られた、よりアプリっぽい快適な動作をするWebアプリ」のことをProgressive Web Appsと呼びましょう、これからのWebはそうやって作っていきましょう、という宣言のようなもの。上記エントリでは次のように表現されている。

they’re just websites that took all the right vitamins.

こういった考え方が出てきた背景には、モバイルでの開発を取り巻くいくつかの課題が存在している。

とりあえずアプリ作ればいいと思ってませんか?

ネイティブアプリは確かに使いやすいしユーザとのエンゲージメントも高いけど、インストールされなくては意味が無い。ユーザが1ヶ月で利用する平均的なアプリの数は25個程度で、他のアプリとその枠を巡ってしのぎを削らなくちゃいけない。あなたのアプリは果たして、ストアに存在する膨大なアプリの中から検索され、インストールされ、実際に起動される、その25個の中に入れるだろうか。また、iOSAndroid、その他プラットフォームも含めてそれぞれで開発しなくてはならないし、保守コストに関しても馬鹿にならない。

ネイティブアプリの方が便利じゃないですか?

問題点として、モバイルにおけるWebアプリが根本的にイケてないということが挙げられる。ネイティブアプリよりレスポンスが遅い・タッチした後のフィードバックが作りこまれていない、オフラインで利用できない、プッシュ通知がない、ブラウザはタブが使いにくい等、考えればきりがない。

Progressive Web Appsが解決するモバイルWeb

上記問題に対して、TitaniumやXamarin、PhoneGapなど複数プラットフォームで利用できるハイブリッドアプリの開発が考えられるが、それはプラットフォームごとに開発するコストを減らすのみで、デプロイが楽になるわけでもないし、ストアからインストールされる可能性を上げてくれるわけではない。もっとも、開発コストを減らしてスピーディーに開発ができているかは、実際にハイブリッドアプリからネイティブに書きなおした事例なんかを考えてみると、有用な場面はかなり限定されると思う。

そこで提唱されているのが、HybridではなくProgressiveなWeb Apps。各プラットフォーム上で動くハイブリッドアプリを作るよりも、Web上で動作するアプリケーションを作っていく方が、よりネイティブアプリに近い動きを実現し、またユーザが利用する機会も増やせるのではないかという仮説に基づいている。WebをWebたらしめる性質なので当たり前だが、Web上にホストしてインストール不要で使えること、ハイパーリンクが利用可能であることなどを考えると、ユーザが利用する上でも、アプリケーションを提供する側としても扱いやすいし、プラットフォームごとに開発するコストやストアという仕組み上の制約(上記インストールまで到達する困難さ、課金システム、表現上の問題など)を考慮する必要がないことは大きなメリットとなり得るように思える。App Indexで最近アプリも載せられるようになってきたけど、検索インデックスを利用することもできる。

Webアプリが"appy"になるために必要なテクノロジー

下記のような機能を用いて、よりネイティブらしいアプリケーションを提供する。先に紹介したAlex氏のエントリや動画を見ると他にも列挙されているが、ここではより重要と思われるもののみ抜粋している。

  • Responsive Web Design
  • Service Worker(オフラインでの利用を想定)
  • ネイティブアプリのようなUIとインタラクション
  • Push Notification on the Open Web(Webアプリでのプッシュ通知)
  • App Install Banners(いわゆるブラウザが提供するホームに追加)

Responsive Web Design

割愛。

Service Worker

一応Service Workerについて軽く説明。Service Workerは通常のWebページのとは独立したサイクルでjsの実行コンテクストを提供する、イベント方式の機能。リクエストをフックしてキャッシュから応答したり、サーバのイベントを受けてそれをクライアントに通知するといった、クライアント用proxyとして利用できる。Service WorkerはHTTPSもしくはlocalhostでしか利用できないので、遊びで使うならgithub pagesなどを使うのが遊びではよさそう。デバッグしづらいので、作業はシークレットモードで行った方がよい。まあとにかく、Servie WorkerはProgressive Web Appsのコアとなる技術で、以下のような役割を果たす。

  • 静的ファイルをキャッシュすることで表示速度を改善する
  • サーバから取得したデータをキャッシュすることで、オフラインでの利用が可能になる
  • PUSH通知を受け取る
  • Service Workerを利用する = TLSでの通信が行われることなので、安全性を高められる

http://www.w3.org/TR/service-workers/

Web App Manifest

アプリに関連するメタデータを記述したjsonファイルをサーバに置くことで、それらの情報をブラウザやクローラが解釈してくれる。Service Workerと併用することで、プッシュ通知やホームに追加が実現できる。

https://w3c.github.io/manifest/

Offline Use

Service Workerを使ってfetchイベントをキャプチャし、キャッシュが存在すればそれを返し、なければネットワークから取ってくる、といった動きが実現できる。これによって、1度閲覧したページはキャッシュされ、オフライン状態でもキャッシュから表示ができるようになる。

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        if (response) {
          return response;
        }

        var fetchRequest = event.request.clone();
        return fetch(fetchRequest)
          .then(function(response) {
            if (!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }

            var responseToCache = response.clone();

            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });

            return response;
          });
      })
  );
});

Push Notification

ブラウザからのPUSH通知。facebookなんかはもう実装されていた気がする。今回時間の問題で実装できなかったが、概ね以下のような手続きのはず。

  • GCMを使うためにGoogle Developer Consoleの利用登録してプロジェクトIDを取得する
  • manifest.jsonに書く
  • Service Worker登録
  • pushManagerを利用してsubscribe
  • Service Worker側でpushイベントをlistenする 

App Install Banners

バナーの追加UIを表示させる

  • manifest.jsonの配置
  • ServiceWorkerの登録

manifest.jsonに以下の値を設定する。

{
  "name": "a progressive web app for cats",
  "short_name": "PWA for cats",
  "icons": [{
        "src": "images/touch/ms-touch-icon-144x144-precomposed.png",
        "sizes": "144x144",
        "type": "image/png"
      }],
  "start_url": "/?homescreen=1",
  "display": "standalone",
}
  • iconは144*144サイズのものが必要
  • start_urlはホームから起動したときのURL
  • displayは起動時の表示方式。ネイティブアプリのようにブラウザとは別のタスクとして扱うことが可能
  • Service WorkerはregisterしていればOK

その他

他にも、ページ内のコンテンツとUIの部分を分けてUIのみ先に描画する工夫であったり、ブロッキングを行う読み込みをasyncなどを用いて改善するといった対応が必要。以下のページにこのあたりの改善方法についても書かれている。

Instant Loading Web Apps With An Application Shell Architecture | Web Updates - Google Developers

今回のサンプルは以下

sisidovski/progressive-web-app-sample · GitHub

事例

Flipkart.lite

以前ちょっと話題になっていた、インドのECサイトFlipkartのWebアプリケーション。 通信インフラが整っていない途上国はこういった軽いページに対する需要が高そう。

stories.flipkart.com

Pokedex.org

Progressive Web Appsとして作ったポケモン情報まとめ。パフォーマンス向上のためのテクニックがすごい。60fpsで動作させるための工夫が細かく説明されている。

www.pocketjavascript.com

まとめ

業界全体が「お陰さまで合計◯◯ダウンロード!」とか煽ったりしているしネイティブから脱却するとかは全く思わないけど、ネイティブアプリの市場が成熟しつつある中で、ネイティブ風というだけでなくWebらしさを活かしていくことがモバイルWebの流れとしては出てきたのかなと感じた。Progressive Web Appsに限らずiOS9のSearch API関連(Universal LinksやSpotlightによる検索)も含めると、アプリとWebの境界が曖昧になるというトレンドが浮かび上がってくる。この辺りの話は、先日のmosaic.fmがとても面白かったので未聴の方は是非聴くとよいと思う。

#20 Browser | mozaic.fm