Monaca メモ

Monacaで久しぶりにプロジェクトを作成し Monaca デバッガを立ち上げたところ、以下のエラーが発生しました。

ググッてもヒットしなかったので私の使い方や環境が悪いだけかもしれませんが、プロジェクトの作成から解決するまでをメモっておきます。

開発環境

  • localkit v2.3.0 / Monaca IDE
  • Monaca Debugger v6.1.1
  • PC: Windows10

プロジェクト作成

以下の設定でプロジェクトを作成しました。

カテゴリ Onsen UI
テンプレート Onsen UI V2 JS Minimum

Monaca デバッガ立ち上げ

Monaca デバッガを立ち上げると、以下の2つのエラーがログに出力されました。

Uncaught ReferenceError: Set is not defined
www/lib/onsenui/js/onsenui.min.js: 3
Uncaught ReferenceError: ons is not defined
www/index.html: 16

なにが悪いのか想像すらつきません。
ちなみに localkit/IDEの Preview ではエラーはでていません。

ファイル構成とバージョン確認

index.html のソースをみてみます。

<script src="components/loader.js"></script>
<script src="lib/onsenui/js/onsenui.min.js"></script>

<link rel="stylesheet" href="components/loader.css">
<link rel="stylesheet" href="lib/onsenui/css/onsenui.css">
<link rel="stylesheet" href="lib/onsenui/css/onsen-css-components.css">

lib フォルダ内のファイルを開いてバージョンを確認すると、

onsenui.min.js v2.2.4
onsenui.css v2.2.4
onsen-css-components.css ?不明

次に loader ファイルを開いて中身を確認すると、

components/loader.js monaca-cordova-loader のコード
monaca-core-utils のコード
components/loader.css ヘッダのみ

Onsen UI のリリース情報を調べてみると最新版は v2.3.1。内容をざっと見ても本件と関連するような箇所はわからなかったのですが、v2.2.4 からけっこう更新されてました。

最新版 Onsen UI インストール

ということで、v2.2.4 以降のどこかで修正されていることを祈りつつ Onsen UI の最新版をインストールしてみることにしました。JS/CSSコンポーネントの追加画面で Onsen UI (Monaca Version)を選択し、選択可能なバージョンのなかで最新となる v2.3.0 をインストール。そして、Monaca デバッガで再実行。

エラーが消えました!!!

… が、よくみると 謎メッセージが2個?

ググったところ Shadow DOM を使っていなければ気にしなくていい的なことが書いているように見えた(英語わかりません)ので無視することに。

でも、なんで2個?

index.html 見直し

index.html を見てみると loader ファイルを読み込んでから lib フォルダ内のファイルを読み込んでいます。

そこで、もう一度 loader ファイルを確認してみます。

components/loader.js monaca-cordova-loader のコード
monaca-core-utils のコード
monaca-onsenui のコード追加
components/loader.css onsenui.css と onsen-css-components.css のインポート文追加

loader ファイルに Onsen UI の記述が追加されています。バージョンは v2.3.0。

次に lib フォルダ内のファイルを開いてバージョンを確認すると、js ファイル/css ファイル ともに v2.2.4 のまま変わりありません。

ということは loader ファイルで v2.3.0 を読み込んだ後に lib フォルダ内の v2.2.4 を読み込んでる!
だから同じ内容のメッセージが2個表示されたんですね。

index.html 修正

ということで index.html の lib フォルダ内のファイル読み込みをコメントアウトしました。

  <script src="components/loader.js"></script>
<!--
  <script src="lib/onsenui/js/onsenui.min.js"></script>
-->
  <link rel="stylesheet" href="components/loader.css">
<!--
  <link rel="stylesheet" href="lib/onsenui/css/onsenui.css">
  <link rel="stylesheet" href="lib/onsenui/css/onsen-css-components.css">
-->

実行した結果は以下のようになりました。

まとめ

JS/CSSコンポーネントの追加画面から追加したファイルは loader ファイルに書き込まれます。Onsen UI を追加(更新)した場合は、index.html に前バージョンのファイルの読み込みを行う script 文が残っているので、これを手動で削除する必要があります。

以前は Onsen UI は最初から loader ファイルに記述されていて、 index.html には Onsen UI を読み込む script 文はなかったと思うんです。今後また仕様が変わるかもしれませんが現状報告ということで。

Smoking Note V1.2.4 アップデート

本日、節煙サポートアプリ「Smoking Note」をアップデートしました。

V1.2.4 アップデート内容

  • 前回の記録のグラフを改良しました。今日の喫煙状況を前回の喫煙状況と比較することができます。

先週アップデートしたばかりなのですが、使っているうちに喫煙状況を比較できたらいいのではとひらめきました。試しに実装し数日間使用してみてその便利さに一人感動し、少しでも早くアップデートしたいということで本日リリースに至りました。
v1.2.3 と v1.2.4 のグラフの違いは以下のようになっています。

v1.2.3

v1.2.4(本日アップデート)

今日の喫煙状況を前回の記録と比較しながら容易に把握できます。

最初からそうすればいいのにと自分でツッコミつつ、実際に使ってみない(やってみない)とわからないことって世の中にたくさんあるよねうんあると納得させながら、次に作るものを考え中です。

Smoking Note V1.2.3 アップデート

昨日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 をよろしくお願いします。