Intelligent Technology's Technical Blog

株式会社インテリジェントテクノロジーの技術情報ブログです。

【Monaca】Windows8上での動作確認続報

こんにちは、間藤です。

私の前回の投稿は、TODO管理アプリを各プラットフォーム上で動作させるところまで試してみましたが、Windows8上での動作確認ができませんでした。その原因を見つけるべく試行錯誤してみましたが、その過程でわかったことを以下にまとめてみます。ただ、Monacaではなく、ほとんどWindowsストアアプリに関する情報になってしまいました。

調査のアプローチ

MonacaでビルドしたWindows8アプリをインストールして実行すると、スプラッシュ画面が表示された数秒後にアプリが終了してしまう現象が発生していました。後になって「Monacaのビルドシステムに問題があり対応中である」ということがわかったのですが、当初はこちらの手順に問題がある可能性も考えて、「同等のアプリをVisual Studioで作成してみる」というアプローチを採ってみました。
ところが、いくつかのトラップにかかり、思った以上に動作させるまでに手間取りました。以下では、その顛末を書いていきます。(ですので、Monacaとはほとんど関係のない話になっています。)

プロジェクトの作成

TODO管理アプリは、PhoneGapのAPIを経由してカメラ機能を利用します。そこで、Visual Studio 2012のプロジェクト作成を、PhoneGapのドキュメントに従って行いました。ちなみに、バージョンは2.9を利用します。この記事の執筆時点では、3.0が最新ですが、私の理解が間違っていなければ、バージョン3.0のプラットフォームガイドに記載されている手順では、バージョン3.0を利用することができないようなのです。
途中の手順で、以下のように書かれています。

Download and extract the latest copy of [PhoneGap. You will be working in the lib\windows-8 subfolder.

ですが、当該ページでアーカイブをダウンロードできるのは、2.9までとなっています。3.0のドキュメントがまだ整備されていない可能性もあり、ここはあまり深追いせず、2.9を利用することにしました。

(補足)
PhoneGapのバージョン3.0からは、「プラグインアーキテクチャ」が導入され、必要なプラグインを選択して取り込む方式になるようです。
例えば、Device APIを利用したいなら、以下のようにコマンドを実行します。

$ phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-device.git

ということで、手順の確認に少々躓きましたが、cordova.jsを取り込んだプロジェクトの作成はできました。

jQueryjQuery Mobileを取り込む

TODO管理アプリでは、UIをjQuery Mobileで作成しています。そこで、jQueryjQuery Mobileをプロジェクトに取り込みました。バージョンは、jQueryが1.9.1、jQuery Mobileは1.3.2を選択しました。

f:id:IntelligentTechnology:20130912182112p:plain

このバージョン選択に深い意味があったわけではありませんが、Microsoftのページでも「バージョン 1.7 以降のjQueryなら利用可」と書かれていたので、問題ないだろうと考えました。
ところが、TODO管理アプリのプログラムを反映して、アプリをデバッグ起動してみると、クラッシュしてしまいました。しかも、jQueryの中で落ちています。

f:id:IntelligentTechnology:20130912181932p:plain

ネットで情報を検索してみたところ、以下のページを見つけました。

jQuery Version 2.0 での Windows ストア アプリのサポート

そこで、jQuery 2.0.3 に置き換えてみたところ、無事にアプリが起動しました。但し、jQueryチームは、この問題を完全に制圧できたわけではなさそうです。前回の記事で、2ページ目に戻るボタンを追加しましたが、同様のことを行うと、2ページ目の画面遷移時にクラッシュしました。

f:id:IntelligentTechnology:20130912182257p:plain

WindowsストアアプリでjQueryを安全に利用できるようになるまで、もうしばらく時間がかかりそうです。

カメラを使ってみる

アプリが起動するようになったので、早速カメラが利用できるか試してみました。

f:id:IntelligentTechnology:20130912182343p:plain

上の画像では見え辛いですが、カメラを利用するための権限がないと言われます。カメラを利用できるようマニフェストを変更するのを忘れていました。

f:id:IntelligentTechnology:20130912182617p:plain

ところで、Monacaでは、これ(マニフェスト)に相当する設定を行うメニューがIDE上に見当たりませんでした。(私が見落としているだけかもしれません。)
MonacaでもWindows8の動作確認が行えるようになったら、もう一度見てみようと思います。
いずれにせよ、これでアプリからカメラが使えるようになったので、シミュレータで動作確認してみると、今度は問題なく機能します。カメラで撮影した画像がリストに表示されるようになりました。

f:id:IntelligentTechnology:20130912182817p:plain

次に、アプリパッケージを作成して、Windows8マシンにインストールし、動作を見てみました。
すると、カメラ撮影まではできるものの、撮影結果をOKするとnavigator.camera.getPicture関数のエラーコールバックが呼ばれるようになってしまいました。原因を調べたところ、PhoneGapのプログラムに問題があることがわかりました。撮影結果の画像サイズをnavigator.camera.getPicture関数のオプションで指定していますが、この指定によりPhoneGapのAPI内部で、撮影した画像をリサイズする処理が実行されます。その処理の過程で、加工対象の画像ファイルをコピーする処理を行っていますが、ここに問題があります。

【cordova.js 5925行目】

Windows.Storage.StorageFolder.getFolderFromPathAsync(packageId.path).done(function (storageFolder) {
    file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).then(function (storageFile) {
        success(new FileEntry(storageFile.name, storageFile.path));
    }, function () {
        fail(FileError.INVALID_MODIFICATION_ERR);
    }, function () {
        errorCallback("Folder not access.");
    });
});

ファイルのコピー先ですが、(上記のプログラムだけではわかりませんが)アプリのインストールフォルダになっています。上記プログラムでは、packageId.pathがこれに当たります。この変数の内容を確認すると、C:\Program Files\WindowsApps配下になっていることが確認できました。エクスプローラーでこのディレクトリを確認しようとすると、アクセスできません。このディレクトリ配下を更新するのは、そもそもNGです。

では、シミュレータではなぜ正常に動作したのか?
Visual Studioからデバッグ起動する場合、アプリのインストールフォルダはWindowsApps配下にならないからです。(たとえデバッグ起動だとしても例外を送出してくれると有難いのですが・・・)

ところで、エクスプローラーでWindowsApps配下を確認できると便利な場合もあるでしょう。そのための方法が以下のページで紹介されていました。

Get access to the %ProgramFiles%\WindowsApps folder and view apps source code

とにかく、このままでは動作確認できないので、暫定的な措置として、TemporaryFolderにコピーするよう、以下のようにcordova.jsを修正してみました。

Windows.Storage.StorageFolder.getFolderFromPathAsync(Windows.Storage.ApplicationData.current.temporaryFolder.path).done(function (storageFolder) {
        file.copyAsync(storageFolder, "___" + file.name, Windows.Storage.NameCollisionOption.replaceExisting).then(function (storageFile) {
        success(new FileEntry(storageFile.name, storageFile.path));
    }, function (e) {
        fail(FileError.INVALID_MODIFICATION_ERR);
    }, function () {
        errorCallback("Folder not access.");
    });
});

但し、カメラで撮影した画像もTemporaryFolderに置かれているようなので、コピー先ファイル名の先頭に"___"を付与するようにして、ファイル名のバッティングが起きないようにしてあります。
同様の問題が起きる箇所がもう1つあるので、そちらも修正すると、アプリパッケージからインストールした場合でも、正常に動作するようになりました。

まとめ

なんだかんだと動作させるまでに時間が掛かってしまいましたが、実際に動作させてみると、jQuery Mobileで構築したUIは多少違和感があります。やはり、WindowsストアアプリらしいUIにするならば、例えばリスト表示にはWinJS.UI.ListViewを利用することになるのかなと思いました。

また、Windowsストアアプリの作成にPhoneGapを使うことについても、迷うところではないかと思います。そもそもWindowsストアアプリは、WinJSが用意されているので、PhoneGapの力を借りずともカメラを利用したりといったことはJavaScriptのみで実現できます。Windows8におけるcordova.jsの役割は、他プラットフォームでのインターフェースと揃えるためのラッパーという位置付けになるでしょうか。それはそれで助かることではありますが、前述のように不具合もあったりします。PhoneGap BuildもWindowsストアアプリのビルドをサポートしていないようです。PhoneGapでは、Windows8への対応にはそれほど力を入れていないのではないでしょうか。
さらに言えば、Visual Studioを使って開発すれば、開発言語がJavaScriptであっても、ブレークポイントを設定するなどのデバッグ機能も利用できます。

なるべく1つのプログラムコードで複数のプラットフォームに対応したいわけですが、どこまでそれに拘るのか、それはそれで悩ましいところではないかと思います。