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

Gerald Versluis recently published these great videos on how to sign and publish your .NET MAUI Android app and .NET MAUI iOS app. In this blog post, I’ll be standing on his shoulders and show you how you can set up continuous integration (CI) in Azure DevOps for your .NET MAUI Android app using some of the steps provided in the video. This means that your .NET MAUI project will be built in Azure DevOps each time you push your code.

Create your pipeline

Start off by creating a new pipeline from Azure DevOps. Select the “Starter pipeline” and name your YAML file something like android-maui-build.yml. We’ll modify this with the steps needed to create the AAB file (successor of APK) for your Android app.

Select your VM image

In your new YAML file, we need to modify which VM image we’ll be using. Since we want one that contains .NET 6, we’ll use windows-2022:

  vmImage: windows-2022

As of writing, the windows-latest image has not yet been updated to use Visual Studio 2022 along with .NET 6, so we’ll have to explicitly set it to windows-2022.

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
    script: 'dotnet workload install maui'

Build it!

If you’re planning on shipping your app to Google Play, you need to make sure you’ve signed your app package first. Gerald talks about how to do this in his video, so make sure you add those steps first. Once that’s done, add the .NET Core task to your pipeline and select the build command. “Path to project” should point to your solution file containing the .NET MAUI project. In the “arguments” section we will specify that we will build with the Release configuration and that we should compile for the net6.0-android framework:

- task: DotNetCoreCLI@2
    command: 'build'
    projects: 'MyMAUIProject.sln'
    arguments: '-c Release -f net6.0-android'

And that should result in a signed AAB file!

If you want to use this file for a release pipeline, you need to publish it as a build artifact. To do this, first we need to copy our AAB file to the artifact staging directory. We’ll use the Copy files task for this:

- task: CopyFiles@2
    SourceFolder: '$(agent.builddirectory)'
    Contents: '**/*-Signed.aab'
    TargetFolder: '$(build.artifactstagingdirectory)'
    flattenFolders: true

Finally, we’ll use the Publish build artifacts task to actually publish the file and make it available for a release pipeline:

- task: PublishBuildArtifacts@1
    PathtoPublish: '$(Build.ArtifactStagingDirectory)'
    ArtifactName: 'drop'
    publishLocation: 'Container'

And there you go! You can combine this with a release pipeline for shipping this off to your testers via App Center or directly to the Google Play store if you want.

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

Final thoughts

Being able to use dotnet commands for .NET MAUI makes it very easy to set up your pipeline, especially compared to Xamarin. This also means that there’s much more transferrable knowledge if you’ve worked with pipelines for other apps that use .NET Core or above. I hope you found this useful and let me know if there are other aspects of this you would like to see!

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

  1. Great content!
    I have experience supporting my development team about setting up Build and Release for Android and iOS mobile application with Azure DevOps. I’m personally interested in .net maui but I still have scars about:
    * Building iOS (react native) on MacOS build agents because of “xcode”
    * Signing with the PlayStore provided certificates. App Bundles, etc…
    * Mobileprovision files for iOS…

    How those concepts apply in the .net Maui world? Can we really build for all the target platforms from Windows build agents?

    A small remark. The “PublishBuildArtfact” task is basically deprecated. You should be using the “PublishPipelineArtifact” task and then consume it from another YAML pipeline for the release process (or even the same pipeline if you prefer using multi-stage pipelines) .

    1. Thanks, Andrea!
      With .NET MAUI you will still need a Mac build agent for publishing your iOS apps. Since MAUI still boils it all down to apk/aab and ipa files, you will still have to handle keystores, certificates and provisioning profiles. I have some other guides as well that shows how you can do this for both iOS and Android using both Azure DevOps and GitHub Actions if you want to check out the different ways this can be done.
      Ah, didn’t know that about the “PublishBuildArtifact” task. I’ll keep that in mind, thanks!

  2. Thanks for this great post.

    The dotnet build step failed with error: C:\Program Files\dotnet\sdk\6.0.401\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(267,5): Error NETSDK1005: Assets file ‘D:\a\1\s\SecondMobileApp\SecondMobileApp.Standard.Data\obj\project.assets.json’ doesn’t have a target for ‘net6.0-android’. Ensure that restore has run and that you have included ‘net6.0-android’ in the TargetFrameworks for your project.

    The logs generated when the previous build step (Install MAUI workload) was successfull, but it generated errors indicated there is an issue with restoring nuget packages from my private repository. But the NuGet restore build step (including the restore of the packages of my private store) was successfully.

    I can’t fine out what went wrong.

    1. Could you try adding the “–no-restore” flag in your build step? I had the same issue on another project, where I had to explicitly restore packages from a private NuGet feed first and then adding the “–no-restore” flag on our build step, since “dotnet build” will implicitly try to restore all packages.

      1. Sorry for my late answer. I tried your suggestion adding the –no-restore flag at the dotnet build command. But unfortunately without succes. I’ll still receive this error. The error occur when the solution contain a class library. In this class library I only target net6.0.

        1. I had this exact same issue. Turned out by build task was building all solutions with the -c $(BuildConfiguration) -f net7.0-android or whichever platform it was for.

          I changed the build task to just build the app solution and the issue is fixed.

  3. Do you know if fastlane spaceship works with .NET Maui Blazor? I need to confirm my apple-id while running the release pipeline

    1. From what I googled about fastlane spaceship I think it should work. If your pipeline wants you to confirm your Apple ID with 2FA, see if you can register a personal app token or something that you can confirm with. Not sure how that works together with fastlane spaceship though.

    1. They may have updated their images since the time of writing to include this. If that’s the case then you don’t have to include the task to install the maui workload.

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.