Setting up CI for your .NET MAUI iOS app in Azure DevOps

Last week I blogged about how to set up CI for your .NET MAUI Android app in Azure DevOps. Following up on this, I’ll show you how to do the same for your .NET MAUI iOS app. Again I will be leaning heavily on Gerald Versluis’s videos on publishing your .NET MAUI apps, specifically for iOS.

In his video, Gerald shows the required prerequisites like creating a signing certificate, app identifier and provisioning profile. This guide will assume that you have done all of this already and that you have your signing certificate (.p12) and provisioning profile downloaded or backed up somewhere. Gerald also shows what you need to add to your csproj file for this to work. When all this is done, we can get started in Azure DevOps.

Create your pipeline

Start off by creating a new pipeline. Select the “Starter pipeline” and name your YAML file something like ios-maui-build.yml. We’ll modify this with the steps needed to create the IPA file for your iOS app.

Select your VM image

In your new YAML file, we need to modify this to use an image running MacOS. We’ll be using the macos-latest image:

pool:
  vmImage: macos-latest

As of writing, this image doesn’t contain the .NET 6 bits yet, but we’ll fix that in the next step.

Use .NET 6

To be able to retrieve the MAUI workload, we need to first retrieve the .NET 6 SDK. We’ll do this by using the Use .NET Core task:

- task: UseDotNet@2
  inputs:
    packageType: 'sdk'
    version: '6.x'

You can specify a specific version if you want, but we only care about the major version (6) at this point.

Install the MAUI workload

Next, we’ll install the .NET MAUI workload onto the build agent. We need this to be able to build .NET MAUI apps. This can be done using the Command Line task and the dotnet workload command:

- task: CmdLine@2
  inputs:
    script: 'dotnet workload install maui'

Install certificate

Now we need to install the signing certificate onto the build agent. First you’ll have to upload your certificate to Secure Files in your project in Azure DevOps. See here for how to add a secure file. Don’t worry about the step “Consume a secure file in a pipeline”, as we will get to this now.

Add the Install Apple certificate task to your pipeline. Set the certificate name to the one you uploaded to Secure Files and input the certificate password:

- task: InstallAppleCertificate@2
  inputs:
    certSecureFile: 'MyDistributionCertificate.p12'
    certPwd: '$(certificatePassword)'
    keychain: 'temp'

Note: It is recommended to set your password in your variables or in your variable group in Azure DevOps instead of directly in the YAML file. See this article on how to set secret variables.

Install provisioning profile

To install the provisioning profile that we’ve connected to the signing certificate, we need to upload this as well to Secure Files in Azure DevOps. Once this is done, we can add the Install Apple provisioning profile task to our pipeline:

- task: InstallAppleProvisioningProfile@1
  inputs:
    provisioningProfileLocation: 'secureFiles'
    provProfileSecureFile: 'MyProvisioningProfile.mobileprovision'

Build it!

Finally, we have everything we need to actually build the app. We’ll use the dotnet publish command from the .NET Core task and add some arguments. I’ll explain them below:

- task: DotNetCoreCLI@2
  displayName: 'dotnet publish (Release)'
  inputs:
    command: 'publish'
    publishWebProjects: false
    projects: 'MyMAUIProject.sln'
    arguments: '-f:net6.0-ios -c:Release /p:ArchiveOnBuild=true /p:EnableAssemblyILStripping=false'
    zipAfterPublish: false
    modifyOutputPath: false

In the arguments section, we’ve added -f:net6.0-ios to compile for the net6.0-ios framework. -c:Release means that we’re building with the Release configuration and /p:ArchiveOnBuild=true means that we’re creating an IPA file on build. /p:EnableAssemblyILStripping=false seems to currently be necessary because of a bug, but this might not be needed in the future when MAUI is officially released.

And voíla! You should now see a signed IPA file in your publish-folder. Like in my previous guide on doing this for .NET MAUI Android, you can use the Copy files task and the Publish build artifacts task if you want to use this IPA file in a release pipeline.

Here’s how the full YAML file would look like:

Wrapping up

Since MAUI is still in preview, this guide may be subject to change as this might not be the final way to build your .NET MAUI iOS app when MAUI hits GA. I still hope you found this useful!

EDIT: I was made aware of a bug in the dotnet SDK that may cause some issues when trying to follow this guide. See the solution at the end of the discussion.

6 thoughts on “Setting up CI for your .NET MAUI iOS app in Azure DevOps”

  1. There is currently an issue preventing this build pipeline configuration from working. It is described here: https://github.com/dotnet/sdk/issues/21877

    Basically, DevOps tells you that its missing a runtime identifier within the list of commandline arguments. However, when you also pass -r:ios-arm64 (as requested by DevOps), you will get another error message telling you that this RID is invalid.

    Do you have any suggestions on this and could you update your article in case you have a solution?

    1. I had this same issue when I was testing with the Developer PowerShell in Visual Studio Preview (17.2). When I tested with Visual Studio stable (17.1) it worked fine, and it seemed to pick up the runtime identifier specified in the csproj-file. The pipeline I have set this up with also works fine.

      In the link you provided it seems that the current work-around could be to run `dotnet restore` before the publish step, and run the publish step with a `–no-restore` argument.

      1. I’ve updated the post now to include this issue and how to work around it. Thanks for pointing that out!

  2. Hi Andreas,

    First of all, your content is great.

    I’m working on .NET MAUI Mac-Catalyst (my question is also relevant for MAUI for iOS).

    When we install signing certificates and provisioning profiles on our mac agent, don’t we have to refer the UUID and Signing Identity we got from installing the certificate and provisioning profile to our application building task/process (DotNetCoreCLI@2 in this case).

    If so, how are we going to do that because here you are just building the app right after installing certificates and profiles and if I am missing something here, please guide me.

    Thanks a lot.

    1. Hi Muhammad!

      Thanks for the kind words! I mentioned in the beginning of the post the prerequisites for this to work, which includes adding some things to your .csproj. Check out the YouTube-link I provided where Gerald Versluis shows what you need to add to reference the signing certificate and provisioning profile: https://youtu.be/kpZi5xAvpZA?t=994

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.