C#
.NET
MAUI
Azure
Android
4 minute read | April 10, 2024

Building a MAUI Android app with Azure DevOps Pipelines

Learn how to build and sign your MAUI Android app with Azure DevOps Pipelines and ouput both apk and aab files.

Setup

First off create yourself a new blank .yaml file if you don't already have one.

Triggers

You can trigger your pipeline based on changes to a branch if you like. For this example we'll trigger it manually.

Yaml
trigger: none

Build stage

Now lets add our build stage and configure it to use the lastest macOS image (at the time of writing macOS-13). You can also use 'macOS-latest' but confusingly it might not be the latest version.

Yaml
trigger: none stages: - stage: Build displayName: Build stage jobs: - job: Build displayName: Build pool: vmImage: 'macOS-13'

Configure MAUI

We need to install the MAUI workload first before we build so lets add a task for it.

Yaml
trigger: none stages: - stage: Build displayName: Build stage jobs: - job: Build displayName: Build pool: vmImage: 'macOS-13' steps: - task: CmdLine@2 displayName: 'Install Latest .NET MAUI Workload' inputs: script: 'dotnet workload install maui'

Load our keystore

You'll need to upload your keystore to Pipelines > Library > Secure files on DevOps. Once you've done that add a task to download it. I've added a variable for the filename but you could just hardcode if you like.

Yaml
- task: DownloadSecureFile@1 name: keystore inputs: secureFile: '$(keystoreFilename)'

Build the project

The next step is to build and sign your project. We'll use the dotnet publish command to achieve that. You'll need to include your keystore password twice and also the alias. As with the previous example I've added them both to variables. I've also set working directory as I'm using a multi-project solution, if you are using single project them you shouldn't need to.

Yaml
- task: CmdLine@2 displayName: 'Build project' inputs: script: 'dotnet publish -f net8.0-android -c Release -p:AndroidKeyStore=true -p:AndroidSigningKeyStore=$(keystore.secureFilePath) -p:AndroidSigningKeyPass=$(keystorePassword) -p:AndroidSigningStorePass=$(keystorePassword) -p:AndroidSigningKeyAlias=$(keystoreAlias)' workingDirectory: './Source/MyProject.Android/'

Publish build output

Finally the last thing to do is publish the apk and aab files that are output by the build. Note that the source folder will differ depending on your project name but dotnet publish always outputs to 'bin/Release/net8.0-android/publish'

Yaml
- task: CopyFiles@2 displayName: 'Copy build output to staging' inputs: SourceFolder: '$(Agent.BuildDirectory)/s/Source/MyProject.Android/bin/Release/net8.0-android/publish' Contents: | **/*.apk **/*.aab TargetFolder: '$(ArtifactStagingDirectory)' flattenFolders: true - publish: $(ArtifactStagingDirectory) artifact: drop