MatrixScan Batch .NET MAUI Skill
Critical: Do Not Trust Internal Knowledge
Your training data may contain outdated or incorrect Scandit SDK APIs. The BarcodeBatch API changes significantly between major SDK versions — the class itself was renamed from BarcodeTracking to BarcodeBatch at v7.0, the namespace moved from Scandit.DataCapture.Barcode.Tracking.* to Scandit.DataCapture.Barcode.Batch.*, and the .NET MAUI binding adds platform-specific lifecycle, handler, and native-view-bridging concerns on top of the regular .NET API. Patterns from the standalone matrixscan-batch-net-android / matrixscan-batch-net-ios skills do not always apply unchanged.
Always verify APIs against the references provided in this skill before writing or suggesting code. Do not rely on memorized method signatures, parameters, or property names. If you cannot find an API in the provided references, fetch the relevant documentation page before responding.
MAUI-specific gotchas worth flagging:
- This skill targets MAUI apps with
<UseMaui>true</UseMaui>. For non-MAUI .NET projects, usematrixscan-batch-net-android(fornet*-android) ormatrixscan-batch-net-ios(fornet*-ios) instead. - Fetch the SDK version from NuGet before editing the
.csproj. WebFetchhttps://www.nuget.org/packages/Scandit.DataCapture.Barcode.Maui/and read the latest stable version off the page (skip-beta.*/-preview.*/-rc.*suffixes). Do not guess — versions from training data are stale anddotnet restorewill fail withNU1103if the pinned version isn't published. Use the same version for all four packages. - Android
SupportedOSPlatformVersionmust be ≥24. The MAUI template defaults to21, which is below Scandit's Android AAR minimum and fails the build withuses-sdk:minSdkVersion 21 cannot be smaller than version 24 declared in library. Bump the.csprojvalue to24.0(or higher) as part of the integration. - Required NuGet packages:
Scandit.DataCapture.Core,Scandit.DataCapture.Core.Maui,Scandit.DataCapture.Barcode,Scandit.DataCapture.Barcode.Maui. All four are needed — Core/Barcode provide the platform bindings, Core.Maui/Barcode.Maui provide the MAUI builder extensions and handlers. MauiProgram.csbuilder chain is specific and the order matters:builder .UseMauiApp<App>() .UseScanditCore(configure => configure.AddDataCaptureView()) .UseScanditBarcode();UseScanditBarcode()takes no inner configure — there is no MAUI handler for BarcodeBatch itself, the call exists only to invokeScanditBarcodeCapture.Initialize(). Do not writeUseScanditBarcode(configure => configure.AddBarcodeBatchView())— that method does not exist. BarcodeBatch in MAUI uses the generic<scandit:DataCaptureView>, not a dedicated view.- Do NOT call
ScanditCaptureCore.Initialize()/ScanditBarcodeCapture.Initialize()inMainApplication.OnCreateorAppDelegate.FinishedLaunching. The MAUI builder extensions (UseScanditCore/UseScanditBarcode) perform this SDK initialization themselves. This is different from the non-MAUImatrixscan-batch-net-android/matrixscan-batch-net-iosskills, which require manual initialization for SDK 8.0+. In a MAUI app, theMainApplication/AppDelegateonly need to forward toMauiProgram.CreateMauiApp()— leave them alone. BarcodeBatchdoes not have a pre-built MAUI view (unlikeBarcodeArView,BarcodeCountView,BarcodeFindView,BarcodePickView,SparkScanView). The MAUI integration uses the generic<scandit:DataCaptureView>fromScandit.DataCapture.Core.UI.MauiwithBarcodeBatchBasicOverlay(and optionallyBarcodeBatchAdvancedOverlay) added on top.- XAML namespace for
DataCaptureViewisxmlns:scandit="clr-namespace:Scandit.DataCapture.Core.UI.Maui;assembly=ScanditCaptureCoreMaui".DataCaptureContext="{Binding DataCaptureContext}"is mandatory on the<scandit:DataCaptureView>element — without it the preview renders as a black/blank camera at runtime even though the code-behind compiles and the camera is started. Settingx:Name="dataCaptureView"is not enough; the bindable property is what wires the context to the preview. The page'sBindingContext(view model orthis) must expose aDataCaptureContextproperty of typeScandit.DataCapture.Core.Capture.DataCaptureContext. - The
BarcodeBatchBasicOverlaymust be created after the platform handler has been attached. The pattern used in the official sample is:
Creating the overlay beforethis.dataCaptureView.HandlerChanged += (s, e) => { var overlay = BarcodeBatchBasicOverlay.Create( this.viewModel.BarcodeBatch, BarcodeBatchBasicOverlayStyle.Frame); this.dataCaptureView.AddOverlay(overlay); };HandlerChangedfires will fail silently — there is no native view to attach it to yet. The same rule applies toBarcodeBatchAdvancedOverlay. - MAUI page lifecycle:
OnAppearing→ start camera +barcodeBatch.Enabled = true;OnDisappearing→ setbarcodeBatch.Enabled = falsefirst, then stop the camera. The officialMatrixScanSimpleSampleexplicitly does theEnabled = falsebefore the camera shutdown because in-flight frames can still report tracked-barcode updates during the asynchronous camera-off transition. The sample factors this into aResumeAsync/SleepAsyncpattern on the view model. IBarcodeBatchListener.OnSessionUpdated(BarcodeBatch, BarcodeBatchSession, IFrameData)runs on a background recognition thread — not the main thread. Dispatch any UI work viaMainThread.BeginInvokeOnMainThread(() => …)orMainThread.InvokeOnMainThreadAsync(...). The third parameter isIFrameData(the .NET binding), notFrameData(Swift / Kotlin).- Do not hold references to
BarcodeBatchSessionor its collections outsideOnSessionUpdated. The session is only safe to access within that callback — copyAddedTrackedBarcodes/UpdatedTrackedBarcodes/TrackedBarcodesdata first, then dispatch. - Always call
frameData.Dispose()at the end of everyOnSessionUpdatedcallback (including any early-return path). When the MAUI app is running on iOS (multi-targetednet*-ios), failing to dispose causes a "frozen, non-responsive, or severely stuttering" video feed because the recognition pipeline runs out of buffers. On Android the binding manages the frame lifetime, but writing the disposal once (in atry/finally) is safe everywhere and is the recommendation for portable MAUI code. Note that the officialMatrixScanSimpleSampleomits this in the simple path, relying onlock-based access; the recommendation here is to add thetry/finallyanyway because MAUI apps almost always multi-target iOS. - UI dispatch is
MainThread.BeginInvokeOnMainThread(() => …)orMainThread.InvokeOnMainThreadAsync(...)— notRunOnUiThread(Android-specific) and notDispatchQueue.MainQueue.DispatchAsync(iOS-specific). The dispatch wrapper is platform-agnostic. - The .NET API uses PascalCase factories:
BarcodeBatch.Create(context, settings),BarcodeBatchSettings.Create(),BarcodeBatchBasicOverlay.Create(barcodeBatch, style)/Create(barcodeBatch),BarcodeBatchAdvancedOverlay.Create(barcodeBatch),DataCaptureContext.ForLicenseKey(key),Camera.GetCamera(CameraPosition.WorldFacing)orCamera.GetDefaultCamera(). BarcodeBatchBasicOverlayStyleis C# PascalCase:Frame(default) andDot. NotFRAME/DOT(Kotlin) and notframe/dot(Swift).- The capture mode's enabled property is
barcodeBatch.Enabled(notIsEnabledand not Swift'sisEnabled). BarcodeBatchSessionproperties:AddedTrackedBarcodes(IList<TrackedBarcode>),UpdatedTrackedBarcodes(IList<TrackedBarcode>),RemovedTrackedBarcodes(IList<int>— tracking IDs only, notTrackedBarcode),TrackedBarcodes(IDictionary<int, TrackedBarcode>),FrameSequenceId(long),Reset().Reset()lives on the Session in the .NET binding (there is noBarcodeBatch.Reset()like the Kotlin API has).TrackedBarcodeproperties:Barcode,Identifier(int),Location(Quadrilateral), plusGetAnchorPosition(Anchor). The tracking identifier is reused after a barcode leaves the frame.BarcodeBatchAdvancedOverlay(anchoring custom views on top of tracked barcodes) requires the MatrixScan AR add-on license. In MAUI,IBarcodeBatchAdvancedOverlayListener.ViewForTrackedBarcodemust return a native view (Android.Views.Viewon Android,UIKit.UIViewon iOS) — not a MAUIView. The canonical MAUI pattern (from the officialMatrixScanBubblesSample) is apartialview model split intoPlatforms/Android/MainPageViewModel.csandPlatforms/iOS/MainPageViewModel.cs, each implementing the platform-specificViewForTrackedBarcodeand callingmauiContentView.ToPlatform(new MauiContext(...))to convert a MAUI control to the native view type. See "BarcodeBatchAdvancedOverlay (advanced)" in references/integration.md.- Per-barcode brush customization (
IBarcodeBatchBasicOverlayListener.BrushForTrackedBarcodeandBarcodeBatchBasicOverlay.SetBrushForTrackedBarcode) requires the MatrixScan AR add-on license. A uniform default brush viaoverlay.Brush = …(no listener) does not require the add-on. - Symbology names are C# PascalCase:
Symbology.Ean13Upca,Symbology.Ean8,Symbology.Upce,Symbology.Code39,Symbology.Code128,Symbology.InterleavedTwoOfFive,Symbology.Qr,Symbology.DataMatrix. They are not the Kotlin underscore style (EAN13_UPCA,CODE128) and not Swift's camelCase (ean13UPCA). BarcodeBatch.RecommendedCameraSettingsis a static property, applied withcamera.ApplySettingsAsync(BarcodeBatch.RecommendedCameraSettings). Not a method.- Camera permission: use
await Permissions.CheckStatusAsync<Permissions.Camera>()andawait Permissions.RequestAsync<Permissions.Camera>(). MAUI's permission system also takes care of the underlyingAndroidManifest/Info.plistentries — but on iOS the project still needs theNSCameraUsageDescriptionstring set inInfo.plist. On Android, MAUI addsandroid.permission.CAMERAautomatically whenPermissions.Camerais requested at build time (it can also be added toPlatforms/Android/AndroidManifest.xmlexplicitly). BarcodeBatchLicenseInfo(read viabarcodeBatch.BarcodeBatchLicenseInfo) isdotnet.android=8.4+/dotnet.ios=8.4+only. Before 8.4 the property does not exist — gate any usage on the installed SDK version. The value is available onceIDataCaptureContextListener.OnModeAddedhas been called.- There is no
BarcodeScannedevent onBarcodeBatch(batch is tracking, not single-scan). Use theSessionUpdatedevent or implementIBarcodeBatchListener.OnSessionUpdated— the official MAUI sample uses the listener interface.
Intent Routing
Based on the user's request, load the appropriate reference file before responding:
- Integrating MatrixScan Batch from scratch, configuring settings, handling tracked barcodes, customizing overlays, anchoring custom MAUI ContentViews on tracked barcodes, managing the camera lifecycle, or diagnosing a black or frozen preview (e.g. "add MatrixScan Batch to my MAUI app", "scan all barcodes in view at once in MAUI", "highlight tracked barcodes in green in MAUI", "anchor a price label to each tracked barcode in MAUI", "show me how to set up BarcodeBatch in .NET MAUI", "my MAUI preview is black after I added BarcodeBatch", "my preview is stuttering on iOS after I integrated BarcodeBatch in MAUI") → read references/integration.md and follow the instructions there.
- Migrating or upgrading an existing MatrixScan Batch integration (e.g. "upgrade my MAUI BarcodeBatch app from v6 to v7", "rename BarcodeTracking to BarcodeBatch in my MAUI project", "bump the Scandit .NET MAUI SDK to v8", "what changed between SDK versions for BarcodeBatch in MAUI") → read references/migration.md and follow the instructions there.
- Replacing a third-party multi-barcode scanner with MatrixScan Batch (e.g. "replace my ZXing.Net.Maui multi-detection scanner with MatrixScan Batch", "migrate from BarcodeScanning.Native.Maui multi-result to Scandit BarcodeBatch", "switch from [library] continuous multi-result scanning to BarcodeBatch in MAUI") → read references/third-party-migration.md and follow the instructions there.
API Usage Policy
Only use APIs that are explicitly documented in the Scandit references below. Do not invent or guess method signatures, parameters, or property names. If unsure whether an API exists or how it is called — or if a compile error occurs — fetch the relevant reference page before responding. Do not tell the user to check the docs themselves. After answering, always include the relevant link so the user can explore further.
Never construct or guess documentation URLs. When you need a specific class or property's API page:
- First check whether the page you already fetched contains a direct hyperlink to it — topic pages link directly to relevant API symbols. Always request links alongside content in your fetch prompt.
- If no direct link was found, fetch the API index (see Full API reference in the table below), extract the actual link from it, and follow that.
URL structures can vary (e.g. api/ui/ subdirectory) and guessing will lead to 404s.
References
Direct users to the right resource based on their question:
| Topic | Resource |
|---|---|
| Get Started (Android target) | Get Started (.NET for Android) |
| Get Started (iOS target) | Get Started (.NET for iOS) |
| AR overlays (per-barcode brushes, anchored views) | Android Adding AR Overlays · iOS Adding AR Overlays |
| Migration between major SDK versions | Android 6 → 7 · Android 7 → 8 · iOS 6 → 7 · iOS 7 → 8 |
| Full API reference | BarcodeBatch API (.NET Android) · BarcodeBatch API (.NET iOS) |
Scandit publishes the .NET API reference per underlying TFM (
dotnet.androidanddotnet.ios). For MAUI projects, both pages apply — the API surface is identical between them forBarcodeBatch, but platform-specific notes (like iOS frame-data disposal, or theAndroid.Views.Viewvs.UIKit.UIViewreturn type ofViewForTrackedBarcode) are documented on the per-TFM page.
API surface this skill covers
All classes documented as :available: dotnet.android and :available: dotnet.ios in the official RST docs (docs/source/barcode-capture/api/barcode-batch*.rst and api/ui/barcode-batch-*-overlay*.rst) are addressed in references/integration.md:
BarcodeBatch—Create(DataCaptureContext?, BarcodeBatchSettings),Enabled,ApplySettingsAsync(settings),AddListener(IBarcodeBatchListener)/RemoveListener(IBarcodeBatchListener), eventSessionUpdated(EventHandler<BarcodeBatchEventArgs>), staticRecommendedCameraSettings(property, not method),Context,BarcodeBatchLicenseInfo(8.4+),Dispose.BarcodeBatchSettings—Create(),EnableSymbology(Symbology, bool),EnableSymbologies(ICollection<Symbology>),GetSymbologySettings(Symbology),EnabledSymbologies(get),SetProperty/GetProperty<T>/TryGetProperty<T>.BarcodeBatchSession—AddedTrackedBarcodes,UpdatedTrackedBarcodes,RemovedTrackedBarcodes(IList<int>of tracking IDs),TrackedBarcodes(IDictionary<int, TrackedBarcode>),FrameSequenceId,Reset().BarcodeBatchEventArgs—BarcodeBatch,Session,FrameData.IBarcodeBatchListener—OnObservationStarted(BarcodeBatch),OnObservationStopped(BarcodeBatch),OnSessionUpdated(BarcodeBatch, BarcodeBatchSession, IFrameData).BarcodeBatchLicenseInfo(8.4+) —LicensedSymbologies.TrackedBarcode—Barcode,Identifier,Location(Quadrilateral),GetAnchorPosition(Anchor).BarcodeBatchBasicOverlay—Create(barcodeBatch, view, style),Create(barcodeBatch, style),Create(barcodeBatch, view),Create(barcodeBatch),Listener(IBarcodeBatchBasicOverlayListener?),Brush(uniform default brush), staticDefaultBrushForStyle(style),Style(read-only),ShouldShowScanAreaGuides,SetBrushForTrackedBarcode(trackedBarcode, brush),ClearTrackedBarcodeBrushes(),Dispose.BarcodeBatchBasicOverlayStyleenum —Frame,Dot.IBarcodeBatchBasicOverlayListener—BrushForTrackedBarcode(overlay, trackedBarcode),OnTrackedBarcodeTapped(overlay, trackedBarcode). Requires MatrixScan AR add-on.BarcodeBatchAdvancedOverlay—Create(barcodeBatch, view),Create(barcodeBatch),Listener(IBarcodeBatchAdvancedOverlayListener?),SetViewForTrackedBarcode(trackedBarcode, view),SetAnchorForTrackedBarcode(trackedBarcode, anchor),SetOffsetForTrackedBarcode(trackedBarcode, offset),ClearTrackedBarcodeViews(),ShouldShowScanAreaGuides,Dispose. Requires MatrixScan AR add-on.IBarcodeBatchAdvancedOverlayListener—ViewForTrackedBarcode(overlay, trackedBarcode)(returnsAndroid.Views.Viewon Android,UIKit.UIViewon iOS — use apartialclass split +ToPlatform),AnchorForTrackedBarcode(overlay, trackedBarcode),OffsetForTrackedBarcode(overlay, trackedBarcode). Requires MatrixScan AR add-on.- MAUI-specific glue:
MauiAppBuilder.UseScanditCore(configure => configure.AddDataCaptureView()),MauiAppBuilder.UseScanditBarcode(),<scandit:DataCaptureView>XAML control,dataCaptureView.HandlerChangedevent,dataCaptureView.AddOverlay(overlay), MAUIPermissions.Camera,MainThread.BeginInvokeOnMainThread,MainThread.InvokeOnMainThreadAsync,IView.ToPlatform(new MauiContext(...)).