C#で誤り訂正を設定する方法 | IronQR
ZXing.Net.MAUIからIronBarcodeへの移行
このガイドでは、.NET MAUI開発者向けに、ZXing .NET.MAUIからIronBarcodeへの完全な移行手順を提供します。 このドキュメントでは、チームがこの移行を実施する理由、意思決定の枠組みとなる機能比較、パッケージの置き換えとプロジェクトファイルの更新を行うための手順、主要な使用パターンごとに移行前後のコード例、API変換リファレンス、移行中に発生する問題への対処方法、進捗状況を追跡するための移行チェックリスト、および移行によって得られる成果の概要について説明します。
ZXing .NET.MAUIから移行する理由
ZXing .NET.MAUIからの移行を決定するきっかけとなるのは、通常、1つまたは複数の具体的なプロジェクト条件です。 これらはスタイルの好みの問題ではなく、図書館の建築構造やメンテナンス状況によって要件を満たすことができないケースである。
Windows MAUI はサポートされていません: ZXing .NET.MAUI には Windows カメラの実装がなく、実装する予定もありません。 このライブラリは、iOSおよびAndroidプラットフォームのカメラAPIを中心に構築されています。MAUIプロジェクトが最初のビルド後にWindowsターゲットを追加した場合(モバイルファーストで開発を始めるチームではよくあるパターンです)、ZXing .NET.MAUIはそのターゲットに全く対応できません。 スタブも、フォールバックも、回避策もありません。
iPhone 15 Pro オートフォーカス問題: Redth/ZXing.Net.Maui のGitHub課題トラッカーは、iPhone 15 ProとPro Maxデバイス(iPhone16,1 および iPhone16,2)が CameraBarcodeReaderView を使用する際に、バーコード検出のための信頼性のあるフォーカスを達成できないことを文書化しています。 バーコードはカメラのフレーム内に写っているが、オートフォーカスシステムがデコーダーが結果を抽出できるほど正確にピントを合わせられない。 唯一文書化されている対策は、デバイスとバーコード間の距離をユーザーに手動で調整するように指示することですが、この指示には視覚的に分かりやすいUX上の工夫とユーザーの忍耐力が必要であり、主要なワークフローにおける許容できる生産結果とは言えません。
カメラリソースリーク: CameraBarcodeReaderView は IDisposable を実装していません。 ユーザーがスキャンページから移動しても、カメラのリソースは標準的な解放パターンでは解放されません。 文書化された回避策は、IsDetecting = false を OnDisappearing() に設定することで、この影響を減少させるものの、カメラを正式に解放するものではありません。 スキャンページへの頻繁なアクセスとスキャンページからの離脱を繰り返すアプリケーションは、リソース消費が蓄積され、メモリ使用量の増加、バッテリーの消耗、スキャンページに戻った際のカメラの初期化エラーといった問題が発生する可能性があります。
フォーマット指定のサイレントエラー: ZXing .NET.MAUI は、スキャンを開始する前にスキャンするすべてのバーコードフォーマットを宣言するという ZXing.Net の要件を継承しています。 BarcodeReaderOptions.Formats から省略されたフォーマットは、カメラフレームに明確に見えていても静かに無視されます。 開発者が想定していなかったバーコード形式にデバイスを向けた場合でも、エラーは表示されず、アプリケーションは何も検出しない。 バーコード形式が外部のサプライヤー、顧客、またはサードパーティシステムによって管理されている環境では、この見落としが継続的なサポート上の問題となる。
プレ1.0安定性: ZXing.Net.MAUIはバージョン0.7.4で公開されています — NuGetの安定リリースですが、セマンティックバージョニングではまだ1.0未満です。 マイナーバージョンAPIの変更は1.0以前の可能性があり、バグ修正頻度はコミュニティメンテナーの可用性に依存し、商業サポートのSLAはありません。 依存レビューやソフトウェア構成分析を受けるエンタープライズアプリケーションにとって、商業サポートのないコミュニティのプレ1.0ライブラリは承認プロセスをクリアできない可能性があります。
基本的な問題
構造的な問題は、CameraBarcodeReaderView が開発者をカメラ中心のイベントループにロックし、手動ライフサイクル管理と固定フォーマットリストを強制することです。iOSおよびAndroidでの基本的なカメラスキャンを超え、既知のバーコードフォーマットを使用する場合、このアーキテクチャはその限界に達します。
// 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
IronBarcodeは、イベントループをボタンタップ時の単一の非同期呼び出しに置き換え、フォーマット設定を完全に削除し、ページからライフサイクル管理を排除します。
// 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";
}
// なし 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";
}
// なし 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
' なし OnAppearing / OnDisappearing needed
End Class
IronBarcodeとZXing .NET.MAUI:機能比較
| フィーチャー | ZXing.Net.MAUI | IronBarcode |
|---|---|---|
| リリース状況 | 安定、プレ1.0 (v0.7.4) | 安定した商業リリース |
| iOS MAUI | はい(iPhone 15 Proのフォーカス機能が故障しています) | はい |
| アンドロイド MAUI | はい(カメラ1.5.0のビルドに関する問題) | はい |
| Windows MAUI | サポートされていません | はい |
| macOS MAUI | サポートされていません | はい |
| サーバーサイド / ASP.NET Core | なし | はい |
| ライブカメラビューファインダー | はい | いいえ(MediaPickerシステムUI) |
| フォーマット指定が必要です | はい | いいえ(自動検出、50種類以上のフォーマットに対応) |
| カメラのライフサイクル管理 | 手動(検出中) | 該当なし |
| Dispose() の実装 | なし | 該当なし — 無国籍 |
| iPhone 15 Proのオートフォーカス | 破損(記録あり) | 該当なし |
| PDFバーコード抽出 | なし | はい |
| ファイルパスの入力 | いいえ(カメラのみ) | はい |
| 破損したバーコードの復旧 | TryHarderのみ | はい(機械学習搭載) |
| バーコード生成 | はい(.NET経由) | はい |
| 商用サポート | None | はい |
| ライセンス | MIT (無料) | 商用 |
クイックスタート
ステップ 1: ZXing .NET.Maui.Controls を削除し、MauiProgram.cs をクリーンアップします
ZXing .NET.MAUI NuGetパッケージを削除します。
dotnet remove package ZXing.Net.Maui.Controls
dotnet remove package ZXing.Net.Maui.Controls
ZXing.Net.MAUIはMauiProgram.csでの一度限りの登録呼び出しを必要とします。 この行が存在する場合は削除してください。
// 取り除く this line from MauiProgram.cs
builder.UseBarcodeReader();
// 取り除く this line from MauiProgram.cs
builder.UseBarcodeReader();
この呼び出しをサポートするMauiProgram.csから削除することもできます。
ステップ2: IronBarcodeをインストールする
dotnet add package IronBarcode
dotnet add package IronBarcode
.NET MAUI バーコードスキャナーチュートリアルは、iOSのAndroidManifest.xml許可宣言を含む、プロジェクトの完全な設定について解説しています。
ステップ3:名前空間を更新し、ライセンスを初期化する
すべてのファイルからZXing .NET.MAUI名前空間のインポートを削除します。
// 取り除く these from every .cs file that imported them
using ZXing.Net.Maui;
using ZXing.Net.Maui.Controls;
// 取り除く these from every .cs file that imported them
using ZXing.Net.Maui;
using ZXing.Net.Maui.Controls;
Imports ZXing.Net.Maui
Imports ZXing.Net.Maui.Controls
IronBarcode名前空間を追加し、アプリケーションの起動時にライセンスキーを初期化します。適切な場所は、App.xaml.csで、バーコード操作を行う前に設定してください。
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"
コード移行の例
XAMLカメラコントロールとコードビハインドの置き換え
CameraBarcodeReaderView XAML コントロールとそのサポートコードビハインドは、主要な移行対象です。 この変更により、ページレイアウトからカメラビューが削除され、イベント駆動型のスキャンパターンがボタン操作による非同期キャプチャに置き換えられます。
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>
コードビハインド:
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
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>
コードビハインド:
// 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";
}
// なし 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";
}
// なし 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 = 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
' なし OnAppearing or OnDisappearing required — no camera state exists between scans
End Class
zxing: XAML名前空間、MainThread.BeginInvokeOnMainThread()ラッパー、および両方のライフサイクルオーバーライドは完全に削除されます。 asyncメソッドの継続は、呼び出しコンテキストで実行されます。これはUIのイベントハンドラの場合はメインスレッドであるため、明示的なスレッド委譲は不要です。
フォーマット指定の削除
コードベース内の複数のページまたはスキャンシナリオに散在するBarcodeReaderOptions設定ブロックは削除されます。 IronBarcodeは、事前設定なしで、サポートされている50種類以上のフォーマットすべてにおいて、フォーマットの自動検出を実行します。
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
}
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)
IronBarcodeには、パフォーマンスが重視されるシナリオ向けにフォーマットヒントが用意されていますが、これはオプションです。 オプションオブジェクトに記載されていない形式のバーコードも検出され、返されます。
IsDetectingライフサイクル管理の削除
CameraView.IsDetectingを切り替えるために存在するものはすべて削除されます。 それらのメソッドオーバーライドに他のページのライフサイクルロジックが含まれている場合は、そのロジックを保持し、IsDetecting行だけを削除します。
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
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:同じコード、条件付きコンパイルなし
ZXing .NET.MAUI では、Windows の実装が記述されていないため、プロジェクトに Windows ターゲットを追加すると、コンパイルに失敗するか、プラットフォーム固有のスタブが必要になりました。 IronBarcodeを使えば、iOSやAndroidで動作するコードを、変更を加えることなくWindows上でコンパイルして実行できます。
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
IronBarcodeのアプローチ:
// NuGet: dotnet add package IronBarcode
// なし 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
// なし 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
' なし 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
Windowsでは、MediaPicker.CapturePhotoAsync()がWindowsファイルピッカーにマッピングされ、ユーザーが画像ファイルを選択できるようにします。これはデスクトップ環境に適した動作です。 MAUIデスクトップバーコードガイドでは、WindowsおよびmacOSにおけるMAUIの設定方法を詳細に解説しています。
PDFバーコード読み取り機能(新機能)
ZXing .NET.MAUIには、PDFドキュメントからバーコードを読み取るためのAPIがありません。 これが移行によって可能になる新しい要件である場合、次のパターンが適用されます。
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
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
複数ページの文書、ページ番号メタデータ、および混合形式の文書を含む、PDFバーコード読み取りの完全なワークフローは、 "PDFからバーコードを読み取る"ガイドに記載されています。
ZXing .NET.MAUI API からIronBarcodeへのマッピング リファレンス
| ZXing.Net.MAUI | IronBarcode | ノート | |
|---|---|---|---|
builder.UseBarcodeReader() |
不要 | MauiProgram.cs から削除 |
|
using ZXing.Net.Maui; |
using IronBarCode; |
名前空間の置換 | |
using ZXing.Net.Maui.Controls; |
不要 | 取り除く | |
xmlns:zxing="clr-namespace:ZXing.Net.Maui.Controls;..." |
不要 | XAMLから削除 | |
<zxing:CameraBarcodeReaderView> |
<Button> + MediaPicker.CapturePhotoAsync() |
建築物の交換 | |
Options="{Binding ReaderOptions}" |
不要 | バインディングを外す | |
BarcodesDetected="OnBarcodesDetected" |
BarcodeReader.Read() 戻り値 |
イベント → 非同期リターン | |
| 新しい BarcodeReaderOptions { Formats = BarcodeFormats.X . | ... }` | 不要 | 自動検出によりフォーマットリストが置き換えられます |
BarcodeDetectionEventArgs e |
IEnumerable<BarcodeResult> |
異なる結果の伝達 | |
e.Results |
BarcodeReader.Read() の戻り値 |
||
barcode.Value |
result.Value |
同じプロパティ名 | |
barcode.Format |
result.Format |
同じプロパティ名 | |
BarcodeFormats.QRCode |
BarcodeEncoding.QRCode |
列挙型の名前変更 | |
BarcodeFormats.Code128 |
BarcodeEncoding.Code128 |
列挙型の名前変更 | |
BarcodeFormats.Ean13 |
BarcodeEncoding.EAN13 |
列挙型の名前変更 | |
BarcodeFormats.UpcA |
BarcodeEncoding.UPCA |
列挙型の名前変更 | |
CameraView.IsDetecting = false |
不要 | OnDisappearing から削除 |
|
CameraView.IsDetecting = true |
不要 | OnAppearing から削除 |
|
| ファイル入力APIがありません | BarcodeReader.Read("path/to/image.png") |
新機能 | |
| PDF入力APIなし | BarcodeReader.Read("document.pdf") |
新機能 | |
| iOSとAndroidのみ | iOS、Android、Windows、macOS、サーバー | プラットフォーム拡張 |
一般的な移行の問題と解決策
問題点1:ライブビューファインダーに相当する機能がない
ZXing.Net.MAUI: CameraBarcodeReaderViewは、ページレイアウトで連続したカメラフィードを表示し、ユーザーにオーバーレイされたスキャンフィードバックとともにライブプレビューを提供します。
解決策: IronBarcodeにはライブビューファインダーコントロール機能がありません。 置換パターンはMediaPicker.CapturePhotoAsync()を使用しており、プラットフォームシステムのカメラUIを開きます。 システムカメラは独自のライブプレビュー機能とフォーカスインジケーターを備えています。 ユーザーが画像をキャプチャし、確認すると、その結果がBarcodeReader.Read()に渡されます。 アプリ内ビューファインダーが必要なUX要素であり、システムカメラUIで置き換えることができない場合は、カメラインテグレーションレイヤーをMicrosoft.Maui.MediaまたはプラットフォームカメラAPIを使用して別途構築し、IronBarcodeがデコード手順を処理する必要があります。
第2号:カメラ使用許可宣言
ZXing .NET.MAUI:カメラのアクセス許可は、ZXing .NET.MAUI のセットアップ手順の一部としてプロジェクト内で宣言されている可能性があります。
解決策: カメラ許可は、IronBarcodeのMAUIパターンが使用するMediaPicker.CapturePhotoAsync()呼び出しにとって依然として必要です。 iOSのAndroidManifest.xmlに存在することを確認します。 IronBarcode自体はカメラに直接アクセスしません—画像を処理します—が、画像を提供するためにMediaPicker呼び出しがカメラの許可を必要とします。 権限設定については、 .NET MAUIバーコードスキャナーのチュートリアルで説明されています。
問題3:以前は失敗していたWindowsビルドが成功するようになった
ZXing .NET.MAUI: ZXing .NET.MAUI で Windows ターゲットを含めようとしたプロジェクトでは、通常コンパイル エラーが発生するか、条件付き MSBuild ロジックによってライブラリを Windows ビルドから除外する必要がありました。
解決策: ZXing .NET.MAUI を削除し、 IronBarcodeをインストールした後、Windows MAUI のビルドはプラットフォーム条件なしで成功します。 #if ANDROID を削除してください。 || iOS のガードは、ZXing .NET.MAUI 呼び出しを Windows ビルドから除外するために配置されました。 IronBarcode BarcodeReader.Read()呼び出しは、すべてのターゲットフレームワークでコンパイルおよび実行されます。 WindowsビルドからMediaPicker.CapturePhotoAsync()が除外されていた場合、その除外も削除できます。このメソッドはWindows MAUIでサポートされており、ファイルピッカーにマッピングされます。 条件分岐を削除した後、すべての対象フレームワークで完全なソリューションが正常にビルドされることを確認してください。
第4号:バーコードフォーマット列挙型参照
ZXing.Net.MAUI: BarcodeFormats BarcodeReaderOptionsの設定で広く使用されています。 パッケージを削除した後、残っている参照箇所はすべてコンパイルエラーを引き起こします。
解決策: フォーマットリストの設定に使用されたすべてのBarcodeReaderOptions初期化ブロックを削除します。 IronBarcodeは、正しく動作するためにフォーマット指定を必要としません。 ロギング、表示、比較目的でBarcodeEncoding値に置き換えます。 パッケージ削除後に残っている参照をすべて見つけるためにgrep -rn "BarcodeFormats\." --include="*.cs" .を実行します。
ZXing .NET.MAUI 移行チェックリスト
マイグレーション前のタスク
変更を加える前に、コードベース内のZXing .NET.MAUIの使用状況をすべて監査してください。
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" .
監査で特定されたすべてのスキャンページを文書化する。 IsDetecting管理(削除対象)のみを含むものと、他のロジックを含むものを部分的に修正する必要があるものをメモします。 検出設定を超えた方法で使用されるフォーマットリストを持つBarcodeReaderOptionsインスタンスをメモします。
コード更新タスク
- プロジェクトファイルから
ZXing.Net.Maui.ControlsNuGetパッケージを削除します builder.UseBarcodeReader()を削除します- すべてのファイルから
using ZXing.Net.Maui.Controls;名前空間のインポートを削除します IronBarcodeNuGetパッケージをインストールします- バーコード読み取りを使用するすべてのファイルに
using IronBarCode;を追加します - アプリケーションの開始時に
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";を追加します - すべてのXAMLファイルから
xmlns:zxing名前空間の宣言を削除します - XAMLファイルからすべての
<zxing:CameraBarcodeReaderView>要素を削除します - 削除されたカメラビューを各XAMLファイルの
<Button>コントロールで置き換えます - 各スキャンボタンに
Clicked="ScanButton_Clicked"を追加します - すべてのコードビハインドファイルから
OnBarcodesDetectedイベントハンドラメソッドを削除します - 各ページに
MediaPicker.CapturePhotoAsync()+BarcodeReader.Read()を追加します - すべての
BarcodeReaderOptions初期化ブロックを削除します OnAppearingオーバーライドを削除します- 他のロジックを含む
IsDetecting行を削除します #if ANDROIDをすべて削除します。 || IOSの条件付きコンパイルガードにより、ZXing .NET.MAUIがWindowsビルドから分離されていました。- 残っている
BarcodeEncoding.X等価物に置き換えます
移行後のテスト
マイグレーションが正常にコンパイルされたら、以下の点を確認してください。
- Android MAUI: スキャンボタンを押すとシステムカメラが起動し、写真が撮影され、正しいバーコード結果が返されます。Androidスキャンガイドで確認してください。
- iOS MAUI: 同じフローはiOSでも動作し、以前オートフォーカスの問題が発生していたiPhone 15 Proハードウェアでも動作します。
- Windows MAUI: Windowsビルドはエラーなくコンパイルされ、スキャンボタンをクリックするとファイルピッカーが開き、選択した画像から正しい結果が返されます。
- Formats: 古い
BarcodeFormatsリストに含まれていない形式のバーコードスキャンをテストし、自動検出を確認します - ページナビゲーション:スキャンページへの移動とスキャンページからの移動を複数回繰り返し、メモリの増加やカメラの初期化エラーが発生しないことを確認します。
- PDF読み取り:移行によってPDFバーコード読み取りが新しい機能として追加される場合、複数ページのPDFが正しいページ番号メタデータを含む結果を返すことを確認してください。
IronBarcodeへの移行の主なメリット
プラットフォーム対応範囲の拡大:移行後、アプリケーションはiOSとAndroidに加え、WindowsとmacOSのMAUIターゲットもサポートするようになりました。これらはすべて同じパッケージ、同じスキャンパターンで提供されます。 これまでプラットフォーム固有のスタブが必要だったり、Windowsをバーコード機能から除外していたプロジェクトでも、追加コードなしで完全な対応が可能になります。
現世代ハードウェアの信頼性: BarcodeReader.Read()を介した画像キャプチャのアプローチは、iPhone 15 ProとPro Maxハードウェアで失敗するCameraBarcodeReaderViewオートフォーカスモデルによって影響を受けません。 システムカメラはフォーカスを独立して制御し、ユーザーが撮影を確認した後、 IronBarcodeが撮影した画像を処理します。
カメラリソース管理の排除: CameraBarcodeReaderViewを削除すると、カメラのリソースリークバグのカテゴリ全体が除去されます。 OnDisappearingボイラープレートをすべてのスキャンページで維持する必要もなく、ナビゲーションサイクル全体でカメラリソースが蓄積されることもありません。 ステートレスAPIにより、スキャンページはリソースのライフサイクルに関して他のページと区別がつかなくなります。
設定不要のフォーマット対応:現場で遭遇するあらゆるバーコードフォーマットを自動的に検出します。 BarcodeFormatsリストにエントリが欠けているため発生するスキャンの失敗が排除されます。 サプライヤーがラベルのフォーマットを変更したためにバーコードが無視されたユーザーからのサポート依頼は発生しなくなる。
ファイルおよびドキュメント処理:今回の移行により、追加のライブラリなしで、PDFドキュメント、画像ファイル、バイトストリームからバーコードを読み取ることが可能になります。 ZXing.Net.MAUIの範囲外だったワークフロー—アップロードされた請求書からのバーコードの読み取り、デジタルチケットの処理、画像ディレクトリのバッチスキャン—が同じBarcodeReader.Read()呼び出しを使用することで実現可能になります。
実運用レベルの安定性: IronBarcodeは、活発な開発サイクル、商用サポート、および.NETバージョンのリリースに合わせた定期的なアップデートを備えた、安定した商用リリースとして提供されます。 依存関係監査、ソフトウェア構成分析、およびEnterprise承認プロセスでは、コミュニティのプレリリースパッケージではなく、保守に関する文書化されたコミットメントを持つサポート対象ライブラリに遭遇します。
よくある質問
なぜZXing.Net.MAUIからIronBarcodeに移行する必要があるのですか?
一般的な理由としては、ライセンスの簡素化(SDK + ランタイムキーの複雑さの排除)、スループット制限の排除、ネイティブPDFサポートの獲得、Docker/CI/CDデプロイの改善、プロダクションコード内のAPI定型文の削減などが挙げられます。
ZXing.Net.MAUIのAPIコールをIronBarcodeに置き換えるには?
インスタンスの作成とライセンスの定型文をIronBarCode.License.LicenseKey = "key "に置き換えてください。リーダー・コールをBarcodeReader.Read(path)に、ライター・コールをBarcodeWriter.CreateBarcode(data, encoding)に置き換えてください。静的メソッドはインスタンス管理を必要としません。
ZXing.Net.MAUIからIronBarcodeに移行する際、コードはどのくらい変更されますか?
ほとんどのマイグレーションでは、コード行数は少なくなります。ライセンスの定型文、インスタンス・コンストラクタ、明示的なフォーマット設定が削除されます。コアとなる読み取り/書き込み操作は、より短いIronBarcodeに対応し、よりきれいな結果オブジェクトが得られます。
移行時にZXing.Net.MAUIとIronBarcodeの両方をインストールしておく必要がありますか?
ほとんどのマイグレーションは、並列操作ではなく、直接置き換えです。一度に1つのサービスクラスを移行し、NuGet参照を置き換え、インスタンス化とAPI呼び出しパターンを更新してから次のクラスに移行します。
IronBarcodeのNuGetパッケージ名は何ですか?
パッケージは'IronBarcode'(大文字のBとC)です。Install-Package IronBarcode'または'dotnet add package IronBarcode'でインストールしてください。コード中のusingディレクティブは'using IronBarcode;'である。
IronBarcodeはZXing.Net.MAUIと比較して、どのようにDockerデプロイを簡素化しますか?
IronBarcodeは外部SDKファイルやマウントされたライセンス設定のないNuGetパッケージです。Dockerでは、IRONBARCODE_LICENSE_KEY環境変数を設定すると、パッケージが起動時にライセンス検証を処理します。
IronBarcodeはZXing.Net.MAUIから移行した後、すべてのバーコードフォーマットを自動的に検出しますか?
IronBarcodeは、サポートされているすべてのフォーマットのシンボルを自動検出します。明示的なBarcodeTypesの列挙は必要ありません。フォーマットが既に知られていて、パフォーマンスが重要な場合、BarcodeReaderOptionsは最適化として検索空間を制限することができます。
IronBarcodeは別のライブラリなしでPDFからバーコードを読み取ることができますか?
BarcodeReader.Read("document.pdf")は、PDFファイルをネイティブに処理します。結果には、見つかった各バーコードの PageNumber、Format、Value、および Confidence が含まれます。外部のPDFレンダリングステップは必要ありません。
IronBarcodeはどのようにパラレルバーコード処理を行うのですか?
IronBarcodeの静的メソッドはステートレスでスレッドセーフです。Parallel.ForEachをスレッドごとのインスタンス管理なしにファイルリスト上で直接使用します。BarcodeReaderOptions.MaxParallelThreadsは内部のスレッドバジェットを制御します。
ZXing.Net.MAUIからIronBarcodeに移行した場合、どのような結果が変更されますか?
一般的なリネーム:BarcodeValueはValueに、BarcodeTypeはFormatに。IronBarcodeの結果にはConfidenceとPageNumberも追加されます。ソリューション全体の検索と置換は、既存の結果処理コードで名前の変更を処理します。
CI/CDパイプラインでIronBarcodeのライセンスを設定するには?
IRONBARCODE_LICENSE_KEYをパイプラインシークレットとして保存し、アプリケーションの起動コードにIronBarCode.License.LicenseKeyを割り当てます。1つのシークレットで、開発環境、テスト環境、ステージング環境、本番環境を含むすべての環境をカバーできます。
IronBarcodeはカスタムスタイルのQRコード生成に対応していますか?
はい。QRCodeWriter.CreateQrCode()は、ChangeBarCodeColor()によるカスタムカラー、AddBrandLogo()によるロゴ埋め込み、設定可能なエラー訂正レベル、PNG、JPG、PDF、ストリームなどの複数の出力形式をサポートしています。

