.NET MAUI iOS – Azure Pipelines error: ‘x’ is not available in iOS 16

The Error: The error message suggests that the ‘UIKit.UISceneSessionActivationRequest’ type, used as a parameter in ‘UIKit.UIApplication.ActivateSceneSession,’ is not available in iOS 16.2 and was introduced in iOS 17.0. This discrepancy indicates a version misalignment in the development environment, specifically with the iOS SDK and Xcode.

Root cause

The root cause of this error lies in the version of the macOS image used in the Azure Pipelines configuration. By default, the ‘macOS-latest’ image is pulled, which corresponds to macOS 12 (at the time of the blog post). However, the .NET MAUI app with Azure Pipelines requires macOS v13 to work seamlessly, as it aligns with the necessary dependencies for iOS development.

Resolution

To resolve this error, developers need to update the macOS image specified in the Azure Pipelines configuration. Instead of using ‘macOS-latest,’ the configuration should be modified to use ‘macOS-13.’ This ensures that the appropriate version of macOS is utilized during the build process, addressing the compatibility issues with iOS 16.2 and the required UIKit types.

Step-by-Step

-Open your Azure Pipelines configuration file (typically named azure-pipelines.yml).
-Locate the section where the macOS image is specified. It might look something like this:

pool:
  vmImage: 'macOS-latest'

-Update the image reference to ‘macOS-13’:

pool:
  vmImage: 'macOS-13'

-Save the changes to the configuration file.
-Commit the updated configuration file to your version control system (e.g., Git).
-Trigger a new build in Azure Pipelines, and the updated macOS image will be used.

Azure DevOps: Setup private NuGet feed with CI

In case you need a private NuGet feed, you can do it in Azure DevOps. This can be handy for businesses reusing their code between several codebases.

What will contain the example

In this tutorial, I will show you how to share code through NuGet packages so that it can be used in multiple projects. The Example will walk you through the game engine of an IDLE game. IDLE games are games that do not require much user interaction. The point of games is that they run or produce even when the user is not playing them. The goods produced offline can eventually be used by the player, to upgrade producers or to buy more producers.

The game engine is developed on the IDLEGAMEENGINE branch. Different games, such as a restaurant game or a programming game, can use this game engine. The games have a common logic of operation, only the story of the games differs. This design helps in development to fix bugs by only having to fix the bug in one place and it will be fixed in all games.

Step 0: Create your shared code

I will not go into details about the implementation of the game engine in this tutorial. The point is to create source code that you want to share with other source code.

Step 1: Create the NuGet feed

Go to your projects Azure DevOps site, and select Artifacts from the list on the left. Push the Create feed button. You can select from several visibility options for the new feed.

Step 2. Automate NuGet package publish to the feed

You probably have a repository with the code, what you want to share. Go To Pipelines on the left, then create a pipeline to get NuGet packages published automatically. (If you are experienced, you can make Release pipelines) In the following sections, i will guide you through how to make a CI pipeline, to pack and publish the NuGet packages automatically every time the main branch gets updated.

Navigate to Pipelines section

Go to pipelines and Select create pipeline button.

Select where do you store the code what you want to publish to your private NuGet feed. In my case, I store the GameEngine code in Azure DevOps, so I will continue with this.

Select the Repository which contains the code to be shared.

Select the desired build template for the project. I’ve implemented the core code in .NET Core, so i will continue with ASP.NET Core.

By default this template creates you a NuGetToolInstaller task, a Nugetcommand Task, and a VS Build task.

We will add a 4th task which can be added by searching for NuGet task.

Set up the tasks parameters as the following: Command should be push. The path to the NuGet packages to publish should be the path where the VSBuild builds the application.

Select the target feed location properly. My target feed is at the same organization, so it will appear in the dropdown list. For External NuGet server, you will need to specify a connector to that resource.

Ensure that, the NuGet package will only build, when the csproj is configured to build as a NuGet package. You will need the following settings for your project in order to make a NuGet from it.

Save the pipeline and run it. If you have configured everything correctly, you will see a lot of green ticks in the progress window

This seems to be well configured

When you navigate to the Artifacts/Packages section, you will see that the NuGet package has been pushed successfully to the private feed.

The recently pushed NuGet will appear here

Step 3.: Use your private repository on your projects

In order to use the recently updated package, you will need to set up your local Visual Studio instance to be able to use your private feed.

Adding a new package source

Go to your VS settings, select the NuGet section, and click on the Sources subsection. Click On add and define the connection details presented by clicking the “Connect to feed” button in the Azure DevOps / artifacts section.

Once you have configured the Visual Studio well, you will see the NuGet Package available when you are trying to add a new package to your proejct.

This content has 2 years. Some of the information in this post may be out of date or no longer work. Please, read this page keeping its age in your mind.

Complete CI/CD tutorial for Xamarin Android with Google Play publish in Azure DevOps | Part 2.

If you haven’t seen part 1, click here, and start build up your CI/CD pipeline now.

Part 2 Contains:

  • Configuring build with creating signed APK, and making artifacts from it
  • Setting up branch policy to master

Configure some magic

Let’s go back to Pipelines. Edit your previously created pipeline by clicking the three dot on the pipelines row.

Edit the previously created pipeline

CI is based on cloud machines hosted somewhere over the world. This computers called as agents. They are used to follow your instructions, defined in the yml file. The base Xamarin.Android yml is only to build your code. But we will make some additional steps in order to create a signed APK of every build. Follow up, to complete this setup.

Recommended branching strategy for this is to keep a development branch, and pull request your feature branches to it, and finally pull request the development branch to the master, and keep your master is always at your production version. The figure below shows visually this method. Source: https://dzone.com/articles/feature-branching-using-feature-flags-1

Create a signed APK or bundle from every build

First, set up some variables for this pipeline. You will find a Variables button on the right top of the tab. Click on it.

Add variables with new variable button

Let’s add a new variable by clicking the “New variable” button. We will need 4 vars.

Adding a new variable.

Remember, that i told you, you will need to remember the alias, password, and the keystore name? You can forget them, after you have declared the variables for them.

Variables needed:
keystore_filename - AnAwesomeAppDelivery.keystore
keystore_alias - AnAwesomeAppDelivery
keystore_password - The password of the keystore.

When you create var for keystore_password, tick the “Keep this value secret” checkbox.

Go to the end of the boilerplate YAML file, and on the right top of the text editor, you can see a task wizard button. Click on that.

Search for “Download secure file” task on the search bar. Click on it, and set the “Secure file” to the value below, and click on “Add”.

$(keystore_filename)

This will get the variable value defined above. Press some enters to seperate our next task from the download secure file task, and jump into signing the APK.

Search for “Android signing” in tasks.

Android signing task

And set up the task like on the picture below. Please regret me for messing up the “Key password” value in the screenshot, the $(keystore_password) variable goes in that field too.

Setting up Android signing task

If everything set up correctly, it will make our APK in the output directory signed. But how we will access it? We need to drop our result to the pipeline artifacts. You can set the build output to the artifact staging directory, but i recommend to only copy the file, that you will need as a result. So make a copy task after Adding the Sign task, and some enters to the end of the YAML file. Follow the configurations in the picture.

We will copy every file with APK extension, from the output directory to the ArtifactStagingDirectory.

Okay, we have copied the files, but the files wont appear in Azure DevOps, until we drop our packages to the Artifacts section of our build. Search for “Publish build artifacts”, select the task, and configure as the image below.

Finally creating the result to be ready to download

So how our YAML Looks like now? Like this below? Then go and save it. If not, correct your mistakes.

How your YAML file supposed to look like

After saving the YAML, it recommends to Run it, so jump right into the fun, click on the “Run” button.

The build is running, and creating us the binaries.

If everything is correct, it will show only green ticks. When you click on “Pipelines/pipelines” in the left menu of the DevOps page, you will see your state of your build. On the detailed view, you can access the created artifacts in order to download them.

Of course, a success build for the first try.. 😀

Click on the row, and you can access the details of the build. If you have set up the pipeline correctly, it will show “1 published” label. Click on it, and you can access your signed application binary.

1 published
The signed APK

Merge the pipeline config branch to master

Create a pull request to master.

Set up main branch policies to run CI automatically

Go to Repos/Branches, and select the main branch, click on the three dot in the end of the row, and select “Branch policies”.

Add a build policy to the branch.

In the Build validation option, you can configure the previously created pipeline to run automatically whenever a new pull request gets accepted.

This content has 3 years. Some of the information in this post may be out of date or no longer work. Please, read this page keeping its age in your mind.

Complete CI/CD tutorial for Xamarin Android with Google Play publish in Azure DevOps | Part 1.

This tutorial will drive you through setting up a great CI/CD pipeline for Xamarin Android in a fully hosted Azure DevOps enviroment.

Part 1 contains:

  • Creating an empty Xamarin.Android build pipeline
  • Uploading keystore file to secure files

Start with some code

An Initial repository

I have added some basic code to my demo repository. It is a boilerplate Xamarin Application, with no additional customized code. If you have code in your repo, make sure it builds successfully.

Create your first pipeline

On the left side menu, go to Pipelines/Pipelines. This menu will show up a welcome page, to create new pipeline.

Let’s do it!

Click on ‘Create Pipeline’ button, or if you have already created your first pipeline, find a button to add a new one.

On the next page, a wizard will guide you through the basic setup.

Point for your repository

If you have your code in Azure Repos, click the button for that.

Select your repo

Select your repository where your Xamarin Android code lives.

Select Xamarin.Android Template

On the next page, you can select a template to create your pipeline yml. Let’s choose Xamarin.Android.

Rename your yml file if you want

If you want, you can rename your yml file. Pipeline files will be placed in your repository root by default. YML file extension stands for YAML files. Review your newly created file, how it looks like. Luckily, you do not have to write yaml too much, but good to know, how it markups the build process.

Lets save the YAML

Okay it is enough for now, we have some things to do outside of the pipeline editor. Go save your configuration.

Create a new branch for that

Create a new branch for the pipeline setup with name like pipeline_configuration. You can directly push the config to the main branch, but in this step of the tutorial, i recommend to create a branch for that. Later on, we will set branch policies 😉

Store your app signing key securely

Your app signing key is a very important file to keep your binaries trusted for your users. You can provide with signing, that the binary has been built by you, and not by a bad guy. Keeping this file secure is a must have thing.

Azure DevOps pipelines have a library function, where you can store your custom agent connection settings, and files needed to build or sign your applications securely.

Jump to library

Let’s jump into library menu. Select secure files option, and upload your keystore file.

Creating a keystore in Visual Studio for Mac

If you do not have a keystore, you can create a new one when you are trying to publish a Xamarin.Android application as AdHoc. Keep your Alias, Password in mind, you will need this in the future.

Location of release keystores on Mac

The location of the release keystores on Mac is:

~/Library/Developer/Xamarin/Keystore/

Once, you have uploaded your keystore to the secure file storage, you need to set the permissions, to pipelines in order to access your secure files. Note your secure file filename, you will need this too in the future. Click the three dots on the uploaded file, and select edit.

Set permissions for pipelines

Check the pipeline permissions checkbox, and save your file.

In the next session

We will continue set up CI to our Android project.

Go to Part 2 to continue configuring your repository

This content has 3 years. Some of the information in this post may be out of date or no longer work. Please, read this page keeping its age in your mind.