.xcworkspace と Swift Package を活用して XcodeGen 等に頼らずともほぼコンフリクトしないプロジェクト設計
Summary
- Xcode Project(.xcodeproj)による開発では
project.pbxproj
によるコンフリクトが多発する - XcodeGen などのツールでコンフリクトしないようにしてきたが、外部ツールに頼らない方針でいきたい
- Xcode Workspace(.xcworkspace)と Swift Package を使って Xcode Project(.xcodeproj)内でのファイル操作をなくし、コンフリクトが起きないようにする
まえがき
2021年5月19日に行われた CA.swift #14 〜いま考える次世代の設計〜 にて、@ry-itto(Ryoya Ito) さんが発表した「isowords の構成で3週間開発して得た知見」で紹介されたファイル等構成がおもしろく、実際に自分の手で試してみました。
YouTubeのvideoIDが不正です
概要
Xcode を使ったアプリケーション開発において、Xcode Project(.xcodeproj)による開発では project.pbxproj
によるコンフリクトが多発し、それを防ぐために XcodeGen などのツールを使用してきました。
しかし、外部ツールに依存すると、例えば年に1度の Xcode のメジャーアップデートが来た際に Xcode の新機能等を使うにはそのツールの対応を待つ必要があります(新しい App Extension が登場し、TARGET に追加したい場合など)。
また、CI / CD を使う場合などでは xcodebuild
のみで動作できる方がよいです。
主にファイルの追加や削除によって project.pbxproj
の変更が発生する Xcode Project(.xcodeproj)とは異なり、Swift Package ではファイルの追加や削除を行ってもファイル構成を管理する project.pbxproj
やその役割を持つファイルが Swift Package には無いため、これについて心配する必要がありません。
さらに、Swift tools version 5.3 以降では各リソースファイルも Swift Package に加えられるようになりました。
そして、Xcode Workspace(.xcworkspace)や Xcode Project(.xcodeproj)に Swift Package を追加できるようになったことから、これらをうまく組み合わせることで、Xcode Project(.xcodeproj)内でファイル操作をしないことによるコンフリクトの軽減が見込まれます。
以下に Xcode Workspace(.xcworkspace)と Swift Package を使って、SwiftUI の iOS・macOS Multiplatform App のプロジェクトを始めるとした場合の構成手順を掲載します。こちらで構成したプロジェクト一式は GitHub で公開しています。
構成手順
-
Xcode Workspace(.xcworkspace)を作成する
-
Xcode Workspace(.xcworkspace)を作成した状態
-
App のための Xcode Project(.xcodeproj)を作成する
-
このとき、「Add to」と「Group」に先程作成した Xcode Workspace(.xcworkspace)をを選んで「Create」する
-
Xcode Workspace(.xcworkspace)のなかに MyApp.xcodeproj を作成した状態
-
Swift Package を作成する
-
このとき、「Add to」と「Group」に先程作成した Xcode Workspace(.xcworkspace)を選んで「Create」する
-
Xcode Workspace(.xcworkspace)のなかに MyApp.xcodeproj と MyAppPackage を作成した状態
-
MyApp の ContentView.swift を MyAppPackage へ移動する
-
外部からアクセスできるように
internal
なところをpublic
等に変更する
-
MyAppPackage のプラットフォームを設定する (今回は
ContentView.swift
で SwiftUI を使用しているため iOS 13.0 以降等にした) また必要に応じて dynamically linked library にする
-
MyApp の TARGET で MyAppPackage を追加する
-
import MyAppPackage
でインポートする
-
Build、Run して動作を確かめる
これ以降の開発では、基本的に Swift Package の方に実装を行います。外部のライブラリを使いたい場合も、Swift Package(上記例では MyAppPackage
)の Package.swift
の dependencies
に追加します。Swift Package ではなく CocoaPods や Carthage を使用しなければならないライブラリの場合は、.xcframework
としてそれらのライブラリを書き出し、Package.swift
の targets
に binaryTarget
として追加する方法をとります。
おわりに
@ry-itto(Ryoya Ito) さんが発表してくださるまでこのような構成を取れることを知らず、今後使っていきたいと思う内容でした。
また、これまでであれば Mint を使用して使ってきたようなツールが欲しい場合であっても、Mint ではなく Swift Package の dependencies
に追加すればよい、という点も非常に興味深いと感じました。
この記事で紹介しなかったメリットやデメリットについても述べられていますので、YouTube 上のアーカイブや SpeakerDeck、また @ry-itto(Ryoya Ito) さんによるサンプルリポジトリが非常に参考になりますので、下の関連項目からチェックしてみてください。
関連項目
Discussion