TitaniumのHTTPClient

TitaniumでTitanium.Network.createHTTPClientをネストさせて使おうとするとうまくいかない。

var url = 'http://example.com/a';

var http = Ti.Network.createHTTPClient();
http.onload = function(){
  var url2 = this.responseText;
  var http2 = Ti.Network.createHTTPClient();
  http2.onload = function(){
    //素敵なサムシング
  };
  http2.open('GET, url2);
  http2.send();
};
http.open('GET', url);
http.send();

詳しく調べていないが、なんとなく試してみたら下のようにするとうまく動作する。

function http_client_two(url){
  var http = Ti.Network.createHTTPClient();
  http.onload = function(){
    //素敵なサムシング
  };
  http.open('GET', url);
  http.send();
}
function http_client_one(){
  var url = 'http://example.com/a';
  var http = Ti.Network.createHTTPClient();
  http.onload = function(){
    var url2 = this.responseText;
    http_client_two(url2);
  };
  http.open('GET', url);
  http.send();
}

http_client_one();

こんな感じでネストするHTTPクライアントを関数として外に出す。とりあえずのメモ。

Popularity: 2% [?]

Titaniumもvimで

vimで作業する方が何かと楽なので、Titaniumでも基本的にはターミナル上で作業しています。その際、エミュレータ上で動かすのにいちいちあちこちをクリックしたくないので、/usr/loca/bin/tiとして下のようなものを置いています。

#!/usr/bin/env ruby
android_sdk = " #{ENV['HOME']}/android-sdk" 

sdk = ARGV[2] if ARGV[2]
sdk = Dir.entries("/Library/Application Support/Titanium/mobilesdk/osx/").sort.last unless ARGV[2]

platform = ARGV[1]
platform = 'iphone' unless platform

android_sdk = '' if platform == 'iphone'

exec "/Library/Application\\ Support/Titanium/mobilesdk/osx/#{sdk}/#{platform}/builder.py run #{File.expand_path(ARGV[0]).gsub(/[\s]/, '\ ')} #{android_sdk}"

まあ出来はともかく、Resouces以下で作業中にvimで

:!ti ../

でiPhoneのエミュレータにインストール、または

:!ti ../ android

で起動済みのAndroidエミュレータにインストールする、みたいな使い方をしています。

Popularity: 2% [?]

HyperCardとiPhoneアプリ

あんまりいわれてないみたいだから、ちょこっと書いておく。iPhone/iPad/iPod向けアプリを作っていて、ふと思ったんだけど、これってHyperCardに似てるよね。画面を「スタック」と考えると、iPhoneアプリではそれを積んで画面を遷移させて、前画面に戻ることについてはプログラマは特に考えなくてもナビゲーションバーで自動的によろしくやってくれるんだけど、これもスタックだと思えばそれは最後に積んだのを降ろすんだから自動でやってくれて当然だし、そういう具合にアプリの遷移を組み立てていくことになる。

Mac OSで動作するHyperCardが出ることはもうないだろうけど、意外なところで復活してたんだな、と思った次第。

Popularity: 1% [?]

TiStorekitを公開しておきました

Titanium MobileでStoreKitを扱うTiStorekitがあったのですが、いろいろと大人の事情で更新できなくなっていました。チェックしてみるといくつか直しておかないといけない箇所があったので、forkしておきました。

yagitoshiro / TiStoreKit

リファレンス通りに素直な作りになっているので、変更したのはfinishTransactionの変な挙動だけです。finishTransactionは購入処理が完了すると呼ばれる処理で、paymentQueueに溜まったtransactionを終了させるためにあるのですが、TiStorekitに限らず、いろいろなプログラムでどういうわけかtransactionがキューに残ってしまう現象が報告されています。例えば、手元のプログラムではAppStoreでアプリが公開されたもののIn App Purchaseの方がまだ販売開始になっていない状態でエラーになると確実に残ってしまっていました。害があるかどうかはアプリの構成によりますが(大半はないと思います)、気持ちが悪いですね。そこでざっと調べてみました。例えばこちら。

Transaction comes back after finishTransaction: has been called on it

iPhone inApp Purchase Queue won’t clear out

でも、Appleから提供されている資料では、結局どこをどうすればよいのかはっきりとはわかりませんでした。上のリンクでも、どうやらiOS 4になって何か変更されたらしいというところまでしか判明しなかったようです。そこで、下の方のリンクを参考に、transactionがキューから消えないなら、それを監視して不要なところで復活させてしまう諸悪の根源のObserverを問答無用で削除してしまうのが、こちらの変更です(たった1行でざっくり)。

もっとスマートな方法もあるのかもしれませんが、ここらで手一杯でした。こうした方がいいよ、という案をお持ちの方は、是非forkするかパッチをください。

Popularity: 3% [?]

In App Purchase利用アプリを公開すると

アプリが先に発売されてしまって、In App Purchaseの方が有効にならないで誰も購入できず、ユーザ様からの苦情が殺到して、いったい何が問題なんだと大騒ぎになり、ああでもないこうでもないと検討して2時間以上経過した後、Appleが平然とAppStoreを更新して購入が可能になるなんてことがあるかもしれませんよ。

辛い。。。

Popularity: 1% [?]

Titaniumとi18nとXcode

UPDATE: Titnaium mobile SDK 1.7系だとLocalizable.stringsが壊れてちゃんと動かない!自前でXMLをパースしてテキストに変換して対応した。

Titanium Mobileにはプロジェクト/i18n/locale(jaとかenとか)/strings.xmlというファイルを置くだけで国際化対応できる仕組みが用意されているのだけれど、Xcodeとの相性が悪い。Titaniumでビルドした後、Xcodeからコード署名やら何やらをしてリビルドすると、文字列の変換をやってくれなくなるのだ。普通にTitaniumからビルドして実機で確認したりリリースまでやってしまえば問題ないのだけれど、なかなかそうもいかない(ソースコードで納品するとか)場合は困ってしまう。というか、実装としてこれはいかがなものか。

そこでいろいろ調べてみたのだけれど、Titaniumでビルドを実行して作成される.appの中にi18n以下に作成したロケールの分だけ「en.lproj/Localizable.strings」「ja.lproj/Localizable.strings」みたいなファイルが作成されているのがわかった。これらはiOSの国際化対応の仕組みで利用される言語ファイルなのだが、どうやらTitaniumがビルド時にi18nディレクトリ以下を走査してXMLから生成しているようだ。でも、Xcodeがビルドする際には当然ながらi18nディレクトリなんか見ないので、一度クリーンしてビルドすると無から有は生まれないように、各ロケール用ファイルは無視されてしまう。

もっとも単純なやり方は、いったんTitaniumからビルドして、transport.pyなどで必要なファイルをプロジェクト/build/iphone以下にコピーする。それから、作成された.appファイルをプロジェクト/build/iphone/build以下のどこかから探してきて、右クリックでもなんでもいいからパッケージの中身を表示、中にある「ロケール名.lproj/Localizable.strings」をどこかにコピーしてバックアップする。Xcodeからプロジェクトファイルを開き、Resouces以下とかにこのLocalizable.stringsを追加したら、ちゃんと動作した。命名規則でこのファイル名ならローカライゼーション用のリソースだと判定されるらしい。

Localizable.stringsはUTF-16で記述されているので、読み込んだ際は盛大に文字化けするので驚かされるが、文字エンコーディングを指定すれば直る。

Popularity: 2% [?]

Titanium DeveloperとXcodeの連携

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

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

Popularity: 4% [?]

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に限って動かないケース。繰り返しになるが、よくまあリリースしたもんだ。

Popularity: 4% [?]

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

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

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

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

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

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

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

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

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

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

Popularity: 3% [?]

Titanium DeveloperでAndroid(3)

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

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

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

Popularity: 2% [?]