Migrating from BarcodeScanning.Native.Maui to IronBarcode
This guide provides a complete migration path from BarcodeScanning.Native.Maui to IronBarcode, covering the camera event pattern replacement, namespace changes, code migration examples, and the handling of scenarios that BarcodeScanning.Native.Maui cannot address — Windows MAUI, file and PDF input, server-side processing, and barcode generation.
Why Migrate from BarcodeScanning.MAUI
Teams migrating from BarcodeScanning.Native.Maui report these triggers:
Windows MAUI Target Required: BarcodeScanning.Native.Maui wraps iOS and Android native APIs. It has no Windows implementation and none is planned. If your MAUI app targets Windows alongside iOS and Android, you need a library that works on all three targets without platform-specific branching.
File or PDF Input Added to Requirements: BarcodeScanning.Native.Maui only accepts live camera frames. When users need to upload an image from their gallery, or when a server-side endpoint needs to extract barcodes from PDFs, the library has no code path to offer. Any file or PDF barcode scenario requires a different tool.
iOS UPC-A Data Was Wrong in Production: Apple's Vision framework returns 13 digits for UPC-A barcodes (EAN-13 encoding). BarcodeScanning.Native.Maui passes this through uncorrected. If UPC-A codes were being stored with a leading zero, inventory records, point-of-sale lookups, or supply chain integrations may have been silently broken. IronBarcode returns the correct 12-digit UPC-A value without manual normalization.
PDF417 Scanning Was Unreliable: The library's own GitHub issues document PDF417 as "very problematic — most scans never occur." For shipping labels, driver's licenses, and boarding passes, this is a direct blocker.
Generation Was Needed: BarcodeScanning.Native.Maui cannot generate barcodes. IronBarcode generates Code128, QR, DataMatrix, and other formats as image files or byte arrays.
Server-Side Processing Introduced: BarcodeScanning.Native.Maui is a camera UI control — it cannot run in a server process. When server-side barcode reading is required alongside mobile scanning, IronBarcode covers both sides with the same package and the same API.
The Fundamental Problem
BarcodeScanning.Native.Maui ties your barcode reading entirely to the live camera event model. The moment any requirement falls outside that model, the library offers nothing:
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
var barcode = e.BarcodeResults.FirstOrDefault();
if (barcode != null)
ResultLabel.Text = barcode.DisplayValue;
}
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
var barcode = e.BarcodeResults.FirstOrDefault();
if (barcode != null)
ResultLabel.Text = barcode.DisplayValue;
}
Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
Dim barcode = e.BarcodeResults.FirstOrDefault()
If barcode IsNot Nothing Then
ResultLabel.Text = barcode.DisplayValue
End If
End Sub
IronBarcode accepts any data input — camera capture, file, PDF, byte array — and runs on every platform:
using IronBarCode;
private async void ScanBarcodeButton_Clicked(object sender, EventArgs e)
{
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
ResultLabel.Text = results.FirstOrDefault()?.Value ?? "No barcode found";
}
using IronBarCode;
private async void ScanBarcodeButton_Clicked(object sender, EventArgs e)
{
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
ResultLabel.Text = results.FirstOrDefault()?.Value ?? "No barcode found";
}
Imports IronBarCode
Private Async Sub ScanBarcodeButton_Clicked(sender As Object, e As EventArgs)
Dim photo = Await MediaPicker.CapturePhotoAsync()
If photo Is Nothing Then Return
Using stream = Await photo.OpenReadAsync()
Using ms As New MemoryStream()
Await stream.CopyToAsync(ms)
Dim results = BarcodeReader.Read(ms.ToArray())
ResultLabel.Text = If(results.FirstOrDefault()?.Value, "No barcode found")
End Using
End Using
End Sub
IronBarcode vs BarcodeScanning.MAUI: Feature Comparison
| Feature | BarcodeScanning.MAUI | IronBarcode |
|---|---|---|
| Live camera frame reading | Yes — CameraView control | No (use MediaPicker to capture, then read) |
| In-app camera viewfinder | Yes — real-time continuous | No — uses system camera UI via MediaPicker |
| Read from image file | No | Yes — BarcodeReader.Read(path) |
| Read from byte array | No | Yes — BarcodeReader.Read(bytes) |
| Read from stream | No | Yes — BarcodeReader.Read(stream) |
| Read from PDF | No | Yes — BarcodeReader.Read(pdf) |
| Barcode generation | No | Yes — BarcodeWriter + QRCodeWriter |
| Windows MAUI support | No | Yes |
| iOS MAUI support | Yes | Yes |
| Android MAUI support | Yes | Yes |
| macOS MAUI support | Not documented | Yes |
| Server-side / ASP.NET | No | Yes |
| Docker / Azure / AWS Lambda | No | Yes |
| iOS UPC-A accuracy | Returns 13 digits (bug), requires manual normalization | Returns correct 12-digit UPC-A |
| PDF417 reliability | "Most scans never occur" (GitHub issues) | Supported |
| Multi-barcode detection | Yes (multiple per frame via e.BarcodeResults) |
Yes (ExpectMultipleBarcodes option) |
| Reading speed control | None | ReadingSpeed.Faster / Balanced / Detailed / ExtremeDetail |
| License | MIT (open source, free) | Commercial — Lite $749, Plus $1,499, Professional $2,999, Unlimited $5,999 |
| .NET Framework support | No (MAUI only) | Yes — .NET Framework 4.6.2+ |
Quick Start: BarcodeScanning.MAUI to IronBarcode Migration
Step 1: Replace NuGet Package
Remove BarcodeScanning.Native.Maui:
dotnet remove package BarcodeScanning.Native.Maui
dotnet remove package BarcodeScanning.Native.Maui
Install IronBarcode:
dotnet add package IronBarcode
dotnet add package IronBarcode
Step 2: Update Namespaces
Remove the BarcodeScanning namespace from all files:
// Remove
using BarcodeScanning;
// Remove
using BarcodeScanning;
Imports BarcodeScanning
Add the IronBarCode namespace:
// Add
using IronBarCode;
// Add
using IronBarCode;
Imports IronBarCode
In XAML files, remove the scanner: XML namespace declaration:
xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui"
xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui"
Step 3: Initialize License
Add license initialization at application startup — in MauiProgram.cs or App.xaml.cs:
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronBarCode
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
Code Migration Examples
Camera Scanning: CameraView to MediaPicker
The CameraView control provided a real-time viewfinder with continuous frame detection. The IronBarcode replacement uses MAUI's MediaPicker to open the system camera, capture a photo, and process the resulting image.
BarcodeScanning.MAUI Approach — XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui">
<StackLayout>
<scanner:CameraView x:Name="CameraView"
OnDetectionFinished="OnBarcodeDetected"
CameraEnabled="True"
BarcodeFormats="All"
VerticalOptions="FillAndExpand" />
<Label x:Name="ResultLabel" Text="Waiting for scan..." />
</StackLayout>
</ContentPage>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui">
<StackLayout>
<scanner:CameraView x:Name="CameraView"
OnDetectionFinished="OnBarcodeDetected"
CameraEnabled="True"
BarcodeFormats="All"
VerticalOptions="FillAndExpand" />
<Label x:Name="ResultLabel" Text="Waiting for scan..." />
</StackLayout>
</ContentPage>
BarcodeScanning.MAUI Approach — code-behind:
using BarcodeScanning;
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
var barcode = e.BarcodeResults.FirstOrDefault();
if (barcode != null)
MainThread.BeginInvokeOnMainThread(() =>
ResultLabel.Text = barcode.DisplayValue);
}
using BarcodeScanning;
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
var barcode = e.BarcodeResults.FirstOrDefault();
if (barcode != null)
MainThread.BeginInvokeOnMainThread(() =>
ResultLabel.Text = barcode.DisplayValue);
}
Imports BarcodeScanning
Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
Dim barcode = e.BarcodeResults.FirstOrDefault()
If barcode IsNot Nothing Then
MainThread.BeginInvokeOnMainThread(Sub()
ResultLabel.Text = barcode.DisplayValue
End Sub)
End If
End Sub
IronBarcode Approach — XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui">
<StackLayout>
<Button Text="Scan Barcode" Clicked="ScanButton_Clicked" />
<Label x:Name="ResultLabel" Text="Tap to scan..." />
</StackLayout>
</ContentPage>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui">
<StackLayout>
<Button Text="Scan Barcode" Clicked="ScanButton_Clicked" />
<Label x:Name="ResultLabel" Text="Tap to scan..." />
</StackLayout>
</ContentPage>
IronBarcode Approach — code-behind:
using IronBarCode;
private async void ScanButton_Clicked(object sender, EventArgs e)
{
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
var first = results.FirstOrDefault();
ResultLabel.Text = first?.Value ?? "No barcode found";
}
using IronBarCode;
private async void ScanButton_Clicked(object sender, EventArgs e)
{
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
var first = results.FirstOrDefault();
ResultLabel.Text = first?.Value ?? "No barcode found";
}
Imports IronBarCode
Imports System.IO
Imports System.Linq
Private Async Sub ScanButton_Clicked(sender As Object, e As EventArgs)
Dim photo = Await MediaPicker.CapturePhotoAsync()
If photo Is Nothing Then Return
Using stream = Await photo.OpenReadAsync()
Using ms As New MemoryStream()
Await stream.CopyToAsync(ms)
Dim results = BarcodeReader.Read(ms.ToArray())
Dim first = results.FirstOrDefault()
ResultLabel.Text = If(first?.Value, "No barcode found")
End Using
End Using
End Sub
This code runs on iOS, Android, and Windows MAUI without any platform-specific branching. The user experience changes from a live in-app viewfinder to the platform's native camera screen — appropriate for most business applications. The IronBarcode MAUI reading guide covers additional configuration options.
Handling Multiple Barcodes Per Scan
BarcodeScanning.MAUI Approach:
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
foreach (var barcode in e.BarcodeResults)
{
MainThread.BeginInvokeOnMainThread(() =>
Console.WriteLine($"Found: {barcode.DisplayValue}"));
}
}
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
foreach (var barcode in e.BarcodeResults)
{
MainThread.BeginInvokeOnMainThread(() =>
Console.WriteLine($"Found: {barcode.DisplayValue}"));
}
}
Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
For Each barcode In e.BarcodeResults
MainThread.BeginInvokeOnMainThread(Sub()
Console.WriteLine($"Found: {barcode.DisplayValue}")
End Sub)
Next
End Sub
IronBarcode Approach:
using IronBarCode;
private async void ScanButton_Clicked(object sender, EventArgs e)
{
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var options = new BarcodeReaderOptions
{
Speed = ReadingSpeed.Balanced,
ExpectMultipleBarcodes = true
};
var results = BarcodeReader.Read(ms.ToArray(), options);
foreach (var result in results)
Console.WriteLine($"{result.Format}: {result.Value}");
}
using IronBarCode;
private async void ScanButton_Clicked(object sender, EventArgs e)
{
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var options = new BarcodeReaderOptions
{
Speed = ReadingSpeed.Balanced,
ExpectMultipleBarcodes = true
};
var results = BarcodeReader.Read(ms.ToArray(), options);
foreach (var result in results)
Console.WriteLine($"{result.Format}: {result.Value}");
}
Imports IronBarCode
Imports System.IO
Private Async Sub ScanButton_Clicked(sender As Object, e As EventArgs)
Dim photo = Await MediaPicker.CapturePhotoAsync()
If photo Is Nothing Then Return
Using stream = Await photo.OpenReadAsync()
Using ms As New MemoryStream()
Await stream.CopyToAsync(ms)
Dim options As New BarcodeReaderOptions With {
.Speed = ReadingSpeed.Balanced,
.ExpectMultipleBarcodes = True
}
Dim results = BarcodeReader.Read(ms.ToArray(), options)
For Each result In results
Console.WriteLine($"{result.Format}: {result.Value}")
Next
End Using
End Using
End Sub
ExpectMultipleBarcodes = true tells the reader to continue scanning after finding the first barcode. Without this option, the call returns on the first match, which is faster for single-barcode scenarios.
iOS UPC-A Fix: Remove the Normalization Workaround
If your codebase has the UPC-A leading-zero workaround, remove it entirely. IronBarcode returns the correct 12-digit value without any manual intervention.
BarcodeScanning.MAUI Approach — workaround in place:
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
var barcode = e.BarcodeResults.FirstOrDefault();
if (barcode == null) return;
var value = barcode.DisplayValue;
// Workaround: Apple Vision returns 13 digits for UPC-A
if (barcode.BarcodeFormat == BarcodeFormats.Upca && value.Length == 13)
value = value.Substring(1);
ProcessBarcode(value, barcode.BarcodeFormat.ToString());
}
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
var barcode = e.BarcodeResults.FirstOrDefault();
if (barcode == null) return;
var value = barcode.DisplayValue;
// Workaround: Apple Vision returns 13 digits for UPC-A
if (barcode.BarcodeFormat == BarcodeFormats.Upca && value.Length == 13)
value = value.Substring(1);
ProcessBarcode(value, barcode.BarcodeFormat.ToString());
}
Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
Dim barcode = e.BarcodeResults.FirstOrDefault()
If barcode Is Nothing Then Return
Dim value = barcode.DisplayValue
' Workaround: Apple Vision returns 13 digits for UPC-A
If barcode.BarcodeFormat = BarcodeFormats.Upca AndAlso value.Length = 13 Then
value = value.Substring(1)
End If
ProcessBarcode(value, barcode.BarcodeFormat.ToString())
End Sub
IronBarcode Approach — no workaround needed:
using IronBarCode;
private async void ScanButton_Clicked(object sender, EventArgs e)
{
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
var first = results.FirstOrDefault();
if (first == null) return;
// result.Value is the correct 12-digit UPC-A — no normalization needed
ProcessBarcode(first.Value, first.Format.ToString());
}
using IronBarCode;
private async void ScanButton_Clicked(object sender, EventArgs e)
{
var photo = await MediaPicker.CapturePhotoAsync();
if (photo == null) return;
using var stream = await photo.OpenReadAsync();
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
var first = results.FirstOrDefault();
if (first == null) return;
// result.Value is the correct 12-digit UPC-A — no normalization needed
ProcessBarcode(first.Value, first.Format.ToString());
}
Imports IronBarCode
Imports System.IO
Imports System.Linq
Imports System.Threading.Tasks
Private Async Sub ScanButton_Clicked(sender As Object, e As EventArgs)
Dim photo = Await MediaPicker.CapturePhotoAsync()
If photo Is Nothing Then Return
Using stream = Await photo.OpenReadAsync()
Using ms As New MemoryStream()
Await stream.CopyToAsync(ms)
Dim results = BarcodeReader.Read(ms.ToArray())
Dim first = results.FirstOrDefault()
If first Is Nothing Then Return
' result.Value is the correct 12-digit UPC-A — no normalization needed
ProcessBarcode(first.Value, first.Format.ToString())
End Using
End Using
End Sub
Delete any matches for BarcodeFormats.Upca paired with Substring(1) — that code is dead after migration.
Adding File and PDF Support
BarcodeScanning.Native.Maui has no equivalent for file or PDF input. If this is a new requirement being fulfilled at migration time:
BarcodeScanning.MAUI Approach:
// No equivalent exists — BarcodeScanning.Native.Maui cannot read from files or PDFs
// No equivalent exists — BarcodeScanning.Native.Maui cannot read from files or PDFs
' No equivalent exists — BarcodeScanning.Native.Maui cannot read from files or PDFs
IronBarcode Approach:
using IronBarCode;
// Read from a file the user picked with FilePicker
private async void ReadFileButton_Clicked(object sender, EventArgs e)
{
var file = await FilePicker.PickAsync(new PickOptions
{
PickerTitle = "Select image or PDF"
});
if (file == null) return;
var results = BarcodeReader.Read(file.FullPath);
foreach (var result in results)
ResultLabel.Text += $"\n{result.Format}: {result.Value}";
}
// Read barcodes from a PDF directly — no intermediate image step
private void ReadPdfBarcodes()
{
var results = BarcodeReader.Read("shipment-manifest.pdf");
foreach (var result in results)
Console.WriteLine($"{result.Format}: {result.Value}");
}
using IronBarCode;
// Read from a file the user picked with FilePicker
private async void ReadFileButton_Clicked(object sender, EventArgs e)
{
var file = await FilePicker.PickAsync(new PickOptions
{
PickerTitle = "Select image or PDF"
});
if (file == null) return;
var results = BarcodeReader.Read(file.FullPath);
foreach (var result in results)
ResultLabel.Text += $"\n{result.Format}: {result.Value}";
}
// Read barcodes from a PDF directly — no intermediate image step
private void ReadPdfBarcodes()
{
var results = BarcodeReader.Read("shipment-manifest.pdf");
foreach (var result in results)
Console.WriteLine($"{result.Format}: {result.Value}");
}
Imports IronBarCode
' Read from a file the user picked with FilePicker
Private Async Sub ReadFileButton_Clicked(sender As Object, e As EventArgs)
Dim file = Await FilePicker.PickAsync(New PickOptions With {
.PickerTitle = "Select image or PDF"
})
If file Is Nothing Then Return
Dim results = BarcodeReader.Read(file.FullPath)
For Each result In results
ResultLabel.Text &= vbCrLf & $"{result.Format}: {result.Value}"
Next
End Sub
' Read barcodes from a PDF directly — no intermediate image step
Private Sub ReadPdfBarcodes()
Dim results = BarcodeReader.Read("shipment-manifest.pdf")
For Each result In results
Console.WriteLine($"{result.Format}: {result.Value}")
Next
End Sub
The IronBarcode PDF reading documentation covers multi-page PDF support and page range selection.
Server-Side Barcode Processing
If your application has a backend ASP.NET API that also needs barcode processing, the same BarcodeReader.Read() call runs there without modification. BarcodeScanning.Native.Maui has no server-side equivalent.
BarcodeScanning.MAUI Approach:
// No equivalent exists — BarcodeScanning.Native.Maui is a camera UI control
// and cannot run in a server process
// No equivalent exists — BarcodeScanning.Native.Maui is a camera UI control
// and cannot run in a server process
' No equivalent exists — BarcodeScanning.Native.Maui is a camera UI control
' and cannot run in a server process
IronBarcode Approach:
using IronBarCode;
// ASP.NET endpoint — reads barcodes from an uploaded file
[HttpPost("scan")]
public async Task<IActionResult> ScanBarcode(IFormFile file)
{
using var ms = new MemoryStream();
await file.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
var values = results.Select(r => new { r.Value, Format = r.Format.ToString() });
return Ok(values);
}
using IronBarCode;
// ASP.NET endpoint — reads barcodes from an uploaded file
[HttpPost("scan")]
public async Task<IActionResult> ScanBarcode(IFormFile file)
{
using var ms = new MemoryStream();
await file.CopyToAsync(ms);
var results = BarcodeReader.Read(ms.ToArray());
var values = results.Select(r => new { r.Value, Format = r.Format.ToString() });
return Ok(values);
}
Imports IronBarCode
Imports Microsoft.AspNetCore.Mvc
Imports System.IO
Imports System.Threading.Tasks
' ASP.NET endpoint — reads barcodes from an uploaded file
<HttpPost("scan")>
Public Async Function ScanBarcode(file As IFormFile) As Task(Of IActionResult)
Using ms As New MemoryStream()
Await file.CopyToAsync(ms)
Dim results = BarcodeReader.Read(ms.ToArray())
Dim values = results.Select(Function(r) New With {Key .Value = r.Value, Key .Format = r.Format.ToString()})
Return Ok(values)
End Using
End Function
The same package, the same API, the same behavior — on mobile and server.
Generating Barcodes
BarcodeScanning.Native.Maui has no generation API. IronBarcode generates multiple formats.
BarcodeScanning.MAUI Approach:
// No equivalent exists — BarcodeScanning.Native.Maui cannot generate barcodes
// No equivalent exists — BarcodeScanning.Native.Maui cannot generate barcodes
' No equivalent exists — BarcodeScanning.Native.Maui cannot generate barcodes
IronBarcode Approach:
using IronBarCode;
// QR code
QRCodeWriter.CreateQrCode("https://example.com/product/12345", 500)
.SaveAsPng("qr.png");
// Code128 barcode sized to specific dimensions
BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
.ResizeTo(400, 100)
.SaveAsPng("label.png");
// Get bytes for returning from an API or storing in a database
byte[] barcodeBytes = BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
.ToPngBinaryData();
using IronBarCode;
// QR code
QRCodeWriter.CreateQrCode("https://example.com/product/12345", 500)
.SaveAsPng("qr.png");
// Code128 barcode sized to specific dimensions
BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
.ResizeTo(400, 100)
.SaveAsPng("label.png");
// Get bytes for returning from an API or storing in a database
byte[] barcodeBytes = BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
.ToPngBinaryData();
Imports IronBarCode
' QR code
QRCodeWriter.CreateQrCode("https://example.com/product/12345", 500) _
.SaveAsPng("qr.png")
' Code128 barcode sized to specific dimensions
BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128) _
.ResizeTo(400, 100) _
.SaveAsPng("label.png")
' Get bytes for returning from an API or storing in a database
Dim barcodeBytes As Byte() = BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128) _
.ToPngBinaryData()
The IronBarcode generation documentation covers all supported formats and styling options.
BarcodeScanning.MAUI API to IronBarcode Mapping Reference
| BarcodeScanning.Native.Maui | IronBarcode |
|---|---|
CameraView XAML control |
Remove — use Button + MediaPicker.CapturePhotoAsync() |
OnDetectionFinished event |
BarcodeReader.Read(imageBytes) return value |
OnDetectionFinishedEventArg e |
IEnumerable result from BarcodeReader.Read() |
e.BarcodeResults |
Return value of BarcodeReader.Read() |
e.BarcodeResults.FirstOrDefault() |
results.FirstOrDefault() |
barcode.DisplayValue |
result.Value |
barcode.BarcodeFormat |
result.Format |
BarcodeFormats="All" |
Auto-detected — no configuration needed |
CameraEnabled="True" |
await MediaPicker.CapturePhotoAsync() |
| iOS + Android only | iOS, Android, Windows, macOS MAUI |
| No file input | BarcodeReader.Read(filePath) |
| No PDF input | BarcodeReader.Read("document.pdf") |
| No generation | BarcodeWriter.CreateBarcode() / QRCodeWriter.CreateQrCode() |
| iOS UPC-A returns 13 digits | Returns correct 12 digits — no normalization needed |
| PDF417 unreliable | Supported |
Common Migration Issues and Solutions
Issue 1: Live Viewfinder Experience Lost
BarcodeScanning.MAUI: The CameraView control embedded a real-time camera preview directly in the MAUI page. Users could see the camera feed and aim at a barcode — detection happened automatically with no button press.
Solution: MediaPicker.CapturePhotoAsync() shows the platform camera screen instead. For most business workflows this is acceptable. For consumer apps that require a continuous live preview, camera frames can be passed directly to BarcodeReader.Read():
using IronBarCode;
// Continuous scanning: pass camera frame bytes to BarcodeReader.Read()
// (frame capture depends on your MAUI camera frame source)
private void ProcessCameraFrame(byte[] frameBytes)
{
var results = BarcodeReader.Read(frameBytes);
if (results.Any())
{
var first = results.First();
MainThread.BeginInvokeOnMainThread(() =>
ResultLabel.Text = first.Value);
}
}
using IronBarCode;
// Continuous scanning: pass camera frame bytes to BarcodeReader.Read()
// (frame capture depends on your MAUI camera frame source)
private void ProcessCameraFrame(byte[] frameBytes)
{
var results = BarcodeReader.Read(frameBytes);
if (results.Any())
{
var first = results.First();
MainThread.BeginInvokeOnMainThread(() =>
ResultLabel.Text = first.Value);
}
}
Imports IronBarCode
' Continuous scanning: pass camera frame bytes to BarcodeReader.Read()
' (frame capture depends on your MAUI camera frame source)
Private Sub ProcessCameraFrame(frameBytes As Byte())
Dim results = BarcodeReader.Read(frameBytes)
If results.Any() Then
Dim first = results.First()
MainThread.BeginInvokeOnMainThread(Sub()
ResultLabel.Text = first.Value
End Sub)
End If
End Sub
This requires wiring up a camera frame source separately from IronBarcode. Evaluate whether a live preview is genuinely required or whether the system camera UI is sufficient before taking this path.
Issue 2: e.BarcodeResults Property Name and Enum Changes
BarcodeScanning.MAUI: barcode.DisplayValue returns the decoded string; barcode.BarcodeFormat returns a BarcodeScanning library enum value.
Solution: Replace DisplayValue with result.Value and barcode.BarcodeFormat with result.Format. The iteration pattern is the same:
// Before
foreach (var barcode in e.BarcodeResults)
Console.WriteLine(barcode.DisplayValue);
// After
var results = BarcodeReader.Read(imageBytes);
foreach (var result in results)
Console.WriteLine(result.Value);
// Before
foreach (var barcode in e.BarcodeResults)
Console.WriteLine(barcode.DisplayValue);
// After
var results = BarcodeReader.Read(imageBytes);
foreach (var result in results)
Console.WriteLine(result.Value);
' Before
For Each barcode In e.BarcodeResults
Console.WriteLine(barcode.DisplayValue)
Next
' After
Dim results = BarcodeReader.Read(imageBytes)
For Each result In results
Console.WriteLine(result.Value)
Next
Issue 3: Thread Marshaling for UI Updates
BarcodeScanning.MAUI: OnDetectionFinished fires on a background thread, so all UI updates require MainThread.BeginInvokeOnMainThread().
Solution: With the MediaPicker + async pattern, the continuation after await returns on the calling context — typically the main thread. The MainThread.BeginInvokeOnMainThread() wrappers around result display can generally be removed, simplifying the handler code.
Issue 4: MAUI Camera Permissions
BarcodeScanning.MAUI: The package adds camera permissions to AndroidManifest.xml and Info.plist automatically as part of its setup.
Solution: With IronBarcode using MediaPicker, the standard MAUI camera permissions must be present manually. These are the same permissions any MAUI app needs for MediaPicker.CapturePhotoAsync() and are typically already in place. Verify that android.permission.CAMERA is declared in AndroidManifest.xml and NSCameraUsageDescription is set in Info.plist before testing on device.
BarcodeScanning.MAUI Migration Checklist
Pre-Migration Tasks
Run these searches to find all BarcodeScanning.Native.Maui usage before making any changes:
grep -rn "using BarcodeScanning" --include="*.cs" .
grep -rn "using BarcodeScanning" --include="*.xaml" .
grep -rn "CameraView" --include="*.cs" .
grep -rn "CameraView" --include="*.xaml" .
grep -rn "OnDetectionFinished" --include="*.cs" .
grep -rn "OnDetectionFinishedEventArg" --include="*.cs" .
grep -rn "e\.BarcodeResults" --include="*.cs" .
grep -rn "DisplayValue" --include="*.cs" .
grep -rn "BarcodeFormats\.Upca" --include="*.cs" .
grep -rn "scanner:" --include="*.xaml" .
grep -rn "using BarcodeScanning" --include="*.cs" .
grep -rn "using BarcodeScanning" --include="*.xaml" .
grep -rn "CameraView" --include="*.cs" .
grep -rn "CameraView" --include="*.xaml" .
grep -rn "OnDetectionFinished" --include="*.cs" .
grep -rn "OnDetectionFinishedEventArg" --include="*.cs" .
grep -rn "e\.BarcodeResults" --include="*.cs" .
grep -rn "DisplayValue" --include="*.cs" .
grep -rn "BarcodeFormats\.Upca" --include="*.cs" .
grep -rn "scanner:" --include="*.xaml" .
Document each hit. Note which files contain CameraView XAML usage (require XAML changes) versus which contain only code-behind changes. Identify any UPC-A normalization workarounds that must be deleted after migration.
Code Update Tasks
- Remove
BarcodeScanning.Native.MauiNuGet package - Install
IronBarcodeNuGet package - Add
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";inMauiProgram.csorApp.xaml.cs - Replace
using BarcodeScanning;withusing IronBarCode;in all.csfiles - Remove
xmlns:scanner="..."namespace declarations from all XAML files - Replace
scanner:CameraViewcontrols in XAML with aButtontriggeringMediaPicker.CapturePhotoAsync() - Remove
OnDetectionFinished="..."event wiring from XAML - Replace
OnDetectionFinishedevent handlers withasyncbutton click handlers usingBarcodeReader.Read() - Replace
barcode.DisplayValuewithresult.Valuethroughout - Replace
barcode.BarcodeFormatwithresult.Formatthroughout - Delete all
BarcodeFormats.Upca+Substring(1)normalization workarounds - Add
ExpectMultipleBarcodes = truetoBarcodeReaderOptionswhere multi-barcode detection was previously relying one.BarcodeResultsreturning multiple items - Remove
MainThread.BeginInvokeOnMainThread()wrappers from result display code where the async pattern makes them unnecessary - Verify
AndroidManifest.xmlandInfo.plistcamera permissions are present
Post-Migration Testing
- Verify iOS barcode scanning works and UPC-A values are returned as 12-digit strings without leading zeros
- Verify Android barcode scanning produces correct values for all formats used in the application
- Verify Windows MAUI barcode scanning works if Windows is a build target
- Test PDF417 scanning against real shipping labels, driver's licenses, or boarding passes if these are used
- Test multi-barcode scenarios with
ExpectMultipleBarcodes = trueand confirm all barcodes in an image are returned - Verify file picker scanning (
BarcodeReader.Read(filePath)) works on all MAUI targets - Verify PDF barcode reading if this was a new capability added alongside migration
- Confirm server-side
BarcodeReader.Read()produces correct results if a backend component was added - Run any existing automated tests and compare barcode value outputs to pre-migration baselines
Key Benefits of Migrating to IronBarcode
Full Windows MAUI Support: IronBarcode runs on all four MAUI targets — iOS, Android, Windows, and macOS — using the same code and the same package. No platform-specific barcode implementation is needed for Windows, and no #if WINDOWS blocks are required in application code.
Any Input Source: BarcodeReader.Read() accepts file paths, byte arrays, streams, and PDF documents. Any barcode scenario — camera capture, file upload, gallery image, server-side PDF processing — uses the same static method with the same result type.
Correct UPC-A Values: IronBarcode returns the correct 12-digit UPC-A value on iOS without any normalization code in the application. Historical UPC-A data stored with a leading zero due to BarcodeScanning.Native.Maui's behavior does not affect the accuracy of values read after migration.
Reliable PDF417: PDF417 is fully supported and reads reliably. Shipping labels, driver's licenses, and boarding passes scan without the "most scans never occur" limitation documented in BarcodeScanning.Native.Maui's GitHub issues.
Barcode Generation: BarcodeWriter.CreateBarcode() and QRCodeWriter.CreateQrCode() generate Code128, QR, DataMatrix, and other formats as PNG files or byte arrays. Generation and reading are available from the same package with no additional dependency.
Server-Side Deployment: The same BarcodeReader.Read() call runs in ASP.NET, Azure Functions, Docker containers, and AWS Lambda. Mobile and server barcode logic can share the same API, the same format support, and the same result type without maintaining two separate barcode implementations.
Frequently Asked Questions
Why should I migrate from BarcodeScanning.MAUI to IronBarcode?
Common reasons include simplifying licensing (removing SDK + runtime key complexity), eliminating throughput limits, gaining native PDF support, improving Docker/CI/CD deployment, and reducing API boilerplate in production code.
How do I replace BarcodeScanning.MAUI API calls with IronBarcode?
Replace instance creation and licensing boilerplate with IronBarCode.License.LicenseKey = "key". Replace reader calls with BarcodeReader.Read(path) and writer calls with BarcodeWriter.CreateBarcode(data, encoding). Static methods require no instance management.
How much code changes when migrating from BarcodeScanning.MAUI to IronBarcode?
Most migrations result in fewer lines of code. Licensing boilerplate, instance constructors, and explicit format configuration are removed. Core read/write operations map to shorter IronBarcode equivalents with cleaner result objects.
Do I need to keep both BarcodeScanning.MAUI and IronBarcode installed during migration?
No. Most migrations are direct replacements rather than parallel operation. Migrate one service class at a time, replace the NuGet reference, and update the instantiation and API call patterns before moving to the next class.
What is the NuGet package name for IronBarcode?
The package is 'IronBarCode' (with capital B and C). Install it with 'Install-Package IronBarCode' or 'dotnet add package IronBarCode'. The using directive in code is 'using IronBarCode;'.
How does IronBarcode simplify Docker deployment compared to BarcodeScanning.MAUI?
IronBarcode is a NuGet package with no external SDK files or mounted license configuration. In Docker, set the IRONBARCODE_LICENSE_KEY environment variable and the package handles license validation at startup.
Does IronBarcode detect all barcode formats automatically after migrating from BarcodeScanning.MAUI?
Yes. IronBarcode auto-detects symbology across all supported formats. Explicit BarcodeTypes enumeration is not required. If format is already known and performance matters, BarcodeReaderOptions allows restricting the search space as an optimization.
Can IronBarcode read barcodes from PDFs without a separate library?
Yes. BarcodeReader.Read("document.pdf") processes PDF files natively. Results include PageNumber, Format, Value, and Confidence for each barcode found. No external PDF rendering step is required.
How does IronBarcode handle parallel barcode processing?
IronBarcode's static methods are stateless and thread-safe. Use Parallel.ForEach directly over file lists without per-thread instance management. BarcodeReaderOptions.MaxParallelThreads controls the internal thread budget.
What result properties change when migrating from BarcodeScanning.MAUI to IronBarcode?
Common renames: BarcodeValue becomes Value, BarcodeType becomes Format. IronBarcode results also add Confidence and PageNumber. A solution-wide search-and-replace handles the renames in existing result-processing code.
How do I set up IronBarcode licensing in a CI/CD pipeline?
Store IRONBARCODE_LICENSE_KEY as a pipeline secret and assign IronBarCode.License.LicenseKey in application startup code. One secret covers all environments including development, test, staging, and production.
Does IronBarcode support QR code generation with custom styling?
Yes. QRCodeWriter.CreateQrCode() supports custom colors via ChangeBarCodeColor(), logo embedding via AddBrandLogo(), configurable error correction levels, and multiple output formats including PNG, JPG, PDF, and stream.

