『入る学科間違えた高専生』の日記

プログラミングのコードを書いたりする予定です。あとは日記等。あといつまで高専生やねん

Swift Package Manager ライブラリを xcframework ビルドする

はじめに

タイトル通り Swift Package Manager (以下 SwiftPM) で作ったライブラリを xcframework にする方法を n 番煎じですが備忘録がてら書きます。

xcframework についてはこちら

developer.apple.com

環境

Mint を使って上記で前置きした CLI ツールをインストールした。

github.com

最近まで Xcode12.5.1 環境がないとビルドができなかったが Xcode13.x でもビルドが可能な状態になっていました!!

  • Xcode 13.4
    • Swift 5.6.1
  • Mint 0.17.1
    • swift-create-xcframework v2.2.0
mint install unsignedapps/swift-create-xcframework@v2.2.0

または Mintfile に以下を追記して mint bootstrap でも可能です。

unsignedapps/swift-create-xcframework@v2.2.0

ライブラリを作る

Xcode からでもコマンドからでもいいですが適当にライブラリを作りました。

たったこれだけのライブラリを作りました。

  • 内部からのみ変更が可能な text: String プロパティ
  • text: String の内部をコンソールに表示するメソッド ( echo() )
  • text: String を変更するメソッド ( updateText(_:) )

xcframework ビルドをする

Package.swift があるディレクトリに移動し以下を実行します。

mint run swift-create-xcframework --clean MyLibrary --output Products --platform ios

引数の説明は今回は省略します。
また、 --zip フラグがあるのでこれをつかうことで xcframework を zip に固めて一緒にハッシュ値も出力してくれるので SwiftPM で配布したいときに targets に対して binaryTarget で URL 指定での配布が簡単に行うことができます。

上記でビルドが完了したら --output で指定したディレクトリに成果物が出力されます。

組み込んでみる

とりあえずまっさらなプロジェクトを作ってプロジェクトに xcframework を依存フレームワークに追加してみました。

ちょっとした画面を作ってみる

雑な部分が多々あるが一旦こんな感じで表示される Interface を作ってみた。以下ソースコード

import MyLibrary
import UIKit

class ViewController: UIViewController {
    // MARK: - Properties
    @IBOutlet private var textField: UITextField!
    @IBOutlet private var button: UIButton!

    private var library = MyLibrary()

    // MARK: - Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        library.echo()
    }

    @IBAction private func onTapButton(_ sender: Any) {
        guard let text = textField.text else { return }
        library.changeText(text)
        textField.text = ""
        library.echo()
    }
}

以下実行をして、 UITextField に aaaaaaa と入力して UIButton を1度タップしたときの結果である。

Hello, World!
aaaaaaa

ちゃんと目的通りのログが表示されていることが確認できた。

ちなみに定義へジャンプしてみると実際にどんなコードが実装されているのかは確認することができない。

これは、 xcframework 内にある swiftinterface とほぼ一致する内容である。

依存ライブラリを増やしてみる

ライブラリ側の Package.swift を変更した。

  dependencies: [
+    .package(url: "https://github.com/nnsnodnb/AnyErrorConvertible", from: "1.0.0")
-
  ],
  targets: [
    .target(
      name: "MyLibrary",
+     dependencies: ["AnyErrorConvertible"]),
-     dependencies: []),

とりあえず依存を追加しただけでもう1度 xcframework をビルドして、
アプリケーション側に Xcode で SwiftPM に dependencies に指定したライブラリを追加して再度アプリケーションをビルドをしてみた。

dyld[59403]: Library not loaded: @rpath/AnyErrorConvertible.framework/AnyErrorConvertible
  Referenced from: /Users/nnsnodnb/Library/Developer/Xcode/DerivedData/App-fdpxqniiilivhieveezgolatvbsq/Build/Products/Debug-iphonesimulator/MyLibrary.framework/MyLibrary
  Reason: tried: '/Users/nnsnodnb/Library/Developer/Xcode/DerivedData/App-fdpxqniiilivhieveezgolatvbsq/Build/Products/Debug-iphonesimulator/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/Users/nnsnodnb/Library/Developer/Xcode/DerivedData/App-fdpxqniiilivhieveezgolatvbsq/Build/Products/Debug-iphonesimulator/PackageFrameworks/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/Applications/Xcode13.4.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/swift/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/usr/lib/swift/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/Applications/Xcode13.4.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/Applications/Xcode13.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/Applications/Xcode13.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/Users/nnsnodnb/Library/Developer/CoreSimulator/Devices/4B6FDEB8-4036-4F9C-BD83-5B4E4ECCAB63/data/Containers/Bundle/Application/9FA861B6-B93D-4BAA-A87E-50E679D6FF97/App.app/Frameworks/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/Users/nnsnodnb/Library/Developer/CoreSimulator/Devices/4B6FDEB8-4036-4F9C-BD83-5B4E4ECCAB63/data/Containers/Bundle/Application/9FA861B6-B93D-4BAA-A87E-50E679D6FF97/App.app/Frameworks/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/Applications/Xcode13.4.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file)
Library not loaded: @rpath/AnyErrorConvertible.framework/AnyErrorConvertible
  Referenced from: /Users/nnsnodnb/Library/Developer/Xcode/DerivedData/App-fdpxqniiilivhieveezgolatvbsq/Build/Products/Debug-iphonesimulator/MyLibrary.framework/MyLibrary
  Reason: tried: '/Users/nnsnodnb/Library/Developer/Xcode/DerivedData/App-fdpxqniiilivhieveezgolatvbsq/Build/Products/Debug-iphonesimulator/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/Users/nnsnodnb/Library/Developer/Xcode/DerivedData/App-fdpxqniiilivhieveezgolatvbsq/Build/Products/Debug-iphonesimulator/PackageFrameworks/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/Applications/Xcode13.4.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/swift/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/usr/lib/swift/AnyErrorConvertible.framework/AnyErrorConvertible' (no such file), '/Applications/Xcode13.4

というような感じでエラーが発生した。フレームワークが見つからないらしい。
外部ライブラリを依存するときは別でライブラリを追加を委ねるようにするのはだめなのかな😫
ここらへん全く詳しくないので詳しい人教えてほしいです。

とりあえず SwiftPM だけで対応させたい場合は xcframework を依存ライブラリごとビルドをすることでこれを回避することは確認している。

mint run swift-create-xcframework@v2.2.0 --clean MyLibrary AnyErrorConvertible --output Products --platform ios

という感じで外部ライブラリをビルド対象に追加した。
外部ライブラリも同様に xcframework がビルドされるので xcframework としてプロジェクトに追加する。

これで動作する。

もしくは、 CocoaPods に頼ってもいいということであれば CocoaPods で外部ライブラリをプロジェクトに追加したら同様に動作が確認できた。

最後に

ということで SwiftPM 製のライブラリを xcframework ビルドするという記事を書いた。
滅多に今回のようなライブラリを xcframework ビルドして配布をするようなパターンはないかと思うがその想定があると仮定した。

久しぶりに書いたから敬体と常体混合になったがまぁいいでしょう。