hagino3000's blog

平成アーカイブス (更新停止)

PhoneGAPを使ったアプリケーションのコードをオンラインパッチで修正する

仕事でPhoneGAP使い始めて1ヶ月ぐらい経った。PhoneGAPを使ったiOSアプリケーションをリリース後にちょっと直したい時、AppStoreに再申請するのは面倒くさい。なので、なんらかの方法でパッチを当ててクライアントの動作を変更するのがセオリーだと思っているのだが、どうやるのがBestなのかイマイチわかっていない、とりあえず1時間ぐらい考えた結果を書いておく。

要件として一度取得したパッチは、次回以降アプリが起動した時には当っている状態にしたい。もちろん端末がオフラインの時にアプリが起動されたとしても同様の動作をしなければならない。あと、iOSのUIWebViewはHTML5のApplication cache APIが使えないので、別の方法を探す。

クライアントとサーバー、それぞれに持つ物

  • クライアント
    • 現在適用されているパッチバージョン、1stリリース時には0
    • 現在のソースリビジョン、svnとかのrevision
    • 保存したパッチファイル
  • サーバー
    • 最新のパッチファイル(patch.js)
    • 最新のパッチバージョン

パッチファイルの取得

なんらかのタイミング。applicationDidBecomeActive とか online とか1時間に一回とか適当に。
サーバーに最新のパッチバージョンを問いあわせて、自分の奴より新しいのがあったら取りにく。

パッチの適用

サーバーから取得したパッチをevalする。危ないのでパッチファイルはHTTPSで配布する。

ファイルはこんな感じ、Sencha Touchを使っている場合はExt.overrideという対象のクラスのメソッドを書き変えるための関数が用意されているので、それを使うとそれっぽい。

if (App.revision < 500) {
  // クライアントのソースRevisionが500未満の場合は
  // App.views.MainPanel#handleTapBackButtonを修正する
  Ext.override(App.views.MainPanel, {
    handleTapBackButton: function() {
      //
      // 新しい内容
      // 
    }
  });
}
App.currentPatchVersion = 2;

パッチの保存

サーバーから取得したパッチファイルは、次回以降のアプリケーション起動時にも使うためファイルシステムに保存する。ここはPhoneGAPのfileWriterを使う。

function savePatch(patchScriptStr) {
  window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);

  function gotFS(fileSystem) {
    fileSystem.root.getFile("patch.js", {create: true}, gotFileEntry, fail);
  }

  function gotFileEntry(fileEntry) {
    fileEntry.createWriter(gotFileWriter, fail);
  }

  function gotFileWriter(writer) {
    writer.onwrite = function(evt) {
      console.log("write success");
    };
    writer.write(patchScriptStr);
  }
}

保存したパッチのロード

ファイルシステムに保存したパッチはindex.htmlからスクリプトタグで読む様にしておく。こうするとonDevicecReadyまで待ってfileReaderを使って取り出すなんて事をしなくても良いし、アプリケーションの初期化処理の上書きもできる。

<!-- アプリケーションのコード -->
<script type="text/javascript" src="application.js"></script>
<!-- パッチファイル -->
<script type="text/javascript" src="../../Documents/patch.js"></script>

うごくけど

これがスマートなのかどうか判断がつかない。