Friday, January 27, 2012

iOS App PhotoHistory Released!

iPhone / iPod Touch アプリ PhotoHistory (Apple App Store 170円) をリリースしました

このアプリは僕自身が Apple 標準の写真アプリを使ってみて不便に感じたところを解決しようとしている試みです。何が問題かというと、「iPodTouch のカメラで撮った写真やデジカメなどからの大量の写真を整理せずに iOS に放り込むと、スクロールして写真を探すのは不可能」ということです。

大量の情報を扱う可能性のあるアプリの例としては、「連絡先」や「ミュージック」があります。これらのアプリは一覧の右側の「インデックス」により素早く目的のものを見つけることができます。PhotoHistory は写真の日付をインデックスにして、例えば「2008年のクリスマス」に瞬時に戻ることができます。

I released iPhone / iPod Touch App PhotoHistory (Apple App Store $1.99)

The PhotoHistory is designed to solve a problem when I used Photo.app of Apple. What's wrong with Photo.app? Photo.app is pretty simple and I was content till I had thousands of photos in my device. It is almost impossible to find a photo by scrolling and keep watching. Yes, I should organize photos in albums or events, but I wouldn't.

On the other hand, some apps possibly to manage lot of informations or data, say Music.app and Contacts.app, have "index" on the right side of their table interface. PhotoHistory simply use same design by "index" dates of photos. Now you can find "Christmas 2008" in an instant.

Thursday, January 5, 2012

Synching Address Book on Lion, GMail Contacts and an Android

Mac (Lion) のアドレスブックと Gmail の Contacts と Android の連絡先を同期させるという基本的な作業が結構難しかったので書いときます。

まずは Lion のアドレスブックと GMail Contacts を同期させるには、

アドレスブックの環境設定 -> アカウント -> この Mac 内 -> アカウント情報 -> Google と同期 -> 構成
でアカウント情報を入力して OK すると、mac の メニューバーに sync アイコンが表示され、メニューから「今すぐ同期」を実行すると Google Contacts と同期が取れます。

過去にアドレスブックと Gmail Contacts をインポート/エクスポートでコピーしてた場合など、単純に同期を開始するとダブったりするので、

  • アドレスブックか Gmail Contacts のどちらかがゴミならバックアップをとってから全部削除 (僕の場合、 Gmail Contacts がゴミだったので削除してから同期させました)
  • 両方とも活かしたいなら、同期させてから、 Gmail Contacts で2つ以上のコンタクトをチェックしてから、 More メニューで "Merge Contacts" でまとめる
  • アドレスブックにも「選択したカードを結合」というメニュー項目があるので同じようなことができるかもしれません(試してませんが)

Gmail Contacts の内容がマトモになったら、 Android の設定 -> アカウント から同期するようにチェックすればいいのですが、Motorola の端末だと "Power Control widget" というやつで sync を off にしてると自動では同期できなくなるようです。 Android 端末のカスタマイズっぷりを把握してないので Motorola 以外の端末にもあるのかもしれませんが、不明。

実行環境は

  • Mac OS X Lion 10.7.2
  • au / Motorola PHOTON / Android 2.3.4

ちなみに、アドレスブックと iOS 端末も iCloud で同期できるのですが、 アドレスブックの「アカウント情報」のヘルプには

「iCloud アカウントを追加するきに Google 連絡先との同期が入になっている場合、その同期オプションは切になります。iCloud 連絡先サービスを利用している間は、その同期オプションを切にしておくことをお勧めします。」
と書いてあって怖いので試してません。

Thursday, December 1, 2011

make testflight

Xcode の Organizer を使って IPA を生成してから、ブラウザからアップロードするのは面倒なので、ネット上には Testflight upload API を使ってアップロードを自動化するスクリプトはいくつか転がっていますが、 xcarchive のパス, Code sign identity, API token, Team token などの設定が自動化されていないのしか見つけれられなかったので Makefile を書いて見ました。

特筆すべき必要条件

  • Xcode 4 の設定項目についてのある程度の知識
  • ruby 1.9.x or `gem install json`

準備

Build Phases の最後に "Run Script" を追加。

ここで CODE_SIGN_IDENTITY を Makefile から参照するためにファイルに保存しているのですが、 "Automatic Profile Selector" を利用している場合は、 CODE_SIGN_IDENTITY の値は "iPhone Distribution" だけで署名者名が入らないので、固有の Identity を選択するようにしてください。

Xcode scheme の "Archive" build action の Post-actions に "Run script" を追加。

通常 scheme は "shared" しない設定にしてリポジトリに追加しないようにしていると思います。なので、この Post-action を設定する scheme は "XXX-testflight" みたいな名前で "duplicate" して "shared": on, "show": off にしてリポジトリに追加すると、共有できて Xcode の scheme 選択からも見えなくなるのでいいかと思います。

あとは、プロジェクトのディレクトリに Makefile を置いて、 `make testflight` を実行するだけです。 Testflight のノートを入力するフォームが開くのでノートを変更して配信先を選択してください。

初回実行時には "Team Token" と "API Token" の入力を要求されるので、ブラウザに Testflight のセッションが残っていれば、表示されるはずなのでコピペしてください。

Xcode の archive から実行したい人は、 Makefile を fork して工夫してみてください。

Thursday, July 14, 2011

iOS autoresizing UIView TIPS

2011-11-26: 根本的に理解が足りない気がしてきた。 autoresizingMask や layoutSubviews を使えば済む場合が多いはずなので整理ができたらまとめます。
2011-10-04: view controller を window に直接 addSubview するのでなく UINavigationController や UITabBarController 配下にするばあいは viewWillAppear でも orientation は反映されているようなので、あとで調べて情報を更新したい
2011-08-05: orientation が landscape の場合には - didRotateFromInterfaceOrientation: まで待つ必要があったので修正

InterfaceBuilder を使わずにコードで iOS の view 階層を作成して画面サイズや orientation にあわせて autoresize させるにはいろいろと注意が必要になるのですが、イマイチ情報が無かったのでわかったことを書いておきます。

ポイントとしては、 Apple のドキュメント "View Controller Programming Guide for iPhone OS" (rev. 2010-05-03) の "Custom View Controllers" だと、コードで view 階層を作成するには loadView でやれみたいに読めるのですが、 loadView や viewDidLoad のタイミングでは autoresize はまだ反映されず、 viewWillAppear のタイミングで反映されるようです。
さらに、 orientation が landscape (ヨコ) の場合には viewWillAppear ではダメで didRotateFromInterfaceOrientation: まで待たないとダメなようです。

ちなみに、 orientation が viewController.view に反映されているかどうかは、 view.transform に rotation の値が入ってるかどうかで分かるようです。
<UIView: 0x5b59d80; frame = (20 0; 748 1024); transform = [0, -1, 1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x5b532a0>>


従って、画面のサイズ(iPhone or iPad)、 navigation bar などの表示の有無 によって autoresize される view の frame や bounds に反映されるのは viewWillAppear のタイミングなので、例えば、それらの autoresize される view の subviews として view をグリッド状に並べたりするのは viewWillAppear でやれってことになります (orientation が portrait でないときは didRotateFromInterfaceOrientation)。

ちなみに、 loadView で生成して addSubview する view をおまかせで画面に fit させる場合、
initWithFrame する必要は無く、 frame は (0 0; 0 0) で OKのようです。
- (void)laodView
{
    UIView *rootView = [[[UIView alloc] init] autorelease];
    rootView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    self.view = rootView;
}


逆に fit させる大きさ(この場合、navigation bar などを除いたサイズ) より大きい frame を設定してしまうと autoresize はうまくゆかないようです。

また、 [super loadView] で自動生成される view は [[UIView alloc] init] した view とは違い、そのタイミングでの (orientation の反映されていない) frame になっていたり、プロパティの値が違うのか、期待どおりの動きにするのが面倒な感じなので自前で [[UIView alloc] init] したほうがよさそうです。

Sunday, May 22, 2011

Rails 3.1 HTTP Streaming and content_for in controller

2012-01-14: content_for_in_controllers を gem にしてくれた人がいます。 thanks!

Rails 3.1 では HTTP Streaming が導入されますが、 stream ON だと template と layout の処理順序がいままでの rails のように template -> layout ではなく layout 前半 -> template -> layout 後半 という自然な流れになるのですが、 content_for が絡むとややこしいことになります (詳しくは action_controller/metal/streaming.rb のコメントを参照)。

この関係で、 layout 前半で content_for :bar が先に実行されていることを期待した yield :bar が空振りしないように、 layout 前半で yield :bar などが実行されると stream であるのにも係わらず template が先に実行されます。このジレンマを緩和するために provide というヘルパーが導入されて、 provide :bar されると、以降の template の処理を中断して layout 前半を処理しているようです。

もうこうなると stream ON のときは content_for は使わないで、 controller で @title = "foo" とかやってしまいそうになるので、 content_for を controller でも実行できるようにしてみました。 rails 2.X, 3.0 で使っていたやっつけ実装なのですがいちおう rails 3.1 でも動くことは確認しました。




みたいな感じで使います。

あと HTTP Streaming に関しては、
いままでは view のベンチマーク結果に DB の負荷が混ざらないためにも DB アクセスは action 内で実行されるようにしてたけど stream の場合 view のレンダリング中に DB アクセスが実行されるようにしたほうがよいことになりますね。(ソースのコメントにもかいてありますけど。)

また、HTTP Streaming は ruby 1.9 の Fiber が使われているので、 Encoding の問題が煩わしくて ruby 1.9 にする必要性が感じられない場合に ruby 1.9 導入のきっかけになるといいですね。

Monday, May 2, 2011

processing png

web や iOS app の開発をしているときにボタンとかに使うチマチマした画像が必要なことがあります。いままでは Seashore でドットを打ったりしてましたが、 Processing.js を使うとプログラムで簡単に絵を描くことができるので、プログラマとしては色やサイズの微調整とかの応用がしやすいですね。

以下は iframe に展開したデモです。 m とか s の値を変えて update すると更新されるのがわかるかと思います。


基本的には Processing.js Web IDEの簡易版ですが、 canvas の内容を img タグに画像としてコピーしているので、その画像をファイルとして保存すれば素材として使えます。

現状、ワークフロー的にはローカルリポジトリのファイルとブラウザ上の textarea, img との手作業のコピペが何度も発生するので洗練されてませんが、工夫すればもうちょっとマシになるかもしれません。

ソースのhtmlは gist にあります (raw を iframe の src に指定すると text/plain になっちゃってダメなので dropbox のファイルを参照)

Tuesday, April 19, 2011

goo.gl Automator service

Mac で選択したテキストのURL短縮できると便利だと思って、調べてみると bit.ly の API を使って Apple Script で実装されたやつは見つかったんですけど、 API key が必要なのは面倒だし Apple Script はいやなので goo.gl を利用するサービスを shell と ruby で書いてみました。



このサービスは選択したテキスト(URL)を短縮して置換します。元のURLは念のためにクリップボードに保存します。
テキストを置換するので、編集可能なテキストしかダメなので、逆に短縮 URL をクリップボードに保存したい人は改造してください。

Automator で作ったサービスは裏で "/System/Library/CoreServices/Automator Runnder.app" を起動して実行するんですけど、コイツの起動が遅いのでメニューバーに常駐する app がサービスを提供する感じにしたほうが速くなると思うのでそのうちに...。

goo.gl の API は ApiKey 無しではあんまり頻繁に実行するとダメかもしれないので、ヘビーに使う人は goo.gl API の詳細: Getting Started - Google URL Shortener API - Google Code を見て自分の ApiKey を設定してみたりしてください。

ちなみにこの記事のコード部分には gist を使ってるんですけど、gist への投稿もサービスでできたら(たぶん使わないけど)便利だと思いましたが、 gist を作成する API は Coming soon だそうです (2011-04-19 現在)。