Quick Start - MAUI

Follow this guide to set up a project for MAUI in order to easily implement the Anyline .NET SDK.

Setup

In this section we will go through the basic process of creating and configuring a simple Anyline scanning application. If you are not yet familiar with .NET MAUI, dotnet-android, and/or dotnet-ios follow the Official .NET MAUI Documentation to develop an understanding of the fundamentals of .NET MAUI development, and to create your first project.

Create a new .NET MAUI Project

If you are using Visual Studio, click New, select Multiplatform App > App > and create a new .NET MAUI App.

Generate an Anyline License Key

In order to run the Anyline SDK in your app, you require a license key. In order to create a license key for your application, you have to identify the ApplicationId of your MAUI app.

License <> ApplicationId

Every license key is bound to an ApplicationId. If you change your ApplicationId, you will require a new license key. This also ensures that your license key cannot be used in any other application.

How to identify the Application ID

To generate a license key for your application, refer to the ApplicationId of your MAUI project. More information about Application Ids can be found in the Official .NET MAUI guide.

With the ApplicationId you are now able to Generate a License Key.
Make sure to include the ApplicationId for both Android and iOS, in case they are different.

Once you generated your license key for the ApplicationId of your app, move on to the next steps.

The Anyline MAUI project basic structure

Before using any scan mode, the Anyline SDK has to be initialized within the target platforms (Android / iOS). This initialization only needs to be execute once, at the beginning of your app’s lifecycle.

One straightforward way of doing this in the MAUI layer is to use partial classes, but you can initialize the Anyline SDK however best fits your project.

The advantage of using a partial class is that you can initialize native components, receive the results and act upon them from within the MAUI layer. To do that, in the MAUI layer, create a new class (Right-click on the project > Add > New Class). We’ll call it AnylineSDKService.cs:

AnylineSDKService.cs
// this namespace name must match the namespace of the native implementations of this partial class
namespace Anyline
{
	/// <summary>
	/// This class is responsible for the Initialization of the Anyline SDK.
	/// </summary>
	public partial class AnylineSDKService
	{
		/// <summary>
		/// This method is implemented inside the Android and iOS platforms via partial classes: AnylineSDKService.Android and AnylineSDKService.iOS.
		/// </summary>
		/// <param name="licenseKey">Your Anyline License Key created for your Application IDs.</param>
		/// <param name="licenseErrorMessage">Contains the error message when the SDK initialization fails.</param>
		/// <returns>True when the Anyline SDK is successfully initialized, False otherwise.</returns>
		public partial bool SetupWithLicenseKey(string licenseKey, out string licenseErrorMessage);
	}
}

You are now able to call the Anyline SDK initialization anywhere in your MAUI code. Let’s call it in the MainPage.cs:

MainPage.cs
namespace Anyline.Examples.MAUI
{
	public partial class MainPage : ContentPage
	{
		public MainPage()
		{
			InitializeComponent();

			...

			// YOUR LICENSE KEY HERE
			// (this license key should be, ideally, securely fetched from your back-end server, a secret manager/provider, or obfuscated in the final app)
			string licenseKey = "YOUR_LICENSE_KEY";

			string licenseErrorMessage = null;

			// Initializes the Anyline SDK natively in each platform and gets the result of the initialization back
			bool isAnylineInitialized = new AnylineSDKService().SetupWithLicenseKey(licenseKey, out licenseErrorMessage);

			if (isAnylineInitialized)
			{
				// Allow users to use Anyline
			}
			else
			{
				// Implement alternative workflow and/or show the licenseErrorMessage
			}
		}
	}
}
Platform-specific implementation

The other part of this partial class will be implemented within the platform folders. Check the next pages for more details.

Setup the Anyline ScanView

The best approach to setting up the Anyline ScanView is to use a JSON configuration file. Read about this in the next section.

Providing an Anyline Configuration

With the Anyline Configuration, you can define your whole use case, including scanning parameters and the look & feel of your scanning view.
The configuration parameters define the visual information presented to the user, as well as the scan settings (like the resolution, etc.) and feedback that is presented to the user.

Have a look at the Scanning Capabilities section for more specific implementation details.

You can adapt your ScanView easily by adding a .json file as an asset to your project and loading it. In this example, we will create a .json file and configure it for the MRZ scanning.

Visual Studio

  • In the MAUI layer, in your Resources/Raw treenode, right-click on the folder and select Add > New Item..

  • Choose Visual C# > Text File and name it scanConfig.json

Make sure that the build action for this file is set to MauiAsset (Right-click > Properties > Build Action).

Now open the file and paste the code from the following MRZ config example:

{
	"cameraConfig": {
		"captureResolution": "1080p",
		"zoomGesture": true
	},
	"flashConfig": {
		"mode": "manual",
		"alignment": "top_left"
	},
	"viewPluginConfig": {
		"pluginConfig": {
			"id": "ID",
			"cancelOnResult": true,
			"mrzConfig": {
				"strictMode": false,
				"cropAndTransformID": false
			}
		},
		"cutoutConfig": {
			"style": "none",
			"maxWidthPercent": "90%",
			"maxHeightPercent": "90%",
			"alignment": "center",
			"ratioFromSize": {
				"width": 50,
				"height": 31
			},
			"cropPadding": {
			},
			"outerColor": "000000",
			"outerAlpha": 0.3,
			"strokeWidth": 2,
			"strokeColor": "0099FF",
			"cornerRadius": 4,
			"feedbackStrokeColor": "0099FF"
		},
		"scanFeedbackConfig": {
			"style": "rect",
			"visualFeedbackRedrawTimeout": 100,
			"strokeWidth": 2,
			"strokeColor": "0099FF",
			"fillColor": "220099FF",
			"beepOnResult": true,
			"vibrateOnResult": true,
			"blinkAnimationOnResult": false
		}
	}
}

This JSON builds the whole MRZ scanning use-case.

A minimum Anyline MAUI project will require another View and two aditional pages: A ScanPage and a ResultsPage.

Calling the scan page

To call the scan page, you can use, for example, the following snippet:

MainPage.xaml.cs
...

private async void BtScan_Clicked(object sender, EventArgs e)
{
	// request the camera permission beforehand (required)
	var status = await Permissions.CheckStatusAsync<Permissions.Camera>();
	if (status != PermissionStatus.Granted)
	{
		await Permissions.RequestAsync<Permissions.Camera>();
	}

	(sender as Button).IsEnabled = false;

	await Navigation.PushAsync(new MyScanningWithAnylinePage("scanConfig.json"));

	(sender as Button).IsEnabled = true;
}

First, let’s create the ScanPage. We will call it MyScanningWithAnylinePage. In the root your MAUI layer, create a new Content Page (Right-click on the project > Add > New Item > Content Page):

MyScanningWithAnylinePage.xaml
<?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="Anyline.Examples.MAUI.MyScanningWithAnylinePage"
			Padding="0,0"
			Title="Scan Page">

	<Grid x:Name="gridContent" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" BackgroundColor="Black">

	</Grid>
</ContentPage>
MyScanningWithAnylinePage.xaml.cs
using Anyline.Examples.MAUI.Models;
using Anyline.Examples.MAUI.Views;

namespace Anyline.Examples.MAUI;

/// <summary>
/// This is your app's page where Anyline will be integrated.
/// </summary>
public partial class MyScanningWithAnylinePage : ContentPage
{
	/// <summary>
	/// The constructor initializes a new "AnylineScanningView" (which is rendered natively in the platforms),
	/// and provides a "myResultAction", which will be called once the scanning process is successfully completed.
	/// </summary>
	/// <param name="jsonConfigFilePath">JSON config file path (used for initializing the ScanView).</param>
	public MyScanningWithAnylinePage(string jsonConfigFilePath)
	{
		InitializeComponent();
		Action<string, byte[]> myResultAction = (result, cutoutImage) =>
		{
			DoSomethingWithResult(result, cutoutImage);
		};

		var view = new AnylineScanningView(jsonConfigFilePath, myResultAction);

		gridContent.Add(view);
	}

	/// <summary>
	/// This method is called inside the Action, used to process the Scan Results.
	/// </summary>
	/// <param name="result">The string containing the MRZ result, coming from the native platform.</param>
	/// <param name="cutout">The cutout image as a byte array, coming from the native platform.</param>
	private void DoSomethingWithResult(string result, byte[] cutoutImage)
	{
		Dispatcher.Dispatch(new Action(async () =>
		{
			Navigation.InsertPageBefore(new ResultsPage(result, cutoutImage), Navigation.NavigationStack.Last());
			await Navigation.PopAsync();
		}));
	}
}

The AnylineScanningView is rendered natively on Android and iOS to execute the Scan functionality. In your MAUI layer create a folder called "Views" and, inside of it, create a new View (Right-click on the project > Add > New Item > Content View (C#)):

AnylineScanningView.cs
namespace Anyline.Examples.MAUI.Views
{
	/// <summary>
	/// This ContentView is rendered natively in each individual platform.
	/// The scanning results are received in the 'OnResult' action.
	/// </summary>
	internal class AnylineScanningView : ContentView
	{
		public string JSONConfigPath;
		public Action<string, byte[]> OnResult;

		/// <summary>
		/// Holds the information necessary for the ScanView Initialization and Result processing.
		/// </summary>
		/// <param name="jsonConfigPath">The path to the JSON config file.</param>
		/// <param name="onResultAction">The Action that should be called once the results are available.</param>
		public AnylineScanningView(string jsonConfigPath, Action<string, byte[]> onResultAction)
		{
			JSONConfigPath = jsonConfigPath;
			OnResult = onResultAction;
			BackgroundColor = Color.FromArgb("00000000");
		}
	}
}

Results Page

Now we create the Results Page, the page responsible for displaying the scan results. In the MAUI layer, create a new Page (Right-click on the project > Add > New Item > Content Page). We’ll call it ResultsPage.xaml

ResultsPage

This ResultsPage is built to simply display an Image and a MRZ string result. In your project, you can work with a strongly typed object in the MAUI layer containing all of the necessary information.

ResultsPage.xaml
<?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="Anyline.Examples.MAUI.ResultsPage"
			Title="Scan Results"
			BackgroundColor="#1A1A1A">

	<ScrollView>
		<VerticalStackLayout VerticalOptions="FillAndExpand" Padding="20" >
			<Label x:Name="lbResult" TextColor="#32ADFF" FontSize="15" />
			<Image x:Name="imResult" Aspect="AspectFill" />

			<BoxView HeightRequest="1" BackgroundColor="#30FFFFFF" />

			<Button x:Name="btHome" Text="Home" BackgroundColor="#32ADFF" TextColor="White" HorizontalOptions="FillAndExpand" />
		</VerticalStackLayout>
	</ScrollView>
</ContentPage>
ResultsPage.xaml.cs
namespace Anyline.Examples.MAUI;

public partial class ResultsPage : ContentPage
{
	public ResultsPage(string result, byte[] cutoutImage)
	{
		InitializeComponent();

		lbResult.Text = result;
		imResult.Source = ImageSource.FromStream(() => new MemoryStream(cutoutImage));

		btHome.Clicked += async (s, e) => await Navigation.PopToRootAsync();
	}
}

As a last step in the MAUI layer, we need to register the Renderer for the AnylineScanView.

Configure AnylineScanView Renderer

Open the MauiProgram.cs file and modify it so the your renderer is registred for the specific platforms:

MauiProgram.cs
namespace Anyline.Examples.MAUI;

using Views;

#if ANDROID
using Anyline.Examples.MAUI.Platforms.Android.CustomRenderers;
#endif

#if IOS
using Anyline.Examples.MAUI.Platforms.iOS.CustomRenderers;
#endif

public static class MauiProgram
{
	public static MauiApp CreateMauiApp()
	{
		var builder = MauiApp.CreateBuilder();
		builder
			.UseMauiApp<App>()
			.UseMauiCompatibility()
			.ConfigureMauiHandlers(handlers =>
			{
				handlers.AddHandler(typeof(AnylineScanningView), typeof(AnylineScanningViewRenderer));
			})
			.ConfigureFonts(fonts =>
			{
				fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
				fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
			});

		return builder.Build();
	}
}

For this example, this is all we need in the MAUI layer. In the next section we will implement the AnylineSDK initialization and also the Android and the iOS renderers for our AnylineScanView.