ibtoolが突然xibファイルを見つけられなくなったときの対処

ibtoolはNIBファイルをコマンドラインで処理することができる便利なツールです。私は、NIBファイルのローカライズを行うときに、使っていますが、Xcode5.0.1 + Mavericksにしてから、以下のようなエラーで失敗することが、ときどき起きるようになりました。

$ ibtool --strings-file XXXXXXXX.strings --write XXXXXXXX.xib ../English.lproj/XXXXXXXX.xib 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.ibtool.errors</key>
	<array>
		<dict>
			<key>description</key>
			<string>Interface Builder could not open the document "XXXXXXXX.xib" because it does not exist.</string>
		</dict>
	</array>
</dict>
</plist>

もちろん、エラーの原因になっているファイルは存在しています。それにもかかわらず、見つからないと言われている状況です。
残念ながら、原因や再現性はわかっていませんが、とりあえず、エラーを回避する方法を見つけることができたので、書いておきます。

ibtoolを実行すると、バックグラウンドで、ibtooldというプロセスが2つ起動されるようです。これらを強制終了してからもう一度ibtoolを実行すると、正常に処理されました。

私の場合は、とりあえずこの方法で回避できました。
同じような状況でお困りの方は、お試しください。

PhoneGapを使ってみた

最近は、HTML5で作られたモバイル向けWebアプリケーションをベースに、ネイティブアプリケーションを開発する、ハイブリッド型のアーキテクチャを採用するケースも増えてきているようです。
今さらですが、とりあえず、その代表的なプラットフォームであるPhoneGapを使ってみようと思いたち、最近のバージョンをベースに簡単に日本語で説明されている記事を探してみましたが、見つからなかったので、PhoneGapのサイトにある「Getting Started with iOS」を参考に、少し触ってみました。

Getting Started with iOS

インストールから、HelloWorldアプリケーションを動かすところまでの手順が説明されています。
ここでは、簡単に、そこで説明されている手順をたどってみます。

Requirements

実機を使用しないのであれば、事前に準備しておく必要があるのはは、Xcodeのみですが、ここで説明されている通り、Xcode Command Line Toolsをインストールしておく必要があります。

Install Cordova

以下のページから最新版をダウンロードして、任意の場所に展開します。
http://phonegap.com/download/

注: この記事を書いた時点の最新版は2.8.0ですが、私が試したところでは、Camera APIの一部の機能が正しく動作しなかったので、2.7.0を使っています。

Project Creation
  • Determine Project Location

このチュートリアルで作成するHelloWorldプロジェクトを配置するディレクトリを準備します。

$ mkdir ~/Documents/Cordova27
  • Open Terminal

説明の対象になっているバージョンが2.3.0となっていますが、現在はディレクトリ構成が変わっており、phonegap-2.7.0/lib/ios/bin になっているようです。
ターミナルを開いて、そのディレクトリに移動しておきます。

  • Create New Project

HelloWorldプロジェクトを作成します。

$ ./create ~/Documents/Cordova27/HelloWorld org.apache.cordova.HelloWorld HelloWorld

プロジェクトをXcodeで開くことで、実行することができます。


オプション: Camera APIのサンプルを実行してみる

HelloWorldだけでは面白くないので、もう少しPhoneGapの機能がわかるサンプルを実行してみましょう。
PhoneGapのアプリケーションは、UIWebViewにHTMLをロードすることで実行されます。デフォルトでは、作成されたプロジェクトのwww/index.htmlがアプリケーション起動時に実行されるスタートページとして設定されています。その指定は、config.xmlというファイルで行われています。

    <content src="index.html" />

通常、独自のアプリケーションを作成するときには、このindex.htmlを置換えることになります。とりあえず、PhoneGapのドキュメントに記載されている、Camera APIのサンプルを実行してみましょう。

以下の場所にある、「Full Example」の内容をコピーし、index.htmlにペーストして置換えてください。
http://docs.phonegap.com/en/2.7.0/cordova_camera_camera.md.html#camera.getPicture_full_example

Xcodeから実行すると、以下の画面に置き換わっているはずです。

デバイス固有の機能は、deviceReadyイベント後でないと使用できないので、最初は各ボタンを無効にしておいて、deviceReadyが来たら有効にするといった処理を付け加えてもいいかもしれません。

        <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>

            // Cordova is ready to be used!
            //
            function onDeviceReady() {
                pictureSource=navigator.camera.PictureSourceType;
                destinationType=navigator.camera.DestinationType;
                $(".camerabutton").removeAttr("disabled");
            }

    <body>
        <button class="camerabutton" disabled onclick="capturePhoto();">Capture Photo</button> <br>
        <button class="camerabutton" disabled onclick="capturePhotoEdit();">Capture Editable Photo</button> <br>
        <button class="camerabutton" disabled onclick="getPhoto(pictureSource.PHOTOLIBRARY);">From Photo Library</button><br>
        <button class="camerabutton" disabled onclick="getPhoto(pictureSource.SAVEDPHOTOALBUM);">From Photo Album</button><br>
        <img style="display:none;width:60px;height:60px;" id="smallImage" src="" />
        <img style="display:none;" id="largeImage" src="" />
    </body>

注:
iOS Simulatorで実行する場合には、カメラの撮影機能を動作させることはできませんのでご了承ください。
フォトアルバムに写真が入っていない場合は、事前に登録しておく必要があります。登録方法は、以下の記事が参考になるかと思います。
iPhoneシュミレータに画像を登録する方法 - satoko's blog - s21g




JavaScriptから簡単にネイティブの機能が使えるので、たしかにObjective-Cは知らなくても、iOSアプリケーションが作れてしまいますね。
尚、今回は、とりあえず使ってみることが目的だったので、UIについては二の次になっています。実際のアプリケーションでは、jQuery MobileSencha Touchといった、モバイルWebアプリケーションフレームワークと組合せることで、もっと洗練されたUIを実現することになります。そのあたりも面白そうなので、また時間があるときに調べてみたいと思います。

iPhoneのRetina4ディスプレイ判定方法

Retina4か否かを判定する方法をいろいろ調べてみました。
正しいディスプレイのサイズを取得するためには、+[UIScreen mainScreen]メソッドで得られるオブジェクト使うのですが、以下のように3つの値が取得できます。

NSLog(@"mainScreen bounds height %f", [[UIScreen mainScreen] bounds].size.height);
NSLog(@"mainScreen applicationFrame height %f", [[UIScreen mainScreen] applicationFrame].size.height);
NSLog(@"mainScreen currentMode height %f", [[UIScreen mainScreen] currentMode].size.height);

それぞれの結果を見てみると、以下の通りになりました。

  1. mainScreen bounds height 568.000000
    Retina以前のディスプレイと、互換のあるサイズ表記
  2. mainScreen applicationFrame height 528.000000
    1と同様だけど、ステータスバーを含まない高さであり、ステータスバーの状態によって値が変わる。この例は、着信ステータスバーがONになっている状態なので、1より40px少ない値になっている。
  3. mainScreen currentMode height 1136.000000
    物理的なpixel値。解像度の判定まで必要な場合は、この値を使うのが適切かもしれない。

SysStats Monitor/Liteでは、現在2を使っているので、ステータスバーの状態によって取得される値が変わってしまい、着信中やテザリング中にアプリが起動されると、正しく判定できていないことがわかりました。
今回の目的では1と3のどちらでもいいと思いますが、とりあえず1を採用し、以下の形でチェックすることにしました。

#define R4_DISPLAY_HEIGHT 568.0

+ (BOOL)is4InRetinaDisplay {
    
    if ([[UIScreen mainScreen] bounds].size.height == R4_DISPLAY_HEIGHT) {
        return YES;
    } else {
        return NO;
    }

}

とりあえず、アプリの画面サイズを、Retina4 (640 x 1136 pixels) に対応させる方法

まず、結論から言ってしまうと、640 x 1136 pixels の Launch Image が設定されていれば、Retina4 デバイスでアプリが実行されたときに、画面サイズが640 x 1136pixelsになるようです。

具体的な設定方法は、 iOS App Programming Guide を参照していただくとして、最も簡単な方法は以下の通りです。

1) Xcodeで、Retina4 用の Launch Image が設定されていないプロジェクトを開き、左ペインをIssue Navigatorに切替えると、以下のようなWarningが表示されます。

2) この Warning メッセージをクリックすると、以下の Alert パネルが表示されます。

3) Add をクリックすると、とりあえず、真っ黒な Default-568h@2x.png ファイルがプロジェクト内に作成され、Launch Image として認識されます。

この状態で、とりあえずRetina4デバイスの実機かSimulatorでアプリを実行すると、それまで上下にあった隙間が埋められ、画面サイズが640 x 1136 pixelsで実行されるようになります。

autoresizing 機能により、ほとんどの画面は、最適化されて表示してくれるはずですが、絶対座標が指定されていたり、autoresizing の設定が適切でないコンポーネントは、思った通りにならない場合もあるので、一通りの動作確認をして、想定通りに機能するよう、調整する必要があります。

実際に、私の場合は、TabBarをタップしても反応しないという問題や、表示がズレる問題が発生しました。
いくつかハマりどころがありそうです。

それらについては、また後日書いてみたいと思います。

補足

iOS Human Interface Guidelines の Launch Image の説明によると、

For apps that run on iPhone 5 and iPod touch (5th generation), create a launch image that measures 640 x 1136 pixels.

と書かれていますので、Appleのマニュアルの中では、これが、画面サイズを640 x 1136pixelsにするための条件を、暗黙的に示しているのかもしれません。

Retinaディスプレイで画像リソースをキレイに表示するには?

iPadRetinaディスプレイになったことで、また1つ、解像度の異なるiOSデバイスが増えました。

どれだけの種類があるかというのは、List of iOS devices - Wikipedia, the free encyclopedia
にまとめられています。

ここから、ディスプレイの解像度に関する情報だけ抜き出してみると、以下の4パターンになります。

アプリのユーザインタフェースでは、さまざまな箇所で画像リソースを使用していますが、各デバイスの解像度に適合したサイズのものを用意しないと、それらがキレイに表示されなくなってしまいます。
実際にどのような考慮が必要なのか、例を挙げてまとめてみました。

Application icon

各解像度に対して、以下の4種類のサイズが必要になります。

解像度 デバイス イコン画像サイズ
480 × 320 px iPhone 3GS, 〜iPod touch 3G 57 x 57
960 × 640 px(Retina) iPhone 4/4S, iPod touch 4G 114 x 114
1024×768 px iPad, iPad2 72 x 72
2048×1536 px(Retina) new iPad 144 x 144

簡単に言ってしまうと、

  • iPhone/iPod touchiPadは、画面の大きさが違うので、表示するアイコンのサイズが違う。
  • Retinaは2倍の解像度なので、サイズも2倍にしないと、粗い画像になってしまう。

ということですね。

SysStats Monitorというアプリの場合は、480 × 320 pxのデバイスしか存在しないころにリリースしたものなので、新しい解像度のデバイスが出るたびに、アイコンを追加しています。

上記のアイコンは「Small App Icon」と呼ばれるもので、アプリの中にバンドルするものです。
それに加えて、もう一つApp Storeで表示するときのアートワーク画像用として、512 x 512の「Large App Icon」も用意する必要があります*1。こちらは、iTunes Connectでアプリの申請をするときのメタデータとして登録します。
私の場合、それを縮小して各アイコンを作っているので、これに関してはあまり手間をかけずにできています。

裏を返せば、まず最初に「Large App Icon」を作成しておく方が、よいということですね。
これから、iPhoneアプリ開発を始める方は、ご注意ください。

Tab bar icon

それ以外にも、アプリの中のTab barのボタンに使う画像も、解像度を考慮する必要があります。
こちらは、iPhoneiPadの違いはないので、Retinaか、そうでないかの2種類になります。

私の場合、当初、30 x 30で作成してしまったので、もう一度60 x 60を作り直す必要があり、やや手間がかかってしまいました。
なので、こちらも、最初から大きめのサイズで作っておくのが無難ですね。

その他の画像

これ以外にも、Launch image(起動時のスプラッシュ画像)や、Spotlightの検索結果や設定画面で表示されるアイコンなど、いくつか画像リソースの種類があります。
以下のドキュメントには、全般的な説明が書かれています。

iOS Human Interface Guidelines - Custom Icon and Image Creation Guidelines

その他の画像については、こちらを参照してください。

*1:必須ではありませんが、Retina用に1024 x 1024のものも作成することが推奨されています。

iOSと絵文字について

iOS4.xまでは、絵文字キーボードが使える場所は、SMS/MMSと、i.softbank.jpのメールに限定されていました。このときの絵文字は、Unicodeの私用領域(PUA: Private Use Area)を使って表現されていました。

そのことは、以下の記事でわかりやすく説明されているので、参考にさせていただきました。

  • いまの段階では、iPhone絵文字は主にSMS/MMSなどシフトJISの世界で使われるものだが、Unicodeで表現することもできる。iPhoneでは、文字化けを防ぐために、絵文字キーボードは絵文字が使えるシーン(シフトJISの世界)でしか出てこないようになっている。しかし、たとえばSMS/MMSで絵文字を入力した上でクリップボードにコピーし、Unicodeの世界に連れてくることは可能である。
  • Unicodeでは、iPhone絵文字は基本的に私用領域(PUA)の符号位置で表現される。それに加え、日本のケータイ絵文字がUnicodeに収録されたことを受けて、iOSはこちらの(PUAではない)符号位置もサポートしている。おそらくiOS 5では、PUAではない符号位置のほうがデフォルトになるものと思われる。
iPhone絵文字についてUnicodeの視点からまとめてみた - Mac OS Xの文字コード問題に関するメモ

ここで、「おそらくiOS 5では、PUAではない符号位置のほうがデフォルトになるものと思われる。」というように言及されていますが、まさに正解ですね。

携帯電話の絵文字 - Wikipedia

iOS5からは、どこでも絵文字キーボードが使えるようになりました。そこで使われているのは、Unicodeに正式に収録された方の絵文字になっているようです。
ただし、そこで入力された絵文字は、どこでも思った通りに表示されるわけではないというのが現実です。
いわゆる、機種依存文字」と同じような問題が、そこに潜んでいます。

Twitterに投稿した場合を例に、具体的に見てみましょう。

SysStats Monitorでは、現在のデバイスの状況をTwitterに投稿する機能を備えています。そこに、バッテリーの状態を示す絵文字を入れるように機能追加する予定です。*1

まずは、SysStats Monitor画面の下の方にある、「シェア」というボタンをタップします。

すると、以下のようなTwitterに投稿する画面が開きます。

ここで送信ボタンをタップすると、表示されているメッセージが、Twitterに投稿されます。

実際に投稿した内容を、いろいろなビューワで見てみると、Unicode絵文字のサポート状況が見えて来ると思います。

iPhoneTwitter公式アプリ

まずは、定番のiPhoneTwitter公式アプリから見てみましょう。

問題なく表示されていますね。

Mac版のTwitter公式アプリ

Mac版のTwitter公式アプリではどうでしょうか?

「⚡」だけ、少し違う絵柄になっていますが、何とか表示されていますね。

Safari

Safariではどうでしょう?

Twitter公式アプリと同じですね。
Macの場合、10.7 Lionで、「Appleカラー絵文字」というフォントが使われるようになっている場所でないと、カラーの稲妻は表示されないようです。
MacOSX標準のテキストエディットをリッチテキストモードに設定し、「文字ビューア」で絵文字を入力しながら、フォントを確認してみると、そのことがわかると思います。

Firefox(Mac版)

では、最後に、Firefox(Mac版)はどうでしょう?

こちらは、残念ながら、全く表示されないようです。
chrome(Mac版)も同じような結果でした。


現時点では、こういった状況であることを意識しつつ使う必要があるようですね。

ちなみに、そういうことがわかっていながら、SysStats Monitorで絵文字を入れるようにしたのは、そもそもiOSユーザをターゲットにしているとともに、環境によって表示に問題が出る場合があったとしても、致命的な問題とはならないと思ったからです。

なお、今回はSysStats MonitorとTwitterを例に説明しましたが、これは特定のアプリやWebサービスに依存する問題ではなく、他のWebサービスやアプリでも起こりうるということを、ご理解ください。

*1:この記事を書いている段階では、まだアップデートの申請中ですので、次のバージョンが出るまでは、まだ絵文字は入りません。

日本語キーボードの変換候補表示方法の変更への対応

iOS5で、日本語キーボードの変換候補表示方法が変わったことに、みなさんすでに気付いていることと思います。

iOS4.xでは、以下のように、カーソルの近くに表示される仕様でした。

iOS5では、以下のように、変換候補の表示領域が固定で確保されるようになったので、画面の一部のボタンなどが隠れてしまうようになりました。

それに対応できるようにするために、iOS5から、キーボードの大きさが変わったことを、アプリで検知するためのNotification(UIKeyboardWillChangeFrameNotification)が新たに追加されました。

それを使って、隠れてしまう部分のサイズや、表示位置を調整する必要があります。
SysStatsMonitorで、その対応を実施中なのですが、その結果、以下のようになる予定です。

具体的なコーディングについては、以下の記事を参考にさせていただきました。

画面いっぱいのUITextViewがキーボードに隠れないようにする « LANCARD.LAB|ランカードコムのスタッフブログ

あと、1点注意すべきことがあります。
UIKeyboardWillChangeFrameNotificationは、iOS5から追加された機能なので、iOS4.xをターゲットとするアプリの場合は、OSのバージョンをチェックして、iOS5.0以降のときだけ、有効になるよう考慮が必要です。(iOS4.xでこのNotificationを使用すると、アプリが異常終了します)

チェックの方法は、前回の記事(iOSのバージョンチェック方法 - The iPhone Development Playground)で説明していますので、必要であれば、参考にしてください。