昨日5/18(木)、節煙サポートアプリ「Smoking Note」をアップデートしました。
V1.2.3 アップデート内容
- [前回の喫煙記録] のグラフを追加
- グラフ画面のブラッシュアップ
- Android 4.4 以前のバージョンに対応
今回のアップデートのきっかけは、アプリが動作しないというレビューを頂いたことです。ついでに、前から考えていたグラフの追加、さらにデザインの改良(自分的に)を行いました。ひさしぶりのブログ更新ということもあり、ついでのついでに今回の作業を記録に残しておきたいと思います。
経緯
先週アプリが動作しないというレビューを頂きました。OS は Android 4.2。一応 Android 4.4 以前のバージョンでも動作するように最初から作ってきたつもりだったのですが、Android 4.4.2 しか持っていないため、それ以外の実機では動作確認していません。瞬間「すみませんが対応していません」で済まそうかと思ったのですが、なぜ動かないのかが気になりました。そこで、弟が Android 4.2 だったことを思い出し連絡したところ、一週間前にスマホを新しく買い替え、前のスマホは手元にとってあると。なんというタイミング!ということで、スマホを送ってもらいました。福岡から岩手北部へ。送料?し、知りません。
デバッグ開始
届いたスマホを確認すると既に Smoking Note がインストールされていました。ラッキーと思いアプリを起動。ボタンを押してみると。。。動かない。ぴくりともしない。完全に固まってらっしゃる。アプリのバージョンを確認すると最新版。
とりあえずデバッグビルドでAPKを構築しインストールしてアプリを起動すると。。。動いた!この時点でファイルアクセスがあやしいとあたりを付け(初回はファイルアクセスがないため)、「alert文を埋め込みAPK構築 -> インストール -> 実機確認」を繰り返しました。このスマホには通信機能がなく Monacaデバッガは使えないし Chromeインスペクタもなぜかアプリを認識しないので、これしか方法が思いつかなかったのです。原始的な方法で手間もかかりましたが、それでもなんとか原因にたどり着きました。
原因
犯人は Blob (Binary Large Object) コンストラクタでした。
以下はテスト用のソースとalert出力画像です。
ons.ready(function() {
window.alert("Blob: " + Blob); // (1)
try {
var blob = new Blob(["Hello"]); // (2) ここで例外が発生!
window.alert("new: " + blob); // (3)
} catch(e) {
window.alert("error: " + e); // (4)
}
});
(1)のalert。とりあえず Blob は実装されてる?
(4)のalert。Blob コンストラクタの実行(2)で例外が発生し、catchに飛んできたところでエラー情報を表示。ちなみに(3)のalertは実行されない。
Can I use…で調べてみましたが、Blob コンストラクタが「Android 4.4 では使えて 4.2 では使えない」とは見えないような気が。。。うーん、見方が悪い?
対策
Android の OSバージョンを調べて、Android 4.4 以上の場合と 4.4 以前とで処理を分けました。Crosswalkプラグインを入れてWebViewを新しくすると動くのかちょっと気になりましたが、サイズがかなり増えるのでもし動くとしても本アプリでは採用しないと考え試してません。
OSのバーションを調べる方法は、Cordovaプラグインを使うとプライバシーポリシーがめんどくさそうだったので、userAgentから取得することにしました。
私の実機の userAgent の値は次のようになっていました。
- Android 4.2
- Mozilla/5.0(Linux; U; Android 4.2.2; ja-jp; SO-04E Build/10.3.1.B.2.48) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
- Android 4.4
- Mozilla/5.0(Linux; Android 4.4.2; SO-02E Build/10.5.1.B.0.155) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36
ここから Android のバージョンをとってきて処理を分岐させます。
ソースは以下のようになりました。
/***
* Android バージョン取得
* 文字列ではなく数字で返す(Android 4.4.2 の場合は、「4.4」と返す)
*/
function getOSVersion() {
var version = 0;
var ua = navigator.userAgent;
var idx = ua.indexOf("Android");
if (idx > 0) {
version = parseFloat(ua.slice(idx + "Android".length + 1));
}
return version;
}
/***
* ファイル書き込み
* 指定したコンテンツをファイルに書き込み、コールバックを呼び出す
* ファイルが存在しない場合は、新しいファイルを作成する。
*/
function writeTextFile(path, contents, callback) {
fsDirEntry.getFile(path, {create: true, exclusive: false}, function(entry) {
entry.createWriter(
function(writer) {
var size;
if (Math.floor(getOSVersion() * 10) < 44) {
writer.write(contents); // Android 4.4以前では直接書き込む
size = contents.length;
} else {
var blob = new Blob([contents]);
writer.write(blob); // Android 4.4以上ではBlobを書き込む
size = blob.size;
}
--- (略) ---
}, function(e) {}
);
}, function(e) {});
}
この対策により、Android 4.2 と 4.4 の両方で動くようになりました。
おまけ
Blob とは別件ですが、Android 4.2 で CSSファイルの内容が反映されない事件も起こっていました。
以下のように @supports で「background-clip: text」がサポートされていないケースに対応していたのですが、Android 4.2 は「background-clip: text」だけでなく「@supports」も使えなかったのです。
@supports not ( (-webkit-background-clip: text) or (background-clip: text) ) {
/* background-clip: text がサポートされていない場合 */
...
}
@supports (-webkit-background-clip: text) or (background-clip: text) {
/* background-clip: text がサポートされている場合 */
...
}
対策として、一段目の「@supports not …」の条件文を削除することで「background-clip: text」がサポートされていない場合の設定をデフォルトとし、二段目の「@supports …」内でこれらの設定項目をすべて上書きすることにしました。
最後に
Smoking Note をよろしくお願いします。