Building an iOS Distribution Pipeline — Local POC with Command Line Tools (Part 1)

Efekan Egeli
Trendyol Tech
Published in
4 min readJul 18, 2019
Photo by tian kuan on Unsplash

There are a lot of ways of automating your iOS distributions nowadays. CircleCI, TravisCI, Fastlane just to name a few…

Since we’ve always been a bit of a control freak; we wanted to use 3rd party tools as little as possible. Thus, we’ve only used Jenkins as our automation server.

This will be a step by step guide with parts describing how to build a similar pipeline with the command line tools that Apple provided.

We always take an iterative approach when we are building something ground up. So the first thing we needed was to build an app for different environments. We already had different schemes for different environments so I’m not going to get into that. I’m not going to get into how to set up a Jenkins server as well because you can already find a lot of information on that.

Let’s begin with building our app with command line tools on our local machine. The tool Apple provides for this kind of purpose is xcodebuild. xcodebuild is a command line tool which lets you build your app with different schemes, build configurations, targets. You can find the full list of it’s capabilities with help command.

xcodebuild -help

So let’s pick a scheme for our POC and build it with xcodebuild command.

xcodebuild build -workspace your_project_workspace -scheme your_project_scheme_name

When it builds the project, the console looks like this:

CompileC /Users/jenkins/Library/Developer/Xcode/DerivedData/Trendyol-gtkkcwzykuhaycgnaraksmvhkxbr/Build/Intermediates.noindex/Pods.build/Prod-iphoneos/FBSDKCoreKit.build/Objects-normal/arm64/FBSDKAppEvents.o /Users/jenkins/Documents/workspace/ios-distribution/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.m normal arm64 objective-c com.apple.compilers.llvm.clang.1_0.compiler (in target: FBSDKCoreKit)
cd /Users/jenkins/Documents/workspace/ios-distribution/Pods
export LANG=en_US.US-ASCII
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -x objective-c -arch arm64 -fmessage-length=0...

Seriously? What is this? It should be more readable.

xcpretty to the rescue

There is an open source formatter called xcpretty which formats the xcodebuild outputs. After you install xcpretty, the usage is pretty simple.

xcodebuild build -workspace Trendyol.xcworkspace -scheme TY-Prod | xcpretty

Here is the result:

...
▸ Compiling pop-dummy.m
▸ Compiling TransformationMatrix.cpp
▸ Compiling POPVector.mm
▸ Compiling POPSpringAnimation.mm
▸ Compiling POPPropertyAnimation.mm
▸ Compiling POPMath.mm
...

The final result of the build was successful but let’s be honest; we need more than just a build. We need to archive & export IPA & upload our app to the store. xcodebuild provides both archive & export options.

Next step: Archive

xcodebuild -workspace Trendyol.xcworkspace -scheme TY-Prod -sdk iphoneos -configuration Prod archive -archivePath /Users/jenkins/Documents/workspace/ios-distribution-config/TY-Prod.xcarchive

Final result:

...
▸ Processing Trendyol-Info.plist
▸ Generating 'Trendyol.app.dSYM'
▸ Running script 'Run Script'
▸ Running script 'to do script'
▸ Running script '[CP] Copy Pods Resources'
▸ Touching Trendyol.app (in target: Trendyol)
▸ Archive Succeeded

The archive was successful as well.

Next step: Exporting an IPA

Now before we use xcodebuild’s exportArchive option, first we need to create an exportOptions.plist file. 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">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string>
<key>teamID</key>
<string>your own team id</string>
</dict>
</plist>

Method in the file should be development, app-store, enterprise or ad-hoc. The teamID should be your Apple team id. You can find your team’s id from https://developer.apple.com in membership section after you log in.

After we set our exportOptions.plist up, we use xcodebuild’s exportArchive option. As you can see below, we also put the path of our project’s archive file from the previous step and put another path as exportPath which is the location of the IPA output.

xcodebuild -exportArchive -archivePath /Users/jenkins/Documents/workspace/ios-distribution/TY-Prod.xcarchive -exportOptionsPlist exportOptions.plist -exportPath /Users/jenkins/Documents/workspace/ios-distribution -allowProvisioningUpdates

And we successfully exported our first IPA.

▸ Export Succeeded

Next step: Upload the IPA to the app store

For uploading an IPA to the store, Apple provides us another tool called altool. First thing you should do is add it’s path to the global path so it would be easier to call altool from anywhere.

export PATH=$PATH:/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/

Now let’s upload our first package to the store.

altool --upload-app -f /Users/jenkins/Documents/workspace/ios-distribution-config/TY-Prod.ipa -u your_user_name -p your_password

You should use the username and password of the account which has the right permissions for uploading an app to the app store.

The result:

altool[73409:3603060] No errors uploading '/Users/jenkins/Documents/workspace/ios-distribution-config/TY-Prod.ipa'

At this step of the pipeline guide, we have

  • Built the app with the scheme we picked
  • Archived the app
  • Exported the .ipa file
  • Uploaded the .ipa file to the app store

on our local machine.

Part 2 of this guide will describe setting a Jenkins freestyle project up with parameters and SCM. Part 2 is available here.

--

--