ブラウザアプリで、大量のデータをオフラインで持ちたい


どうも、社内SEに無事転向しました。
のんびりした開発というか、思い切りのんびりした感じで、逆に自分の中でメリハリつけないと大変そうだなぁと思いながら、いろんな要望を聞いています。

で、今回のこれ。

ブラウザアプリで大量のデータをオフラインで持ちたい

※ブラウザはIE、あとiPadに対応させてほしい

chrome縛り可であれば、serviceworkerでなんとでもなるのですが、この条件だと、使える技術が限られます。

  • オフラインはappCacheで
  • そのオフラインデータとやらは、IndexedDBで

ぐらいが妥当な線だと見て、生まれて初めて取得する盆休み中にいじってみました。

先に結論

 十分使える。むしろ自分用ツールをこれに載せたレベル。

実装

appCacheの書き方

まず、HTMLタグに、appcacheを使用することを宣言します。

index.html
<html manifest="manifest.appcache">

肝心のappcacheの定義は以下のような感じ。

manifest.appcache

CACHE MANIFEST
# Version: 1

CACHE:
./count.php
./fonts/MaterialIcons-Regular.eot
./fonts/MaterialIcons-Regular.ijmap
./fonts/MaterialIcons-Regular.svg
./fonts/MaterialIcons-Regular.ttf
./fonts/MaterialIcons-Regular.woff
./fonts/MaterialIcons-Regular.woff2
./styles/materialicons.css
./js/jquery-2.2.4.min.js
./js/riot+compiler.min.js
./js/kl.js
./js/kl.location.js
./js/kl.dom.js
./js/kl.cache.js
./js/kl.syncidb.js
.       :必要なファイルを列挙
./riot/raw.tag
./styles/main.css
./manifest.json

NETWORK:
*

この中でも、

NETWORK:
*

は絶対に忘れないようにしましょう。
どうすることもできなくなります。

次に、HTMLで、BODYが始まった瞬間に、以下のscriptを入れます。
このscriptタグは、このscriptタグだけで終わらせます。

index.html
<body>
    <script>
        var cache = window.applicationCache;
        cache.addEventListener("updateready", function() {
            alert('アプリケーションの新しいバージョンが利用可能なため、更新します')
            cache.swapCache();
            location.reload();

        });
        cache.addEventListener('noupdate', function() {
            //alert('アプリケーションは最新です');
            //cache.swapCache();
            //location.reload();
        });
        if (navigator.onLine) {
            try {
                cache.update();
            } catch (e) {
                console.dir(e);
            }
        }
    </script>

これがないと、iOSで詰みます。
更新できなくなります。怖い。

以上で、オフラインアプリがざっくり作れました。
アイコンとか色とか設定したい場合は、manifest.jsonとか同時に使えます。
サービスワーカーは同時に使えません。

IndexedDBを使う。

 まず、どうしてIndexedDBか。

  • 想定しているファイル量がどう聞いても5M超えそう。
  • 限界突破できるのは、IndexedDBだけ。
  • IE10以降、Mobile Safari8以降縛りだけど、許してね。

 って感じで。

  • どうせ、こういうDBでデータ持つんなら、配信の仕組みいるよな。(a)
  • 配信の仕組みで更新しきれなかったものがもし存在すれば、サーバに送る、ってすれば、もしかしてサーバの情報を、更新しちゃえる?(b)
  • サーバの情報を、別の端末で受信したときに、(b)で(a)が更新されて、あたかも同期できちゃう?
  • あ、じゃあ完全にオフラインアプリになるじゃん。データも。

 みたいな発想から双方向にしました。

 これはコードが長くなったので、githubに置きました。
 https://github.com/zrelyydereva/syncedIndexedDB

 こんなやりとりしてます。

サーバ - クライアント
list sync
list →ID,リビジョン一覧→ indexedDBで比較
put ←自分のほうが新しいもの← --
put  :  --
put ←自分のほうが新しいもの← ---
get ←自分のほうが古いもののID一覧← 比較し終えて残ったもの
get →データ(配列)→ indexDBに保存

 正直、appCacheだけでは眉唾だった、過去のHTML5でのオフラインアプリ!みたいなキャッチで作られたHTML5アプリを見てきたので不安はありましたが、スマホなんかがどんどん外堀を埋めてきてくれた結果、割とすごいのが作れる時代になりましたね。