2

Using Azure pipelines, I am trying to build/deploy a Xamarin iOS app that depends on a push notification iOS service extension developed by Airship.

To build an iOS app and a related iOS service extension requires multiple provisioning profiles, one for the app and another for the service extension.

The Azure pipeline build fails, complaining that the service extension provisioning profile does not match the apps provisioning profile.

How do I get an Azure pipeline build to succeed when multiple provisioning profiles are required?

In case it matters, the app is developed using Visual Studio for Mac. I am able to build and run it on a physical test device.

Update #1:

This is the error message we get in the Azure pipeline console. This message is output when trying to build the service extension.

Info.plist : error : Project bundle identifier 'com.orgname.ServiceExtension' does not match specified provisioning profile 'xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx'

(The xxxxx's represent our apps provisioning profile uuid)

Reviewing the Azure code, it looks like there is no way to tell the build step to use multiple provisioning profiles. If I am understanding the code correctly, it looks like the Xamarin iOS Azure pipeline task can only handle a single provProfileUuid value.

Update #2 - The .yml files:

azure-pipelines-prod.yml

variables:
  productName: 'OurAppName'
  projectBuildNumber: $[counter('', 800)]
  versionName: $[format('{0:yyyy}.{0:MM}.{0:dd}', pipeline.startTime)]

name: $(versionName) ($(projectBuildNumber))

jobs:
- template: pipelines/build-ios.yml
  parameters:
    productionBuild: true
    provisioningProfile: 'match_AppStore_com_orgname_appname.mobileprovision'
    serviceExtensionProvisioningProfile: 'orgname_appname_service_ext.mobileprovision'

azure-pipeline-build-ios.yml

parameters:
  - name: productionBuild
    type: boolean
    default: false
  - name: provisioningProfile
    displayName: 'Provisioning Profile'
    type: string
  - name: serviceExtensionProvisioningProfile
    displayName: 'Provisioning Profile for App Extension'
    type: string

jobs:
- job: iOS
  pool:
    vmImage: 'macOS-latest'

  variables:
    iosRoot: '$(system.defaultworkingdirectory)/$(productName).iOS'
    iosProjectPath: '$(iosRoot)/*iOS.csproj'
    NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages
    buildConfiguration: 'Release'
    outputDirectory: '$(build.binariesDirectory)/$(buildConfiguration)'
    infoPlist: '$(iosRoot)/Info.plist'
    # if not a production build, add the QA build symbol for compiler switches
    ${{ if eq(parameters.productionBuild, false) }}:
      buildArgs: '/p:DefineConstants="QA"'
    ${{ if eq(parameters.productionBuild, true) }}:
      buildArgs: ''

  steps:
    # restore and run unit tests
  - template: unit-tests.yml

  # Set build number and version Name
  - task: ios-bundle-version@1
    displayName: 'Set build number and version Name'
    inputs:
      sourcePath: '$(infoPlist)'
      versionCodeOption: 'buildid'
      versionCode: '$(projectBuildNumber)'
      versionName: '$(versionName)'
      printFile: true

  # Install signing certificate
  - task: InstallAppleCertificate@2
    displayName: 'Install signing certificate'
    inputs:
      certSecureFile: 'AppleSigningCertificate.p12'
      certPwd: '$(ios-cert-key)'

  # Install Provisioning Profile
  - task: InstallAppleProvisioningProfile@1
    displayName: 'Install Provisioning Profile'
    inputs:
      provProfileSecureFile: ${{ parameters.provisioningProfile }}  

  # Install App Extension Provisioning Profile
  - task: InstallAppleProvisioningProfile@1
   displayName: 'Install Provisioning Profile for App Extension'
   inputs:
     provProfileSecureFile: ${{ parameters.serviceExtensionProvisioningProfile }}

  # Build iOS ipa package
  - task: XamariniOS@2
    displayName: Build iOS ipa package
    inputs:
      solutionFile: '$(iosProjectPath)'
      configuration: '$(buildConfiguration)'
      buildForSimulator: false
      packageApp: true
      signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)'
      signingProvisioningProfileID: '$(APPLE_PROV_PROFILE_UUID)'
      args: /p:IpaPackageDir="$(Build.ArtifactStagingDirectory)" /p:OutputPath="$(outputDirectory)/iPhone/" /p:RestorePackages=false $(buildArgs)"

  # Archive dSYM
  - task: ArchiveFiles@2
    displayName: 'Archive dSYM'
    inputs:
      rootFolderOrFile: '$(outputDirectory)/iPhone/$(productName).iOS.app.dSYM'
      includeRootFolder: false
      archiveType: 'zip'
      archiveFile: '$(Build.ArtifactStagingDirectory)/$(productName).iOS.app.dSYM.zip'
      replaceExistingArchive: true

  # on non-prod builds, make a simulator build
  - ${{ if eq(parameters.productionBuild, false) }}:
    # Create simulator build
    - task: XamariniOS@2
      displayName: 'Create simulator build'
      inputs:
        solutionFile: '$(iosProjectPath)'
        configuration: '$(buildConfiguration)'
        buildForSimulator: true
        packageApp: false
        args: /p:OutputPath="$(outputDirectory)/iPhoneSimulator/" /p:RestorePackages=false $(buildArgs)

    # Archive Simulator Build
    - task: ArchiveFiles@2
      displayName: 'Archive Simulator Build'
      inputs:
        rootFolderOrFile: '$(outputDirectory)/iPhoneSimulator/$(productName).iOS.app'
        includeRootFolder: false
        archiveType: 'zip'
        archiveFile: '$(Build.ArtifactStagingDirectory)/$(productName).iOS.app.zip'
        replaceExistingArchive: true

    # Archive Simulator dSYM
    - task: ArchiveFiles@2
      displayName: 'Archive Simulator dSYM'
      inputs:
        rootFolderOrFile: '$(outputDirectory)/iPhoneSimulator/$(productName).iOS.app.dSYM'
        includeRootFolder: false
        archiveType: 'zip'
        archiveFile: '$(Build.ArtifactStagingDirectory)/$(productName).iOS.app.Simulator.dSYM.zip'
        replaceExistingArchive: true

  # publish artifacts to pipeline
  - task: PublishBuildArtifacts@1
    displayName: 'publish artifacts to pipeline'
    inputs:
      PathtoPublish: '$(Build.ArtifactStagingDirectory)'
      ArtifactName: 'drop'
      publishLocation: 'Container'
Chris Simeone
  • 755
  • 1
  • 10
  • 26
  • 1
    If you're getting an error message, post the **entire** error message, and post the code (or in this case, YAML) that was responsible for the error message. – Daniel Mann Aug 11 '21 at 20:46
  • Thanks @DanielMann. I updated my post with the exact error message. I have to locate the YAML file and see what I can post here safely and not reveal any private data or info. I'll work on that tomorrow AM. – Chris Simeone Aug 11 '21 at 21:41
  • @DanielMann, I just added the `.yml` files as an update to my original post. Thanks! – Chris Simeone Aug 12 '21 at 16:42

0 Answers0