T

決戦!Titanium 対 PhoneGap

結論:文句あったらプラグイン書けばまあたいていどっちでもなんとかなるYO!

以上。

PhoneGapで起動画面(Android)

PhoneGapで作成したアプリの起動画面の設定は以下の通り。ここでは画像をドーンと表示する例。まずメインとなるJavaのonCreateにsetIntegerPropertyを追加する。

public class movie extends DroidGap{
  super.onCreate(savedInstanceState);
  super.setIntegerProperty("splashscreen", R.drawable.splashscreen); //←ココ
  super.loadUrl("file:///android_asset/www/index.html");

それから、対応する画像をres/drawable/splashscreen.pngとして用意する。おしまい。

PhoneGap雑感

PhoneGapでAndroid向けアプリを制作してみての雑感。

よいところ

・学ぶのが簡単

基本的に設定が終わったらあとはHTMLとJavaScriptを書くだけ。デザイン的なこともHTMLで記述している分には慣れている人にはほとんど問題ない。

サードパーティーのツールも豊富

Sencha touchやjQtouchといったJavaScriptライブラリもあってUIの作成は簡単。他にも各プラットフォーム向けのプラグインがたくさん公開されている。

・仕組みが単純

DroidGapクラスをextendsするクラスを用意するだけで済むので、onCreateやいろんなところでちょっとしたフックを挿入したいと思ったらTitaniumより楽に動作させられる。Titaniumの場合、プロキシの仕組みを追いかけてどこで何をやっているのかちゃんと把握していないと変なところで動かなくなってしまう。それから、単純な分だけapkファイルのサイズも小さいのもいい。

困ったところ:

・ハマると大変

HTMLとJavaScriptで書けばいい、とはいうものの、例えばjQtouchやSencha touchを使う場合はHTMLの書き出しまでJavaScriptのライブラリ任せになるので、細かい調整はいろいろと難しくなる。ドキュメントも豊富とはいえないので、ソースを追いかけ始めると大変。

・onResumeやonPauseでうまく動かすのが難しい

他のアプリやActivityを起動して元の画面に戻ると、初回起動と同じシーケンスが走る。つまり、ウェブブラウザをリロードして最初の画面に戻ってしまう状態になる。つまり、Ajaxをバリバリ使ってウェブアプリを作成しているのときに外部サイトにリンクしてそこから戻るボタンを押したのと同じような問題が起きる。ステートレスなウェブの考え方をステートフルなアプリの世界に持ち込むことの弊害とでもいおうか。これエミュレータだけの現象みたい。

・遅い、遅い、遅い

WebViewはメモリも食うし、とにかく動作が遅い。エミュレータだと不安になるくらい重い。起動から動き出すまでにかなり時間がかかる。

PhoneGap (Android)でローテーションの固定

Titaniumでも同じような手が使えたので試してみたら大丈夫だった。

AndroidManifest.xmlで各Activityのところを(portraitで固定したいなら)こんな風に記述する。

android:configChanges="keyboardHidden"←ココ
android:screenOrientation="portrait"

keyboardHiddenからあとの部分を消す。

Titanium DeveloperとXcodeの連携

Titaniumで作成したプロジェクトをXcodeでビルドする際に必要なファイルをコピーしてくれるスクリプトがAppceleratorの開発者の好意で用意されている

残念ながら日本語を含むディレクトリ名が途中にあると動かないようなので、ちょっといじってこちらに置いておいた

Titanium DeveloperでAndroid(5)

今まで見つけた、Androidの場合に起きる不具合について。

(1) httpClientでPOSTリクエストが送れない、外部とのsocket通信ができない

これは笑っちゃうようなレベルの不具合で、よくもまあリリースしたもんだと飽きれる。HTTPによる非同期通信を起動しても、POSTリクエストで値を送信することができない。じゃあsocket通信でなんとかしようと気合いを入れ直すと、実はAndroidではsocket通信も動作しない

対応方法は、GETまたはリクエストヘッダに細工してデータを送るくらいしかない。次期リリースで改善されるという噂だが、どうだろう。正直まだあまり信用できない。

(2) 暗黙のIntentで適切なメディア再生用アプリケーションが起動できない

Intentで直接メディアプレーヤーやPDFビューワを起動したくても、いったんブラウザが起動してからブラウザ経由で呼ばれてしまう。

対処方法としては、AndroidManifest.xmlにIntentFilterを記述してやればいいようだが、時間がなかったのでIntentを作成している箇所をいじってTitanium mobileの機能を拡張した。ちょうどここにやり方が出ていたのでこれをヒントにやってみたらうまくいった。

(3) MediaPlayerがサーバ上のデータにアクセスできない

驚いたことに、KitchenSinkからリモートサーバのメディアへのアクセスがAndroid版から削除されていた。これはどうしようもないので、(2)と同じようにTitanium mobile側を改造するか、諦めるしかない。

というのも、例えばUIWebViewでHTML5のvideoタグを使ってメディアプレーヤの代用としてみても、Androidではアプリ内から起動するwebviewではvideoタグは起動しない仕様なので、いくら頑張っても無駄になる。

ただし、(2)の方法を使うと、openURLの改造でIntentが思い通りに動くようになるので、その場合はTitanium.Platform.openURL(またはそれを拡張した関数)でリモートのURLを呼び出してしまえばいい。メディア再生用の別アプリケーションが立ち上がるが、iPhoneと違ってAndroidなら再生が完了したらまた自分のアプリに画面が戻る。

(4) orientationの制限がまともに動作しない

これはAndroidManifest.xmlをいじって対応できる。まあ、魔術としかいいようがないが。

これらはいずれもiPhoneでは正常動作しているものが、Androidに限って動かないケース。繰り返しになるが、よくまあリリースしたもんだ。

携帯サイトに未来はなかった

jpmobile便利だなあ、でもやっぱり携帯公式サイトに未来は無いわ、と思ったのでメモ。前にも同じことを思ったけど、あのときの思いつきは間違っていなかった。2年以上、携帯公式サイトというビジネスがゆるゆると崩壊する様を見ていて、そう思う。

もし、jpmobileみたいなものを自分で作るとしたら、どんな機能を盛り込んだか。もちろん、絵文字の処理やテンプレートの切り替え、アクセス制限、半角カタカナなどの文字列処理、UIDに関する処理やクッキー食べないdocomo端末を考えたセッションの処理なんてのは、携帯サイトを作ったことのあるある程度以上のプログラマなら当然思いつくだろう。このあたりが全て実装されたjpmobileの機能自体はとてもよく出来ていて、まったくもって不満はない。実際、案件で使ったこともある。

でも、もし本当に携帯公式サイトを楽に構築するためのパッケージを考えるなら、ここにキャリアと連携した月額課金と従量課金の機能を追加しないと完成とはいえない。

もちろん、それがないのはjpmobileの作者が悪いせいでもなんでもない。当然ながら、これくらいの機能を作るだけの能力がないわけがないだろう。そんなことは考えなくてもわかる。でも、もし作ったとしても、公開できないんじゃないかと思うのだ。まず、お金が絡んでくる機能なので、出来ました、はい公開、とやるのは、いくらライセンスなどがあっても、ちょっとリスクが高い。また、それ以上に、課金周りの仕組みを作ってもキャリアのNDAがある以上は、実装でさえもちょっと公開は躊躇われる。

もし、NDAによる制約がなく、エンジニア同士の交流で技術情報の交換が広まれば、jpmobileコミュニティみたいなのが立ち上がって、キャリアが立ち上げる新しいサービスに次々とリファレンス実装を公開していくことで、誰もが簡単に新サービスをサイトに追加していくことができるような世界になれば、携帯公式サイトの立ち上げにはほとんど障壁がなくなり、携帯界隈はアイデアをどんどん実現できる激しい競争の場になる、なんてことも夢想できる。

でも、実際には、公の場でそんなことはできない。携帯サイトというのは、一見するとBtoCのビジネスのようだが、実際にはキャリアに向けてサービスを売りつつ一般ユーザの世話をするようなもので、企業相手のビジネスなのだからエンジニアが所属する企業の枠を飛び越えて何かやる余地は少ない。そこで企業の方が肩代わりしてやろうとするわけだが、企業の倫理から各社が虎の子のように守っているわずかな技術的優位性を手放すわけがない。だから、出来上がるのはビジネス寄りの業界団体が関の山で、いくらコミットしても結局プログラムはキャリアの仕様書とにらめっこしながらゼロから実装するしかなく、だから参加者もこれといって代わり映えしないいつものメンツで、そこでは微笑ましい規模のカルテルみたいなものがほのめかされるだけだ。

携帯公式サイトのサービスというのは、こんなのがあったらいいな、というアイデアが実現される場ではない。なぜなら、そういう思いつきのほとんどが、NDAの壁に塞がれて技術交流が促進されないため、実現するにはコストがかかりすぎるため消えてしまうので、残るのはみんな本当はキャリアが考え出したアイデアで、そのほとんどがくだらない画像をメールに添えて喜ぶようなガキ向けのお遊びか版権ビジネスの延長であり、スマートフォンの登場に至って、遂に競争は救命ボートの場所取り争いの様相を呈している。

おそらく、最後の一手になるであろう、携帯公式サイトの終わりは、少額決済の問題だ。携帯公式サイトのビジネスが最も誇るべきはその課金システムであり、そこを上手に解放できなかったことが終わりの始まりだったわけだが、この一点さえ突破されてしまえば、ビジネスとしての存在意義は携帯公式サイトには存在しなくなる。Appleでは既に実装され、とうとうAndoridでも実施されるアプリ内課金がその一手になり、次は元締めの取り分が大きすぎると怒れる事業者がもっといいソリューションを提案してくるようになると、開発者としてはとても嬉しい限りだ。

というわけで、キャリアのみなさんがAndroidマーケットに小額課金システムを携えて殴り込んできてくれたらいいな、というのが結論でした。

Titanium DeveloperでAndroid(4)

いろいろと発見することが多い反面、だんだんとまとまりがなくなっていくシリーズ。というか、Androidがマジで嫌いになってきましたシリーズ。

AndroidのUIWebViewが曲者だ。例えばcreateWebViewして、その中のHTMLにvideoタグを埋め込んで動画再生しようとしても、iPhoneでは動くのにAndroidでは動かない。

じゃあ、どうすればいいか?調べると、Titanium側でcreateWebViewした際にUIWebViewのインスタンスにsetPluginStateまたはsetPluginsEnabledが設定されていないので、Titanium Mobileのソースコードを眺めて、webviewの作成時にはsetPluginsEnabled(true)を呼ぶように指定してリビルドしてみたが効果がなかった。そこでさらに調べてみると、どうやらアプリ内で作成されるviewからはHTML5の機能が動作しないのが仕様らしい。

これだけならAndroid師ねで終わるのだが、驚いたことに今度はTitanium側からもキツい攻撃が。リモートのファイルを普通にcreateVideoPlayerに設定しても、例外を吐いてクラッシュする(Androidのみ。当然iPhoneでは動く)。

.......
//どこかの大自然
var media_url = 'http://www.pocketjourney.com/downloads/pj/video/famous.3gp';
var activeMovie = Titanium.Media.createVideoPlayer({
  contentURL:media_url,
});
win.add(activeMovie);
win.addEventListener('close', function(){
  alert("Window closed");
  activeMovie.stop();
});
activeMovie.play();
.......

まとめると:

(1)AndroidではvideoタグのようなHTML5の機能をアプリ内のwebviewから利用することは出来ない。これはAndroidの仕様なので、PhoneGapを使っていても同じ目に遭う

(2)Titanium Mobile (SDK 1.5)ではAndroidでcreateVideoPlayerからリモートの動画を読み込むことは出来ない。

つまり、Androidでリモートの動画を再生したければ、aタグでちょちょいとやっつけるか、PhoneGapでプラグインを作成するか、またはちゃんとJavaで書くしかない、ということ。プロジェクトをeclipseにエクスポートする機能は公式には存在しないが、いちおうスクリプトが用意されてはいる。

Titanium DeveloperでAndroid(3)

前回の内容からほとんど進捗がなかったので、今回はちょっとしたbkを。

Titaniumではビルドする際に最初からコンパイルし直すかどうかを判定して、時間のかかるコンパイル作業を必要最小限しか実行しないように工夫されている。が、どうやら早すぎる最適化の罠にはまっているらしく、ときどきAPIドキュメント通りに書いたプログラムやサンプルをコピーしただけのテストコードが動かなくなっていることがある。

そんなときは、「Edit」タブから「Titanium SDK」を選択し、現在使用中のSDK以外のバージョンを指定して「Save Changes」をクリックして、もう一度試してみる。その結果は無視して、さらにもう一回「Edit」から「Titanium SDK」のバージョンを戻し、ビルドを実行する。すると、最初からリビルドが始まるので、おかしくなっていた箇所の挙動が修正されることもある。または、プロジェクトのディレクトリ直下にあるtieapp.xmlをtouchでタイムスタンプだけ更新する。

Titanium DeveloperでAndroid(2)

前回まででSDKの用意ができたので、今度はサンプルを動かしてみよう。Titanium mobileには開発元のAppceleratorが公開してくれている「Kithchen Sink」というサンプルがあり、githubから入手できるので、さっそくインポート。失敗したら、新規にプロジェクトを作成してファイルをコピー(とチュートリアルに書いてある)。

ではエミュレータを起動、ほらすごい!といいたいところだが、なんとこのサンプルが、動かないのである。困ったものだ。原因はいろいろあるのだろうが、そもそもエミュレータで起動しない。もうどうしようもないので諦めるしかない。ちなみにiPhoneではちゃんと動く。 update: 動くようになった。

Androidに関してはKitchen Sinkはクソの役にも立たないわけだが、これでTitanium mobileのAndroid向け開発の能力には多いに疑念が湧いたため、シンプルなプロジェクトを新規に作成してサンプルにある各機能を試してみたが、全く先に進まない機能もある。でも試行錯誤するうちに、そんなときには、たまに何かわからないことがあったら、AndroidのSDKからこんなツールを起動してみるといいことがわかった。

Dalvik Debug Monitor

201012242236.jpg  

これは起動中のエミュレータをアタッチしてログ情報を表示してくれる便利ツールで、Android SDKのtools/ddmsという名前で格納されている。ちなみにマルチモニタに対応していないため、MacBookなどで主画面以外で起動するとクラッシュするので要注意。

もちろん、それでもダメなものはダメだ。例えば、ビデオのストリーミング再生はどう頑張っても音声しか出てこない。エラーをみるとバッファの取得中にタイムアウトしているようだが、だからなんだというのか。困ったものだ。