XCFrameworkはiOSやiPadOS、macOSで利用可能な共有ライブラリです。フレームワークなので、単にバイナリファイルだけではなく、ヘッダーファイルやリソースファイルなどの関連ファイルをすべて含めることができます。SDKを作るときにもお勧めです。
この記事では、XCFrameworkの作成手順やフレームワーク、フレームワークとXCFrameworkの違いについて解説します。
XCFrameworkの作成方法
XCFrameworkはターミナルのコマンドラインツールを使用して作成します。以下のような手順で作成します。
- XCFrameworkに含めるフレームワークのアーカイブを作成する。
- アーカイブ内のフレームワークをコードサイニングする。
- 手順2のアーカイブからXCFrameworkを作成する。
- XCFrameworkコードサイニングする。
アーカイブを作成する
XCFrameworkは、異なるプラットフォーム向けのフレームワークを含んでいます。たとえば、iOS/iPadOS用のSDKを作成する場合には、以下のプラットフォーム向けのフレームワークを内部に組み込みます。
- iOS/iPadOSデバイス用のフレームワーク
- シミュレータ用のフレームワーク
xcodebuild
を使用してアーカイブを作成します。たとえば、上記の2つのプラットフォーム用のアーカイブは以下のように実行します。
xcodebuild archive -project MySDK.xcodeproj -scheme MySDK -destination "generic/platform=iOS" -archivePath "archives/MySDK-iOS"
xcodebuild archive -project MySDK.xcodeproj -scheme MySDK -destination "generic/platform=iOS Simulator" -archivePath "archives/MySDK-iOS_Simulator"
-project
オプションはビルドするプロジェクトファイルを指定します。
-scheme
はビルドするスキーム名を指定します。スキーム名は一般的にはターゲット名と同じです。確認するには、Xcodeの「Product」メニューから「Scheme」の「Manage Schemes…」を選択します。スキームの管理画面が表示され、スキーム名も確認できます。
-destination
はビルドするプラットフォームを指定します。本記事執筆時点では以下の値が定義されています。
- macOS
- iOS
- iOS Simulator
- watchOS
- watchOS Simulator
- tvOS
- tvOS Simulator
- DriverKit
また、詳細な変種を指定することで、Mac Catalyst用にビルドするなども可能です。-destination "generic/platform=macOS,variant=Mac Catalyst"
のように指定します。
-archivePath
はアーカイブの出力先を指定します。
フレームワークをコードサイニングする
フレームワークのコードサイニングを行います。以前は、フレームワークやXCFrameworkなどのSDKに対してコードサイニングは不要でした。これはアプリをビルドする際にアプリの電子証明書で一緒にコードサイニングされるためです。しかし、フレームワークがリリースされてから、アプリ開発者に渡るまでの間に改竄されていないことを証明するためにはコードサイニングが必要です。また、2024年の春以降、プライバシーマニフェストに対応する必要があり、プライバシーマニフェストを含むXCFrameworkはコードサイニングが必須となっています。対応していなくてもビルドは可能ですが、AppStoreの審査でリジェクトされる可能性があります。
アーカイブ内のフレームワークをコードサイニングするには、`codesign`を使用します。たとえば、以下のようにします。
codesign --timestamp -f -s "CODESIGN_IDENTITY" archives/MySDK-iOS.xcarchive/Products/Library/Frameworks/MySDK.framework"
codesign --timestamp -f -s "CODESIGN_IDENTITY" archives/MySDK-iOS_Simulator.xcarchive/Products/Library/Frameworks/MySDK.framework"
CODESIGN_IDENTITY
には使用する電子証明書を指定します。キーチェーンアクセスで使用する証明書を選択し、名前を調べます。
使用する電子証明書は、AppStore配布用かエンタープライズ配布用かによって異なります。
- AppStore配布用: Apple Distribution証明書
- エンタープライズ配布用: iOS Distribution証明書, Mac Distribution証明書など
XCFrameworkを作成する
XCFrameworkを作成するためには、`xcodebuild`を使用して、以下の手順を実行します。これまでの例で示したiOS用アーカイブとiOSシミュレータ用アーカイブからXCFrameworkを作成する方法を紹介します。
xcodebuild -create-xcframework \
-archive archives/MySDK-iOS.xcarchive -framework MySDK.framework \
-archive archives/MySDK-iOS_Simulator.xcarchive -framework MySDK.framework \
-output xcframeworks/MySDK.xcframework
-archive
オプションでXCFrameworkに含めるアーカイブを指定します。-archive
オプションを繰り返して、含めるアーカイブを全て指定します。
-output
は出力するXCFrameworkのパスです。
XCFrameworkをコードサイニングする
最後にXCFrameworkをコードサイニングします。
codesign --timestamp -f -s "CODESING_IDENTITY" xcframework/MySDK.xcframework
これで完成です。作成した`MySDK.xcframework`をSDKとして配布します。
アプリがMySDK.xcframework
を利用すると、実行するプラットフォームに応じて適切なフレームワークが選択されます。
Frameworkとは?
フレームワークは、Appleプラットフォームで使用される共有ライブラリの一種であり、実体は.framework
という拡張子を持つディレクトリ形式のバンドルです。
このバンドル内には、以下のようなファイルが含まれています。
- 共有ライブラリ
- ヘッダーファイル
- Swiftモジュール
- リソースファイル
アプリにフレームワークを組み込むと、アプリ内にコピーされ、実行時にロードされます。
実行時に不要なファイルについて
実行時にはヘッダーファイルは不要です。これらのファイルはXcodeのEmbed Frameworkビルドフェーズで自動的に削除されます。しかし、古いバージョンのXcodeではこの削除が行われませんでした。そのため、古いXcodeを使用している場合は、スクリプトフェーズを追加して、ビルドしたアプリ内のフレームワークからスクリプトでヘッダファイルを削除していました。
フレームワークとXCFrameworkの違い
フレームワークとXCFrameworkの主な違いは、フレームワークが単一のプラットフォーム向けであるのに対し、XCFrameworkは複数のプラットフォームに対応している点です。
さらに、XCFrameworkはフレームワークのコンテナであり、使用時にはフレームワークとしてロードされる共有ライブラリを含んでいます。
XCFramework自体もバンドルであり、拡張子が.xcframework
のディレクトリです。各プラットフォームごとにディレクトリが作成され、その中にXCFramework作成時に指定したフレームワークが格納されています。たとえば、iOSデバイスとシミュレータ用のフレームワークを含むXCFrameworkは、以下のようなディレクトリ構成になります。
ios-arm64/MySDK.framework
ios-arm64/dSYMs
iOS-arm64_x86_64-simulator/MySDK.framework
iOS-arm64_x86_64-simulator/dSYMs
Info.plist
_CodeSignature
iOS-arm64_x86_64-simulator
ディレクトリに含まれるバイナリは、その名前からIntel Mac専用のように見えますが。実際には以下の2つのCPUアーキテクチャをサポートするユニバーサルバイナリです。
- arm64
- x86_64
名前はIntel Mac用のように見えますが、Apple Silicon Mac上でシミュレータを使用する際にも、恐らくこのバイナリが使用されていると考えられます。
XCFrameworkが解決した課題
XCFrameworkが存在しなかった時代にSDKを作成する際は、ユニバーサルバイナリを利用していました。当時は、Apple Silicon Macが存在せず、macOS上のシミュレータはx86_64バイナリで動作していました。一方、デバイス用にはarm64やarmバイナリが使用されていました。異なるCPUアーキテクチャを持つこれらのバイナリをユニバーサルバイナリとして1つにまとめることで、実行時に適切なバイナリがロードされていました。
しかし、Apple Silicon Macの登場により、この方法は使用できなくなりました。Apple Silicon Macのシミュレータも、iOSデバイスと同じarm64アーキテクチャを使用しています。ユニバーサルバイナリを使用するには、同じarm64のバイナリを使用しながらも、シミュレータ用とデバイス用は別々にする必要があります。デバイス用とシミュレータ用の2つのバイナリからユニバーサルバイナリを作成すると、複数のarm64が存在することになり、実行時にどのバイナリをロードするか判断できなくなります。
XCFrameworkはこのような問題を解決しました。