Intelligent Technology's Technical Blog

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

PhoneGap Buildを使ってみました

こんにちは、間藤です。

Monacaに関していろいろと投稿を行うつもりでしたが、前回Windowsストアプリの話に終始してしまいました。そして、今回もまた脇道に逸れます。

PhoneGap Buildは、Adobeが提供するハイブリットアプリ開発環境です。iOSAndroidWindows Phone、BlackBerryといったプラットフォーム向けのPhoneGapアプリをビルドする環境を提供しています。Monacaと競合するサービスと言ってもよいでしょう。PhoneGap Buildの特徴については、こちらのページが参考になると思います。

今回少しだけPhoneGap Buildを利用してみたので、Monacaとの違いも意識しながら、以下に利用レポートを書いてみようと思います。ただ、最初に断っておきますと、MonacaにしてもPhoneGap Buildにしても、「ほんの少し使ってみた」という程度でして、どちらが優れていると語れるほど理解はできていません。多少なりとも感想は述べますが、参考程度と思っていただければ幸いです。

PhoneGap Buildの使い方

使い方については、すでに詳細を書いてくださっている方(Adobeの方です)がいらっしゃいました。こちらのページが参考になると思います。私も、この手順を参考にさせていただきました。

ところで、PhoneGap Buildに連携するZIPファイル(あるいはGitHubリポジトリ)はどうように構成しておくべきなのでしょうか?
これについては、PhoneGap Buildのドキュメントに記載がありました。

Preparing Your Application for PhoneGap Build

つまり、PhoneGapアプリのwww配下の構成を用意すればよいということです。
新規作成するなら、PhoneGap3.0をインストールして、「The command-line interface (CLI)」でプロジェクト作成すれば、必要なファイルを手に入れることができるでしょう。

もっと手軽に必要なファイルを入手する方法もあります。ベースとなるプログラム一式を、こちらのリポジトリから入手可能です。簡単に試してみるなら、この一式をそのまま編集せずにPhoneGap Buildに連携してビルドすることも可能です。

Hydration機能とDebug機能

Hydration機能は、Monacaデバッカに近い役割を担ってくれます。上に紹介したページの最後でも触れられていますが、PhoneGap Buildでのアプリの更新を検知して、更新されたアプリを取り込む仕組みとなっています。これにより、アプリを更新した際に、いちいちアプリを再インストールする手間が省けます。Monacaデバッカとの違いは、自分が作成したアプリそのものにHydration機能が埋め込まれるということです。Monacaデバッカの場合は、Monacaデバッカアプリ内で自分が作成したアプリが動作する形態です。一方、Hydration機能の場合、自身のアプリ内にHydration機能が埋め込まれます。つまり、主従が逆になってます。PhoneGap Buildでビルドしたapkファイルの中身を覗いてみるとわかりますが、自分が作成したアプリがHydration機能にラップされています。アプリ更新を検知したら、アプリを再インストールするのではなく、更新されたアプリ本体をダウンロードして差し替えているようです。

Debug機能は、解説のページを読んでも、私にはよく理解できませんでした。ただ、わからないなりに「多分こういうことだろう」というところまでは確認できましたので、以下にまとめてみます。
まず、weinreを利用しているということです。weinreについては、こちらのページを参考にしてください。この参考ページを読んでもわかるように、weinreを利用するためには、weinreが用意するスクリプトを取り込んでおく必要があります。

<script type="text/javascript" src="http://localhost:8080/target/target-script-min.js#hogefuga"></script>

ですが、この取り込みは、デバッグするときにだけ必要なので、最終的には削除しなければなりません。
PhoneGap Buildは、このスクリプト取り込みのための1行を、ビルド時に自動で埋め込んでくれるようです。ですから、デバッグの際にこの1行を追加したり、不要になったら削除したり、といったことを行う必要がありません。
ただ、自動で埋め込むと言っても、weinreが動作するホスト(上の例だとlocalhost)や、識別用の文字列(上の例だと"hogefuga")などを指定しておく必要があります。そのために、config.xmlに例えば以下のような設定を追加しておく必要があります。

<feature name="debug-server" required="true">
   <param name="domain" value="http://localhost:8080"/>
   <param name="key" value="hogefuga"/>
</feature>

また、指定したホストに接続できるよう、access要素にも設定をします。

<access origin="(指定したホスト)" />

このようにしたうえでビルドし、weinreのサーバを所定のマシン上で起動しておけば、リモートデバッグが実現できます。
上に紹介した参考ページにも書かれていますが、Android端末から利用する場合は、--boundHostオプションを指定してweinreを起動してください。

ということで、私の理解では、PhoneGap Buildが行ってくれるのは、スクリプトの埋め込みだけです。weinreを用意して、起動しておくなど、自分でやらなければなりません。Monaca IDEも内部ではweinreを利用しているようですが、weinreを用意したり起動したりといった手間はなく、PhoneGap Buildよりも格段に使い勝手は良いと思いました。

PhoneGap3.0のインストール

最後に、PhoneGap3.0についても触れておきます。

今回、MacOS X 10.8.4)と、Windows8のマシンにPhoneGapをそれぞれインストールしました。Mac上ではiOSアプリの動作確認を、Windows8上ではAndroidアプリの動作確認を行いました。
PhoneGapは、バージョン3.0からNode.jsのモジュールになりました。ですから、npmコマンドで簡単にインストールできます。

> npm install -g phonegap

プロジェクトの作成や、ビルドなどは、phonegapコマンドで行います。

> phonegap create helloworld

そうすると、"helloworld"という名前のフォルダが作成されますので、このディレクトリに移動します。

> cd helloworld

プロジェクトを作成した時点では、各プラットフォームのビルドに必要なファイルは揃っていない状態です。例えば、iOS用のファイルを揃えるには、以下のようにコマンド実行します。
※事前にXcodeとCommand Line Toolsをインストールしてください。

> phonegap build ios

このコマンド実行によりplatformsディレクトリ配下に"ios"というディレクトリが作成されます。この配下にXcodeのプロジェクトが作成されており、Xcodeからプロジェクトを開いて、ビルドやアプリ起動が可能です。
Xcodeを起動せずに、phonegapコマンドでアプリを実行することも可能です。

> phonegap run ios

これによりiOSシミュレータが起動し、アプリが実行されます。但し、事前にios-simをインストールしておく必要があるようです。私は、こちらのページを参考にしました。

【追記】
ios-simはbrewではなくnpmでインストールしたほうがよいようです。

なお、Macに実機を接続すれば、上記コマンドで実機上でアプリが実行されるかと思ったのですが、どういうわけかデバイスが認識されませんでした。どうやっても、iOSシミュレータが起動してしまいました。
iOSに関しては、phonegapコマンドで実機にインストールできなかったことを除いては、特に躓くことなく、上記の手順で確認することができました。

一方、Windows8上でAndroid環境を構築しようとしたところ、少々苦労しました。なお、Android Platform Guideに従って、Android SDKのインストールなど、設定を行う必要があります。また、このドキュメントは、ところどころ情報が古いようなので、注意してください。例えば、cordovaというコマンドの実行例が掲載されていますが、phonegapコマンドに置き換える必要があります。指定できるオプションも異なるようなので、正しいオプションをphonegapコマンドのヘルプで確認する必要もあります。

さて、PhoneGapのインストールは問題なくできたのですが、プロジェクトを作成しようとすると、エラーとなってしまいました。

> phonegap create helloworld
[warning] missing library phonegap/www/3.0.0
[phonegap] downloading https://github.com/phonegap/phonegap-app-hello-world/archive/3.0.0.tar.gz...

TypeError: Cannot read property 'length' of undefined
at Request.request.get.pipe.pipe.tar.Extract.path [as _callback] (C:\Users\matoh\AppData\Roaming\npm\node_modules\phonegap\node_modules\cordova\src\lazy_load.js:83:88)
at self.callback (C:\Users\matoh\AppData\Roaming\npm\node_modules\phonegap\node_modules\cordova\node_modules\request\index.js:148:22)
at Request.EventEmitter.emit (events.js:117:20)
at ClientRequest.self.clientErrorHandler (C:\Users\matoh\AppData\Roaming\npm\node_modules\phonegap\node_modules\cordova\node_modules\request\index.js:257:10)
at ClientRequest.EventEmitter.emit (events.js:95:17)
at CleartextStream.socketErrorListener (http.js:1500:9)
at CleartextStream.EventEmitter.emit (events.js:95:17)
at Socket.onerror (tls.js:1336:17)
at Socket.EventEmitter.emit (events.js:117:20)
at net.js:807:16

プロジェクトディレクトリは作成されますが、www配下にファイルが作成されていません。つまり、プロジェクトが正常に作成されていない状態です。
プロジェクトディレクトリを削除してリトライすると、別のエラーが表示されます。

>phonegap create helloworld
[error] downloaded www assets in C:\Users\matoh\.cordova\lib\www\phonegap\3.0.0\www does not contain index.html, or www subdir with index.html

このエラーについて、私は以下のように理解しました。

プロジェクト作成のための雛形を、ネットワーク経由で取得しようとしてエラーになったのが1回目。2回目実行時のエラーは、ローカル環境(ユーザディレクトリの.cordova配下)に保存された雛形を使おうとしますが、その雛形がダウンロードできていないために発生していると思われます。1回目の実行で、.cordovaディレクトリだけが作成されてしまったのが原因でしょう。
そこで、1回目のエラーログを確認してみると、lazy_load.jsの83行目で問題が起きているとあります。そして、この箇所のプログラムを確認してみると、以下のようなコードになっています。

var proxy;
if (uri.protocol == 'https:') {
    proxy = npm.config.get('https-proxy');
} else if (uri.protocol == 'http:') {
    proxy = npm.config.get('proxy');
}

shell.mkdir('-p', download_dir);
var size = 0;
var request_options = {uri:url};
if (proxy) {
    request_options.proxy = proxy;
}
events.emit('log', 'Requesting ' + JSON.stringify(request_options) + '...');
request.get(request_options, function(err, req, body) { size = body.length; })

npmのPROXY設定を確認して、requestモジュールのgetメソッドのオプションとしています。どうやら、うまく動作しなかったのは、私の環境でhttps-proxyの設定を漏らしていたことが原因だったようです。以下のように設定を行います。

> npm config set https-proxy http://(プロキシサーバのURL):(ポート番号)/

これでphonegapコマンドが正常に機能するようになりました。Android端末を接続して、以下のコマンドを実行すると、実機にアプリがインストールされ、アプリが起動されることも確認できました。逆にiOSのようにエミュレータにアプリをインストールして、アプリ起動することはできませんでした。つまり、iOSと全く逆の現象が起きていました。

> phonegap run android

なお、Mac環境では、https-proxyを設定していなくても、proxyの設定が参照されるようなので、https-proxyを別途設定する必要はありませんでした。

まとめ

PhoneGap Buildは、Monacaに比べると、やや使い辛い印象でした。ただ、冒頭にも書いたように、「ちょっと使っただけ」なので、私の理解が浅いだけかもしれません。後半は、PhoneGap3.0の話題になってしまいましたが、上にも書いたように、ドキュメントがいまひとつ整備されていないようです。PhoneGap関連の情報は、今後もキャッチアップしていきたいと考えています。