Implementing barcode and QR code scanning in a .NET MAUI application is straightforward with the right libraries. Here are the main approaches:
Option 1: Using ZXing.Net.MAUI
The most popular solution is the ZXing.Net.MAUI library:
Install the package:
dotnet add package ZXing.Net.MAUI
Initialize in MauiProgram.cs:
builder.UseMauiApp<App>() .UseBarcodeReader(); // Add this line
Add camera permission:
For Android, add to AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
For iOS, add to Info.plist:
<key>NSCameraUsageDescription</key> <string>This app needs camera access to scan barcodes</string>
Create a scanning page:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:zxing="clr-namespace:ZXing.Net.MAUI.Controls;assembly=ZXing.Net.MAUI" x:Class="YourApp.ScanPage"> <zxing:CameraBarcodeReaderView x:Name="barcodeReader" BarcodesDetected="BarcodesDetected" /> </ContentPage>
Handle the scan results:
private void BarcodesDetected(object sender, BarcodeDetectionEventArgs e) { foreach (var barcode in e.Results) { Console.WriteLine($"Barcode: {barcode.Format} -> {barcode.Value}"); // Process the scanned value } }
Option 2: Using Google's ML Kit (Android/iOS)
For more advanced scanning capabilities:
Install Google ML Kit for MAUI
Follow the platform-specific setup instructions
Implement scanning similar to ZXing but with ML Kit's enhanced features
Option 3: Device Camera + Custom Processing
For complete control:
Use MAUI's MediaPicker to take photos
Process images with a library like ZXing.Net:
var photo = await MediaPicker.CapturePhotoAsync(); using var stream = await photo.OpenReadAsync(); var reader = new BarcodeReader(); var result = reader.Decode(stream);
Tips for Better Scanning
Ensure proper camera permissions are requested at runtime
Add a viewfinder overlay to guide users
Consider adding vibration on successful scan
Handle low-light conditions with torch/toggle flash option
Test with various barcode types (QR, UPC, EAN, etc.)
Adding a Viewfinder Overlay for Barcode Scanning in MAUI
To improve the user experience when scanning barcodes/QR codes, you can add a viewfinder overlay that helps users align the code properly. Here's how to implement it with ZXing.Net.MAUI:
Option 1: Simple Rectangle Overlay (XAML)
<Grid> <!-- Camera Preview --> <zxing:CameraBarcodeReaderView x:Name="barcodeReader" BarcodesDetected="BarcodesDetected" /> <!-- Viewfinder Overlay --> <Grid> <!-- Semi-transparent surrounding area --> <BoxView Color="Black" Opacity="0.6"/> <!-- Transparent center area with border --> <Frame HorizontalOptions="Center" VerticalOptions="Center" WidthRequest="250" HeightRequest="250" CornerRadius="10" BackgroundColor="Transparent" BorderColor="White" Padding="0"> <!-- Corner marks (optional) --> <Grid> <!-- Top-left corner --> <BoxView Color="White" WidthRequest="30" HeightRequest="5" HorizontalOptions="Start" VerticalOptions="Start"/> <BoxView Color="White" WidthRequest="5" HeightRequest="30" HorizontalOptions="Start" VerticalOptions="Start"/> <!-- Top-right corner --> <BoxView Color="White" WidthRequest="30" HeightRequest="5" HorizontalOptions="End" VerticalOptions="Start"/> <BoxView Color="White" WidthRequest="5" HeightRequest="30" HorizontalOptions="End" VerticalOptions="Start"/> <!-- Bottom-left corner --> <BoxView Color="White" WidthRequest="30" HeightRequest="5" HorizontalOptions="Start" VerticalOptions="End"/> <BoxView Color="White" WidthRequest="5" HeightRequest="30" HorizontalOptions="Start" VerticalOptions="End"/> <!-- Bottom-right corner --> <BoxView Color="White" WidthRequest="30" HeightRequest="5" HorizontalOptions="End" VerticalOptions="End"/> <BoxView Color="White" WidthRequest="5" HeightRequest="30" HorizontalOptions="End" VerticalOptions="End"/> </Grid> </Frame> <!-- Instruction text --> <Label Text="Align barcode within the frame" TextColor="White" FontSize="16" HorizontalOptions="Center" VerticalOptions="End" Margin="0,0,0,40"/> </Grid> </Grid>
Option 2: Animated Viewfinder (Code-Behind)
For a more dynamic effect, add this to your page's code-behind:
// Add to your page class private BoxView _scanLine; private bool _isAnimating; protected override void OnAppearing() { base.OnAppearing(); StartScanLineAnimation(); } protected override void OnDisappearing() { base.OnDisappearing(); _isAnimating = false; } private void StartScanLineAnimation() { _scanLine = new BoxView { Color = Colors.Red, WidthRequest = 250, HeightRequest = 2, HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center, TranslationY = -125 // Start at top of viewfinder }; if (this.FindByName<Grid>("overlayGrid") is Grid overlayGrid) { overlayGrid.Children.Add(_scanLine); } _isAnimating = true; Device.StartTimer(TimeSpan.FromMilliseconds(16), () => { if (!_isAnimating) return false; _scanLine.TranslationY += 2; if (_scanLine.TranslationY >= 125) { _scanLine.TranslationY = -125; } return true; }); }
Option 3: Custom GraphicsView (Advanced)
For complete control over the drawing:
<GraphicsView x:Name="viewfinderOverlay" Drawable="{StaticResource ViewfinderDrawable}" HorizontalOptions="Fill" VerticalOptions="Fill"/>
Create a custom drawable class:
public class ViewfinderDrawable : IDrawable { public void Draw(ICanvas canvas, RectF dirtyRect) { // Draw semi-transparent overlay canvas.FillColor = Colors.Black.WithAlpha(0.6f); canvas.FillRectangle(dirtyRect); // Clear center area var centerWidth = 250; var centerHeight = 250; var centerX = (dirtyRect.Width - centerWidth) / 2; var centerY = (dirtyRect.Height - centerHeight) / 2; canvas.BlendMode = BlendMode.Clear; canvas.FillRectangle(centerX, centerY, centerWidth, centerHeight); canvas.BlendMode = BlendMode.Normal; // Draw border canvas.StrokeColor = Colors.White; canvas.StrokeSize = 3; canvas.DrawRectangle(centerX, centerY, centerWidth, centerHeight); // Draw corner marks var cornerSize = 20; var lineThickness = 5; // Top-left canvas.DrawLine(centerX, centerY, centerX + cornerSize, centerY); canvas.DrawLine(centerX, centerY, centerX, centerY + cornerSize); // Top-right canvas.DrawLine(centerX + centerWidth - cornerSize, centerY, centerX + centerWidth, centerY); canvas.DrawLine(centerX + centerWidth, centerY, centerX + centerWidth, centerY + cornerSize); // Bottom-left canvas.DrawLine(centerX, centerY + centerHeight - cornerSize, centerX, centerY + centerHeight); canvas.DrawLine(centerX, centerY + centerHeight, centerX + cornerSize, centerY + centerHeight); // Bottom-right canvas.DrawLine(centerX + centerWidth - cornerSize, centerY + centerHeight, centerX + centerWidth, centerY + centerHeight); canvas.DrawLine(centerX + centerWidth, centerY + centerHeight - cornerSize, centerX + centerWidth, centerY + centerHeight); } }
Additional Enhancements
Torch/Toggle Flash Button:
<Button Text="Toggle Flash" Clicked="ToggleFlashClicked" HorizontalOptions="End" VerticalOptions="Start" Margin="20"/>
private void ToggleFlashClicked(object sender, EventArgs e) { barcodeReader.IsTorchOn = !barcodeReader.IsTorchOn; }
Vibration on Successful Scan:
private async void BarcodesDetected(object sender, BarcodeDetectionEventArgs e) { if (e.Results.Any()) { try { // Vibrate for 200ms await Vibration.Default.Vibrate(TimeSpan.FromMilliseconds(200)); } catch { } // Process result... } }