[iOS][CI/CD] Xcode Cloudでプライベートリポジトリをライブラリとして取り込む
はじめに
こんにちは。モバイル開発のヒロヤ(@___TRAsh)です。
弊社ではいくつもの内製開発プロダクトがありますが、多くのプロダクトでXcode Cloudを採用しています。
Xcode CloudはAppleが公式に提供しているCI/CDサービスで、iOSアプリのビルドやCD(TestFlightへのデプロイ)を自動化できます。
今回は、Xcode Cloudでプライベートリポジトリをライブラリとして取り込む方法についてあまり参考資料が無く、ビルドを通すのに苦労したので、調査した結果をこちらにまとめておきます。
対象
今回の内容はiOS環境のCI/CDの話になるので、ある程度iOS開発の知識がある方を対象としています。
環境
- Xcode 15.4
- SwiftPMでライブラリを管理してる
- 参照しているライブラリにプライベートリポジトリがある
- GitHub Actions + FastlaneでTestFlightへデプロイしてる
やりたいこと
TestFlightのデプロイをGitHub Actions + FastlaneからXcode Cloudに移行したいと考えています。
これをすることで、Fastlaneへの依存をなくすことができ、App申請までのフローに必要なツールを減らすことができます。
また、申請に必要な証明書の管理もXcode Cloud上で直接Apple Developerの証明書を参照してくれるので、証明書の管理も楽になります。
悩み
ここまで利点しかないXcode Cloudですが、ライブラリとしてプライベートリポジトリを参照する際には、ユーザー認証が必要になります。Xcode Cloudではそういった認証設定が考慮されていないため、プライベートリポジトリをライブラリとして参照するには一工夫する必要があります。
そこでXcode Cloudから提供されている ci_scripts/ci_post_clone.sh
を活用して認証の設定することで、プライベートリポジトリを参照できるようになります。
.netrcの設定
Xcodeには12.5の頃から.netrc
を参照する機能が追加されています。
.netrc
はユーザー名とパスワードを記述したファイルで、~/.netrc
に配置することで、git clone
時に認証情報を自動で入力してくれます。
また、今回はライブラリをプライベートリポジトリのGitHub Releaseで管理する方法をとっているので、 api.github.com
も追加しています。
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
ユーザー名とアクセストークンをXcode Cloudの環境変数にSecretで設定しておき、ci_post_clone.sh
で参照するようにしています。
追加のリポジトリにURL追加
App Store Connect内のXcode Cloud の設定にある 追加のリポジトリ
にライブラリのリポジトリURLを追加します。
defaults delete で設定を削除する
上記の設定でプライベートリポジトリのライブラリを取得できる様になってもまだライブラリの依存関係を解決できず、以下の様なエラーに遭遇しました。
このエラーはXcode Cloud上でSwiftPMが、Package.resolvedを参照せず、自動でパッケージのバージョンを解決しようとしていることが原因です。
それぞれ、Xcodeのdefaultsを削除するとうまくビルドが通る様になります。
defaults delete com.apple.dt.Xcode IDEPackageOnlyUseVersionsFromResolvedFile
defaults delete com.apple.dt.Xcode IDEDisableAutomaticPackageResolution
この2つの設定なんですが実は違いが明確にわからなかったです...
ローカルで xcodebuild
のhelpコマンドを叩いて見てみると、似た様な設定があるのでそちらを参考にしても
$ 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
Package.resolvedファイルに記録されているバージョン以外に、パッケージが自動的に解決されるのを防ぎます。
となっているので全く同じ内容しか書かれてないんですよね...
一応SwiftPMのIssueでも同じ様な内容の質問があって、この対応で解決しているので、現状はこれで問題ないと思います。
ひとまず、この2つの設定を削除することで、SwiftPMが参照するライブラリの依存関係をPackage.resolvedのみ参照し、依存関係を解決してくれる様になります。
結論
Xcode Cloudで起動前に参照される ci_scripts/ci_post_clone.sh
に .netrc
を設定することで、プライベートリポジトリを参照できるようになり、ライブラリの依存関係を解決するために、defaults delete
を設定することで、Xcode Cloud上でのビルドが通るようになりました。
#!/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
最後に
Fastlaneは古くからある偉大なツールですが、Xcode Cloudの利用により、App申請までのフローをシンプルにできました。
先にも述べましたが、Xcode Cloudを使うことによるメリットは多いので、ぜひ導入を検討してみてください。
Appendix
関連記事 | Related Posts
We are hiring!
【iOS/Androidエンジニア】モバイルアプリ開発G/東京
モバイルアプリ開発GについてKINTOテクノロジーズにおける、モバイルアプリ開発のスペシャリストが集まっているグループです。KINTOやmy routeなどのサービスを開発・運用しているグループと協調しながら品質の高いモバイルアプリを開発し、サービスの発展に貢献する事を目標としています。
【iOSエンジニア】モバイルアプリ開発G/大阪
モバイルアプリ開発GについてKINTOテクノロジーズにおける、モバイルアプリ開発のスペシャリストが集まっているグループです。KINTOやmy routeなどのサービスを開発・運用しているグループと協調しながら品質の高いモバイルアプリを開発し、サービスの発展に貢献する事を目標としています。