跳過到頁腳內容
使用IRONBARCODE

使用IronBarcode的MAUI條碼掃描器:逐步指南

行動應用程式越來越依賴條碼掃描來進行庫存管理、銷售點系統和產品追蹤。 建立 MAUI 條碼掃描器,可以將條碼偵測直接整合到.NET MAUI應用程式中,結合攝影機畫面和影像檔案處理來偵測二維碼、資料矩陣和其他條碼格式。 雖然許多條碼庫專注於相機預覽,但IronBarcode即使在具有挑戰性的條件下也能準確讀取條碼——傾斜的角度、光線不足和損壞的標籤,所有這些都無需額外配置即可處理。

本指南將逐步介紹如何使用IronBarcode在.NET MAUI專案中實作條碼掃描。 到最後,您將能夠從單一影像檔案掃描多個條碼,從裝置攝影機擷取條碼,並自信地將該程式庫整合到您自己的跨平台專案中。

建置 MAUI 條碼掃描器需要哪些先決條件?

在開始之前,請確保您的開發環境已準備就緒:

  • 已安裝.NET MAUI工作負載的Visual Studio 2022 (版本 17.8 或更高版本)。
  • .NET 10 SDK -- 從.NET官方網站下載 -具備基本的 C# 知識-熟悉 async/await 模式會有幫助
  • 用於相機測試的實體設備或模擬器 IronBarcode許可證-提供免費試用版供評估

在建立專案之前確保 Visual Studio 已安裝 MAUI 工作負載,可以節省後續大量的故障排除時間。 您可以在 Visual Studio 安裝程式的"單一元件"下搜尋".NET多平台應用程式 UI 開發"來驗證這一點。

了解IronBarcode如何融入 MAUI

.NET MAUI為您提供一個可同時針對 Android、iOS、macOS 和 Windows 的程式碼庫。 在這種環境下進行條碼掃描的挑戰在於,每個平台處理攝影機存取的方式都不同。 IronBarcode透過在影像處理層進行處理來解決這個問題——您透過 MAUI 的 MediaPicker 擷取影像,然後將位元組交給IronBarcode進行分析。

這種關注點分離的做法可以保持程式碼簡潔,避免使用特定於平台的條碼 SDK。 IronBarcode 的離線處理模型也意味著條碼資料永遠不會離開設備,這對於受監管行業的應用來說非常重要。

支援的條碼格式

IronBarcode可讀取多種格式,包括:

IronBarcode支援的條碼格式
格式類別 格式 常見用例
一維線性 Code 128、Code 39、EAN-13、UPC-A、ITF 零售、物流、醫療保健
二維矩陣 二維碼、資料矩陣、阿茲特克、PDF417 行動支付、票務、製造業
郵政 美國郵政、英國皇家郵政、德國郵政 運輸和郵政服務
專業 MaxiCode、GS1、MicroPDF417 供應鏈、運輸、包裹

如何設定 MAUI 條碼掃描項目?

首先在 Visual Studio 2022 中建立一個新的.NET MAUI應用程式專案。將其命名為 BarcodeScannerApp,並選擇.NET 10 作為目標框架。 Visual Studio 會產生標準的 MAUI 專案結構,其中包含 Android、iOS、macOS 和 Windows 等平台特定的資料夾。

透過NuGet安裝IronBarcode

開啟NuGet套件管理器控制台並執行:

Install-Package BarCode

或者,在解決方案資源管理器中右鍵單擊您的項目,選擇"管理NuGet套件",搜尋 IronBarCode,然後安裝最新的穩定版本。 專門針對.NET MAUI項目,IronBarcode 的NuGet套件包含了所有必要的本機相依性。

啟動您的許可證

安裝完成後,請在應用程式生命週期的早期階段使用您的許可證金鑰啟動IronBarcode 。 最佳位置是在應用程式建構器運行之前,即 MauiProgram.cs 處:

IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
$vbLabelText   $csharpLabel

從 IronSoftware 網站取得免費試用許可證金鑰。試用金鑰可讓您在開發過程中不受時間限制地評估所有功能,但輸出結果可能包含試用浮水印,直到您申請完整授權為止。

如何設定安卓和iOS系統的相機權限?

平台特定的相機權限對於條碼掃描功能至關重要。 每個平台都需要在其清單檔案中進行特定配置,然後 MediaPicker.CapturePhotoAsync() 才能成功。

Android權限

編輯 Platforms/Android/AndroidManifest.xml 以聲明攝影機存取權限:

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

android.permission.CAMERA 條目請求使用者在執行時授予權限。 uses-feature 聲明告知 Google Play 商店,您的應用程式需要相機硬體和自動對焦功能。 如果沒有這些,Android 裝置可能會授予權限請求,但仍會在內部阻止相機存取。

對於 Android 13 及更高版本(API 等級 33+),您可能還需要使用 MainActivity.cs 來處理細粒度的媒體權限。 MAUI MediaPicker 抽象層會自動處理大部分此類操作,但建議在發布前進行實體設備測試。

iOS權限

修改 Platforms/iOS/Info.plist,使其包含相機使用說明:

<key>NSCameraUsageDescription</key>
<string>This app requires camera access to scan barcodes</string>
<key>NSCameraUsageDescription</key>
<string>This app requires camera access to scan barcodes</string>
XML

iOS 要求對每一項涉及隱私的權限都提供易於理解的解釋。 如果缺少此描述或描述含糊不清,蘋果應用商店的審核流程將拒絕您的應用程式。 該文字出現在應用程式首次要求存取相機時向使用者顯示的系統權限對話方塊中。

對於 iPadOS,如果您打算讓使用者除了使用即時相機外,還可以掃描已儲存照片中的條碼,請考慮新增 NSPhotoLibraryUsageDescription

Windows 和 macOS

對於 Windows Desktop 和 macOS 目標平台,相機存取權限分別透過應用程式清單檔案和授權檔案進行管理。 MAUI 框架在範本層級處理了大部分此類問題,但請驗證 Windows 上的 Package.appxmanifest 是否包含網路攝影機裝置功能。

如何建立條碼掃描器介面?

MainPage.xaml 中設計一個使用者介面,使用戶在掃描過程中獲得清晰的回饋。 簡潔而實用的佈局包括影像預覽、結果顯示區和掃描觸發按鈕:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="BarcodeScannerApp.MainPage"
             Title="Barcode Scanner">
    <VerticalStackLayout Padding="20" Spacing="20">
        <Label Text="Point the camera at a barcode"
               FontSize="16"
               HorizontalOptions="Center"
               TextColor="#555555" />
        <Image x:Name="CapturedImage"
               HeightRequest="300"
               Aspect="AspectFit"
               BackgroundColor="#F0F0F0" />
        <Label x:Name="ResultLabel"
               Text="Tap Scan to begin"
               FontSize="18"
               HorizontalOptions="Center"
               FontAttributes="Bold" />
        <Label x:Name="FormatLabel"
               Text=""
               FontSize="13"
               HorizontalOptions="Center"
               TextColor="#888888" />
        <Button Text="Scan Barcode"
                Clicked="OnScanClicked"
                BackgroundColor="#007ACC"
                TextColor="White"
                CornerRadius="8"
                HeightRequest="50" />
        <Button Text="Load from Gallery"
                Clicked="OnPickFromGalleryClicked"
                BackgroundColor="#5C5C5C"
                TextColor="White"
                CornerRadius="8"
                HeightRequest="50" />
    </VerticalStackLayout>
</ContentPage>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="BarcodeScannerApp.MainPage"
             Title="Barcode Scanner">
    <VerticalStackLayout Padding="20" Spacing="20">
        <Label Text="Point the camera at a barcode"
               FontSize="16"
               HorizontalOptions="Center"
               TextColor="#555555" />
        <Image x:Name="CapturedImage"
               HeightRequest="300"
               Aspect="AspectFit"
               BackgroundColor="#F0F0F0" />
        <Label x:Name="ResultLabel"
               Text="Tap Scan to begin"
               FontSize="18"
               HorizontalOptions="Center"
               FontAttributes="Bold" />
        <Label x:Name="FormatLabel"
               Text=""
               FontSize="13"
               HorizontalOptions="Center"
               TextColor="#888888" />
        <Button Text="Scan Barcode"
                Clicked="OnScanClicked"
                BackgroundColor="#007ACC"
                TextColor="White"
                CornerRadius="8"
                HeightRequest="50" />
        <Button Text="Load from Gallery"
                Clicked="OnPickFromGalleryClicked"
                BackgroundColor="#5C5C5C"
                TextColor="White"
                CornerRadius="8"
                HeightRequest="50" />
    </VerticalStackLayout>
</ContentPage>
XML

此佈局提供了兩種掃描路徑:使用相機拍攝新照片和從圖庫中選擇現有影像。 對於使用者預先拍攝條碼或透過電子郵件接收影像的工作流程來說,這一點很重要。 FormatLabel 顯示偵測到的條碼格式以及解碼值,這有助於偵錯和使用者驗證。

新增掃描狀態回饋

為了獲得更流暢的體驗,可以考慮將掃描按鈕包裹在 ActivityIndicator 中,這樣在處理過程中就會顯示出來。 IronBarcode 的非同步 API 讓這變得很簡單——你可以在呼叫 BarcodeReader.ReadAsync 之前設定 IsRunning = true,然後在 finally 程式碼區塊中重置它。

如何實現條碼閱讀器功能?

MainPage.xaml.cs 中實作核心掃描邏輯。 以下程式碼同時處理相機拍攝和圖庫選擇,並具有適當的非同步模式和錯誤處理:

using IronBarCode;
using IronSoftware.Drawing;

namespace BarcodeScannerApp;

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    private async void OnScanClicked(object sender, EventArgs e)
    {
        await ScanFromSource(() => MediaPicker.Default.CapturePhotoAsync());
    }

    private async void OnPickFromGalleryClicked(object sender, EventArgs e)
    {
        await ScanFromSource(() => MediaPicker.Default.PickPhotoAsync());
    }

    private async Task ScanFromSource(Func<Task<FileResult?>> sourceFunc)
    {
        try
        {
            var photo = await sourceFunc();
            if (photo is null) return;

            using var stream = await photo.OpenReadAsync();
            using var memoryStream = new MemoryStream();
            await stream.CopyToAsync(memoryStream);
            var imageBytes = memoryStream.ToArray();

            // Show the captured image in the UI
            CapturedImage.Source = ImageSource.FromStream(() =>
                new MemoryStream(imageBytes));

            // Process with IronBarcode
            var bitmap = AnyBitmap.FromBytes(imageBytes);
            var options = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Balanced,
                ExpectMultipleBarcodes = false
            };

            var results = await BarcodeReader.ReadAsync(bitmap, options);

            if (results.Any())
            {
                var first = results.First();
                ResultLabel.Text = $"Value: {first.Value}";
                FormatLabel.Text = $"Format: {first.BarcodeType}";
            }
            else
            {
                ResultLabel.Text = "No barcode detected";
                FormatLabel.Text = string.Empty;
            }
        }
        catch (FeatureNotSupportedException)
        {
            await DisplayAlert("Unsupported",
                "Camera is not available on this device.", "OK");
        }
        catch (PermissionException)
        {
            await DisplayAlert("Permission Required",
                "Please grant camera permission in Settings.", "OK");
        }
        catch (Exception ex)
        {
            await DisplayAlert("Error",
                $"Scanning failed: {ex.Message}", "OK");
        }
    }
}
using IronBarCode;
using IronSoftware.Drawing;

namespace BarcodeScannerApp;

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    private async void OnScanClicked(object sender, EventArgs e)
    {
        await ScanFromSource(() => MediaPicker.Default.CapturePhotoAsync());
    }

    private async void OnPickFromGalleryClicked(object sender, EventArgs e)
    {
        await ScanFromSource(() => MediaPicker.Default.PickPhotoAsync());
    }

    private async Task ScanFromSource(Func<Task<FileResult?>> sourceFunc)
    {
        try
        {
            var photo = await sourceFunc();
            if (photo is null) return;

            using var stream = await photo.OpenReadAsync();
            using var memoryStream = new MemoryStream();
            await stream.CopyToAsync(memoryStream);
            var imageBytes = memoryStream.ToArray();

            // Show the captured image in the UI
            CapturedImage.Source = ImageSource.FromStream(() =>
                new MemoryStream(imageBytes));

            // Process with IronBarcode
            var bitmap = AnyBitmap.FromBytes(imageBytes);
            var options = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Balanced,
                ExpectMultipleBarcodes = false
            };

            var results = await BarcodeReader.ReadAsync(bitmap, options);

            if (results.Any())
            {
                var first = results.First();
                ResultLabel.Text = $"Value: {first.Value}";
                FormatLabel.Text = $"Format: {first.BarcodeType}";
            }
            else
            {
                ResultLabel.Text = "No barcode detected";
                FormatLabel.Text = string.Empty;
            }
        }
        catch (FeatureNotSupportedException)
        {
            await DisplayAlert("Unsupported",
                "Camera is not available on this device.", "OK");
        }
        catch (PermissionException)
        {
            await DisplayAlert("Permission Required",
                "Please grant camera permission in Settings.", "OK");
        }
        catch (Exception ex)
        {
            await DisplayAlert("Error",
                $"Scanning failed: {ex.Message}", "OK");
        }
    }
}
$vbLabelText   $csharpLabel

此實作使用共享的 ScanFromSource 輔助方法,以避免在相機和圖庫路徑之間重複影像處理邏輯。 AnyBitmap.FromBytes 方法可自動處理 JPEG、PNG、WebP 和其他常見影像格式—無需手動偵測格式。

結果物件公開了 first.BarcodeType(格式枚舉)和 first.BarcodeImage(偵測到的條碼區域的裁切影像)等屬性。 請參閱BarcodeResult 類別文件以取得完整清單。

測試您的掃描實施

程式碼編寫完成後,就可以使用標準條碼進行測試了:

如何使用IronBarcode建立 MAUI 條碼掃描器:圖 2 - 輸入測試條碼

掃描後,解碼值會顯示在螢幕上:

如何使用IronBarcode建立MAUI條碼掃描器:圖3 - 掃描的條碼值

如何配置進階掃描選項?

IronBarcode公開了一個 BarcodeReaderOptions 對象,您可以根據特定用例微調檢測行為。 了解這些選項有助於您根據應用程式的需求,在速度和準確性之間取得平衡。

針對特定條碼類型

指定所需的條碼類型可以顯著縮短處理時間,因為IronBarcode會跳過不需要的格式檢查:

var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Balanced,
    ExpectMultipleBarcodes = true,
    ExpectBarcodeTypes = BarcodeEncoding.QRCode | BarcodeEncoding.Code128
};

var results = await BarcodeReader.ReadAsync(bitmap, options);
var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Balanced,
    ExpectMultipleBarcodes = true,
    ExpectBarcodeTypes = BarcodeEncoding.QRCode | BarcodeEncoding.Code128
};

var results = await BarcodeReader.ReadAsync(bitmap, options);
$vbLabelText   $csharpLabel

如何使用IronBarcode建立 MAUI 條碼掃描器:圖 4 - 從相同影像掃描多個條碼

設定 ExpectMultipleBarcodes = true 指示IronBarcode在找到第一個結果後繼續掃描,這對於倉庫工作流程至關重要,因為一張裝箱單可能包含十幾個條碼。

閱讀速度選項

ReadingSpeed 枚舉提供了四個等級:BalancedQuickScan。 在條碼清晰明亮、列印量大的場景下,可使用 QuickScan。 當掃描低解析度相機拍攝的影像或部分損壞的標籤時,請切換到 DetailedExtremeDetail

有關調整 BarcodeReaderOptions 的更多信息,包括圖像校正濾波器和置信度閾值,文件提供了詳細的範例。

影像校正和預處理

IronBarcode內建影像校正功能,可自動處理旋轉、傾斜或光線不足的條碼。 您也可以透過 BarcodeReaderOptions.ImageFilters 手動套用預處理過濾器:

var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Detailed,
    ImageFilters = new ImageFilterCollection
    {
        new SharpenFilter(),
        new ContrastFilter(1.2f)
    }
};
var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Detailed,
    ImageFilters = new ImageFilterCollection
    {
        new SharpenFilter(),
        new ContrastFilter(1.2f)
    }
};
$vbLabelText   $csharpLabel

當應用程式面向配備低品質相機感應器的舊款 Android 設備,或者用戶可能在倉庫或戶外環境等光線不足的條件下拍攝條碼時,預處理濾鏡尤其有用。

您如何處理常見的故障排除場景?

即使使用配置良好的 MAUI 條碼掃描器,也可能出現因裝置特定行為、影像品質問題或平台限製而導致的問題。

相機無法開啟

如果相機啟動失敗,請驗證 AndroidManifest.xmlInfo.plist 中是否正確聲明了權限。 然後從全新建置版本重新部署應用程序,而不是進行熱重載。 在 Android 系統上,也要檢查您的測試裝置是否使用非標準相機配置——某些具有多個相機的裝置需要明確選擇鏡頭。

在模擬器上,不支援 MediaPicker.CapturePhotoAsync()。 請務必在真機上測試相機功能。模擬器支援圖庫選擇功能(PickPhotoAsync),您可以使用預先載入的圖片進行基本的使用者介面測試。

掃描準確率差

如果IronBarcode沒有傳回任何結果或傳回錯誤值,請嘗試下列調整:

  • Speed 增加到 ReadingSpeed.DetailedExtremeDetail
  • SharpenFilterContrastFilter 新增至影像濾鏡管道中
  • 確保擷取影像的解析度至少為 720p;解析度過低會導致資料矩陣等高密度格式的資料偵測出現漏檢。
  • 檢查您的 ExpectBarcodeTypes 遮罩中是否包含條碼類型

IronBarcode故障排除指南涵蓋了針對特定格式問題的額外診斷步驟。

記憶體管理

大型相機影像載入到 MemoryStream 時會消耗大量記憶體。 始終在所有流物件上使用 using 語句以確保釋放。 對於使用者依序掃描多個項目的連續掃描工作流程,處理完成後也應明確呼叫 bitmap.Dispose(),而不是等待垃圾回收器。

對於堆空間有限的 Android 設備,如果掃描的是清晰、高對比度的條碼,不需要全解析度即可準確解碼,則應考慮在將影像傳遞給IronBarcode之前對其進行降採樣。

平台特定的 iOS 行為

在 iOS 系統中,當你的應用程式首次要求相機權限時,系統會顯示一次性對話方塊。 如果使用者拒絕,則後續對 CapturePhotoAsync 的呼叫將拋出 PermissionException。 處理此案例的方法是引導使用者進入設置,您可以使用 AppInfo.ShowSettingsUI() 來完成此操作。

在提交到 App Store 之前,請確認 NSCameraUsageDescription 存在於 Info.plist 中。 缺少隱私字串會導致系統自動拒絕審核,審核團隊不會給予詳細解釋。 請查閱Apple 人機互動指南,以了解有關相機存取權限的最佳實踐,包括權限請求的時機和訊息傳遞方式。

下一步計劃是什麼?

現在您已經擁有一個可正常運作的 MAUI 條碼掃描器和IronBarcode,根據您的應用程式需求,有幾種方法可供選擇:

-產生條碼-- IronBarcode包含一個 條碼產生 API ,可根據字串資料建立二維碼、Code 128 標籤和其他格式的條碼。 -批次掃描-- 使用 BarcodeReader.ReadAsyncExpectMultipleBarcodes = true 在循環中處理多個影像檔案; 請參閱批量掃描範例

  • PDF 條碼擷取-- IronBarcode可使用相同的 BarcodeReader 類別讀取嵌入在 PDF 文件中的條碼; 查閱PDF 條碼讀取文檔 -樣式和品牌-使用​​顏色、標誌和註釋自訂產生的條碼的視覺輸出; 查看條碼樣式選項 -其他 IronSoftware 產品——如果您的 MAUI 應用還需要 PDF 生成、OCR 或電子表格支持,請探索完整的Iron Suite套件,以獲得一致的跨平台功能。

首先申請免費試用許可證,在評估期內可以不受限制地部署。 有關生產許可選項和批量定價,請訪問IronBarcode定價頁面IronBarcode文件入口網站IronBarcode GitHub儲存庫提供了更多程式碼範例和社群支援。

常見問題解答

在 MAUI 條碼掃描器中使用 IronBarcode 的優勢是什麼?

IronBarcode 在圖像層處理條碼,支持離線工作,支持超過 30 種格式,並能在無需額外配置的情況下應對偏斜角度和光照不足等挑戰。

IronBarcode 能夠在一個圖像中检测到多個條碼嗎?

是的。在 BarcodeReaderOptions 中設置 ExpectMultipleBarcodes = true,並呼叫 BarcodeReader.ReadAsync。IronBarcode 將在結果集合中返回所有檢測到的條碼。

如何在 MAUI 中為 Android 和 iOS 配置攝像機許可權?

對於 Android,將 CAMERA uses-permission 和 uses-feature 元素添加到 AndroidManifest.xml 中。對於 iOS,將 NSCameraUsageDescription 與人類可讀的解釋添加到 Info.plist 中。

IronBarcode 支持離線條碼掃描嗎?

是的。IronBarcode 完全在設備上處理圖像,而不將數據發送到外部服務器,這對隱私敏感的應用程序至關重要。

IronBarcode 在 MAUI 中支持哪些條碼格式?

IronBarcode 支持 QR Code、Code 128、Code 39、EAN-13、UPC-A、Data Matrix、PDF417、Aztec、MaxiCode 及更多。您可以通過 BarcodeEncoding 標誌來指定特定格式。

如何提高對低質量圖像的掃描準確性?

將 ReadingSpeed 切換到 Detailed 或 ExtremeDetail,將 SharpenFilter 和 ContrastFilter 添加到 ImageFilters,並確保捕獲到的圖像至少為 720p 分辨率。

IronBarcode 能否在 MAUI 應用程序中從 PDF 文件中讀取條碼?

是的。IronBarcode 的 BarcodeReader 類可以使用與圖像文件相同的 ReadAsync API 從 PDF 文件中提取嵌入的條碼。

如何處理當相機存取權限被拒時的PermissionException?

在try/catch區塊中捕捉PermissionException,並呼叫AppInfo.ShowSettingsUI()以引導用戶到設備的設定中重新啟用相機存取。

Jordi Bardia
軟體工程師
Jordi 在 Python、C# 和 C++ 上最得心應手,當他不在 Iron Software 展現技術時,便在做遊戲編程。在分担產品测测试,產品開發和研究的责任時,Jordi 為持续的產品改進增值。他说这种多样化的经验使他受到挑战并保持参与, 而这也是他与 Iron Software 中工作一大乐趣。Jordi 在佛罗里达州迈阿密长大,曾在佛罗里达大学学习计算机科学和统计学。

鋼鐵支援團隊

我們每週 5 天,每天 24 小時在線上。
聊天
電子郵件
打電話給我