24/7 twenty-four seven

iOS/OS X application programing topics.

iOS 13にしかないフレームワークを使用したアプリをiOS 12以下でも動くようにするには

SwiftUI、Combile、RealityKitなどiOS 13以上の環境にしか存在しないフレームワークを使用するアプリをiOS 12以下の環境で実行すると、その機能を実際に呼び出さないようにしていたとしても、起動時にダイナミックリンクに失敗してクラッシュしてしまいます。

dyld: Library not loaded: /System/Library/Frameworks/RealityKit.framework/RealityKit
  Referenced from: /Users/katsumi/Library/Developer/CoreSimulator/Devices/7D73BD02-5C30-4723-9023-4D19BCDAE1AA/data/Containers/Bundle/Application/A9E00179-1DDD-4051-9207-7CC6C9DC50AE/UseIOS13.app/UseIOS13
  Reason: image not found

iOS 12以下のサポートは残しつつ、最新のOSにアップデートした人に対しては部分的にRealityKitやその他の最新機能は提供したいというユースケースでは問題になります。

この問題を解決するにはWeak Linkという仕組みを利用します。

最近はAuto Linkが作用するので明示的にフレームワークのリンクを設定することはめったにありませんが、Weak Linkを設定する場合は、明示的なリンクを利用します。

Xcodeのターゲットの設定から、Build Phases > Link Binary With Librariesを表示して、「+」ボタンから該当のフレームワークを選択して追加します。そしてStatusのカラムをOptionalに変更します。

f:id:KishikawaKatsumi:20190618151337g:plain

Combine.frameworkやRealityKit.frameworkは「+」ボタンからのダイアログの中には見つからないので/Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/を直接Finderで表示してドラッグ&ドロップで設定します。

f:id:KishikawaKatsumi:20190618152111p:plain

当然ながら、iOS 12以下ではその機能を呼び出さないようにコードで分岐したりそもそも画面を表示しないなど無いフレームワークの機能を使用しないように実行時にガードが必要です。

if #available(iOS 13.0, *) {
    ...
} else {
    ...
}

参考:

blog.kishikawakatsumi.com