娘が生まれました
2/22に娘が生まれました。元気な子です。名前は「そよ」です。かみさんが種田山頭火の句から取ったみたいです。可愛いんですが、どれくらい可愛いかというと、すごく可愛いです。
Popularity: 1% [?]
Titanium MobileのGeocodingで日本語を扱う
Titanium Mobileにも住所から緯度経度を取得(Geocoding)したり、その逆に緯度経度から住所番地を取得(Reverse Geocoding)する機能があります。しかし日本語やその他言語でローカライズされた住所を扱うことができません。
これはGeocodingのプロバイダにGoogleなど他のサービスを利用すれば解決できます。割と簡単にできるのでさくっとコードを書いていたのですが、@k0sukeyさんがcommonJSのモジュールにしてくれていますので紹介します。使い方は簡単、READMEにある通りです。
引数のlanguageプロパティで戻り値の言語を設定できます。Google MapsのAPIなのでサポートされている言語はこちらの通りです。ただ、使用例にあるTi.Platform.localeの値は中国語だとzh_hansやzh_hantになるので、Google側はzh-CNやzh-TWを期待しているため調整が必要です。ロケールについてはあまり詳しく知らないのですが、ググってみるとGoogle側の方が正しい解釈をしているようですね速攻で対応されたらしいぞ!
なお、Ti.Geocoding.forwardGeocoderとかreverseGeocoderとかは筋が悪いのでしばらくは絶対に使わない方がいいです。
Popularity: 2% [?]
Lavishでカラースキーム
画像のURLを指定すると、画像に使用されている主な色をprizmで解析、そこからカラースキームを作ってウェブページのテンプレートを吐き出す「Lavish」というRailsアプリケーションをTwitter経由で知ったので試してみたが、素晴らしかった。使い方は画像のURLをフォームに入力して「Go Lavish」ボタンをクリックするだけ。
モノクロ画像だとレイアウトがおかしくなったり、まだまだ熟成していないプロジェクトではあるが、開発者がちょっとしたデザイン仕事をするのには強力な手助けになってくれる。
ちなみにprizmもLavishも同じQuan Nguyenさんが作っている。素晴らしい。
Popularity: 1% [?]
Rails3 + Sorceryで複数のモデル(管理者と一般ユーザとか)を扱う
Deviseが魔術すぎるので一部のユーザには人気のあるシンプル指向のユーザ認証用プラグインSorceryですが、例えば「管理者」と「一般ユーザ」みたいに複数の種類があるアカウントをそれぞれ別のモデルとして扱うのはあまり得意ではありません。どのウェブアプリケーションでも普通はこれくらいのアカウント種別はあるでしょうし、もし一般ユーザに管理側の機能やアカウントが使えるようになってしまっては困るので、うっかりミスでとんでもないことにならないよう、それぞれ別のモデルで扱いたくなるのは当然です。これが出来ないのであれば、折角シンプルさが気に入ってSorceryを使い始めても、すぐに挫折してしまいます。大変残念です。
でも、まあ確かに得意じゃないとはいっても、別に出来ないというわけではありません。Sorceryで複数のモデルで複数のアカウント種別を扱う最も一般的なやり方は、Single Table Inheritance(単一テーブル継承)を利用するものです。備忘録として使い方をまとめておきます。
単一テーブル継承といっても、別にPostgreSQLにあるようなテーブルの継承を利用するような高度なものではありません。単純に、同じテーブルにデータを格納しつつ、typeカラムに入った文字列でアカウントの種別を判定する、というだけのことです。データとしてはそんなしょぼい構成になりますが、アクセスするモデルを別にすることができるのが利点です。
ややこしいのでモデルの例で説明すると、
$ bundle exec rails g sorcery:install
これでusersテーブルを扱うUserモデルが作成されます。これにtypeカラムを追加します。
$ bundle exec rails g migration addTypeToUsers type:string $ bundle exec rake db:migrate
さて、これで親となるモデル「User」が完成しました。Sorceryのマニュアルに従い、app/models/user.rbを編集してSorceryで使えるようにしましょう。initializerの設定も忘れずに。config.user_classはUserで構いません。ひとつだけ、config/initializers/sorcery.rbで継承の利用をtrueにしておくことをお忘れなく。
user.subclasses_inherit_config = true
次に、これを「継承」した子モデルを作成します。そうですね、memberとadminという名前にしましょうか。
railsのジェネレータで作成したモデルはActiveRecord::Baseを継承しています。でもSingle Table Inheritanceのモデルは親テーブルを扱うクラスを継承します。これにより親テーブルのvalidationなどの情報を引き継ぐことができます。またSorcery固有のauthenticates_with_sorcery!も子テーブルでは呼ぶ必要はありません。
class Admin < User end class Member < User end
これで何が出来るようになるかというと、Sorceryの各種メソッドが使えるようになったのはもちろん、例えば
@member = Member.new(params[:member]) @member.save
これでtypeカラムに「Member」という文字列が入った状態でデータが保存されます。保存されるテーブルは「users」です。同じくAdminモデルから作成したオブジェクトではtypeカラムに「Admin」という文字列が入ります。
またそれぞれのモデルからデータを引っ張り出すときには、勝手にtypeカラムの内容を検索条件に追加してくれます。
User.find(params[:id])
#=> SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
Member.find(params[:id])
#=> SELECT `users`.* FROM `users` WHERE (`users`.`id` = 2 AND `users`.`type` IN ('Member')) LIMIT 1
Admin.find(params[:id])
#=> SELECT `users`.* FROM `users` WHERE (`users`.`id` = 2 AND `users`.`type` IN ('Admin')) LIMIT 1
あとは、各コントローラでAdminかどうか認証する場合は、application_controller.rbに
protected
def is_admin?
if current_user && current_user.type == 'Admin'
true
else
false
end
end
def admin_required
unless is_admin?
redirect_to root_path, :alert => "You are so cool..."
end
end
こんな感じのフィルタ用メソッドを用意しておけば、管理者のみアクセスさせたいコントローラで
class TopSecretsController < ApplicationController before_filter :admin_required
アクセス制限をかけることができるようになります。「Admin」という文字がハードコーディングされているのがキモいので定数にしておくといいでしょう。
Popularity: 2% [?]
Titanium MobileではAnalyticsを切っておきましょう
2年前の記事ですが、AppStoreのトップ無料や人気上位のアプリの68%がUDID(Universal Device Identifier)を送信しているという報告がありました(関連の日本語記事)。
利用状況などを収集してアプリの改善に利用するのはよくあることだとは思います。行動分析のためにデータを収集する場合、端末の識別のために何らかのIDが必要となるわけですが、スマートフォンでは最も簡単に利用できるのがこのUDIDです。このようなIDは以前から日本の携帯電話のサービスプロバイダでは広く利用されており、中にはウェブサービスの認証にまで使われているケースもありましたので、ある意味われわれにとっては非常に身近なものでもあります。
しかし、端末固有の一意なIDとして何かと便利に思われるUDIDですが、これを第三者に送信するのはあまり感心できません。上の報告ではHTTP通信のGETリクエストで送信しているアプリもあったようですが、これは論外です。しかし、もちろんそれだけが理由ではありません。
UDIDの送信がなぜ問題なのかについては諸説あるでしょうが、主な理由として考えられるのがエンドユーザの行動をトラッキングできてしまうことがプライバシーの侵害になるかもしれないという懸念です。同じようなことがいわれてきたブラウザのクッキーであれば、第三者のクッキー(Third-party Cookie)はブラウザの設定などでオプトアウトできるわけですが、UDIDは変更することができないため一度送信されてしまえば相手側の対応がなければ削除されません。アプリによってはその性格上、いつ起動していつ利用されたのか他人に知られたくないケースもあるでしょう。しかしUDIDが取得されてしまえば、第三者にその情報が漏れてしまいます。この手の試みはこれまでもウェブ広告の世界などでプライバシーとビジネスの間のせめぎ合いが何度も繰り返されてきた歴史があるわけですが、たいていはプライバシーの擁護が重視される結論に至っています。
ところでTitanium Mobileですが、Appcelerator社のサービスに登録している方なら一度くらいはAnalyticsの画面を見たことがあるかと思います。アプリのインストールされた数の推移や様々な行動分析が見られるので、開発者だけでなく企画等の担当者も大変重宝します。これらの情報はTitanium MobileのAnalyticsという機能を利用して送信されています。送信はSSLで暗号化されたPOSTリクエストになっているので、途中で覗き見られることについては、iPhoneの3G回線の通信がEnd-to-endのSSLではないなんてことはないでしょうから(ガラケーだとゲートウェイとウェブサーバ間のSSLになっていたりするようですが)、さほど憂慮する必要はなさそうです。さらに、当然ながらAppcelerator社は集積したデータをさらに第三者に転売したり、広告などに悪用したりするようなことはしないと明言しています。その点で現時点で懸念する必要はないと思います。しかし、いくつか問題はあります。(1)データを集積しているAppcelerator社はアプリの配信元、エンドユーザにとっては無関係の第三者であること(2)送信される情報についてアプリの利用者から明確な許諾を得ていないこと(3)UDIDが送信されていること、などがそうです。
これらの対応策は非常に簡単で、tieapp.xmlをテキストエディタなどで開いて
<analytics>false</analytics>
とするだけでこの機能をオフにすることができます。個人的な意見ですが、上記の理由から、現時点ではリリースされるアプリについては必ずこれをやっておく方がよいでしょう。もちろん、UDIDの送信が即、何か悪いことをしている証拠にはならないと思います。しかし、このような取り扱いに注意が必要なデータについては、トラブルを避けるためにも万全な状況でなければ利用しない方がいいはずです。また、iOS5からUDIDの取得が非推奨となったことに伴い、やはりUDIDの送信は避けるべきでしょう。
実際のところどうなっているのか確認してみましたが、残念なことに1.8系の実装(iphone/Classes/PlatformModule.mやiphone/Classes/TiUtils.mを参照のこと)を見る限り、Titanium.Platform.idを送信していますね。1.8.0.1の場合はiphone/Classes/AnalyticsModule.mmを見るとわかります。実際にデータをダンプするには(SSLの通信をキャプチャするような面倒なことが好きな人を除いて)このファイルを下のように変更します。
$ git diff iphone/Classes/AnalyticsModule.mm
diff --git a/iphone/Classes/AnalyticsModule.mm b/iphone/Classes/AnalyticsModule.mm
index f76a472..46c6e81 100644
--- a/iphone/Classes/AnalyticsModule.mm
+++ b/iphone/Classes/AnalyticsModule.mm
@@ -217,6 +217,9 @@ NSString * const TI_DB_VERSION = @"1";
[request setUseCookiePersistence:YES];
[request setShouldRedirect:YES];
NSString * stringifiedData = [SBJSON stringify:data];
+ //debug
+ NSLog(@"[DEBUG] Analytics sending data: %@", stringifiedData);
+ //debug
[request appendPostData:[stringifiedData dataUsingEncoding:NSUTF8StringEncoding]];
[request setDelegate:self];
ご覧頂ければわかる通り、UDIDが送信されていますので、やはり上に書いた方法でAnalyticsは停止した方がいいですね。それと、Appcelerator社が悪意をもってこの機能を実装しているのではないこともおわかり頂けるかと思います。だって、そうじゃなきゃソース公開してないですよね?個人的にはこういうところがTitanium Mobileを使い続けることの大きな理由になっています。
*決してここの部分をいたずらして集積サーバに変なデータを送り込んでしまおうとか考えてるわけじゃないですからね!
また、この点について各方面に問い合わせたところ、Analytics自体は非常に有望なサービスなので、今後はUDIDを利用しないよう変更する予定になっているとのことでした。そのときが来たら再度検討してみたいと思います。
この数日、エントリを書いておきながら公開するべきか非常に悩んでいました。上で説明はしたつもりですが、これは別に情報が勝手に第三者に集積されてしまったというような事件ではなく、単純に機能としてソースまで公開され、ドキュメントにも書かれていることなわけで、簡単に調査も可能なことですから、開発者としては知っていてある意味当然なことです。ただ、どこかで誰かがこの機能について悪意的にかき立てるようなことがあれば、まだまだ少数のコミュニティで活発にやり取りしている状態のTitanium Mobileが今後プラットフォームとして成長する妨げになってしまうような打撃を受けると嫌だな、と思ったので、情報の周知徹底を目的に公開することにしました。
もう一度まとめます。
(1)Analyticsはオフにできるよ
(2)オフにしとけばなんにも怖くないよ
(3)UDIDは今後は使われなくなるよ
以上です。
Popularity: 3% [?]
Titanium Mobileでアプリ内課金(iOS編)
アプリ内課金の実装方法について知りたいという声があったので、参考になればと書いておきます。アプリ開発者の方は権利の15%で取引に応じますの苦労がこれで少しでも減るなら喜ばしいことです。とはいえ、世知辛い世の中ですから、このコードで生じた金銭的問題の責任は放棄しますので、ご利用の際はあくまでも参考程度にとどめ、十分検証した上で実装されるようお願いします。
一応、動作はTiStorekit1.4、Titanium Mobile SDK 1.8.1、非消費型コンテンツで確認しています。
iOSの場合、課金の手続きは
- In App Purchaseが有効になっているかを確認する
- 正しいProduct IDかを確認する
- 購入開始
- 成功ならレシートを受信してチェック、キャンセルやエラーならエラー処理
となります。ここではAppcelerator社から公開されているTiStorekitを使った実装の例で説明します。以前に実装したものを参考にざっと書いた関係で、細かい条件は検証していませんのであしからず。CoffeeScriptだけどいいよね?
事前にiTunes ConnectでIn App Purchaseの設定が完了していることが前提になります。iTunes Connectの使い方は割愛しますが、支払い関連の設定が完了していないとIn App Purchaseは有効になりません。またProvisioning Portalで設定を確認して、正しいProvisioning Profileでビルドしましょう。iOS5からシミュレータからも利用できるようになったようですが、必ず実機で動作確認してください。
そうそう、下のコードではコンストラクタで@SANDBOXをtrueにしていますが、リリース時には変更しましょう!
class InAppPurchase
constructor:()->
@ERROR_PRODUCT_ID = {type:'product_id', message:L('inapp_error_product_id')}
@ERROR_CANMAKEPAYMENT = {type:'canmakepayment', message:L('inapp_error_settings')}
@ERROR_UNKNOWN = {type:'unknown', message:L('inapp_error_unknown')}
@SANDBOX = true
start:(data, success, error)->
###
args dataは課金対象の商品オブジェクト({product_id:プロダクトID})
sccess、errorはそれぞれcallback関数
###
storekit = require 'ti.storekit'
if data.product_id == '' || data.product_id == null || data.product_id == undefined
# なんて防衛的なコード! #
error(@ERROR_PRODUCT_ID)
else if !storekit.canMakePayments
# AppStoreが有効になっていない #
error(@ERROR_CANMAKEPAYMENT)
else
# 正しいProduct IDかどうかチェック #
storekit.requestProducts([data.product_id], (e)=>
if e.success
product = e.products[0]
if product != null
_success = success
_error = error
storekit.purchase(product, (elem)->
if elem.state == storekit.FAILED
error(@ERROR_PRODUCT_ID)
else if elem.state == storekit.PURCHASED
callback = (response)=>
if response.success && response.valid
_success()
else
_error(@ERROR_UNKNOWN)
# subscriptionの場合は下のオブジェクトにsharedSecretプロパティを追加 #
args = {
receipt:elem.receipt
sandbox:@SANDBOX
callback:callback
}
storekit.verifyReceipt(args)
else if elem.state == storekit.RESTORED
storekit.restoreCompletedTransactions()
success()
else
Ti.API.info "purchasing..."
)
else
error(@ERROR_UNKNOWN)
else
error(@ERROR_PRODUCT_ID)
)
TiStorekit = new InAppPurchase()
TiStorekit.start(product, success, error)
canMakePaymentsは定数でiOSの設定画面でAppStoreが有効になっていないのでそもそもアプリ内で課金ができない場合はfalseになります。requestProductsでProduct IDが正しいかどうかを確認し、purchaseで購入処理を開始します。successが返ればveryfyReceiptで確認して完了処理を実行します。
レシートの確認まで実装しましたが、ここは迷うところですね。通信に時間がかかったり、またはこのタイミングで処理が中断してしまった場合、利用者にとってはお金を払ったのに購入が正常に完了しないように見えてしまいます。時間がかかるようならキューに入れてレシートは後で確認し、いったん完了処理をしてから、不正があったらそれなりの処理をする、といったような手段で対応するしかないでしょう。かといってレシートを確認しないと、不正な利用を完全に防ぐことができなくなります。
Popularity: 4% [?]
男子バレーボールが強くならない理由
昔、自分がバレーボールをやっていた話になると、「なぜ男子バレーボールは弱いのか」と聞かれることが多いので、いつも答えていることを書いておく。ちなみに、筆者が高校生の頃に関東地区の選抜チームで指導を受けていた人が、今の全日本の男子チームの編成を担当していたりする。いろいろ面白い話も聞いているが、ここでは関係ないので触れないでおく。
男子バレーボールが世界的にお世辞にも強いチームとはいえない状態が20年くらい続いているのはご存知の通り。オリンピックでは1992年の6位を最後に上位入賞どころか予選敗退が半分以上になっている。日本に極端に有利な条件で実施されるワールドカップですら、出場が12カ国となった92年以降の成績だけみても95年の5位を最高に後は9位か10位だ。ちなみにワールドカップというのは、4年に一度、常に日本で開催される大会で、オリンピックと世界選手権と合わせて一応「世界三大大会」のひとつなのだが、ジャニーズとフジテレビが派手なキャンペーンを繰り広げ、耳をつんざくような黄色い声でひたすら日本を応援するジャニーズのファンが押し掛ける異空間だ。日本チームの出場は必ずテレビの放映時間に合わせて日程が組まれるのでコンディショニングでも非常に有利になっている。さすがに試合前のジャニーズのショーは国際バレーボール連盟の要請で中止になったらしいが。
かつて、といっても1970年代だが、日本はオリンピックで金メダルを獲得したこともあり、何度も上位入賞を果たした強豪国だった。当時の監督で先頃亡くなった松平康隆のPRマンとしての手腕もあり、80年代までは人気の上では絶頂期だったといえる。だが、その頃から徐々に坂を転げ落ちるように国際大会での成績も下降して、人気も凋落していった。近頃は小学校でのバレーボール人気が復活しつつあるそうだが、それもこの年代にファンだったりプレーしていた人たちが親になって自分たちの子供に教えているからだそうだ。
さて、ではなぜ日本代表が弱くなってしまったのか。その理由として最も多く挙げられるのが、身長の問題である。リベロ制度やサービスエリアの撤廃、ラリーポイント制で、とにかく背が高く攻撃力のあるチームが有利になったために日本が活躍できない、というわけだ。実際、身長を比較してみると、確かに世界ランク1位の常連国ブラジルが平均身長197.8cm、中央値197.5cmのチームであるのに対して日本代表の平均身長は7cm程度低い190.6cmとなっている。両チームからリベロを抜いたり、中央値をみてもさほど変わらないので傑出して足を引っ張っている選手もいないようだ。伝統的に身長の高い選手が多いロシア(ロシアではブロックは「壁」ではなく「屋根」という、と昔教えられていましたが本当でしょうか?)もおそらく同じような結果になるだろう。確かに、これもひとつの理由はありそうだ。
だが、それで疑問は全て解決するわけではない。なぜ、背が低いのだろうか。平成20年度の日本人男性の平均身長は25歳から29歳で172.11cm、標準偏差が5.59となっている。サンプル数もそれなりに多い(380万人くらいらしい)ので信頼できる数字だと仮定すると、統計的にはおよそ全体の70%くらいの人たちが166.52cmから177.7cmの範囲内に収まっていることになる。また95%が160.93cmから183.29cmの範囲内にいることも予想される。つまり、チームに入れそうな年齢の男性の5%しかこの範囲から外れる人はおらず、その中でも半数以上(おそらくhydeとか)は下の方にはみ出しているので、下手をすると2%や1%の人材から選手を調達しない限りは高さで世界各国と対抗することは出来ない。
というとなんだか絶望的に聞こえるかもしれないが、日本の人口はとても多いので、25歳から29歳までの男性は380万人もいるのだから、この2%なら実は7万数千人も候補者がいることになる。世界ランク5位のセルビアの総人口は1,000万人に満たず、成人男性の平均身長は178cmだ。200cmの人口は日本より少ないと予想される。つまり、日本は単純に背の高い人材を確保できていないか、育成できていないだけなのではないか。
では、それはコーチングの問題なのだろうか。そう単純な話であれば、外国の指導者を連れてくるだけで事態は改善されるだろう。しかし、状況をみるにそうではないように見える。なぜなら、バレーボールの周辺環境は非常に厳しいものだからだ。
ここからが結論になるのだが、なぜ男子バレーボールが弱いのか(そして、なぜ女子はまあまあなのか)は、手っ取り早くいえば男性の平均年収と女性の平均年収の違いが原因だ。バレーボールは一日6時間以上練習することが出来るので実業団の選手は午前中だけ勤務して練習するか、朝から練習している。このような生活を30歳くらいまで続けるとどうなるか。同じ企業チームでもラグビーではそんなことをしたらみんな死んでしまうので、基本的には定時で上がってから練習をする。曲がりなりにも定時までは仕事をしているので、ラグビーの選手なら引退後もなんとかなるかもしれない。実際、早めに引退して仕事の方で本格的なキャリアを積むケースが多い。でも、バレーボールの他には何もせず、ほとんど業務経験もないまま過ごしてきた30歳に出来る仕事なんかあるだろうか。指導者として残る人などごくわずかであり、大半はとりあえず物流など力仕事中心の部署で自分よりずっと年下の人たちに混じって再スタートすることになるか、そのような環境にも居づらくて退職して連絡がつかなくなる。ましてや、プロ契約など結んでしまっては引退後の身分保証はほとんどない。給与をもらっている男性の平均年収は533万円くらいだが、このレベルになるためにはいつまでも選手を続けていては無理なのだ。男子バレーボールに人材が集まらない理由は、食えないからである。
一方、同じく女性の平均はそれよりずっと低く271万円なので、正社員であれば定時上がりの仕事であってもこのレベルに到達するのはさほど難しくはない。そのため、選手を続けてそのまま会社に残ったとしても、一部の専門職を除けばとりわけ同世代と比較しても待遇が悪いこともない。ましてやこの不景気に実業団に属してプレーすることができればかなりいい身分であるともいえる。
以上が男子バレーボールが強くならない理由だ。細かいところを見れば他にもいろいろあるだろうが、ここが根本的に対策されない限りは、このスポーツに未来はない。
Popularity: 2% [?]
どうしてTitanium Mobileなの?
ウェブ開発者がiOSやAndroid向けアプリを作ろうと思い立った場合、今なら大きく分けて2つの選択肢があります。ひとつは他の人たちと同じようにObjective-CやJavaで素直にアプリを作ることです。まあ、当たり前ですね。もうひとつの方は、PhoneGapやTitanium Mobileのようなサードパーティーのツールを利用してJavascriptなどウェブ開発者の慣れ親しんだ言語で開発するやり方です。それぞれ一長一短があります。先のやり方では、ネイティブな開発用言語だけあって全ての機能を最大限に活かすことができます。AppleやGoogleも最大限の開発支援を提供してくれることでしょう。しかし、Objective-CやJavaに慣れ親しんでいた人でなければ学習曲線がなかなか上昇してくれないかもしれません。特にウェブ開発者はWebObjectsをやっていた人でもない限りはObjective-Cに馴染みの無い人が多いでしょう。また、ヘッダファイルを書くことやDelegateみたいなまだるっこしいデザインに疲れてしまうかもしれません。そんな場合、サードパーティーのツールで素早く開発しながら徐々に慣れていく方が安全なやり方といえます。一方で、サードパーティーのツールには最上位のベンダつまりAppleやGoogleの意向でいつ排除されてしまうかわからないというリスクもあります。これまで見たところでは、今年や来年にそんなことが起きるとは到底考えられないのですが、それでも細かいトラブルはあるでしょう。
以上のような状況を鑑みるに、もしあなたがObjective-CやJavaでの開発に不安が残る状態であるなら、迷わず後者の方を選択するべきでしょう。その上で、自分の開発しているプラットフォームについて知ることは重要であり、そうであればいずれはネイティブな言語での理解が必須になるでしょうから、得られる知見を最大限に活かしてObjective-CやJavaでの開発について学んでいくのが理想です。例えば、PHPを使って開発をしていても、それだけしか知ろうとせず、ウェブサーバやPHP自体の実装といった抽象化されて隠された部分に分け入って進もうとしない人が、筆者の経験ではありますが、競争に耐えうる優秀な人材であった試しはありません。幸いにもサードパーティーのツールにはソースコードにアクセスできるものもあるので、良い手本になることがたくさん見つかるでしょう。
では、数あるサードパーティーのツールの中で、一体どれを選べばいいのでしょうか。
もちろん、おみくじで決めたとしても、それは当人の責任の範疇ですから、全く構いません。しかし、それでもやはり、いくらなんでももう少し真面目に考えないと不安になるかもしれません。なので、そうですね、それぞれのツールの特徴を掴んだ上で判断する方がいいでしょう。私自身も決定的な答えを用意しているわけではないので、知っている範囲で自分の意見を述べたいと思います。情報は最新とは限りませんので、ここは違う、いや今はこうなっている、などなどご意見あれば是非聞かせてください。いずれにせよ、現段階ではちょっとした宗派の争いみたいになりがちな話題なので、リラックスしてお読みくださいね。
サードパーティーのツール、と上ではひとくくりにしましたが、大きく分けるとこれも二種類に分かれます。ひとつはPhoneGapやRhodesのようにHTMLとJavaScriptで作ったUIをWebView(UIWebView)を使って表示させる、ウェブアプリとネイティブアプリが合体したようなもの、もうひとつはTitanium MobileのようにネイティブなAPIを叩いてJavascriptで記述しながらネイティブアプリとして動作するものです。ここでは実際に使ったことのあるPhoneGapとTitanium Mobileを比較します。
私見では、PhoneGapのいいところは第一にそれがシンプルであることです。例えば生成されるJavaのクラスは非常にシンプルで、実際に使ってみたところカスタマイズも容易でした。APIも数えるほどしかなく、プラグインの作成もそれほど難しいものではありません。また、UIはHTMLとJavascriptで作るので、ウェブ開発者やデザイナのこれまでに培った技術を活用することができそうです。
それに、例えばFacebookアプリは現在PC向けのものはHTMLで作られていますが、モバイル向けも今後は同じくHTML5を利用して記述され、Facebookのモバイル用アプリ内で動作するといったものになっていくことが予想されます。クロスプラットフォームでの開発が容易なのはHTMLの強みですから、こうした流れにソーシャルゲームのプラットフォームも追随していくのではないかと思います。
しかし、欠点もないわけではありません。jQuery MobileやSencha Touchといったツールを使ってなるべくネイティブアプリに似せることは出来ますが、それでもUIはネイティブなものではありません。これらのツールキットはまだ開発されてから日も浅くベストプラクティスも少ないので、開発はお世辞にも快適とはいえないのですが、それなのに特にiOSではHTMLとCSSででっち上げた「ネイティブっぽい」UIの「偽物」っぽさが際立ちます。動作もまだまだ快適とはいえません。またネイティブな機能への橋渡しをしてくれるAPIも豊富とは言い難いので、少しでも複雑なことに挑戦すると結局Objective-CやJavaでプログラムを作成する必要が生じます。UIレベルの話ならまだしも、例えばiCloudへの対応といった要求にはツール側での対応を待つかそれなりの工数を費やしてプラグインを作成することになってしまうでしょう。それに、これは年月が解消してくれる問題なのかもしれませんが、例えばSnapdoragonの第1世代のIS03のような貧弱なハードウェアではWebViewのようなリソースを消費するものはどうしても動作が遅くなります。オリエンテーションの変更の際にレイアウトが酷く崩れるといったユーザに不安を与えるような現象が発生することもあります。
最近、PhoneGapの開発元がAdobeに買収されることが発表されましたが、資金的には大きな後ろ盾を得たと同時に、大企業であり、これまで数々のプロダクトをディスコンにしてきたAdobeにその命運を握られてしまったともいえます。
以上、駆け足ですが個人的に思うところを述べてみました。先ほども書きました通り、ここは違う、いや現在はこうなっているといったご意見などございましたらお知らせください。
さて、その一方でTitanium Mobileの場合、Javascriptで記述した内容は評価された後にプロキシを通じてiOSやAndroidのAPIに渡されて実行されるため、実際に動作するのは通常のアプリと同じものなので外観は全くネイティブなアプリと変わりません。と同時に、Titanium.UI.WebViewというものが用意されているので、やろうと思えばHTMLとJSでUIを作ってしまうことも可能です。またこのJSとネイティブな機能を繋ぐのも非常に容易なので、この点でも大きなアドバンテージがあります。動作速度はネイティブアプリと比較すれば、インタプリタとコンパイル言語ほどではなくても、まあある程度の差はあります。しかし、シビアな反応が求められるゲームや電子書籍リーダといった特定用途のアプリでなければ実際に問題になるほどではありません。ネットワーク越しにデータをやり取りするアプリ、ウェブサービスのフロントエンド用アプリとして利用するには十分といえます。それに、驚くべきことに、最近ではQuickTiGame2dのような高速で動作するゲームエンジンも開発されていますので、ゲームの開発に利用されるようになる日も近いでしょう。また、このようなサードパーティーのモジュール開発も盛んで、Open Mobile Marketplaceで有料、無料を問わずたくさんの機能拡張用モジュールが公開されています。Githubにソースコードが公開されているものも少なくありません。
それから、jQuery MobileやSencha Touch(Ext.JS)といった一種独特なJavascriptよりも、commonJSといったモダンなJavascriptで記述することが推奨されているのもポイントです。最近ではNode.jsのようなサーバサイドのJavascriptもありますが、Titanium MobileのJavascriptもCoffeeScriptやcommonJSのような今時の技術を習得する近道となるでしょう。というのも、Titanium Mobileは基本的にはよくあるイベント駆動型のGUIのプログラミングなので、Node.jsのようなコールバックにつぐコールバックの連続にも面食らうことはありません。
と、いいことばかり並べましたが、もちろん問題もないわけではありません。Aptanaを買収してEclipseベースの独自のIDEがリリースされましたが、Eclipseがそうであるように人によってはあまり快適とはいえないものです。もちろん使わないで開発することも可能ですが、最初はやはり公式なツールを使いたくなる方も多いでしょうから、そこら辺で面食らうこともあるかもしれません。またビルドスクリプト内部にビルドにかかる時間短縮のため高速化する工夫があるのですが、何度も繰り返してビルドするうちにそれが邪魔をしてアプリの挙動がおかしくなることがありますので、ときどきCleanしてあげる必要があるといった癖のあるところも見受けられます。また海外製品にありがちなことですが、Pythonを使ったビルドスクリプトはUTF-8のMac OS Xで日本語の処理に問題がある箇所が多数ありますのでアプリ名称やプロジェクト名、ソースコードのフルパスに日本語が含まれていると辛い目に遭います。その辺りは、日本語でも有志によるサポートコミュニティがありますので、活用してください。
これらは今後改善されるべきことではありますが、一方で大半は公開されたソースコードから追いかけることも可能なことであり、ついでにいえばパッチを送って直してしまうことだって出来ます。個人的には、いつか大金持ちになって暇を持て余すようになったら、面倒の多いPythonの部分を全部Rubyにしてしまいたいと思っています。また、Titanium Mobileを入り口としていろいろと学びましたが、逆にネイティブな言語で開発しなくてもいいやという気にもなってきました。やっぱりDelegateとかってうんざりますよね?
以上、駆け足で比較していきましたので粗雑な部分、間違いなどもあるかもしれません。上にも何回か申し上げましたように、これは違うぞ、といったところがあればどしどしご指摘ください。よろしくお願いします。
Popularity: 7% [?]
ImageAsResized for Androidの問題
指摘を受けたので調べてみましたが、Titanium MobileのAndroid用モジュールとして公開しているImageAsResizedモジュールにはちょっとした問題があります。
例えば、ここになんともいえず愛らしい息子の写真があるとします。縦横サイズは1536 × 2048ピクセルです。ちょっと大きいのでここでは縮小して表示しますね。

これを半分(768 x 1024)にリサイズします。大きいので表示は縮小します。

全く問題ありません。
じゃあ、1/8にしてみましょう(192 x 256)。こちらは実物大。

全然問題ありません。パパは萌え死にそうです。
ですが、これを1/10(153.6 x 204.8)にしようとすると、おかしなことになります。

あれ?切れてるよ!?まめちゃん切れてる!許せない、もう絶対許せない!
思わずモンスターペアレントになってしまいました。なぜこんな現象が起きるかというと、このモジュールはAndroidのBitmapクラスを利用しているのですが、こいつがbitmapデータの作成時に縦横サイズとしてintegerしか受け付けてくれないからです。1/10に縮小しようとして縦横サイズをfloatで指定しても途中でキャストされてしまいます。そうなった場合、縦横比もおかしいのでうまくリサイズされなくなります。モジュールは内部的にはメモリ節約のためいったん近似値までリサイズするようになっているのですが、どうやらそこから先はこの状態だと細かいリサイズをしてくれないで画像を切り取って処理してしまうようなのです(この辺の理解は適当)。
元々、このモジュールは同時期に作ったCropImageモジュールと併用して、縦横サイズが前もって予測できた上で使うことを前提としていたので、その辺りは細かい調整をしていませんでした。で、今日ちょっと質問されたので眺めてみましたが、上のような事情でうまくいきませんでした。何かうまい手はないでしょうか。例えば縮小する際に縦横サイズを指定するときは最大公約数を計算してどちらもちゃんとintegerになるようなヘルパーを用意するとかですかね。
Popularity: 1% [?]



