Build apps with Xcode using Azure Pipelines or Team Foundation Server

Azure Pipelines | TFS 2018 | TFS 2017

This guidance explains how to use Azure Pipelines or Team Foundation Server (TFS) to automatically build Xcode projects with CI/CD pipelines.

Example

For a working example of how to build an app with Xcode, import (into Azure Repos or TFS) or fork (into GitHub) this repo:

https://github.com/MicrosoftDocs/pipelines-xcode

The sample code includes an azure-pipelines.yml file at the root of the repository. You can use this file to build the app.

Follow all the instructions in Create your first pipeline to create a build pipeline for the sample app.

Build environment

You can use Azure Pipelines to build your apps with Xcode without needing to set up any infrastructure of your own. Xcode is preinstalled on Microsoft-hosted macOS agents in Azure Pipelines. You can use the macOS agents to run your builds.

For the exact versions of Xcode that are preinstalled, refer to Microsoft-hosted agents.

Create a file named azure-pipelines.yml in the root of your repository. Then, add the following snippet to your azure-pipelines.yml file to select the appropriate agent pool:

# https://docs.microsoft.com/azure/devops/pipelines/languages/xcode
pool:
  vmImage: 'macOS-10.13'

Build an app with Xcode

To build an app with Xcode, add the following snippet to your azure-pipelines.yml file. This is a minimal snippet for building an iOS project using its default scheme, for the Simulator, and without packaging. Change values to match your project configuration. See the Xcode task for more about these options.

variables:
  scheme: ''
  sdk: 'iphoneos'
  configuration: 'Release'

steps:
- task: Xcode@5
  inputs:
    sdk: '$(sdk)'
    scheme: '$(scheme)'
    configuration: '$(configuration)'
    xcodeVersion: 'default' # Options: 8, 9, 10, default, specifyPath
    exportPath: '$(agent.buildDirectory)/output/$(sdk)/$(configuration)'
    packageApp: false

Signing and provisioning

To sign and provision your app, see Sign your mobile app during CI.

CocoaPods

If your project uses CocoaPods, you can run CocoaPods commands in your pipeline using a script, or with the CocoaPods task. The task optionally runs pod repo update, then runs pod install, and allows you to set a custom project directory. Following are common examples of using both.

- script: /usr/local/bin/pod install
  displayName: 'pod install using a script'

- task: CocoaPods@0
  displayName: 'pod install using the CocoaPods task with defaults'

- task: CocoaPods@0
  inputs:
    forceRepoUpdate: true
    projectDirectory: '$(system.defaultWorkingDirectory)'
  displayName: 'pod install using the CocoaPods task with a forced repo update and a custom project directory'

Testing on Azure-hosted devices

Add the App Center Test task to test the app in a hosted lab of iOS and Android devices. An App Center free trial is required which must later be converted to paid.

# App Center Test
# Test app packages with Visual Studio App Center.
- task: AppCenterTest@1
  inputs:
    appFile: 
    #artifactsDirectory: '$(Build.ArtifactStagingDirectory)/AppCenterTest' 
    #prepareTests: # Optional
    #frameworkOption: 'appium' # Required when prepareTests == True# Options: appium, espresso, calabash, uitest, xcuitest
    #appiumBuildDirectory: # Required when prepareTests == True && Framework == Appium
    #espressoBuildDirectory: # Optional
    #espressoTestApkFile: # Optional
    #calabashProjectDirectory: # Required when prepareTests == True && Framework == Calabash
    #calabashConfigFile: # Optional
    #calabashProfile: # Optional
    #calabashSkipConfigCheck: # Optional
    #uiTestBuildDirectory: # Required when prepareTests == True && Framework == Uitest
    #uitestStoreFile: # Optional
    #uiTestStorePassword: # Optional
    #uitestKeyAlias: # Optional
    #uiTestKeyPassword: # Optional
    #uiTestToolsDirectory: # Optional
    #signInfo: # Optional
    #xcUITestBuildDirectory: # Optional
    #xcUITestIpaFile: # Optional
    #prepareOptions: # Optional
    #runTests: # Optional
    #credentialsOption: 'serviceEndpoint' # Required when runTests == True# Options: serviceEndpoint, inputs
    #serverEndpoint: # Required when runTests == True && CredsType == ServiceEndpoint
    #username: # Required when runTests == True && CredsType == Inputs
    #password: # Required when runTests == True && CredsType == Inputs
    #appSlug: # Required when runTests == True
    #devices: # Required when runTests == True
    #series: 'master' # Optional
    #dsymDirectory: # Optional
    #localeOption: 'en_US' # Required when runTests == True# Options: da_DK, nl_NL, en_GB, en_US, fr_FR, de_DE, ja_JP, ru_RU, es_MX, es_ES, user
    #userDefinedLocale: # Optional
    #loginOptions: # Optional
    #runOptions: # Optional
    #skipWaitingForResults: # Optional
    #cliFile: # Optional
    #showDebugOutput: # Optional

Retain artifacts with the build record

Add the Copy Files and Publish Build Artifacts tasks to store your IPA with the build record or test and deploy it in subsequent pipelines. See Artifacts.

- task: CopyFiles@2
  inputs:
    contents: '**/*.ipa'
    targetFolder: '$(build.artifactStagingDirectory)'
- task: PublishBuildArtifacts@1

Deploy

App Center

Add the App Center Distribute task to distribute an app to a group of testers or beta users, or promote the app to Intune or the Apple App Store. A free App Center account is required (no payment is necessary).

# App Center Distribute
# Distribute app builds to testers and users via App Center
- task: AppCenterDistribute@1
  inputs:
    serverEndpoint: 
    appSlug: 
    appFile: 
    #symbolsOption: 'Apple' # Optional. Options: apple
    #symbolsPath: # Optional
    #symbolsPdbFiles: '**/*.pdb' # Optional
    #symbolsDsymFiles: # Optional
    #symbolsMappingTxtFile: # Optional
    #symbolsIncludeParentDirectory: # Optional
    #releaseNotesOption: 'input' # Options: input, file
    #releaseNotesInput: # Required when releaseNotesOption == Input
    #releaseNotesFile: # Required when releaseNotesOption == File
    #distributionGroupId: # Optional

Apple App Store

Install the Apple App Store extension and use the following tasks to automate interaction with the App Store. By default, these tasks authenticate to Apple using a service connection that you configure.

Release

Add the App Store Release task to automate the release of updates to existing iOS TestFlight beta apps or production apps in the App Store.

- task: AppStoreRelease@1
  displayName: 'Publish to the App Store TestFlight track'
  inputs:
    serviceEndpoint: 'My Apple App Store service connection' # This service connection must be added by you
    appIdentifier: com.yourorganization.testapplication.etc
    ipaPath: '$(build.artifactstagingdirectory)/**/*.ipa'
    shouldSkipWaitingForProcessing: true
    shouldSkipSubmission: true

Promote

Add the App Store Promote task to automate the promotion of a previously submitted app from iTunes Connect to the App Store.

- task: AppStorePromote@1
  displayName: 'Submit to the App Store for review'
  inputs:
    serviceEndpoint: 'My Apple App Store service connection' # This service connection must be added by you
    appIdentifier: com.yourorganization.testapplication.etc
    shouldAutoRelease: false