生成、测试和部署 Xcode 应用

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

了解如何使用 Azure Pipelines 生成和部署 Xcode 项目。

先决条件

创建管道

  1. 登录到你的 Azure DevOps 组织,并转到你的项目。

  2. 转到“管道”,然后选择“新建管道”或是“创建管道”(如果是首次创建管道)。

  3. 完成向导中的各个步骤。首先选择 GitHub 作为源代码位置。

  4. 可能会重定向到 GitHub 进行登录。 如果是这样,请输入 GitHub 凭据。

  5. 看到存储库列表时,请选择你的存储库。

  6. 你可能会被重定向到 GitHub 来安装 Azure Pipelines 应用。 如果是,请选择批准并安装

出现“配置”选项卡时,选择“Xcode”。

  1. 当新管道出现时,请查看 YAML 以了解其功能。 准备就绪后,选择“保存并运行”。

    新 YAML 管道中的“保存并运行”按钮

  2. 系统会提示你将新的 azure-pipelines.yml 文件提交到存储库。 对消息感到满意后,再次选择“保存并运行”。

    如果你要观察管道的运行情况,请选择生成作业。

    你刚刚创建并运行了我们为你自动创建的管道,因为你的代码看起来与 Xcode 模板非常匹配。

    现在你的存储库中有一个正常工作的 YAML 管道 (azure-pipelines.yml),你可以对其进行自定义!

  3. 准备好更改管道后,请在“管道”页面中选择它,然后选择“编辑”来编辑 azure-pipelines.yml 文件。

请参阅以下部分来了解一些比较常见的管道自定义方法。

提示

若要按照本主题中所述更改 YAML 文件,请在“管道”页中选择管道,然后选择“编辑”打开 azure-pipelines.yml 文件的编辑器。

生成环境

可以使用 Azure Pipelines 通过 Xcode 生成应用,而无需设置自己的任何基础结构。 Azure Pipelines 中 Microsoft 托管的 macOS 代理上已预装了 Xcode。 可以使用 macOS 代理来运行生成。

有关预装的确切 Xcode 版本,请参阅 Microsoft 托管的代理

在存储库的根目录中创建一个名为 azure-pipelines.yml 的文件。 然后,将以下代码片段添加到 azure-pipelines.yml 文件以选择适当的代理池:

# https://learn.microsoft.com/azure/devops/pipelines/ecosystems/xcode
pool:
  vmImage: 'macOS-latest'

使用 Xcode 生成应用

若要使用 Xcode 生成应用,请将以下代码片段添加到 azure-pipelines.yml 文件。 此代码片段非常简短,它使用默认方案为模拟器生成 iOS 项目,但不会打包。 请更改值以便与项目配置匹配。 有关这些选项的详细信息,请参阅 Xcode 任务。

pool:
  vmImage: 'macos-latest'

steps:
- task: Xcode@5
  inputs:
    actions: 'build'
    scheme: ''
    sdk: 'iphoneos'
    configuration: 'Release'
    xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace'
    xcodeVersion: 'default' # Options: 10, 11, 12, 13, 14, default, specifyPath

签名和预配

Xcode 应用必须经过签名和预配才能在设备上运行或发布到 App Store。 签名和预配过程需要访问你的 P12 签名证书以及一个或多个预配配置文件。 在生成期间,安装 Apple 证书安装 Apple 预配配置文件任务将为 Xcode 提供这些证书和配置文件。

请参阅为移动应用签名了解详细信息。

Carthage

如果项目使用具有专用 Carthage 存储库的 Carthage,你可以通过设置一个名为 GITHUB_ACCESS_TOKEN 的、值为有权访问该存储库的令牌的环境变量,来设置身份验证。 Carthage 将自动检测并使用此环境变量。

不要将机密令牌直接添加到管道 YAML。 应该创建新的管道变量,并在“变量”窗格中为其启用锁定以加密此值。 请参阅机密变量

以下示例使用名为 myGitHubAccessToken 的机密变量作为 GITHUB_ACCESS_TOKEN 环境变量的值。

- script: carthage update --platform iOS
  env:
    GITHUB_ACCESS_TOKEN: $(myGitHubAccessToken)

在 Azure 托管的设备上进行测试

添加 App Center 测试任务,以在 iOS 和 Android 设备的托管实验室中测试应用。 需要一个 App Center 免费试用帐户,以后必须将其转换为付费帐户。

首先在 App Center 中注册

# App Center test v1
# Test app packages with Visual Studio App Center.
- task: AppCenterTest@1
  inputs:
    appFile: # string. Alias: app. Required. Binary application file path. 
    artifactsDirectory: '$(Build.ArtifactStagingDirectory)/AppCenterTest' # string. Alias: artifactsDir. Required. Artifacts directory. Default: $(Build.ArtifactStagingDirectory)/AppCenterTest.
  # Prepare Tests
    #prepareTests: true # boolean. Alias: enablePrepare. Prepare tests. Default: true.
    frameworkOption: 'appium' # 'appium' | 'espresso' | 'calabash' | 'uitest' | 'xcuitest'. Alias: framework. Required when enablePrepare = true. Test framework. Default: appium.
    #appiumBuildDirectory: # string. Alias: appiumBuildDir. Required when enablePrepare = true && framework = appium. Build directory. 
    #espressoBuildDirectory: # string. Alias: espressoBuildDir. Optional. Use when enablePrepare = true && framework = espresso. Build directory. 
    #espressoTestApkFile: # string. Alias: espressoTestApkPath. Optional. Use when enablePrepare = true && framework = espresso. Test APK path. 
    #calabashProjectDirectory: # string. Alias: calabashProjectDir. Required when enablePrepare = true && framework = calabash. Project directory. 
    #calabashConfigFile: # string. Optional. Use when enablePrepare = true && framework = calabash. Cucumber config file. 
    #calabashProfile: # string. Optional. Use when enablePrepare = true && framework = calabash. Profile to run. 
    #calabashSkipConfigCheck: false # boolean. Optional. Use when enablePrepare = true && framework = calabash. Skip Configuration Check. Default: false.
    #uiTestBuildDirectory: # string. Alias: uitestBuildDir. Required when enablePrepare = true && framework = uitest. Build directory. 
    #uitestStorePath: # string. Optional. Use when enablePrepare = true && framework = uitest. Store file. 
    #uiTestStorePassword: # string. Alias: uitestStorePass. Optional. Use when enablePrepare = true && framework = uitest. Store password. 
    #uitestKeyAlias: # string. Optional. Use when enablePrepare = true && framework = uitest. Key alias. 
    #uiTestKeyPassword: # string. Alias: uitestKeyPass. Optional. Use when enablePrepare = true && framework = uitest. Key password. 
    #uiTestToolsDirectory: # string. Alias: uitestToolsDir. Optional. Use when enablePrepare = true && framework = uitest. Test tools directory. 
    #signInfo: # string. Optional. Use when framework = calabash || framework = uitest. Signing information. 
    #xcUITestBuildDirectory: # string. Alias: xcuitestBuildDir. Optional. Use when enablePrepare = true && framework = xcuitest. Build directory. 
    #xcUITestIpaFile: # string. Alias: xcuitestTestIpaPath. Optional. Use when enablePrepare = true && framework = xcuitest. Test IPA path. 
    #prepareOptions: # string. Alias: prepareOpts. Optional. Use when enablePrepare = true. Additional options. 
  # Run Tests
    #runTests: true # boolean. Alias: enableRun. Run tests. Default: true.
    credentialsOption: 'serviceEndpoint' # 'serviceEndpoint' | 'inputs'. Alias: credsType. Required when enableRun = true. Authentication method. Default: serviceEndpoint.
    #serverEndpoint: # string. Required when enableRun = true && credsType = serviceEndpoint. App Center service connection. 
    #username: # string. Required when enableRun = true && credsType = inputs. App Center username. 
    #password: # string. Required when enableRun = true && credsType = inputs. App Center password. 
    appSlug: # string. Required when enableRun = true. App slug. 
    devices: # string. Required when enableRun = true. Devices. 
    #series: 'master' # string. Optional. Use when enableRun = true. Test series. Default: master.
    #dsymDirectory: # string. Alias: dsymDir. Optional. Use when enableRun = true. dSYM directory. 
    localeOption: 'en_US' # 'da_DK' | 'nl_NL' | 'en_GB' | 'en_US' | 'fr_FR' | 'de_DE' | 'ja_JP' | 'ru_RU' | 'es_MX' | 'es_ES' | 'user'. Alias: locale. Required when enableRun = true. System language. Default: en_US.
    #userDefinedLocale: # string. Optional. Use when enableRun = true && locale = user. Other locale. 
    #loginOptions: # string. Alias: loginOpts. Optional. Use when enableRun = true && credsType = inputs. Additional options for login. 
    #runOptions: # string. Alias: runOpts. Optional. Use when enableRun = true. Additional options for run. 
    #skipWaitingForResults: false # boolean. Alias: async. Optional. Use when enableRun = true. Do not wait for test result. Default: false.
  # Advanced
    #cliFile: # string. Alias: cliLocationOverride. App Center CLI location. 
    #showDebugOutput: false # boolean. Alias: debug. Enable debug output. Default: false.

将工件与生成记录一起保留

添加复制文件发布生成工件任务以将 IPA 与生成记录或测试一起存储,并将其部署到后续管道中。 请参阅工件

- task: CopyFiles@2
  inputs:
    contents: '**/*.ipa'
    targetFolder: '$(build.artifactStagingDirectory)'
- task: PublishBuildArtifacts@1
  inputs:
    PathtoPublish: '$(Build.ArtifactStagingDirectory)'
    ArtifactName: 'drop'
    publishLocation: 'Container'

部署

应用中心

添加 App Center 分发任务,以将应用分发给一组测试人员或 beta 版用户,或将应用升级到 Intune 或 Apple App Store。 需要一个 App Center 免费帐户(无需付款)。

# App Center distribute v3
# Distribute app builds to testers and users via Visual Studio App Center.
- task: AppCenterDistribute@3
  inputs:
    serverEndpoint: # string. Required. App Center service connection. 
    appSlug: # string. Required. App slug. 
    appFile: # string. Alias: app. Required. Binary file path. 
    #buildVersion: # string. Build version. 
    releaseNotesOption: 'input' # 'input' | 'file'. Alias: releaseNotesSelection. Required. Create release notes. Default: input.
    releaseNotesInput: # string. Required when releaseNotesSelection = input. Release notes. 
    #releaseNotesFile: # string. Required when releaseNotesSelection = file. Release notes file. 
    #isMandatory: false # boolean. Require users to update to this release. Default: false.
    destinationType: 'groups' # 'groups' | 'store'. Required. Release destination. Default: groups.
    #distributionGroupId: # string. Alias: destinationGroupIds. Optional. Use when destinationType = groups. Destination IDs. 
    #destinationStoreId: # string. Required when destinationType = store. Destination ID. 
    #isSilent: # boolean. Optional. Use when destinationType = groups. Do not notify testers. Release will still be available to install. 
  # Symbols
    #symbolsOption: 'Apple' # 'Apple' | 'Android' | 'UWP'. Alias: symbolsType. Symbols type. Default: Apple.
    #symbolsPath: # string. Optional. Use when symbolsType == AndroidNative || symbolsType = Windows. Symbols path. 
    #appxsymPath: # string. Optional. Use when symbolsType = UWP. Symbols path (*.appxsym). 
    #symbolsDsymFiles: # string. Alias: dsymPath. Optional. Use when symbolsType = Apple. dSYM path. 
    #symbolsMappingTxtFile: # string. Alias: mappingTxtPath. Optional. Use when symbolsType = Android. Mapping file. 
    #nativeLibrariesPath: # string. Optional. Use when symbolsType == Android. Native Library File Path. 
    #symbolsIncludeParentDirectory: # boolean. Alias: packParentFolder. Optional. Use when symbolsType = Apple. Include all items in parent folder.

Apple App Store

安装 Apple App Store 扩展并使用以下任务来自动与 App Store 交互。 默认情况下,这些任务会使用你配置的服务连接向 Apple 进行身份验证。

发布

添加 App Store 发布任务,以自动向 App Store 中的现有 iOS TestFlight beta 版应用或生产应用发布更新。

请查看将此任务与 Apple 双因素身份验证配合使用时的限制,因为 Apple 身份验证特定于区域,而且快速通道会话令牌很快就会过期,过期后必须重新创建并重新配置。

- 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

升级

添加 App Store 升级任务,以自动将以前提交的应用从 iTunes Connect 升级到 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