iOS SDKは年々進化を続けているのはイイんだけど、後方互換性は一部犠牲になっている。他のプラットフォームに比べると数倍マシだとは思うけどね。ともあれ、最新OS最新モデルに対応しつつも、以前のOSや機種を切り捨てられない場合も少なくない。しかも初期のSDKで作成したプロジェクトをアップデートし続けるのもスッキリしないので、最新SDKから新しいプロジェクトを作ったりすると、それなりに問題が発生する。
そこでiOS SDK 5.1 (Xcode 4.3.2)で作ったプロジェクトを初代iPhoneの最終OSであるバージョン3.1.3に対応させる方法を書いておくね。ここではテンプレートとしてUtility Applicationを用い、iPhone/iPad両用のユニバーサル・アプリを作ることにします。もちろん、ARCはオフ、Storyboardも使えませんよ。
まず、何はともあれDeploymentを3.1に設定する。
■ プロジェクトのiOS Deployment Targetを 3.1 に設定。
次いで、初代iPhone、iPhone 3G、iPod touch(第1世代と第2世代)のCPUであるarmv6でも動作するように指定する。
■ プロジェクトのBuild SettingsのArchitecturesのArchitecturesに armv6 を追加。
■ プロジェクトのBuild SettingsのArchitecturesのBuild Active Architecture Onlyを NO に設定。
■ ウィンドウの下部にあるValidate Settingsをクリックし、Perform Changesを実行。
■ Info.plistにある Required device capabilities を削除。
Blocksを使う場合には以下の設定も必要。
■ プロジェクトのBuild SettingsのLinkingのOther Linker Flagsに -weak-lSystem を追加。
次に、テンプレートが生成するコードはiOS 3では存在しないクラスやメソッドを使っているので、iOS 3でも動作するように変更する。
まず、テンプレートはiPad用にUIPopoverControllerを使っているので、UIKitのリンクを弱める。
■ ターゲットのBuild PhasesのLink Binary With LibrariesにあるUIKit.frameworkを Optional に設定。
また、デバイスの判断にuserInterfaceIdiomメソッドもiOS 3では使えない。そこで汎用的に利用できるマクロを用意して、ソースコードを書き換える。
■ 〜-Prefix.pchに以下のマクロを定義。
#define UI_USER_INTERFACE_IDIOM() ([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] ? [[UIDevice currentDevice] userInterfaceIdiom] : UIUserInterfaceIdiomPhone)
■ ソースコードの該当箇所を書き換える。AppDedegateに1ヵ所、MainViewControllerに3ヵ所、FlipsideViewControllerに1ヵ所あるはず。
[[UIDevice currentDevice] userInterfaceIdiom]
を
UI_USER_INTERFACE_IDIOM()
に置き換える。
また、UIWindowのrootViewControllerプロパティもiOS 3では使えない。
■ AppDedegate の application:didFinishLaunchingWithOptions: の、
self.window.rootViewController = self.mainViewController;
を
if([self.window respondsToSelector:@selector(rootViewController)])
self.window.rootViewController = self.mainViewController;
else
[self.window addSubview:self.mainViewController.view];
に置き換える。
同じく、UIViewControllerのcontentSizeForViewInPopoverプロパティもiOS 3では使えない。
■ FlipsodeViewController.m の initWithNibName:bundle: の、
self.contentSizeForViewInPopover = CGSizeMake(320.0, 480.0);
を
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
self.contentSizeForViewInPopover = CGSizeMake(320.0, 480.0);
に置き換える。
以上の作業でiOS 3.1.3からiOS 5.1までのすべてのデバイスで動作するユニバーサル・アプリになったハズ。お疲れさまでした。
このようにして作ったテスト用のプロジェクト一式も入れておきますね。
Download RunOnOS3Test.zip
【追記】最後のcontentSizeForViewInPopoverプロパティの説明を追加しました。併せてテスト用プロジェクトも更新しました。