💯

Xcodeプロジェクトに格納したSwift PackageのCIをBitriseで実現する

2022/06/12に公開

0. はじめに

SwiftPackageはiOSのマルチモジュール化を検討する際、有力な選択肢の一つです。

Swift.orgではPackageについて下記のように説明されており、Packageの思想として、単一プロダクトでのコード分割よりも複数プロダクトでのコード共有に重きが置かれていることが推察できます。

原文) When you use a separate module for code that solves a particular problem, that code can be reused in other situations. For example, a module that provides functionality for making network requests can be shared between a photo sharing app and a weather app. Using modules lets you build on top of other developers’ code rather than reimplementing the same functionality yourself.
和文) 特定の問題を解決するコードに別のモジュールを使用すると、そのコードを他の状況で再利用できます。たとえば、ネットワークリクエストを行う機能を提供するモジュールは、写真共有アプリと天気アプリの間で共有できます。モジュールを使用すると、同じ機能を自分で再実装するのではなく、他の開発者のコードの上に構築できます。

とはいえ、Packageを利用することでModuleを実現できますし、アクセス制御も可能です。
またPackagesではxcodeprojファイルに相当するものが存在しないため、Packageのコードを変更した際にプロジェクトファイルのコンフリクトを心配しなくてもよくなる、Frameworkの再ビルドが必要ないなど、複数プロダクト利用を前提としなくてもPackageのメリットを十分に受けることが可能です。

その一方で今日のアプリ開発環境を考えると実際のプロダクトをPackageを利用してマルチモジュール化していくには、PackageのCIをどう実現していくのか、という観点も必要です

調査を進めていく中で、Xcodeに組み込んだPackageをCI上でテストさせるやりかたがわかったので、その手順を残しておこうと思います。

1. 環境

Xcode 13.4.1 環境で実施しています。
BitriseのStackも Xcode 13.4.1 に設定しています。

1.1 プロジェクトの状況

下記のような状況です。

SwiftPMIntegrateTest
├── SwiftPMIntegrateTest
│   ├── AppDelegate.swift
│   ├── Assets.xcassets
│   │   ├── AccentColor.colorset
│   │   │   └── Contents.json
│   │   ├── AppIcon.appiconset
│   │   │   └── Contents.json
│   │   └── Contents.json
│   ├── Base.lproj
│   │   ├── LaunchScreen.storyboard
│   │   └── Main.storyboard
│   ├── Info.plist
│   ├── SceneDelegate.swift
│   └── ViewController.swift
├── SwiftPMIntegrateTest.xcodeproj
│   ├── project.pbxproj
│   ├── project.xcworkspace
│   │   ├── contents.xcworkspacedata
│   │   ├── xcshareddata
│   │   │   ├── IDEWorkspaceChecks.plist
│   │   │   └── swiftpm
│   │   └── xcuserdata
│   │       └── hidemune.xcuserdatad
│   │           └── UserInterfaceState.xcuserstate
│   ├── xcshareddata
│   │   └── xcschemes
│   │       └── SwiftPMIntegrateTest.xcscheme
│   └── xcuserdata
│       └── hidemune.xcuserdatad
│           └── xcschemes
│               └── xcschememanagement.plist
├── SwiftPMIntegrateTestTests
│   └── SwiftPMIntegrateTestTests.swift
├── SwiftPMIntegrateTestUITests
│   ├── SwiftPMIntegrateTestUITests.swift
│   └── SwiftPMIntegrateTestUITestsLaunchTests.swift
└── SwiftPackage
    └── TestSubPackage
        ├── Package.swift
        ├── README.md
        ├── Sources
        │   └── TestSubPackage
        │       └── TestSubPackage.swift
        └── Tests
            └── TestSubPackageTests
                └── TestSubPackageTests.swift

Xcode上では下記のように指定しています。

今回テストに使用したプロジェクトはこちらになります。

2. BitriseでCIを設定する

2.1 まずは一旦CIでビルドできるようにする

通常のiOSアプリと同じようにBitriseでCIを設定してください。
CIを設定したら通常のテストがSuccessするか確認してください、

2.2 SwiftPackage用のCI設定を追加する

プロジェクトに内包しているSwiftPackageManagerをBitrise上でもテストできるよう、BitriseのWorkflowを編集していきましょう。
(すべての画像及びパラメータの設定はこのGitHubリポジトリーを利用する前提で撮影しています。利用者独自の環境で利用する場合適宜画像 or パラメータの設定は読み替えてください)

No 作業手順 スクリーンショット
1 primaryをコピーして新しいWorkflowを作成しましょう。
2 標準で追加されているXocde Test for iOSの設定を添付画像のように変更してみましょう。
Project path → Package.swiftまでのパスを指定してください。今回の場合は SwiftPackage/TestSubPackage/Package.swift を指定しています。
Scheme → テストしたいSwiftPackageのSchemeを記載してください。今回の場合は TestSubPackage を指定しています。
3 ここまでが完了したら、右上のSavedを押して設定を保存してください (スクショ省略)
4 Bitriseのメイン画面に戻って、右上の Start/Schedule a Build からmainブランチに対して primary-packageTest を実行してください
5 成功するはず!

3. 終わりに

今日のユーザーにとってスマートフォンの生活における重要度は数年前のそれと比べて格段に上がりました。
スマホから商品が注文できるサービスや、タクシーが呼べるサービス、電話がかけられたりチャットができたりするサービスなど、ユーザーの皆さんは1つだけではなく様々なアプリを利用しています。

これらのアプリは膨大なコードベースを持つことが多く、マルチモジュール化による適切な粒度での責務分割が欠かせません。

膨大なコードベースを適切な粒度でマルチモジュール化し、各モジュールに対してCIを高頻度で回していくことにより開発者が見落としてしまったバグや、デグレードを防ぐことができユーザーの皆さまによりよいサービスをお届けすることができます。

もし今SwiftPackageを利用してマルチモジュールを実現することをご検討中でしたら、ぜひこの記事を参考にしてCIを導入していただければと思います。

Discussion