KINTO Tech Blog
iOS

Swift Package Manager Is Now Available for the My Route App!

Cover Image for Swift Package Manager Is Now Available for the My Route App!

My name is Ryomm and I am developing the app my route (iOS) at KINTO Technologies. The my route app's library management tool has finally migrated from CocoaPods to Swift Package Manager (SPM)!

Introduction

The my route app used to use CocoaPods.

However, around summer 2024, CocoaPods issued the following announcement.
https://blog.cocoapods.org/CocoaPods-Support-Plans/

That was an announcement stating that CocoaPods would be transitioning to maintenance mode. It doesn't mean it will become unusable, and they will still support security issues and other concerns. However, support for GitHub issues and the addition of new features will no longer be provided.

If you do this, you may find yourself in a situation where you want to add a new library only to find that CocoaPods is no longer supported, or that you are unable to fix a problem with CocoaPods itself.

There had been talk of migrating to SPM at my route for some time, but the announcement of CocoaPods gave us the impetus to finally embark on the migration to SPM.

What is Swift Package Manager?

SPM is a genuine library management tool provided by Apple.
https://github.com/swiftlang/swift-package-manager

Speaking of library management tools for iOS, there are other third-party tools such as CocoaPods and Mint. The biggest difference between these and SPM is that SPM is directly integrated into Xcode. This means that by simply updating Package.resolved when necessary, the latest specified version of the library will be imported when you open or build a project. This means that I no longer need to tell my team to run pod install every time I update the version.

Migration Complete!

It’s simply a matter of transferring everything, but there were a few stumbling points and tips that I encountered, so I’d like to share them with you.

The Specified Version of the Library Is Not Downloaded

I had a problem where, when switching to the desired version, even after executing "Reset Package Caches" or "Update to Latest Package Versions" in Xcode, the version specified in Package.swift would not be downloaded. Even deleting DerivedData doesn't fix this.

This is because residual caches remain in locations such as ~/Library/Caches/org.swift.swiftpm and ~/Library/org.swift.swiftpm. When I delete these, the correct version of the library is downloaded.

Build Doesn't Pass Only During Testing

My route has multiple schemas, each of which depends on slightly different libraries. So, it has a structure separated from the project's own Package.swift as shown below. Configuration

We create a Dependencies package in the same workspace as the project file and manage the library within this package so that it becomes a one-to-one product (framework) with each schema. These products are linked to each target's Frameworks, Libraries, and Embedded Content as shown in the screenshot on the right.

However, with this configuration, I encountered a problem where xcodebuild build passed, but xcodebuild build-for-testing did not. This command corresponds to Run and Test in the Xcode GUI.

Typically, items in a package are tested within that same package. However, with the above configuration, tests are run on the project’s main target instead. This means that the tests are executed outside the package. So yes... this is technically an improper setup... which I do plan to fix, but for now the tests are included in the same package, which allows us to proceed with testing preserving the current configuration.

It seems that the cause was the different behavior around the linker between Run and Test.

The build product for Run is assumed to be 1), and the build product for Test is assumed to be 2). 1) includes SPM in Dependencies, but 2) does not. Therefore, if a test in the MainTarget depends on a library in Dependencies, the build will fail.

A simple solution is to move the libraries required for testing to the SPM in MainTarget, which will be included in the build for both Run and Test. To fundamentally solve the problem, it is a good idea to simplify the tests in one package, as mentioned above.

Putting SwiftLint and LicensePlist on SPM

Since I want to include SwiftLint and LicensePlist in the project's Build Phase so that they are executed during the build, I create a separate package in a location independent of the workspace.

Project/
├── Test.xcworkspace
├── Test.xcodeproj
├── Test/
│   └── ...
├── ...
└── tools // <- this!
    ├── Package.swift
    └── Package.resolved

I placed the libraries I wanted to include in the Build Phase, such as SwiftLint and LicensePlist, into the newly created "tools" package. Then, I created a shell script, which I executed only the first time to download the libraries locally.

SPM_PACKAGE_PATH=tools
SPM_BUILD_PATH=tools/.build/release

echo "swiftlint" && $SPM_BUILD_PATH/swiftlint --version || swift run -c release --package-path $SPM_PACKAGE_PATH swiftlint --version
echo "license-plist" && $SPM_BUILD_PATH/license-plist --version || swift run -c release --package-path $SPM_PACKAGE_PATH license-plist --version

Then, it becomes executable at tools/.build/release/swiftlint, so I add this to the Build Phase. Build Phase

The same applies to LicensePlist. Even when executing from platforms like Bitrise, it can be confirmed that LicensePlist is executed by executing the shell first, followed by building the project.

Conclusion

It's been a few months since the migration, and while there are still some issues, I feel that replacing libraries has become easier. When I want to check whether an issue is caused by a library, I personally find it convenient to quickly check it using the app-version of Praygrounds for a quick test.

Now that SPM is integrated into the project, it has also become possible to use Apple libraries that are only available via SPM. In the future, I would like to use these libraries to improve our implementation.

Facebook

関連記事 | Related Posts

We are hiring!

【PdM】my route開発G/東京

my route開発グループについてmy route開発グループは、my routeに関わる開発・運用に取り組んでいます。my routeの概要 my routeは、移動需要を創出するために「魅力ある地域情報の発信」、「最適な移動手段の提案」、「交通機関や施設利用のスムーズな予約・決済」をワンストップで提供する、スマートフォン向けマルチモーダルモビリティサービスです。

【バックエンドエンジニア】my route開発G/東京

my route開発グループについてmy route開発グループは、my routeに関わる開発・運用に取り組んでいます。my routeの概要 my routeは、移動需要を創出するために「魅力ある地域情報の発信」、「最適な移動手段の提案」、「交通機関や施設利用のスムーズな予約・決済」をワンストップで提供する、スマートフォン向けマルチモーダルモビリティサービスです。

イベント情報

Mobility Night #3 - マップビジュアライゼーション -