Porting Xamarin.Forms Barcode QR Code Scanner to .NET MAUI
Previously, we created a Xamarin.Forms Barcode QR code scanner for Android and iOS. Xamarin.Forms is not the end for developing cross-platform mobile apps in C#, because .NET MAUI is on the way. Microsoft mentions that .NET MAUI is the evolution of Xamarin.Forms, and it supports both mobile and desktop development. Since .NET MAUI is coming soon, this article will show you how to implement .NET MAUI barcode QR code scanner by porting Xamarin.Forms project.
This article is Part 3 in a 3-Part Series.
Porting Steps for .NET MAUI Barcode QR Code Scanner
Although you can refer to Migrating from Xamarin.Forms (Preview), to avoid encountering lots of build errors, it is better to create a new .NET MAUI project and migrate project configuration and code step by step.
*.csproj File Updates
To create a .NET MAUI project, you need to install Visual Studio 2022 Preview beforehand.
A new .NET MAUI project scaffold contains templates for Windows, macOS, Tizen, Android and iOS. We only keep Android and iOS frameworks in csproj file.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0-android;net6.0-ios</TargetFrameworks>
<OutputType>Exe</OutputType>
<RootNamespace>BarcodeQrScanner</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
</Project>
NuGet Package Installation
-
SkiaSharp
SkiaSharp is used to draw pictures and overlay. We install
SkiaSharp.Views.Maui.Controls
instead ofSkiaSharp.Views.Forms
via NuGet Package Manager. -
Barcode.NET.Mobile is a binding library for Dynamsoft Barcode Reader Mobile SDK. It is a substitution for Dynamsoft Xamarin Barcode Reader SDK, because Xamarin NuGet packages are not compatible with .NET MAUI projects. You will suffer from build errors if you use Xamarin Barcode Reader SDK for iOS.
Code Updates
Migrating code from Xamarin.Forms to .NET MAUI is not as easy as expected. Let’s go through the changes.
Invoke platform code
To invoke specific platform APIs, we use interface in Xamarin.Forms.
public interface IBarcodeQRCodeService
{
Task<int> InitSDK(string license);
Task<BarcodeQrData[]> DecodeFile(string filePath);
}
Whereas in .NET MAUI, we use partial classes and partial methods.
public partial class BarcodeQRCodeService
{
public partial void InitSDK(string license);
public partial BarcodeQrData[] DecodeFile(string filePath);
}
The corresponding implementation is as follows:
Xamarin.Forms
public class BarcodeQRCodeService: IBarcodeQRCodeService
{
Task<int> IBarcodeQRCodeService.InitSDK(string license)
{
...
TaskCompletionSource<int> taskCompletionSource = new TaskCompletionSource<int>();
taskCompletionSource.SetResult(0);
return taskCompletionSource.Task;
}
Task<BarcodeQrData[]> IBarcodeQRCodeService.DecodeFile(string filePath)
{
...
TaskCompletionSource<BarcodeQrData[]> taskCompletionSource = new TaskCompletionSource<BarcodeQrData[]>();
taskCompletionSource.SetResult(output);
return taskCompletionSource.Task;
}
}
.NET MAUI
public partial class BarcodeQRCodeService
{
public partial void InitSDK(string license)
{
...
}
public partial BarcodeQrData[] DecodeFile(string filePath)
{
BarcodeQrData[] output = null;
...
return output;
}
}
Change namespaces for content pages
The content page template is different between Xamarin.Forms and .NET MAUI.
The xmlns
is changed to http://schemas.microsoft.com/dotnet/2021/maui
and the xmlns:skia
is changed to clr-namespace:SkiaSharp.Views.Maui.Controls;assembly=SkiaSharp.Views.Maui.Controls
.
Xamarin.Forms
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
.NET MAUI
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:skia="clr-namespace:SkiaSharp.Views.Maui.Controls;assembly=SkiaSharp.Views.Maui.Controls"
Change namespaces for custom renderers
We also need to change the namespaces for custom renderers.
Android
- using Xamarin.Forms;
- using Xamarin.Forms.Platform.Android.FastRenderers;
+ using Microsoft.Maui.Controls.Compatibility;
+ using Microsoft.Maui.Controls.Compatibility.Platform.Android.FastRenderers;
iOS
- using Xamarin.Forms;
- using Xamarin.Forms.Platform.iOS;
+ using Microsoft.Maui.Controls.Compatibility;
+ using Microsoft.Maui.Controls.Handlers.Compatibility;
Register handlers
The final step is to configure SkiaSharp and custom renderers in MauiProgram.cs
to make them work.
using Microsoft.Maui.Controls.Compatibility.Hosting;
using SkiaSharp.Views.Maui.Controls.Hosting;
namespace BarcodeQrScanner;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseSkiaSharp()
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
}).UseMauiCompatibility()
.ConfigureMauiHandlers((handlers) => {
#if ANDROID
handlers.AddCompatibilityRenderer(typeof(CameraPreview), typeof(BarcodeQrScanner.Platforms.Android.CameraPreviewRenderer));
#endif
#if IOS
handlers.AddHandler(typeof(CameraPreview), typeof(BarcodeQrScanner.Platforms.iOS.CameraPreviewRenderer));
#endif
});
return builder.Build();
}
}
.NET MAUI Issues
AVCaptureDevice.DevicesWithMediaType returns null
If you try to use AVCaptureDevice.DevicesWithMediaType
to get the iOS camera devices, you will find it returns null in .NET MAUI. You can use AVCaptureDevice.Devices
to return all the devices and then filter the ones you want.
- var videoDevices = AVCaptureDevice.DevicesWithMediaType(AVMediaTypes.Video.ToString());
+ AVCaptureDevice[] videoDevices = AVCaptureDevice.Devices;
Label text cannot display full string
This issue is weird. The default text length seems to affect the label text display. A temporary workaround is to set the default text with many spaces.
<Label FontSize="18"
FontAttributes="Bold"
x:Name="ResultLabel"
Text=" "
TextColor="Red"
HorizontalOptions="Center"
VerticalOptions="Center"/>
Source Code
https://github.com/yushulx/dotnet-barcode-qr-code-sdk/tree/main/example/maui