Skip to content

Build a barcode scanner with Avalonia and our .NET MAUI SDK – tutorial

Kevin December 19, 2024 7 mins read
app store

Avalonia UI enables developers to build native mobile, desktop, web, and embedded applications using C# and XAML with a single codebase. In this tutorial, we’ll show you how you can build a barcode scanner for Android and iOS in Avalonia UI using our .NET MAUI SDK.

We’ll follow these steps:

  1. Preparing the project
  2. Configuring the camera permissions
  3. Initializing the SDK
  4. Implementing the scanning screen
  5. Building and running the app

Requirements

⚠️ A note for Windows users: If you want to develop your app for iOS, additional setup is required, including having a Mac available as a build server. You can learn more about this in the .NET MAUI documentation. In this tutorial, we’ll assume you’re developing on a Mac and using the CLI.

If this is your first time developing a .NET MAUI application on your machine, execute the following command:

sudo dotnet workload install maui

It may suggest fixes to apply to your environment to ensure smooth app development in Avalonia. Apply them at your own discretion, though it is generally safe to accept the fixes.

Next, we need the project templates. Let’s install them with the following command:

dotnet new install Avalonia.Templates

1. Prepare the project

From a good working directory, run the following to create a new cross-platform Avalonia UI app:

dotnet new avalonia.xplat -o AvaloniaBarcodeScanner -f net8.0

From your terminal, you can navigate to the generated project:

cd AvaloniaBarcodeScanner

Verify that everything is working as expected by running either of the following commands:

dotnet build AvaloniaBarcodeScanner.Android -f net8.0-android
dotnet build AvaloniaBarcodeScanner.iOS -f net8.0-ios

If everything builds as expected, you can be sure your .NET development environment is configured correctly and that the Avalonia UI project will work later on when we’re going to test everything.

The generated app supports multiple target frameworks, but we will only focus on net8.0-android and net8.0-ios in this tutorial, since that’s what our SDK supports.

In Directory.Packages.props, insert the following before the </Project> end tag:

<ItemGroup>
    <PackageVersion Include="ScanbotBarcodeSDK.MAUI" Version="5.1.0" />
    <!-- Missing from the dependency list for our package - but should be fixed in a future version -->      
    <PackageVersion Include="Microsoft.Maui.Controls" Version="8.0.82" />
</ItemGroup>

In AvaloniaBarcodeScanner/AvaloniaBarcodeScanner.csproj, replace:

<TargetFramework>net8.0</TargetFramework>

With:

<TargetFrameworks>net8.0;net8.0-ios;net8.0-android</TargetFrameworks>

Then, insert the following before the </Project> end tag:

<ItemGroup>
    <PackageReference Condition="$(TargetFramework.Contains('ios'))" Include="ScanbotBarcodeSDK.MAUI" />
    <PackageReference Condition="$(TargetFramework.Contains('android'))" Include="ScanbotBarcodeSDK.MAUI" />
    <PackageReference Include="Microsoft.Maui.Controls" />
</ItemGroup>

At the time of writing, the default Avalonia UI app template uses Central Package Management, which is why there are two files to update instead of one. If your project doesn’t make use of Central Package Management, then installing the SDK just requires specifying the appropriate <PackageReference> elements in your project file.

The project structure also separates each platform into their own projects, much like Xamarin.Forms. However, for convience we include our package in the main project, as is now conventional in modern .NET cross-platform projects.

We can verify our changes by testing the build process:

dotnet build AvaloniaBarcodeScanner -f net8.0-android
dotnet build AvaloniaBarcodeScanner -f net8.0-ios -r ios-arm64

If everything builds as expected, we are ready to proceed.

💡 When building for Android, it’s possible for package downgrades to be detected depending on the version of the Avalonia UI SDK being used.

If there are package conflicts, add the appropriate <PackageReference> tags to the project with the relevant information and make sure <PackageReference> has NoWarn="NU1605" added to it so that the related build error will go away for that particular package.

2. Configure the camera permissions

Since scanning barcodes requires access to the device camera, we need to add the corresponding permissions.

For Android, add the following to AvaloniaBarcodeScanner.Android/Properties/AndroidManifest.xml inside the <manifest> element:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />

For iOS, add the following to AvaloniaBarcodeScanner.iOS/Info.plist anywhere inside the <dict> element:

<key>NSCameraUsageDescription</key>
<string>Please provide camera access.</string>

3. Initialize the SDK

In AvaloniaBarcodeScanner/App.axaml.cs, at the very top of the file, add:

using ScanbotSDK.MAUI;

Then, inside the App class, before the Initialize method, add the following line:

private const string licenseKey = "";

Then replace:

public override void Initialize()
{
    AvaloniaXamlLoader.Load(this);
}

With:

public override void Initialize()
{
    ScanbotBarcodeSDK.Initialize(new InitializationOptions
    {
        LicenseKey = licenseKey,
        LoggingEnabled = true,
        // ErrorHandler = (status, feature) =>
        // {
        //     Console.WriteLine($"License error: {status}, {feature}");
        // }
    });

    AvaloniaXamlLoader.Load(this);
}

In AvaloniaBarcodeScanner.Android/MainActivity.cs, inside the MainActivity class, replace the following method override:

protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
{
        return base.CustomizeAppBuilder(builder)
            .WithInterFont();
}

With:

protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
{
        ScanbotSDK.MAUI.DependencyManager.RegisterActivity(this);
        return base.CustomizeAppBuilder(builder)
            .WithInterFont();
}

4. Implement the scanning screen

Now that the SDK is ready, we can use its Ready-To-Use UI Components to integrate and customize the high-level UI components for scanning barcodes.

In AvaloniaBarcodeScanner/Views/MainView.axaml, replace:

<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>

With:

<StackPanel>
    <Button Click="StartSingleScanning">
        Start single-barcode scanning
    </Button>
    <TextBlock x:Name="TextOutput" 
          HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>

In AvaloniaBarcodeScanner/Views/MainView.axaml.cs, at the top of the file, add:

using ScanbotSDK.MAUI;
using ScanbotSDK.MAUI.Barcode;
using ScanbotSDK.MAUI.Common;
using Avalonia.Interactivity;
using Avalonia.Controls;
using System;
using System.Linq;
using System.Threading.Tasks;

Then, inside of the MainView class definition, add the following method:

private async void StartSingleScanning(object sender, RoutedEventArgs e)
{ 
    try
    {
        if (!ScanbotBarcodeSDK.LicenseInfo.IsValid)
        {
            TextOutput.Text = "Trial license expired.";
            return;
        }

        // Create the default configuration object.
        var configuration = new BarcodeScannerConfiguration();

        // Initialize the single-scan use case.
        var singleUsecase = new SingleScanningMode();

        // Set the configured use case.
        configuration.UseCase = singleUsecase;

        var result = await ScanbotBarcodeSDK.BarcodeScanner.OpenBarcodeScannerAsync(configuration); 

        var barcodeAsText = result.Items.Select(barcode => $"{barcode.Type}: {barcode.Text}")
                            .FirstOrDefault() ?? string.Empty;

        TextOutput.Text = barcodeAsText;
    }
    catch (TaskCanceledException)
    {
        // For when the user cancels the action.
    }
    catch (Exception ex)
    {
        // For any other errors that occur.
        System.Diagnostics.Debug.WriteLine(ex.Message);
    }
}

💡 This snippet is very similar to what we use in our quick start guide. The only major difference is the use of ContentDialog to show the alert message instead of DisplayAlert. The first is specific to Avalonia UI and the second to MAUI. Since the project has MAUI inside it, you could technically use both, but we used ContentDialog for illustrative purposes.

5. Build and run the app

Now we’re ready to run our app with:

dotnet build AvaloniaBarcodeScanner.Android -f net8.0-android -t:Run
dotnet build AvaloniaBarcodeScanner.iOS -f net8.0-ios -r ios-arm64 -t:Run

💡 If you have deployment issues for Android to your device, try adding true to the AvaloniaBarcodeScanner.Android.csproj file.

🎉 Congratulations! You’ve successfully integrated a barcode scanner into your Avalonia UI app!

If this tutorial has piqued your interest in integrating barcode scanning functionalities into your MAUI app, make sure to take a look at our SDK’s other neat features in our documentation – or run our example project for a more hands-on experience!

Should you have questions about this tutorial or ran into any issues, we’re happy to help! Just shoot us an email via tutorial-support@scanbot.io.

Happy coding!