Como configurar a correção de erros em C# | IronQR
Migrando de ZXing.Net.MAUI para IronBarcode
Este guia fornece um caminho de migração completo do ZXing .NET.MAUI para o IronBarcode para desenvolvedores .NET MAUI . O documento aborda os motivos pelos quais as equipes realizam essa migração, uma comparação de recursos para embasar a decisão, os passos práticos para substituir o pacote e atualizar os arquivos do projeto, exemplos de código antes e depois para cada padrão de uso principal, uma referência de tradução de API, uma seção de solução de problemas para questões que surgem durante a transição, uma lista de verificação da migração para acompanhar o progresso e um resumo dos resultados que a migração proporciona.
Por que migrar do ZXing .NET para o MAUI?
A decisão de migrar do ZXing .NET.MAUI geralmente é motivada por uma ou mais condições concretas do projeto. Não se tratam de preferências estilísticas — são casos em que a arquitetura ou o estado de conservação da biblioteca impedem que uma exigência seja atendida.
Windows MAUI não é suportado: ZXing .NET.MAUI não possui implementação de câmera para Windows e não há planos públicos para desenvolver uma. A biblioteca é construída em torno das APIs de câmera das plataformas iOS e Android. Se um projeto MAUI adicionar um alvo Windows após a compilação inicial — um padrão comum em equipes que começam com foco em dispositivos móveis — o ZXing .NET.MAUI não poderá atender a esse alvo. Não há solução alternativa, nem alternativa, nem solução falsa.
Problema de Auto-Foco do iPhone 15 Pro: O rastreador de problemas do GitHub para Redth/ZXing.Net.Maui documenta que dispositivos iPhone 15 Pro e Pro Max (iPhone16,1 e iPhone16,2) não conseguem atingir um foco confiável para detecção de códigos de barras ao usar CameraBarcodeReaderView. O código de barras está visível no enquadramento da câmera, mas o sistema de foco automático não trava com nitidez suficiente para que o decodificador extraia um resultado. A única mitigação documentada é instruir o usuário a ajustar manualmente a distância entre o dispositivo e o código de barras — uma instrução que exige uma interação visível com o usuário e paciência, e que não é um resultado aceitável em produção para um fluxo de trabalho principal.
Vazamento de Recursos da Câmera: CameraBarcodeReaderView não implementa IDisposable. Quando o usuário sai de uma página de digitalização, os recursos da câmera não são liberados por meio de um padrão de descarte padrão. A solução documentada é definir IsDetecting = false em OnDisappearing(), o que reduz o impacto mas não libera formalmente a câmera. Aplicativos que navegam frequentemente entre páginas de digitalização acumulam consumo de recursos, o que pode se manifestar como aumento do uso de memória, drenagem da bateria e falhas intermitentes na inicialização da câmera ao retornar à página de digitalização.
Especificação de Formato com Falha Silenciosa: O ZXing .NET.MAUI herda a exigência do ZXing.Net de declarar cada formato de código de barras a ser lido antes do início da leitura. Os formatos omitidos de BarcodeReaderOptions.Formats são silenciosamente ignorados, mesmo quando claramente visíveis no quadro da câmera. Um usuário que aponta o dispositivo para um formato de código de barras que o desenvolvedor não previu não vê nenhum erro — o aplicativo simplesmente não detecta nada. Em ambientes onde os formatos de código de barras são controlados por fornecedores externos, clientes ou sistemas de terceiros, essa falha silenciosa se torna um problema persistente de suporte.
Estabilidade Pré-1.0: ZXing.Net.MAUI é publicado na versão v0.7.4 — um lançamento estável no NuGet, mas ainda pré-1.0 sob versionamento semântico. Mudanças na API da versão menor ainda são possíveis antes de 1.0, o ritmo de correção de bugs depende da disponibilidade dos mantenedores da comunidade, e não há SLA de suporte comercial. Para aplicações empresariais sujeitas a auditorias de dependência ou análise de composição de software, uma biblioteca comunitária pré-1.0 sem suporte comercial pode não passar no processo de aprovação.
O problema fundamental
O problema estrutural é que CameraBarcodeReaderView bloqueia o desenvolvedor em um loop de eventos centrado na câmera com gerenciamento manual do ciclo de vida e uma lista de formatos fixos. Para qualquer coisa além do escaneamento básico de câmera no iOS e Android com formatos de código de barras conhecidos, a arquitetura atinge seu limite:
// ZXing.Net.MAUI: event loop, format list, lifecycle boilerplate on every scan page
public partial class ScannerPage : ContentPage
{
public BarcodeReaderOptions ReaderOptions { get; }
public ScannerPage()
{
InitializeComponent();
ReaderOptions = new BarcodeReaderOptions
{
Formats = BarcodeFormats.QRCode |
BarcodeFormats.Code128 |
BarcodeFormats.Ean13 |
BarcodeFormats.UpcA,
TryHarder = true,
AutoRotate = true
};
BindingContext = this;
}
private void OnBarcodesDetected(object sender, BarcodeDetectionEventArgs e)
{
MainThread.BeginInvokeOnMainThread(() =>
{
foreach (var barcode in e.Results)
ResultLabel.Text = $"{barcode.Format}: {barcode.Value}";
});
CameraView.IsDetecting = false;
}
protected override void OnDisappearing()
{
base.OnDisappearing();
CameraView.IsDetecting = false; // Required — no Dispose() available
}
protected override void OnAppearing()
{
base.OnAppearing();
CameraView.IsDetecting = true;
}
}
// ZXing.Net.MAUI: event loop, format list, lifecycle boilerplate on every scan page
public partial class ScannerPage : ContentPage
{
public BarcodeReaderOptions ReaderOptions { get; }
public ScannerPage()
{
InitializeComponent();
ReaderOptions = new BarcodeReaderOptions
{
Formats = BarcodeFormats.QRCode |
BarcodeFormats.Code128 |
BarcodeFormats.Ean13 |
BarcodeFormats.UpcA,
TryHarder = true,
AutoRotate = true
};
BindingContext = this;
}
private void OnBarcodesDetected(object sender, BarcodeDetectionEventArgs e)
{
MainThread.BeginInvokeOnMainThread(() =>
{
foreach (var barcode in e.Results)
ResultLabel.Text = $"{barcode.Format}: {barcode.Value}";
});
CameraView.IsDetecting = false;
}
protected override void OnDisappearing()
{
base.OnDisappearing();
CameraView.IsDetecting = false; // Required — no Dispose() available
}
protected override void OnAppearing()
{
base.OnAppearing();
CameraView.IsDetecting = true;
}
}
Imports ZXing.Net.MAUI
Public Partial Class ScannerPage
Inherits ContentPage
Public ReadOnly Property ReaderOptions As BarcodeReaderOptions
Public Sub New()
InitializeComponent()
ReaderOptions = New BarcodeReaderOptions With {
.Formats = BarcodeFormats.QRCode Or
BarcodeFormats.Code128 Or
BarcodeFormats.Ean13 Or
BarcodeFormats.UpcA,
.TryHarder = True,
.AutoRotate = True
}
BindingContext = Me
End Sub
Private Sub OnBarcodesDetected(sender As Object, e As BarcodeDetectionEventArgs)
MainThread.BeginInvokeOnMainThread(Sub()
For Each barcode In e.Results
ResultLabel.Text = $"{barcode.Format}: {barcode.Value}"
Next
End Sub)
CameraView.IsDetecting = False
End Sub
Protected Overrides Sub OnDisappearing()
MyBase.OnDisappearing()
CameraView.IsDetecting = False ' Required — no Dispose() available
End Sub
Protected Overrides Sub OnAppearing()
MyBase.OnAppearing()
CameraView.IsDetecting = True
End Sub
End Class
O IronBarcode substitui o loop de eventos por uma única chamada assíncrona ao tocar em um botão, remove completamente a configuração de formato e elimina o gerenciamento do ciclo de vida da página:
// NuGet: dotnet add package IronBarcode
// IronBarcode: stateless, all platforms, auto-detection, no lifecycle boilerplate
using IronBarCode;
public partial class ScannerPage : ContentPage
{
public ScannerPage() => InitializeComponent();
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());
ResultLabel.Text = results.FirstOrDefault()?.Value ?? "No barcode found";
}
// Não OnAppearing / OnDisappearing needed
}
// NuGet: dotnet add package IronBarcode
// IronBarcode: stateless, all platforms, auto-detection, no lifecycle boilerplate
using IronBarCode;
public partial class ScannerPage : ContentPage
{
public ScannerPage() => InitializeComponent();
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());
ResultLabel.Text = results.FirstOrDefault()?.Value ?? "No barcode found";
}
// Não OnAppearing / OnDisappearing needed
}
Imports IronBarCode
Public Partial Class ScannerPage
Inherits ContentPage
Public Sub New()
InitializeComponent()
End Sub
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())
ResultLabel.Text = If(results.FirstOrDefault()?.Value, "No barcode found")
End Using
End Using
End Sub
' Não OnAppearing / OnDisappearing needed
End Class
IronBarcode vs ZXing .NET.MAUI: Comparação de Recursos
| Recurso | ZXing.Net.MAUI | IronBarcode |
|---|---|---|
| Status da versão | Estável, pré-1.0 (v0.7.4) | Lançamento comercial estável |
| iOS PRINCIPAL | Sim (foco do iPhone 15 Pro com defeito) | Sim |
| Android MAUI | Sim (Problemas de compilação da câmera 1.5.0) | Sim |
| Windows MAUI | Não suportado | Sim |
| macOS MAUI | Não suportado | Sim |
| Lado do servidor / ASP.NET Core | Não | Sim |
| Visor da câmera ao vivo | Sim | Não (interface do usuário do sistema MediaPicker) |
| Especificação de formato necessária | Sim | Não (detecção automática, mais de 50 formatos) |
| Gerenciamento do ciclo de vida da câmera | Manual (IsDetectando) | Não aplicável |
| Implementação de Dispose() | Não | Não aplicável — sem estado |
| Foco automático do iPhone 15 Pro | Quebrado (documentado) | Não aplicável |
| Extração de código de barras PDF | Não | Sim |
| Entrada do caminho do arquivo | Não (apenas câmera) | Sim |
| Recuperação de código de barras danificado | Tente com mais afinco, apenas | Sim (com tecnologia de aprendizado de máquina) |
| Geração de código de barras | Sim (via ZXing .NET) | Sim |
| Suporte comercial | None | Sim |
| Licença | MIT (grátis) | Comercial |
Início rápido
Passo 1: Remova ZXing .NET.Maui.Controls e limpe o arquivo MauiProgram.cs.
Remova o pacote NuGet ZXing .NET .MAUI:
dotnet remove package ZXing.Net.Maui.Controls
dotnet remove package ZXing.Net.Maui.Controls
ZXing.Net.MAUI requer uma chamada de registro única em MauiProgram.cs. Remova esta linha se ela estiver presente:
// Remover this line from MauiProgram.cs
builder.UseBarcodeReader();
// Remover this line from MauiProgram.cs
builder.UseBarcodeReader();
A importação using ZXing.Net.Maui; que suporta esta chamada também pode ser removida de MauiProgram.cs.
Passo 2: Instale o IronBarcode
dotnet add package IronBarcode
dotnet add package IronBarcode
O tutorial de scanner de código de barras .NET MAUI cobre a configuração completa do projeto, incluindo entradas de permissão de câmera Info.plist para iOS e declarações de permissão AndroidManifest.xml para Android.
Etapa 3: Atualizar Namespaces e Inicializar Licença
Remova as importações do namespace .NET.MAUI do ZXing de todos os arquivos:
// Remover these from every .cs file that imported them
using ZXing.Net.Maui;
using ZXing.Net.Maui.Controls;
// Remover these from every .cs file that imported them
using ZXing.Net.Maui;
using ZXing.Net.Maui.Controls;
Adicione o namespace IronBarcode e inicialize a chave de licença na inicialização do aplicativo. O local apropriado é MauiProgram.cs ou App.xaml.cs, antes de qualquer operação de código de barras ser realizada:
using IronBarCode;
// In MauiProgram.cs CreateMauiApp() or App.xaml.cs constructor
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
using IronBarCode;
// In MauiProgram.cs CreateMauiApp() or App.xaml.cs constructor
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronBarCode
' In MauiProgram.vb CreateMauiApp() or App.xaml.vb constructor
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
Exemplos de migração de código
Substituindo o controle de câmera XAML e o código subjacente
O controle XAML CameraBarcodeReaderView e seu código de suporte são o principal alvo de migração. A alteração remove a visualização da câmera do layout da página e substitui o padrão de varredura orientado a eventos por uma captura assíncrona acionada por botão.
Abordagem ZXing .NET.MAUI:
XAML:
<ContentPage xmlns:zxing="clr-namespace:ZXing.Net.Maui.Controls;assembly=ZXing.Net.MAUI.Controls">
<StackLayout>
<zxing:CameraBarcodeReaderView
x:Name="CameraView"
Options="{Binding ReaderOptions}"
BarcodesDetected="OnBarcodesDetected"
VerticalOptions="FillAndExpand" />
<Label x:Name="ResultLabel" Text="Scanning..." />
</StackLayout>
</ContentPage>
<ContentPage xmlns:zxing="clr-namespace:ZXing.Net.Maui.Controls;assembly=ZXing.Net.MAUI.Controls">
<StackLayout>
<zxing:CameraBarcodeReaderView
x:Name="CameraView"
Options="{Binding ReaderOptions}"
BarcodesDetected="OnBarcodesDetected"
VerticalOptions="FillAndExpand" />
<Label x:Name="ResultLabel" Text="Scanning..." />
</StackLayout>
</ContentPage>
Código subjacente:
using ZXing.Net.Maui;
using ZXing.Net.Maui.Controls;
public partial class ScannerPage : ContentPage
{
public BarcodeReaderOptions ReaderOptions { get; }
public ScannerPage()
{
InitializeComponent();
ReaderOptions = new BarcodeReaderOptions
{
Formats = BarcodeFormats.QRCode | BarcodeFormats.Code128 | BarcodeFormats.Ean13,
TryHarder = true,
AutoRotate = true
};
BindingContext = this;
}
private void OnBarcodesDetected(object sender, BarcodeDetectionEventArgs e)
{
MainThread.BeginInvokeOnMainThread(() =>
{
foreach (var barcode in e.Results)
ResultLabel.Text = $"{barcode.Format}: {barcode.Value}";
});
CameraView.IsDetecting = false;
}
protected override void OnDisappearing()
{
base.OnDisappearing();
CameraView.IsDetecting = false;
}
protected override void OnAppearing()
{
base.OnAppearing();
CameraView.IsDetecting = true;
}
}
using ZXing.Net.Maui;
using ZXing.Net.Maui.Controls;
public partial class ScannerPage : ContentPage
{
public BarcodeReaderOptions ReaderOptions { get; }
public ScannerPage()
{
InitializeComponent();
ReaderOptions = new BarcodeReaderOptions
{
Formats = BarcodeFormats.QRCode | BarcodeFormats.Code128 | BarcodeFormats.Ean13,
TryHarder = true,
AutoRotate = true
};
BindingContext = this;
}
private void OnBarcodesDetected(object sender, BarcodeDetectionEventArgs e)
{
MainThread.BeginInvokeOnMainThread(() =>
{
foreach (var barcode in e.Results)
ResultLabel.Text = $"{barcode.Format}: {barcode.Value}";
});
CameraView.IsDetecting = false;
}
protected override void OnDisappearing()
{
base.OnDisappearing();
CameraView.IsDetecting = false;
}
protected override void OnAppearing()
{
base.OnAppearing();
CameraView.IsDetecting = true;
}
}
Imports ZXing.Net.Maui
Imports ZXing.Net.Maui.Controls
Public Partial Class ScannerPage
Inherits ContentPage
Public ReadOnly Property ReaderOptions As BarcodeReaderOptions
Public Sub New()
InitializeComponent()
ReaderOptions = New BarcodeReaderOptions With {
.Formats = BarcodeFormats.QRCode Or BarcodeFormats.Code128 Or BarcodeFormats.Ean13,
.TryHarder = True,
.AutoRotate = True
}
BindingContext = Me
End Sub
Private Sub OnBarcodesDetected(sender As Object, e As BarcodeDetectionEventArgs)
MainThread.BeginInvokeOnMainThread(Sub()
For Each barcode In e.Results
ResultLabel.Text = $"{barcode.Format}: {barcode.Value}"
Next
End Sub)
CameraView.IsDetecting = False
End Sub
Protected Overrides Sub OnDisappearing()
MyBase.OnDisappearing()
CameraView.IsDetecting = False
End Sub
Protected Overrides Sub OnAppearing()
MyBase.OnAppearing()
CameraView.IsDetecting = True
End Sub
End Class
Abordagem do IronBarcode:
XAML:
<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>
<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>
Código subjacente:
// NuGet: dotnet add package IronBarcode
using IronBarCode;
public partial class ScannerPage : ContentPage
{
public ScannerPage() => InitializeComponent();
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 != null
? $"{first.Format}: {first.Value}"
: "No barcode found";
}
// Não OnAppearing or OnDisappearing required — no camera state exists between scans
}
// NuGet: dotnet add package IronBarcode
using IronBarCode;
public partial class ScannerPage : ContentPage
{
public ScannerPage() => InitializeComponent();
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 != null
? $"{first.Format}: {first.Value}"
: "No barcode found";
}
// Não OnAppearing or OnDisappearing required — no camera state exists between scans
}
Imports IronBarCode
Public Partial Class ScannerPage
Inherits ContentPage
Public Sub New()
InitializeComponent()
End Sub
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 IsNot Nothing, $"{first.Format}: {first.Value}", "No barcode found")
End Using
End Using
End Sub
' Não OnAppearing or OnDisappearing required — no camera state exists between scans
End Class
O namespace XAML zxing:, a lista de formatos BarcodeReaderOptions, o invólucro MainThread.BeginInvokeOnMainThread() e ambas as substituições de ciclo de vida são eliminados inteiramente. A continuação do método async roda no contexto de chamada — que é a thread principal para um manipulador de eventos de IU — portanto, não é necessário um checkpoint explícito de marshalling de threads.
Removendo a especificação de formato
Qualquer bloco de configuração BarcodeReaderOptions disperso por várias páginas ou cenários de escaneamento na base de código é deletado. O IronBarcode realiza a detecção automática de formatos em todos os mais de 50 formatos suportados, sem necessidade de pré-configuração.
Abordagem ZXing .NET.MAUI:
// ZXing.Net.MAUI: every anticipated format must be listed explicitly
// Formats not listed here will silently fail to detect
var readerOptions = new BarcodeReaderOptions
{
Formats = BarcodeFormats.QRCode |
BarcodeFormats.DataMatrix |
BarcodeFormats.Aztec |
BarcodeFormats.Pdf417 |
BarcodeFormats.Code128 |
BarcodeFormats.Code39 |
BarcodeFormats.Ean13 |
BarcodeFormats.UpcA |
BarcodeFormats.Codabar,
TryHarder = true
};
// ZXing.Net.MAUI: every anticipated format must be listed explicitly
// Formats not listed here will silently fail to detect
var readerOptions = new BarcodeReaderOptions
{
Formats = BarcodeFormats.QRCode |
BarcodeFormats.DataMatrix |
BarcodeFormats.Aztec |
BarcodeFormats.Pdf417 |
BarcodeFormats.Code128 |
BarcodeFormats.Code39 |
BarcodeFormats.Ean13 |
BarcodeFormats.UpcA |
BarcodeFormats.Codabar,
TryHarder = true
};
' ZXing.Net.MAUI: every anticipated format must be listed explicitly
' Formats not listed here will silently fail to detect
Dim readerOptions As New BarcodeReaderOptions With {
.Formats = BarcodeFormats.QRCode Or
BarcodeFormats.DataMatrix Or
BarcodeFormats.Aztec Or
BarcodeFormats.Pdf417 Or
BarcodeFormats.Code128 Or
BarcodeFormats.Code39 Or
BarcodeFormats.Ean13 Or
BarcodeFormats.UpcA Or
BarcodeFormats.Codabar,
.TryHarder = True
}
Abordagem do IronBarcode:
// IronBarcode: no format configuration needed
// All formats are detected automatically on every read call
var results = BarcodeReader.Read(imageBytes);
// Optional: restrict to specific formats for performance tuning (not required for correctness)
var options = new BarcodeReaderOptions
{
ExpectBarcodeTypes = BarcodeEncoding.QRCode | BarcodeEncoding.Code128
};
var tunedResults = BarcodeReader.Read(imageBytes, options);
// IronBarcode: no format configuration needed
// All formats are detected automatically on every read call
var results = BarcodeReader.Read(imageBytes);
// Optional: restrict to specific formats for performance tuning (not required for correctness)
var options = new BarcodeReaderOptions
{
ExpectBarcodeTypes = BarcodeEncoding.QRCode | BarcodeEncoding.Code128
};
var tunedResults = BarcodeReader.Read(imageBytes, options);
Imports IronBarcode
' IronBarcode: no format configuration needed
' All formats are detected automatically on every read call
Dim results = BarcodeReader.Read(imageBytes)
' Optional: restrict to specific formats for performance tuning (not required for correctness)
Dim options As New BarcodeReaderOptions With {
.ExpectBarcodeTypes = BarcodeEncoding.QRCode Or BarcodeEncoding.Code128
}
Dim tunedResults = BarcodeReader.Read(imageBytes, options)
O IronBarcode oferece dicas de formatação para cenários que exigem alto desempenho, mas são opcionais. Um código de barras em um formato não listado em um objeto de opções ainda será detectado e retornado.
Removendo o gerenciamento do ciclo de vida de detecção
Todos os OnAppearing e OnDisappearing substituem que existem para alternar CameraView.IsDetecting são removidos. Se essas substituições de método contiverem outra lógica de ciclo de vida de página, preserve essa lógica e remova apenas as linhas IsDetecting.
Abordagem ZXing .NET.MAUI:
// Required boilerplate on every page — omitting this causes camera resource leaks
protected override void OnDisappearing()
{
base.OnDisappearing();
if (CameraView != null)
CameraView.IsDetecting = false;
}
protected override void OnAppearing()
{
base.OnAppearing();
if (CameraView != null)
CameraView.IsDetecting = true;
}
// Required boilerplate on every page — omitting this causes camera resource leaks
protected override void OnDisappearing()
{
base.OnDisappearing();
if (CameraView != null)
CameraView.IsDetecting = false;
}
protected override void OnAppearing()
{
base.OnAppearing();
if (CameraView != null)
CameraView.IsDetecting = true;
}
' Required boilerplate on every page — omitting this causes camera resource leaks
Protected Overrides Sub OnDisappearing()
MyBase.OnDisappearing()
If CameraView IsNot Nothing Then
CameraView.IsDetecting = False
End If
End Sub
Protected Overrides Sub OnAppearing()
MyBase.OnAppearing()
If CameraView IsNot Nothing Then
CameraView.IsDetecting = True
End If
End Sub
Abordagem do IronBarcode:
// Delete both methods if they contain only IsDetecting management.
// If they contain other logic, remove only the IsDetecting lines and keep the rest.
//IronBarcode is stateless — there is no camera view running between button taps.
// Delete both methods if they contain only IsDetecting management.
// If they contain other logic, remove only the IsDetecting lines and keep the rest.
//IronBarcode is stateless — there is no camera view running between button taps.
' Delete both methods if they contain only IsDetecting management.
' If they contain other logic, remove only the IsDetecting lines and keep the rest.
' IronBarcode is stateless — there is no camera view running between button taps.
Windows MAUI: O mesmo código, sem compilação condicional
Com o ZXing .NET.MAUI, adicionar um alvo Windows a um projeto resultava em falha de compilação ou exigia stubs específicos da plataforma, pois a implementação para Windows nunca havia sido escrita. Com o IronBarcode, o mesmo código que roda no iOS e no Android compila e roda no Windows sem modificações.
Abordagem ZXing .NET.MAUI:
// Windows MAUI: either fails to compile or requires a platform-specific stub
// There is no documented path to Windows support
#if ANDROID || IOS
// ZXing.Net.MAUI scanning — Windows has no implementation
#endif
// Windows MAUI: either fails to compile or requires a platform-specific stub
// There is no documented path to Windows support
#if ANDROID || IOS
// ZXing.Net.MAUI scanning — Windows has no implementation
#endif
Abordagem do IronBarcode:
// NuGet: dotnet add package IronBarcode
// Não platform conditionals — same code runs on iOS, Android, Windows, and macOS
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());
ResultLabel.Text = results.FirstOrDefault()?.Value ?? "No barcode found";
}
// NuGet: dotnet add package IronBarcode
// Não platform conditionals — same code runs on iOS, Android, Windows, and macOS
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());
ResultLabel.Text = results.FirstOrDefault()?.Value ?? "No barcode found";
}
' NuGet: dotnet add package IronBarcode
' Não platform conditionals — same code runs on iOS, Android, Windows, and macOS
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())
ResultLabel.Text = If(results.FirstOrDefault()?.Value, "No barcode found")
End Using
End Using
End Sub
No Windows, MediaPicker.CapturePhotoAsync() mapeia para o seletor de arquivos do Windows, permitindo que o usuário selecione um arquivo de imagem — comportamento apropriado para um ambiente de desktop. O guia de código de barras para desktop do MAUI aborda detalhadamente a configuração do MAUI no Windows e no macOS.
Leitura de código de barras em PDF (Nova funcionalidade)
O ZXing .NET.MAUI não possui uma API para leitura de códigos de barras em documentos PDF. Se este for um novo requisito que a migração possibilita, o seguinte padrão se aplica:
Abordagem ZXing .NET.MAUI:
// ZXing.Net.MAUI: no API for PDF or file-based barcode reading
// Cannot fulfill this requirement — a separate library is required
// ZXing.Net.MAUI: no API for PDF or file-based barcode reading
// Cannot fulfill this requirement — a separate library is required
' ZXing.Net.MAUI: no API for PDF or file-based barcode reading
' Cannot fulfill this requirement — a separate library is required
Abordagem do IronBarcode:
// NuGet: dotnet add package IronBarcode
using IronBarCode;
// Read all barcodes from all pages of a PDF
var pdfResults = BarcodeReader.Read("invoice.pdf");
foreach (var barcode in pdfResults)
Console.WriteLine($"Page {barcode.PageNumber}: {barcode.Format} — {barcode.Value}");
// Read from a user-selected file using MAUI 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 fileResults = BarcodeReader.Read(file.FullPath);
foreach (var result in fileResults)
ResultLabel.Text += $"\n{result.Format}: {result.Value}";
}
// NuGet: dotnet add package IronBarcode
using IronBarCode;
// Read all barcodes from all pages of a PDF
var pdfResults = BarcodeReader.Read("invoice.pdf");
foreach (var barcode in pdfResults)
Console.WriteLine($"Page {barcode.PageNumber}: {barcode.Format} — {barcode.Value}");
// Read from a user-selected file using MAUI 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 fileResults = BarcodeReader.Read(file.FullPath);
foreach (var result in fileResults)
ResultLabel.Text += $"\n{result.Format}: {result.Value}";
}
Imports IronBarCode
' Read all barcodes from all pages of a PDF
Dim pdfResults = BarcodeReader.Read("invoice.pdf")
For Each barcode In pdfResults
Console.WriteLine($"Page {barcode.PageNumber}: {barcode.Format} — {barcode.Value}")
Next
' Read from a user-selected file using MAUI 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 fileResults = BarcodeReader.Read(file.FullPath)
For Each result In fileResults
ResultLabel.Text &= $"\n{result.Format}: {result.Value}"
Next
End Sub
O fluxo de trabalho completo de leitura de códigos de barras em PDF — incluindo documentos com várias páginas, metadados de número de página e documentos com formatos mistos — está documentado no guia de leitura de códigos de barras em PDF .
Referência de mapeamento da API .NET.MAUI do ZXing para o IronBarcode
| ZXing.Net.MAUI | IronBarcode | Notas |
|---|---|---|
builder.UseBarcodeReader() |
Não é necessário | Remova de MauiProgram.cs |
using ZXing.Net.Maui; |
using IronBarCode; |
Substituição de namespace |
using ZXing.Net.Maui.Controls; |
Não é necessário | Remover |
xmlns:zxing="clr-namespace:ZXing.Net.Maui.Controls;..." |
Não é necessário | Remover do XAML |
<zxing:CameraBarcodeReaderView> |
<Button> + MediaPicker.CapturePhotoAsync() |
Substituição arquitetônica |
Options="{Binding ReaderOptions}" |
Não é necessário | Remover a ligação |
BarcodesDetected="OnBarcodesDetected" |
valor de retorno BarcodeReader.Read() |
Evento → retorno assíncrono |
new BarcodeReaderOptions { Formats = BarcodeFormats.X \| ... } |
Não é necessário | A detecção automática substitui as listas de formatação. |
BarcodeDetectionEventArgs e |
IEnumerable<BarcodeResult> |
Entrega de resultados diferenciada |
e.Results |
Valor de retorno de BarcodeReader.Read() |
|
barcode.Value |
result.Value |
Mesmo nome de propriedade |
barcode.Format |
result.Format |
Mesmo nome de propriedade |
BarcodeFormats.QRCode |
BarcodeEncoding.QRCode |
Renomear Enum |
BarcodeFormats.Code128 |
BarcodeEncoding.Code128 |
Renomear Enum |
BarcodeFormats.Ean13 |
BarcodeEncoding.EAN13 |
Renomear Enum |
BarcodeFormats.UpcA |
BarcodeEncoding.UPCA |
Renomear Enum |
CameraView.IsDetecting = false |
Não é necessário | Remova de OnDisappearing |
CameraView.IsDetecting = true |
Não é necessário | Remova de OnAppearing |
| Sem API de entrada de arquivos | BarcodeReader.Read("path/to/image.png") |
Nova capacidade |
| Sem API de entrada de PDF | BarcodeReader.Read("document.pdf") |
Nova capacidade |
| Somente para iOS e Android | iOS, Android, Windows, macOS, servidor | Expansão da plataforma |
Problemas e soluções comuns em migrações
Problema 1: Não existe equivalente ao visor eletrônico
ZXing.Net.MAUI: O CameraBarcodeReaderView exibe um feed contínuo de câmera no layout da página, mostrando ao usuário uma pré-visualização ao vivo com feedback de escaneamento sobreposto.
Solução: O IronBarcode não oferece um controle de visualização em tempo real. O padrão de substituição usa MediaPicker.CapturePhotoAsync(), que abre a IU da câmera de sistema da plataforma. A câmera do sistema oferece sua própria pré-visualização ao vivo e indicador de foco. Depois que o usuário captura a imagem e confirma, o resultado é passado para BarcodeReader.Read(). Se um observador persistente no aplicativo for um elemento de UX necessário que não pode ser substituído pela IU da câmera do sistema, a camada de integração da câmera deve ser construída separadamente usando Microsoft.Maui.Media ou APIs de câmera da plataforma, com IronBarcode lidando com a etapa de decodificação.
Questão 2: Declarações de permissão para uso da câmera
ZXing .NET.MAUI: As permissões da câmera podem ter sido declaradas no projeto como parte das instruções de configuração do ZXing .NET.MAUI.
Solução: Permissões de câmera permanecem necessárias para a chamada MediaPicker.CapturePhotoAsync() que o padrão MAUI do IronBarcode usa. Verifique se NSCameraUsageDescription está presente em Info.plist para iOS e se <uses-permission android:name="android.permission.CAMERA" /> está presente em AndroidManifest.xml para Android. O próprio IronBarcode não acessa a câmera diretamente — ele processa imagens — mas a chamada MediaPicker que fornece imagens requer permissão da câmera. A configuração de permissões é abordada no tutorial do leitor de código de barras .NET MAUI .
Problema 3: A compilação para Windows agora é bem-sucedida onde antes falhava.
ZXing .NET.MAUI: Projetos que tentavam incluir um alvo Windows com ZXing .NET.MAUI normalmente encontravam erros de compilação ou exigiam que a biblioteca fosse excluída da compilação do Windows por meio de lógica condicional do MSBuild.
Solução: Após remover o ZXing .NET.MAUI e instalar o IronBarcode, a compilação do MAUI para Windows é bem-sucedida sem quaisquer condições de plataforma. Remova qualquer #if ANDROID || As proteções do iOS foram colocadas em torno das chamadas .NET.MAUI do ZXing para excluí-las da compilação do Windows. A chamada BarcodeReader.Read() do IronBarcode compila e roda em todas as estruturas alvo. Se MediaPicker.CapturePhotoAsync() foi excluído das construções do Windows, essa exclusão também pode ser removida — o método é suportado noWindows MAUIe mapeia para o seletor de arquivos. Verifique se a solução completa é compilada sem erros para todas as estruturas de destino após a remoção das condições.
Edição 4: Referências da enumeração BarcodeFormats
ZXing.Net.MAUI: O enum BarcodeFormats de ZXing.Net.Maui é extensivamente utilizado em configurações BarcodeReaderOptions. Após a remoção do pacote, quaisquer referências restantes geram erros de compilação.
Solução: Delete todos os blocos de inicialização BarcodeReaderOptions que foram usados para configurar listas de formatos. O IronBarcode não exige especificação de formato para funcionar corretamente. Se algum código restante faz referência aos valores BarcodeFormats para fins de log, exibição ou comparação, substitua-os por valores BarcodeEncoding do namespace IronBarCode. Execute grep -rn "BarcodeFormats\." --include="*.cs" . para encontrar todas as referências restantes após a remoção do pacote.
Lista de verificação para migração do ZXing .NET.MAUI
Tarefas pré-migração
Antes de fazer alterações, verifique toda a utilização do .NET.MAUI do ZXing no código-fonte:
grep -rn "ZXing.Net.Maui" --include="*.cs" --include="*.xaml" .
grep -rn "CameraBarcodeReaderView" --include="*.cs" --include="*.xaml" .
grep -rn "BarcodeDetectionEventArgs" --include="*.cs" .
grep -rn "BarcodeReaderOptions" --include="*.cs" .
grep -rn "BarcodeFormats\." --include="*.cs" .
grep -rn "IsDetecting" --include="*.cs" .
grep -rn "UseBarcodeReader" --include="*.cs" .
grep -rn "zxing:" --include="*.xaml" .
grep -rn "e\.Results" --include="*.cs" .
grep -rn "ZXing.Net.Maui" --include="*.cs" --include="*.xaml" .
grep -rn "CameraBarcodeReaderView" --include="*.cs" --include="*.xaml" .
grep -rn "BarcodeDetectionEventArgs" --include="*.cs" .
grep -rn "BarcodeReaderOptions" --include="*.cs" .
grep -rn "BarcodeFormats\." --include="*.cs" .
grep -rn "IsDetecting" --include="*.cs" .
grep -rn "UseBarcodeReader" --include="*.cs" .
grep -rn "zxing:" --include="*.xaml" .
grep -rn "e\.Results" --include="*.cs" .
Documente todas as páginas digitalizadas identificadas pela auditoria. Note quais substituições OnAppearing e OnDisappearing contêm apenas gerenciamento IsDetecting (a serem deletadas) versus aquelas que contêm outras lógicas (a serem parcialmente modificadas). Note quaisquer instâncias de BarcodeReaderOptions que possam conter listas de formatos usadas de formas além da configuração de detecção.
Tarefas de atualização de código
- Remova o pacote NuGet
ZXing.Net.Maui.Controlsdo arquivo de projeto - Remova
builder.UseBarcodeReader()deMauiProgram.cs - Remova as importações de namespaces
using ZXing.Net.Maui;eusing ZXing.Net.Maui.Controls;de todos os arquivos - Instale o pacote NuGet
IronBarcode - Adicione
using IronBarCode;a todos os arquivos que irão utilizar leitura de código de barras - Adicione
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";no início do aplicativo - Remova a declaração do namespace
xmlns:zxingde todos os arquivos XAML - Remova todos os elementos
<zxing:CameraBarcodeReaderView>dos arquivos XAML - Substitua a visualização da câmera removida por um controle
<Button>em cada arquivo XAML - Adicione
Clicked="ScanButton_Clicked"a cada botão de escaneamento - Exclua os métodos do manipulador de eventos
OnBarcodesDetectedde todos os arquivos de código-behind - Adicione métodos
async void ScanButton_ClickedimplementandoMediaPicker.CapturePhotoAsync()+BarcodeReader.Read()a cada página - Apague todos os blocos de inicialização
BarcodeReaderOptions - Apague todas as substituições
OnDisappearingeOnAppearingque existem apenas para gerenciamentoIsDetecting - Remova as linhas
IsDetectingde qualquer substituiçãoOnDisappearingeOnAppearingque contenham outras lógicas - Remova qualquer
#if ANDROID|| Mecanismos de proteção de compilação condicional do iOS que isolavam a compilação do .NET.MAUI do ZX das compilações do Windows. - Substitua qualquer referência restante ao enum
BarcodeFormats.Xpor equivalentesBarcodeEncoding.X
Testes pós-migração
Após a migração ser compilada sem erros, verifique o seguinte:
- Android MAUI: o botão de leitura abre a câmera do sistema, captura uma foto e retorna o código de barras correto — confirme com o guia de leitura do Android.
- iOS MAUI: o mesmo fluxo funciona no iOS, inclusive no hardware do iPhone 15 Pro, onde o problema de foco automático ocorria anteriormente.
- Windows MAUI: a versão para Windows compila sem erros e o botão de digitalização abre o seletor de arquivos e retorna um resultado correto da imagem selecionada.
- Formatos: teste a leitura de códigos de barras em formatos que não foram incluídos na lista antiga
BarcodeFormatspara confirmar a autodetecção - Navegação entre páginas: navegue até a página de digitalização e retorne a ela várias vezes e verifique se não ocorrem falhas no crescimento da memória ou na inicialização da câmera.
- Leitura de PDF: se a migração adicionar a leitura de código de barras em PDF como uma nova funcionalidade, verifique se os PDFs com várias páginas retornam resultados com os metadados de número de página corretos.
Principais benefícios da migração para o IronBarcode
Cobertura de plataforma expandida: após a migração, o aplicativo oferece suporte a plataformas MAUI para Windows e macOS, além de iOS e Android — tudo a partir do mesmo pacote e do mesmo padrão de verificação. Projetos que anteriormente exigiam stubs específicos para cada plataforma ou excluíam o Windows da funcionalidade de código de barras agora possuem cobertura completa sem código adicional.
Confiabilidade de Hardware de Última Geração: A abordagem de captura de imagem por meio de MediaPicker e BarcodeReader.Read() não é afetada pelo modelo de autofoco CameraBarcodeReaderView que falha no hardware do iPhone 15 Pro e Pro Max. A câmera do sistema gerencia o foco de forma independente, e o IronBarcode processa a imagem capturada após o usuário confirmar a foto.
Eliminação do Gerenciamento de Recursos da Câmera: Remover CameraBarcodeReaderView elimina toda a categoria de bugs de vazamento de recursos da câmera. Não há estado IsDetecting a rastrear, nem boilerplate de OnAppearing e OnDisappearing a manter em cada página de escaneamento, e nem acumulação de recursos da câmera em ciclos de navegação. A API sem estado torna as páginas de varredura indistinguíveis de qualquer outra página em termos de ciclo de vida do recurso.
Cobertura de formatos sem configuração: qualquer formato de código de barras encontrado em campo é detectado automaticamente. Falhas de escaneamento causadas por entradas ausentes em uma lista BarcodeFormats são eliminadas. As solicitações de suporte de usuários cujos códigos de barras foram ignorados silenciosamente porque um fornecedor alterou o formato da etiqueta deixaram de ocorrer.
Processamento de Arquivos e Documentos: A migração possibilita a leitura de códigos de barras em documentos PDF, arquivos de imagem e fluxos de bytes sem a necessidade de bibliotecas adicionais. Fluxos de trabalho que antes estavam fora do escopo do ZXing.Net.MAUI — leitura de códigos de barras de faturas enviadas, processamento de ingressos digitais, escaneamento em lote de diretórios de imagens — se tornam disponíveis através da mesma chamada BarcodeReader.Read() usada para capturas de câmera.
Estabilidade de nível de produção: o IronBarcode é distribuído como uma versão comercial estável com um ritmo de desenvolvimento ativo, suporte comercial e atualizações regulares que acompanham os lançamentos da versão .NET . Auditorias de dependências, análises de composição de software e processos de aprovação Enterprise encontram uma biblioteca com suporte e um compromisso de manutenção documentado, em vez de um pacote de pré-lançamento da comunidade.
Perguntas frequentes
Por que devo migrar do ZXing.Net.MAUI para o IronBarcode?
Entre os motivos comuns estão a simplificação do licenciamento (removendo a complexidade do SDK e da chave de tempo de execução), a eliminação dos limites de taxa de transferência, a obtenção de suporte nativo para PDF, a melhoria da implantação em Docker/CI/CD e a redução do código repetitivo da API em produção.
Como faço para substituir as chamadas da API ZXing.Net.MAUI pelo IronBarcode?
Substitua o código padrão de criação de instâncias e licenciamento por `IronBarCode.License.LicenseKey = "key"`. Substitua as chamadas de leitura por `BarcodeReader.Read(path)` e as chamadas de gravação por `BarcodeWriter.CreateBarcode(data, encoding)`. Os métodos estáticos não exigem gerenciamento de instâncias.
Quanta alteração de código ocorre ao migrar do ZXing.Net.MAUI para o IronBarcode?
A maioria das migrações resulta em menos linhas de código. O código repetitivo de licenciamento, os construtores de instância e a configuração explícita de formato são removidos. As operações principais de leitura/gravação são mapeadas para equivalentes mais curtos em IronBarcode, com objetos de resultado mais limpos.
Preciso manter o ZXing.Net.MAUI e o IronBarcode instalados durante a migração?
Não. A maioria das migrações são substituições diretas, e não operações paralelas. Migre uma classe de serviço por vez, substitua a referência do NuGet e atualize os padrões de instanciação e chamada de API antes de passar para a próxima classe.
Qual é o nome do pacote NuGet para IronBarcode?
O pacote é 'IronBarCode' (com B e C maiúsculos). Instale-o com 'Install-Package IronBarCode' ou 'dotnet add package IronBarCode'. A diretiva using no código é 'using IronBarCode;'.
Como o IronBarcode simplifica a implantação do Docker em comparação com o ZXing.Net.MAUI?
IronBarcode é um pacote NuGet sem arquivos SDK externos ou configuração de licença montada. No Docker, defina a variável de ambiente IRONBARCODE_LICENSE_KEY e o pacote cuidará da validação da licença na inicialização.
O IronBarcode detecta automaticamente todos os formatos de código de barras após a migração do ZXing.Net.MAUI?
Sim. O IronBarcode detecta automaticamente a simbologia em todos os formatos suportados. A enumeração explícita de BarcodeTypes não é necessária. Se o formato já for conhecido e o desempenho for importante, o BarcodeReaderOptions permite restringir o espaço de busca como uma otimização.
O IronBarcode consegue ler códigos de barras de PDFs sem uma biblioteca separada?
Sim. O método `BarcodeReader.Read("document.pdf")` processa arquivos PDF nativamente. Os resultados incluem o número da página, o formato, o valor e a confiança de cada código de barras encontrado. Não é necessária nenhuma etapa externa de renderização de PDF.
Como o IronBarcode lida com o processamento paralelo de códigos de barras?
Os métodos estáticos do IronBarcode são sem estado e thread-safe. Use Parallel.ForEach diretamente em listas de arquivos sem gerenciamento de instâncias por thread. BarcodeReaderOptions.MaxParallelThreads controla o orçamento interno de threads.
Quais propriedades de resultado são alteradas ao migrar do ZXing.Net.MAUI para o IronBarcode?
Renomeações comuns: BarcodeValue torna-se Value, BarcodeType torna-se Format. Os resultados do IronBarcode também incluem Confidence e PageNumber. Uma função de busca e substituição em toda a solução lida com as renomeações no código de processamento de resultados existente.
Como configuro o licenciamento do IronBarcode em um pipeline de CI/CD?
Armazene IRONBARCODE_LICENSE_KEY como um segredo de pipeline e atribua IronBarCode.License.LicenseKey no código de inicialização do aplicativo. Um único segredo abrange todos os ambientes, incluindo desenvolvimento, teste, homologação e produção.
O IronBarcode suporta a geração de códigos QR com estilos personalizados?
Sim. O método QRCodeWriter.CreateQrCode() suporta cores personalizadas através do método ChangeBarCodeColor(), incorporação de logotipo através do método AddBrandLogo(), níveis configuráveis de correção de erros e múltiplos formatos de saída, incluindo PNG, JPG, PDF e fluxo de dados.

