KINTO Tech Blog
CI/CD

[iOS][CI/CD] Integrating a Private Repository as a Library in Xcode Cloud

Cover Image for [iOS][CI/CD] Integrating a Private Repository as a Library in Xcode Cloud

Introduction

Hello. I’m Hiroya (@___TRAsh) from the Mobile App Development Group.

At our company, we have several in-house product teams, and many of them use Xcode Cloud. Xcode Cloud is an official CI/CD service provided by Apple that automates iOS app builds and CD (deployment to TestFlight).

In this post, I’ll cover how to integrate a private repository as a library in Xcode Cloud. Since there weren’t many references available, I faced some challenges getting it to work and wanted to share the solutions I found.

Target Readers

This guide is intended for readers with some experience in iOS development, especially in setting up CI/CD for iOS environments.

Environment

- Using Xcode 15.4
- Managing libraries with SwiftPM
- Referencing a private repository in libraries
- Deploying to TestFlight with GitHub Actions + Fastlane

Objective

To shift TestFlight deployments from GitHub Actions + Fastlane to Xcode Cloud. By doing so, we can reduce dependency on Fastlane and minimize the tools required in the app submission process. Additionally, Xcode Cloud allows direct reference to Apple Developer certificates, making it easier to manage the certificates needed for app submission.

Challenges

Xcode Cloud offers many benefits, but using a private repository as a library requires user authentication. Since Xcode Cloud does not natively support these authentication settings, an extra step is needed to reference a private repository as a library. To achieve this, we can use the ci_scripts/ci_post_clone.sh provided by Xcode Cloud to set up the necessary authentication, allowing access to the private repository.

.netrc configuration

Since Xcode 12.5, .netrc has been supported as a way to store usernames and passwords,`` which can be automatically accessed during git clone operations. By placing in ~/.netrc, the authentication information is automatically applied. Additionally, for managing the private repository as a GitHub Release, I’ve added api.github.com to the .netric configuration.

ci_post_clone.sh
touch ~/.netrc
echo "machine github.com login $GITHUB_USER password $GITHUB_ACCESS_TOKEN" >> ~/.netrc
echo "machine api.github.com login $GITHUB_USER password $GITHUB_ACCESS_TOKEN" >> ~/.netrc

I set my username and access token as secrets in Xcode Cloud’s environment variables and configured ci_post_clone.sh to reference them.

Adding the Repository URL

In Xcode Cloud settings within App Store Connect, I added the repository URL of the library under Additional Repositories.

Removing Settings with Defaults Delete

Even after configuring access to the private repository’s library, I encountered an issue where the library dependencies couldn’t be resolved, resulting in the following error:

:::message alert Could not resolve package dependencies: a resolved file is required when automatic dependency resolution is disabled and should be placed at XX/XX/Package.resolved. Running resolver because the following dependencies were added: 'XXXX' (https://github.com//.git) fatalError :::

This error occurs because, on Xcode Cloud, SwiftPM does not reference Package.resolved and instead attempts to resolve package versions automatically. To fix this issue and allow the build to succeed, I deleted certain Xcode defaults.

ci_post_clone.sh
defaults delete com.apple.dt.Xcode IDEPackageOnlyUseVersionsFromResolvedFile
defaults delete com.apple.dt.Xcode IDEDisableAutomaticPackageResolution

Although I applied these two settings, I couldn't clearly identify the difference between them... To get more information, I ran the xcodebuild help command locally, where I found some similar settings that could help clarify their roles.

$ xcodebuild -help
...

-disableAutomaticPackageResolution        prevents packages from automatically being resolved to versions other than those recorded in the `Package.resolved` file
-onlyUsePackageVersionsFromResolvedFile   prevents packages from automatically being resolved to versions other than those recorded in the `Package.resolved` file

This prevents SwiftPM from automatically resolving packages to versions other than those recorded in the Package.resolved file.

However, both settings seem to do exactly the same thing, as no additional differences were found. I also came across a similar question in a SwiftPM issue thread, and this approach was confirmed to work. So, for now, I believe this setup is sufficient. https://github.com/swiftlang/swift-package-manager/issues/6914

For now, by deleting these two settings, SwiftPM will only refer to Package.resolved for library dependencies and resolve them.

Conclusion

By configuring .netrc in ci_scripts/ci_post_clone.sh, which Xcode Cloud references before starting, I was able to access the private repository. Additionally, setting the defaults delete ensures that SwiftPM resolves dependencies based solely on Package.resolved, allowing the build to succeed on Xcode Cloud.

ci_post_clone.sh
#!/bin/sh

defaults delete com.apple.dt.Xcode IDEPackageOnlyUseVersionsFromResolvedFile
defaults delete com.apple.dt.Xcode IDEDisableAutomaticPackageResolution

touch ~/.netrc
echo "machine github.com login $GITHUB_USER password $GITHUB_ACCESS_TOKEN" >> ~/.netrc
echo "machine api.github.com login $GITHUB_USER password $GITHUB_ACCESS_TOKEN" >> ~/.netrc

Lastly

Fastlane is a great tool that has been around for a long time, but by using Xcode Cloud, the process of submitting an app has been simplified. As mentioned earlier, Xcode Cloud offers numerous benefits, so I encourage you to consider implementing it in your workflow.

Appendix

https://developer.apple.com/documentation/xcode/writing-custom-build-scripts https://speakerdeck.com/ryunen344/swiftpm-with-kmmwoprivatenagithub-releasedeyun-yong-suru https://qiita.com/tichise/items/87ff3f7c02d33d8c7370 https://github.com/swiftlang/swift-package-manager/issues/6914

Facebook

関連記事 | Related Posts

We are hiring!

【iOSエンジニア】モバイルアプリ開発G/東京

モバイルアプリ開発GについてKINTOテクノロジーズにおける、モバイルアプリ開発のスペシャリストが集まっているグループです。KINTOやmy routeなどのサービスを開発・運用しているグループと協調しながら品質の高いモバイルアプリを開発し、サービスの発展に貢献する事を目標としています。

【クラウドエンジニア】Cloud Infrastructure G/東京・大阪

KINTO Tech BlogWantedlyストーリーCloud InfrastructureグループについてAWSを主としたクラウドインフラの設計、構築、運用を主に担当しています。