xcodebuild: Deploy iOS app from Command Line
The deployment of an iOS app to iTunes Connect involves various things and it’s time consuming and fragile activity. It’s very common practice for iOS developers use Xcode to build, test, archive and upload app to iTunes Connect. Fortunately Apple has command line tools to do all this things and one of the most popular utility is xcodebuild. There is fancy wrapper on Apple Developer tools called Fastlane which can be used for scripting deployment of an iOS application. You might be wondering why we need to use command line to deploy iOS application. Can you imagine a day without Xcode ? Or Can you think of deploying an app from server where you don’t have GUI access? Or What if you don’t have scripting skills in Ruby to use Fastlane?
We must know what’s happening behind the scene when we build, test, archive and upload an app. We should aware of the native Apple developer tools used for all these activities. By learning command line interaction, we can get following benefits
- In-Depth knowledge of underlying Apple technologies used while building, deploying an iOS application.
- Ease of automating iOS development task for continuous integration or cloud based servers
- Better understanding of what tools like Fastlane are doing in the background.
In this post, we will see how we can build, test, archive and deploy a sample iOS app to iTunes Connect.
In order to understand the command line deployment process, we should have following things setup in advance.
- Sample app with Xcode workspace. e.g CLI.xcworkspace
- Xcode Scheme with Release configuration : CLI-Release
- Certificates, AppID, Provisioning profiles setup for production in iTunes Connect. Use Apple’s documentation to setup all the things . We will assume provisioning profile CLI Distribution profile for this tutorial.
- macOS with Distribution certificate in the keychain
We will cover cycle of the iOS app from analysing app till deploying to iTunes Connect using xcodebuild.
One of the sensible things to do before we build and test an iOS app is performing static analysis of the source code. The xcodebuild has an ability to clean and analyse the source code for any common syntax errors. We can pass our Xcode project e.g CLI.xcodeproj
$ xcodebuild -project CLI.xcodeproj -scheme CLI -sdk iphonesimulator10.3 clean analyze
We can build an iOS app using xcodebuild ‘build’ action which generate the derived data for our iOS app. Once app is build, it can run inside the simulator or can be used by test bundle.
build for running
We can simply build our app to run inside simulators by using simple command
$ xcodebuild -scheme CLI -workspace CLI.xcworkspace/ build
This will create a derive data inside ~/Library/Developer/Xcode/DerivedData/ directory. Thre are various options that we can pass to override the default settings so that we can control the artifact e.g -destination or -derivedDataPath etc
build for testing
Xcode 8 has introduced this nice feature to allow building once and use the derived data .xctestrun file to test multiple time on different destinations.
We can build for testing using command:
$ xcodebuild build-for-testing -workspace CLI.xcworkspace -scheme
CLI -destination generic/platform=iOS
Now that, we can use test-without-building action to run tests without building an app.
Apple has XCTest framework to perform unit and UI testing of an iOS app. We can update our release scheme to include suite of tests. Assuming our ‘CLI’ scheme is configured to run tests, then we can run tests associated with scheme using
$ xcodebuild -scheme CLI -workspace CLI.xcworkspace/ test
This will build our scheme and start executing tests for that particular tests.
If you have build app using ‘build-for-testing’ option mentioned above, we can perform testing on multiple destinations using same derived data.
$ xcodebuild test-without-building -workspace CLI.xcworkspace
-scheme CLI -destination 'platform=iOS
Simulator,name=iPhone 7' -destination
This will execute tests for iPhone as well as on iPad. We don’t have to build app twice to run the tests on different destinations.
The most of iOS engineers find process of archiving an iOS app is very painful as it involve dealing with provisioning profiles, certificates and build configurations. In order to upload app to iTunes Connect or deploy it on to the provisioned devices, we need to build and app for generic iOS device destination as well as export it in IPA format.
Let’s build our app with release configuration scheme ‘CLI’ with generic iOS device destination.
$ xcodebuild -workspace CLI.xcworkspace \
-scheme CLI \
-destination generic/platform=iOS build
xcodebuild has a new -exportArchive option to create an IPA that works more like Xcode Organizer.
There are two steps
- build an archive with xcodebuild archive
- create the .ipa with xcodebuild -exportArchive
We now build the archive like this:
$ xcodebuild -workspace CLI.xcworkspace -scheme CLI -sdk iphoneos -configuration AppStoreDistribution archive -archivePath $PWD/build/CLI.xcarchive
We now export the .ipa like this:
$ xcodebuild -exportArchive -archivePath $PWD/build/CLI.xcarchive -exportOptionsPlist exportOptions.plist -exportPath $PWD/build
These two command create the file build/myApp.xcarchive and build/myApp.ipa
Note that above command requires a -exportOptionsPlist argument that points to a .plist file with export options. For a complete list of what you can put in that plist, run xcodebuild -help . The minimal contents of the file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
we run this command successfully, we will have IPA file created using provisioning profile ‘CLI Distribution Profile’. At the end we will have our IPA, CLI.ipa binary ready to upload to iTunes Connect.
Uploading IPA to iTunes Connect
The last step of the deploying our app is to upload the binary to iTunes Connect. Usually Xcode has ‘Application Loader’ app to perform this task. Fortunately, we have command line interface for the Application loader app called ‘altool’. The binary file for altool comes up with Xcode so no need to download it separately. The binary is usually located at the path
It would be great idea to export that binary to $PATH so that it can be accessed from anywhere. We can use this binary to upload our IPA to iTunes Connect. We need our Apple ID username and password to upload, assuming we have those credentials in the keychain or have it as ENV Variables $USERNAME and $PASSWORD
$ altool --upload-app -f "CLI.ipa" -u $USERNAME -p $PASSWORD
You can explore other command line options for ‘altool’ on the Apple official documentation. It will take huge amount of time to upload but be patient and enjoy your IPA uploaded to iTunes connect.
Now that, we have successfully uploaded an IPA to iTunes Connect, we can distribute to testFlight for internal testing or submit it to Apple for review from iTunes Connect
At this stage, you might have brief idea about the internal tools that Apple use to build, archive and deploy an iOS app to iTunes Connect. There are various other open-source wrappers available to make our life easy like Fastlane, ios-deploy etc. Please comment if you think something is missing
Happy Continuous delivery !
Like this post from XCBlog By XCTEQ ? You may also like some of our services like guest blogging or Mobile DevOps(CI/CD) or Test Automation. Chekout our services, open source projects on Github or Follow us on Twitter , Facebook, Youtube , LinkedIn. Download Our XCBlog iOS App to read the blogs offline.