How to Build a .NET MAUI Barcode and QR Code Reader for Windows and Android
Tags: dotnet, android, windows, qrcode
Published: 2022-05-11 09:06:02

.NET MAUI is a cross-platform framework that allows developers to create desktop and mobile applications from a single codebase with C#. It is currently in preview and the production release is slated for Q2 2022. This article goes through the steps to build a .NET MAUI barcode and QR code reader app for Windows and Android using [Dynamsoft Barcode Reader SDK](https://www.dynamsoft.com/barcode-reader/overview/).

## Dev Environment
- Visual Studio 2022 Preview
    
    You need to upgrade Visual Studio to 2022 Preview in order to get the MAUI template.

## Steps to Build Barcode and QR Code Reader in .NET MAUI

In the following paragraphs, we make a .NET MAUI app from scratch. You will see how to install different dependencies, as well as how to define cross-platform API for Windows and Android.

### Step 1: Create a .NET MAUI Project
In project creation dialog, we enter `maui` in the search box or select `MAUI` from `All project types` to quickly find the `MAUI` templates.

![create maui project](https://www.dynamsoft.com/codepool/img/2022/05/maui-create-project.png)

By default, the template generates a project skeleton for Windows, Android, iOS, macOS and Tizen. We clean up the project by removing relevant code and configurations of iOS, macOS and Tizen.

### Step 2: Install Dependencies Respectively for Windows and Android 
Launch `NuGet Package Manager` to install Barcode and QR Code SDK:
- [BarcodeQRCodeSDK](https://www.nuget.org/packages/BarcodeQRCodeSDK/) for Windows.
- [Xamarin.Dynamsoft.Barcode.Android](https://www.nuget.org/packages/Xamarin.Dynamsoft.Barcode.Android/) for Android.

Since the dependent packages are platform-specific, they must be conditionally correlated to each platform. After installing NuGet packages automatically, you need to manually editing following items in `*.csproj` file to avoid build errors:

```xml
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0-android'">
<PackageReference Include="Xamarin.Dynamsoft.Barcode.Android">
    <Version>9.0.0</Version>
</PackageReference>
</ItemGroup>

<ItemGroup Condition="$(TargetFramework.Contains('-windows')) == true ">
    <PackageReference Include="BarcodeQRCodeSDK" Version="1.2.1" />
</ItemGroup>
```

### Step3: Define the Cross-platform API
According to the official tutorial - [Invoke platform code](https://docs.microsoft.com/en-us/dotnet/maui/platform-integration/invoke-platform-code), we define a partial class named `BarcodeQRCodeService.cs` in the `Services` folder:

```csharp
namespace BarcodeQRCode.Services
{
    public partial class BarcodeQRCodeService
    {
        public partial void InitSDK(string license);
        public partial string DecodeFile(string filePath);
    }
}
```

Then create `BarcodeQRCodeService.cs` files respectively in Windows and Android folders to implement the API:

![MAUI cross-platform API](https://www.dynamsoft.com/codepool/img/2022/05/maui-crossplatform-api.png)

**Android**
```csharp
using BarcodeQRCode.Platforms.Android;
using Com.Dynamsoft.Dbr;

namespace BarcodeQRCode.Services
{
    public partial class BarcodeQRCodeService
    {
        BarcodeReader reader;

        public partial void InitSDK(string license)
        {
            BarcodeReader.InitLicense(license, new DBRLicenseVerificationListener());
            reader = new BarcodeReader();
        }

        public partial string DecodeFile(string filePath)
        {
            string decodingResult = "";

            try
            {

                TextResult[] results = reader.DecodeFile(filePath);
                if (results != null)
                {
                    foreach (TextResult result in results)
                    {
                        decodingResult += result.BarcodeText + "\n";
                    }
                }
                else
                {
                    decodingResult = "No barcode found.";
                }
            }
            catch (Exception e)
            {
                decodingResult = e.Message;
            }
            
            return decodingResult;
        }
    }
}
```

**Windows**

```csharp
using Dynamsoft;

namespace BarcodeQRCode.Services
{
    public partial class BarcodeQRCodeService
    {
        BarcodeQRCodeReader? reader = null;
        
        public partial void InitSDK(string license)
        {
            BarcodeQRCodeReader.InitLicense(license); 

            try
            {
                reader = BarcodeQRCodeReader.Create();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        public partial string DecodeFile(string filePath)
        {
            if (reader == null)
                return "";

            string decodingResult = "";            
            try
            {
                string[]? results = reader.DecodeFile(filePath);
                if (results != null)
                {
                    foreach (string result in results)
                    {
                        decodingResult += result + "\n";
                    }
                }
                else
                {
                    decodingResult = "No barcode found.";
                }
            }
            catch (Exception e)
            {
                decodingResult = e.Message;
            }

            return decodingResult;
        }
    }
}
```

For Android, in addition to the above, we also need to create a `DBRLicenseVerificationListener.cs` file to implement the interface `IDBRLicenseVerificationListener`:

```csharp
using Com.Dynamsoft.Dbr;

namespace BarcodeQRCode.Platforms.Android
{
    public class DBRLicenseVerificationListener : Java.Lang.Object, IDBRLicenseVerificationListener
    {
        public void DBRLicenseVerificationCallback(bool isSuccess, Java.Lang.Exception error)
        {
            if (!isSuccess)
            {
                System.Console.WriteLine(error.Message);
            }
        }
    }

}

```

### Step 4: Add UI Elements
We use MAUI template to create a new content page named `ReaderPage.xaml`:
    
![MAUI content page](https://www.dynamsoft.com/codepool/img/2022/05/maui-content-page.png)

The page contains a label for displaying barcode and QR code decoding results, a button for loading an image file, and a image for showing the image:

```xml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                x:Class="BarcodeQRCode.ReaderPage"
                Title="ReaderPage">
    <ScrollView>
        <VerticalStackLayout>
            <Button 
                Text="Select a file"
                FontAttributes="Bold"
                SemanticProperties.Hint="Decode barcode and QR code from the file"
                Clicked="OnFilePickerClicked"
                HorizontalOptions="Center" />
            <Label 
                FontSize="18"
                FontAttributes="Bold"
                x:Name="ResultLabel"
                HorizontalOptions="Center" />
            <Image
                x:Name="Image"
                SemanticProperties.Description="Decode barcode and QR code from the image file"
                WidthRequest="640"
                HeightRequest="640"
                HorizontalOptions="Center" />
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>
```

Apply for a [30-day trial license](https://www.dynamsoft.com/customer/license/trialLicense?product=dbr) and then switch to the corresponding `ReaderPage.xaml.cs` file to add file picking and image decoding logic:

```csharp
namespace BarcodeQRCode;

using BarcodeQRCode.Services;

public partial class ReaderPage : ContentPage
{
    BarcodeQRCodeService _barcodeQRCodeService;

    public ReaderPage()
    {
        InitializeComponent();

        InitService();
    }

    private async void InitService()
    {
        await Task.Run(() =>
        {
            _barcodeQRCodeService = new BarcodeQRCodeService();

            try
            {
                _barcodeQRCodeService.InitSDK("DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==");
            }
            catch (Exception ex)
            {
                DisplayAlert("Error", ex.Message, "OK");
            }

            return Task.CompletedTask;
        });
    }

    private async void OnFilePickerClicked(object sender, EventArgs e)
    {
        FileResult file;
        try
        {
            file = await FilePicker.PickAsync(PickOptions.Images);

            if (file == null) return;

            FileLabel.Text = $"File picked: {file.FileName}";

            Image.Source = ImageSource.FromFile(file.FullPath);

            var result = _barcodeQRCodeService.DecodeFile(file.FullPath);
            ResultLabel.Text = result;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
```

So far, the `ReaderPage` is done. We can add a button in `MainPage.xaml` to navigate to the `ReaderPage`:

```xml
<Button 
Text="Barcode/QR Code Reader"
FontAttributes="Bold"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnReaderClicked"
HorizontalOptions="Center" />
```

```csharp
private void OnReaderClicked(object sender, EventArgs e)
{
    Navigation.PushAsync(new ReaderPage());
}
```

Finally, select a framework and build the project.
- Android
        
    ![MAUI Android](https://www.dynamsoft.com/codepool/img/2022/05/maui-android.png)

- Windows
    
    ![MAUI Windows](https://www.dynamsoft.com/codepool/img/2022/05/maui-windows.png)


    ![MAUI barcode and QR code reader](https://www.dynamsoft.com/codepool/img/2022/05/maui-barcode-qrcode-reader.png)


## Source Code
[https://github.com/yushulx/dotnet-barcode-qr-code-sdk/tree/main/example/maui](https://github.com/yushulx/dotnet-barcode-qr-code-sdk/tree/main/example/maui)