マルチモジュールに関する記事はネットで調べれば出てくるのですが、マルチプロジェクトの実装方法に関する記事がなかったので、今回書くことにしました。
誤り等があれば指摘していただけると幸いです。
手順
Workspaceの作成
Xcodeを起動してからメニューの File>New>Workspace...
もしくは ⌘+^+N
からWorkspaceを開きます。
フォルダ作成
terminalもしくはFinderから.workspaceと同じ階層にApp
というフォルダを作成し、MultiProjectsフォルダの配下にiOS
というフォルダを作成して下さい。
AppフォルダにはApp.swift, Assets.xcassetsなどを格納します。
xcodeprojの追加
メニューの File>New>Project...
もしくは ⌘+Shift+N
からStaging
とProduction
というプロジェクトを新規作成し、.xcodeprojをAppフォルダの配下に追加します。
Add to と Group には 1. Workspaceの作成で作成したWorkspaceを選択して下さい。
.xcodeprojのファイル移動
今作成したStagingとProductionのファイルをiOSディレクトリの配下に移動させていきます。
ターミナルもしくはFinderを使用して移動させて下さい。
ここではターミナルを使用した方法を解説します。
// pathには自身のパスを入れてください
cd path/MultiProjects/
mv Production/Production iOS/
// MultiProjectsの階層で行うこと
mv Production/Production.xcodeproj ../MultiProjects/
// pathには自身のパスを入れてください
cd path/MultiProjects
mv Staging/Staging iOS/
// MultiProjectsの階層で行うこと
mv Staging/Staging.xcodeproj ../MultiProjects/
App.swiftの共通化
App.swiftをどの環境(Staging, Production)からでも参照されるよう修正していきます。
StagingとProductionのどちらでも構いませんが、今回はProductionの方を使用します。
ContentView.swiftは後ほど使用するので、任意の場所に残しておいてください。
※StagingとProductionのApp.swiftとContentView.swiftは使用しないので削除します。
// pathには自身のパスを入れてください
cd path/Production
mv ProductionApp.swift App.swift
mv Production/App.swift ../iOS
MultiProjectsの階層にあるStagingディレクトリとProductionディレクトリは必要ないので、削除してしまって大丈夫です。
// MultiProjectsの階層で実行すること
rm -r Staging/
rm -r Production/
workspaceDataを編集して、.xcodeprojが表示されるようにする
contents.xcworkspacedataを編集して、workspaceがファイルを参照できるようにしていきます。
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:App/Staging.xcodeproj">
</FileRef>
<FileRef
location = "group:App/Production.xcodeproj">
</FileRef>
<FileRef
location = "group:">
</FileRef>
</Workspace>
ファイルの参照設定
今のところこのような状態になっていると思うので、ファイルを参照できるようにしていきます。
TARGETS > Build Phases > Compile Sources にApp.swiftを参照させます。
TARGETS > Build Phases > Copy Bundle Resources にはAssets.xcassetsとPreview Contentを参照させます。
swift package initでpackage追加
MultiProjectsの配下にMultiModule化させるためのPackageを追加します。
// MultiProjectsの配下で行うこと
swift package init
workspaceにpackage, Souces, Testsが追加されました。
AppディレクトリにPackage.swiftを追加
隠蔽したい階層にPackage.swiftを追加することで、存在を秘匿できるようになります。
今回の場合ですと、Appディレクトリ配下を隠します。
// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "",
products: [],
targets: []
)
workspaceを確認すると、MultiProjectsの配下からAppディレクトリが表示されなくなっています!
packageにmoduleを追加していく
MultiProjectsの配下にpackage.swiftを追加していきます。
こうすることでMulti Module化を進めていくことができます。
では、実装方法を見ていきましょう。
swift package init
上記コマンドを叩いた階層にPackage.swift, Sources, Testsが追加されています。
.xcodeprojにmoduleを参照し、importする
AppFeatureというフォルダにContentView.swiftを移管して、マルチモジュール対応を行っていこうと思います。
まずは不要なファイルを削除します。
SourcesとTestsの配下にあるファイルをすべて削除し、AppFeatureフォルダを作成してContentView.swiftを移動させます。
このままではエラーが発生するので、MultiProjects配下のPackage.swiftに修正を行います。
let package = Package(
name: "MultiProjects",
+ platforms: [.iOS(.v13)], //SwiftUIはiOS13~でなければ使用できないため
products: [
- .library(
- name: "MultiProjects",
- targets: ["MultiProjects"]),
+ .library(name: "AppFeature", targets: ["AppFeature"])
],
targets: [
- .target(
- name: "MultiProjects"),
- .testTarget(
- name: "MultiProjectsTests",
- dependencies: ["MultiProjects"]),
+ .target(name: "AppFeature")
]
)
また、モジュール外からアクセスできるようにpublic修飾子を追加します。
import SwiftUI
-struct ContentView: View {
+public struct ContentView: View {
+ public init() {}
- var body: some View {
+ public var body: some View {
Text("Hello, world!")
.padding()
}
}
StagingとProductionのそれぞれのTARGETS > Frameworks, Libraries, and Embedded ContentにAppFeatureを追加します。
こうすることでそれぞれのプロジェクトでフレームワークを参照できるようになり、importを行うことができるようになります。
Manage schemeで名前を変更
Scheme名 > Edit Scheme... > Manage Schemes... > Schemeの列を任意の文字に修正すると以下の画像のようにできると思います。
参考