Xcode Cloud is a CI/CD service made by Apple which is deeply integrated into Xcode. Since its introduction, there has been a lot of discussion amongst iOS developers on whether it is a good alternative to existing CI/CD providers and what migration to Xcode Cloud would look like.
Setting up this new service is rather straigh-forward for small or new apps but it can be daunting for big codebases which have been around for a long time. These big codebases tend to still rely to some extent on third-party dependency managers such as CocoaPods and on third-party CI/CD tools such as Fastlane.
The use of such third-party frameworks tends to put people off switching over to Xcode Cloud but, in this article, I will go through how the use of custom CI scripts can help you and your team progressively migrate to Xcode Cloud without having to abandon the tools you have used for a long time. More specifically, this article explains how to build an app using CocoaPods and upload the resulting app archive to AppCenter using Fastlane from an Xcode Cloud workflow.
Xcode Cloud provides a way to run shell scripts at different stages of a workflow. These scripts can install third party dependencies and perform tasks on top of the workflow's pre-defined steps. I won't go into too much detail about how these scripts work as Xcode Cloud's documentation provides a great explanation on the topic, but I will give you a TLDR on the most important things you need to know about them:
- Xcode Cloud looks for a directory called
ci_scriptsin the Xcode project to find scripts to run. These scripts are similar to git hooks in the way they work.
- Xcode Cloud looks for
.shscripts with specific names inside the
ci_scriptsdirectory. It then runs any matched scripts at different stages of the workflow based their names:
ci_post_clone.sh: Runs after the remote repository is cloned.
ci_pre_xcodebuild.sh: Runs before the build process commences.
ci_post_xcodebuild.sh: Runs after the build process finishes.
- The scripts need to have executable permissions:
chmod +x <executable_name>.sh.
Now that we know how CI scripts work, let's see what we can do with them.
Apple recommends installing third-party tools and dependencies in the
ci_post_clone.sh script and they specifically talk about making CocoaPods dependencies available to the build step in that same script too.
To do so, and assuming that you have the pod project setup, create a
ci_post_clone.sh script under the
ci_scripts directory mentioned earlier and add the following contents to it:
#!/bin/sh brew install cocoapods pod install
If you push these changes and trigger a new build, Xcode Cloud will run a post clone step to install the CocoaPods dependencies.
CocoaPods installs and links all its dependencies by creating a
.xcworkspace. You need to update your workflow to use this
.xcworkspaceinstead of the default
On top of using CocoaPods, our project requires us to upload the resulting app archive to AppCenter. Our team currently uses a Fastlane lane to do this, which in turn uses Microsoft's appcenter fastlane plugin.
To run this lane from Xcode Cloud, we must first install Fastlane in the hosted runner using the same
ci_post_clone.sh script from earlier:
#!/bin/sh brew install cocoapods brew install fastlane pod install
After installing Fastlane, we need to create a separate script to upload the app's archive to AppCenter after the build has completed. We can do this by creating a script called
ci_post_xcodebuild.sh in the
ci_scripts directory, making it executable and adding the following contents to it:
#!/bin/sh # Call the custom lane fastlane run upload_to_appcenter ipa:$CI_AD_HOC_SIGNED_APP_PATH/$CI_PRODUCT.ipa
ci_post_xcodebuild.sh script retrieves the path to the app's archive, which is generated by the Xcode Cloud workflow, using environment variables, which are also provided by the workflow itself.