v8.0.0
A rewrite. Every camera capability of mobile_scanner 7.4.0 is now a plain
widget parameter, on top of a scanner UI that is responsive, capability-aware,
themeable and localisable. See the
migration guide
— most apps need a one-line change or none at all.
Fixed
GalleryButtonType.nonehid every control, not just the gallery button
(#176). Gallery
visibility and control visibility are now independent. A custom
appBarBuilderor achildno longer removes the controls either.Null check operator used on a null valuewhen the scanner was popped
while a camera flip or torch toggle was in flight
(#187). The
chrome no longer callssetStateafter anawait; it listens to the
controller instead, so it also picks up torch and zoom changes the platform
reports on its own.- Barcodes inside the reticle would not scan
(#166). Two
causes: the scan window was computed from the screen rather than the camera
preview's box, so an app bar or bottom sheet pushed it out of alignment; and
Android requires a barcode to be entirely inside the window and drops any
barcode with no reported corner points. The window is now derived from the
preview's constraints, and detection is no longer restricted to it by default
(restrictDetectionToScanWindow: false). - Empty boxes instead of icons on iOS
(#188). The
default icons wereCupertinoIcons, whose font is only bundled when the app
itself depends oncupertino_icons. Defaults are now Material icons, which
every app withuses-material-design: truealready ships. - 16 KB page size compliance
(#168,
#171). Requires
mobile_scanner >= 7.4.0, which pulls ML Kit 17.3.0 — 16 KB aligned on both
64-bit ABIs. The README documents the AGP/NDK requirements and how to clear a
stale pub cache. - The camera never paused with the app lifecycle.
useAppLifecycleStatewas
inert, becauseMobileScanneronly manages the lifecycle for a controller it
created and this package always supplied one. The scanner now observes the
lifecycle itself. - Disposing the scanner unlocked every device orientation, clobbering an
orientation policy set by the host app. Orientation is now left alone unless
you setpreferredOrientations. - A failed gallery scan gave no feedback and escaped as an unhandled async
error. It now flashes the overlay and reports throughonGalleryScanError. - Permission denials rendered as "An unknown error occurred." The error view
now distinguishes permission denied, no usable camera, and everything else,
with retry and anonOpenSettingshook. - Pinch-to-zoom was neither symmetric nor proportional — a gentle spread
saturated the zoom while the matching pinch barely moved it — and it rebuilt
the entire tree on every gesture frame. ScannerCornerPainterandScanningLinePainterunder-reported repaints,
so animatingcornerLength,lineThicknessor the colours did nothing.ScannerOverlayConfig.animationwas accepted and ignored. It is honoured
now, and the overlay's ticker stops entirely when no animation is drawn.keywas forwarded to the innerMobileScanner, so
AiBarcodeScanner(key: GlobalKey())threw "Multiple widgets used the same
GlobalKey".- A controller swapped in via
didUpdateWidgetleaked or was wrongly
disposed. Ownership is now recorded once, at creation. galleryIconwas ignored by the icon-style gallery button.- The success/error
ValueNotifierand its timer are disposed; every write is
guarded bymounted. - Controls are no longer swallowed by the preview's gesture recogniser — with
tap-to-focus on (the default), tapping the torch previously did nothing.
Fixed after internal review
A multi-agent adversarial review of the rewrite, before release, turned up a
further set of defects; all are fixed and pinned by tests.
- The scanner crashed in any preview smaller than about 188x144 logical
pixels.ScanWindowConfig.resolvepassed an unclampedminWidthas the
lower limit of anum.clampwhose upper limit was the available width.
clampthrowsArgumentError— not a debug-only assert — when the lower
limit is the larger, so the whole scanner was replaced by an error widget.
Triggered by an embedded scanner in a card or list tile, a desktop or web
window narrowed past that threshold, Android split-screen, or a large
horizontal safe area. - Swapping
controllerleft the preview driving the disposed one.
MobileScannercaptures its controller in alate finalfield, so it never
saw the new one. The preview now remounts on a controller swap. - Every control became untappable when the scan window reached the bottom of
the preview — a short landscape screen, orScanWindowShape.fullPreview.
The control cluster was pinned below the window, so it collapsed to zero
height. It is now anchored to the bottom and sized to its own content. - The overlay threw when its animation configuration changed.
SingleTickerProviderStateMixindoes not release its claim when a ticker is
disposed, so rebuilding the controller asserted. - Batch mode overshot
maxScanswhen one capture carried more barcodes
than the remaining budget, andonScanCompletecould fire more than once
per session. ScanValidators.matchesrejected values its pattern did match.
matchAsPrefixtakes the first alternative that fits and never backtracks,
soRegExp('a|ab')rejectedab. The pattern is now properly anchored, and
its flags are preserved.- A gallery pick was silently discarded when the session was paused or
inside the continuous-mode cooldown, and it analysed with the wrong barcode
formats when the caller supplied a controller. - A rejected barcode held in frame fired the rejection haptic on every
detection callback — a continuous buzz. Rejections are now throttled by
scanCooldown. mailto:andsms:URIs were form-encoded, so a space reached the mail
or SMS client as a literal+.actionUrireturned an unopenable relative URI for a URL payload with
no scheme, so the result sheet offered an "Open" action that could not work.- Two stacked scanner routes both reclaimed the camera on resume. Only the
visible route does now. - The lens control went stale after a camera flip; it re-probes when the
camera direction changes. - A long plain-text payload pushed the result sheet's action buttons off
screen. - The control strip no longer swallows tap-to-focus in the gaps between
buttons, and wraps instead of overflowing at large text scales. ScanWindowConfig.copyWithcould not clear abuilder, so a builder-based
config could never go back to a shape. AddedclearBuilder.- Corrected the capability matrix: the web backend does report barcode
corners (that is what its scan-window filter is built on), so
showBarcodeHighlightsworks there. Also corrected doc comments on
AiBarcodeScanner.embedded,appBarBuilderandanalyzeImage.
Added
AiBarcodeScannerController— a facade over the camera and the scan
session:start/stop/pause,pauseScanning/resumeScanning,
toggleTorch/setTorch,switchCamera/switchLens/useCloseRangeLens,
setZoomScale/resetZoomScale,setFocusPoint,analyzeImage, batch
collect/clearCollected, plusstateand thebarcodesstream.
.rawreaches the underlyingMobileScannerController.- Full
mobile_scannerparity as widget parameters:formats,
detectionSpeed,detectionTimeoutMs,facing,lensType,
cameraResolution,torchEnabled,autoStart,autoZoom,invertImage,
initialZoom,returnImage,webBarcodeReader,
webBarcodeLibraryScriptUrl. showAiBarcodeScannerandshowAiBarcodeScannerBatch— open a scanner
and get the result back in one line.AiBarcodeScanner.embedded— the scanner without aScaffold, for
dropping into a page you already have.- Scan modes:
single,continuous(withscanCooldown) andbatch
(withmaxScansandonScanComplete). ScannerTheme— a palette for the scanner chrome, with
ScannerTheme.fromColorSchemefor brand matching. Overlay colours are now
nullable and fall back to it.ScannerLabels— every user-visible string, overridable, with English
defaults and nointldependency.ScanWindowConfig— declarative scan window sizing:auto,square,
wide,tall,fullPreviewor a builder, with min/max bounds that keep the
reticle sane on tablets and desktop.ScannerFeedbackConfig— configurable haptics and sound, a
ScannerFeedbackConfig.silentpreset, and anonFeedbackhook for your own
scanner beep.ScanValidators—formats,types,contains,startsWith,
matches,url,length, combined withall/either.BarcodeFormatSets— curated presets:qrOnly,twoDimensional,
retail,logistics,documents.ScannerPlatformSupport— the per-platform capability matrix. Controls
the platform or device cannot back now hide themselves: no torch on macOS, no
camera flip on a single-camera device, no gallery on the web, no lens button
unless the device reports more than one lens.- Barcode presentation helpers —
bestValue,typeLabel,typeIcon,
actionUri,boundingBox,fields(structured Wi-Fi, contact, calendar,
geo, SMS, email and driver-licence payloads), andBarcodeFormat.displayName. BarcodeResultSheet— a ready-made sheet that renders the structured
payload with copy, open and share actions.- Tap-to-focus with an animated focus ring, implemented against the
preview's own box rather than the screen. - Zoom slider, lens switching and a close control, as
ScannerAction.zoom,.lensand.close. - Detected-barcode highlights (
showBarcodeHighlights). - On-screen guidance that changes after
idleHintDelaywhen nothing has
been detected. - Accessibility: semantics labels and tooltips on every control, reduced
motion honoured, scrollable control strip at large text scales. - Responsive layout: controls form a row under the reticle on a portrait
preview and a trailing column on a landscape or desktop one. onScannerStarted,onError,onOpenSettings,onZoomChanged,
onTorchChanged,onClose,onGalleryScanErrorcallbacks.- A test suite (102 tests) covering the control-visibility regression, the
detection pipeline, batch limits, rejection throttling, the scan-window
coordinate space and its degenerate cases, small and landscape layouts,
large text scales, capability gating, controller swapping, lifecycle and
ownership.
Changed
- Breaking:
controllertakes anAiBarcodeScannerController. Use
AiBarcodeScannerController.fromMobileScanner(existing)to wrap one you
already have, or drop the controller entirely and pass the camera options to
the widget. - Breaking:
galleryButtonText→labels: ScannerLabels(galleryButton: …). - Breaking:
setPortraitOrientation→preferredOrientations. - Breaking:
onCustomImagePicker→imagePicker, which only chooses the
file. - Breaking:
childis drawn in addition to the controls, not instead of
them. - Breaking:
overlayBuilderreceives the resolvedscanWindow. - Breaking:
ScannerOverlayConfig.backgroundBlurColor→
backgroundColor; colour fields are nullable. - Breaking: the default
detectionSpeedisnoDuplicates, which suits a
scanner screen that closes on the first result. - Default icons are Material rather than Cupertino.
ErrorBuilder→ScannerErrorView.- The dropped
universal_platformdependency is replaced bykIsWeband
defaultTargetPlatform. mobile_scanner>=7.4.0 <8.0.0;image_picker>=1.1.2 <2.0.0(a loose
lower bound so the package still resolves on Flutter 3.29–3.37).- SDK floor: Dart 3.7.0, Flutter 3.29.0, iOS 15.0, macOS 12.0.
- The example app is rewritten and its Android project modernised to the current
Flutter template (Gradle 9.3.1, AGP 9.1.0, Kotlin 2.4.0, compileSdk 36, NDK
r28, Kotlin DSL). - CI now analyses with
--fatal-infos, checks formatting withdart format
(flutter formatno longer exists), runs the tests, scores withpana, and
builds the example for Android, Web, iOS and macOS.