NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #1723 most downloaded on pub.dev
A barcode scanner and generator natively in Flutter with Dart FFI based on ZXing.
Last release 12 days ago
25 Sep 2026
Release timing varies
gaps range from 3 weeks to 8 months
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
5 years old
71 releases · first in 2022
One column per quarter.
feat: add integration test script for streamlined testing and update …
feat: add integration test script for streamlined testing and update …
camera package ships
implementations for Android, iOS and the web only; adding
camera_desktop to your app makes
ReaderWidget and zx.processCameraImage work on the desktop too. See
Camera on desktop for what each platform needs.
Thanks to @bart-iconica (#250), who also
asked for it (#249).cameraImageFormat(CameraImage), which returns the DecodeParams.imageFormat
a camera frame should be decoded with. Frames that say bgra8888 but carry
RGBA — what camera_desktop delivers on Linux and Windows — used to be read
as BGRA, swapping red and blue in the luminance the decoder works from.ReaderWidget no longer tears the camera down when a desktop window merely
loses focus, and hides its flash button on desktop, where there is no torch to
drive.readBarcode asks zxing for errors too, so that onScanFailure can
report a symbol that was found but not read, and zxing stopped at the first
symbol it found — even when that was an error. A code that failed its checksum
in the full-size pass was then reported as a failure, and the downscaled and
inverted passes that would have read it never ran; a dense GS1 DataMatrix
almost never scanned. When the first symbol is an error, the frame is now
searched again for a code that decodes. Frames whose first symbol decodes
cost no more than before. Thanks to
@walkerkz-netizen for the detailed
report (#251).zx.setLogEnabled(true), the native log now says why a symbol could not
be decoded, e.g. Barcode error: ChecksumError @ DMDecoder.cpp:410. Code.error
is unchanged, and stays empty for most such failures.onMultiScan anyway, but each one still used up a place in
maxNumberOfSymbols, so symbols that could not be decoded could crowd out
codes that could.ReaderWidget draws over a scanned code now disappear
once the code leaves the frame. They used to stay on screen until something
else rebuilt the widget, pointing at whatever the camera had turned to.
Thanks to @walkerkz-netizen (#252).ReaderWidget keeps the zoom level when switching cameras, clamped to what the
new camera supports, instead of resetting it. Thanks to
@FrankenApps (#248).Fixed pod install failing with "undefined method pod_target_xcconfig' for an instance of Pod::Specification" while loading the iOS and macOS podspecs.
pod install failing with "undefined method pod_target_xcconfig' for an instance of Pod::Specification" while loading the iOS and macOS podspecs. Pod::Specificationonly defines a writer forpod_target_xcconfig, so reading the value back to merge the NDEBUGsettings into it raised aNoMethodError`.
All the settings are now assigned in a single hash. This affected 2.4.0 and
3.0.0; apps that build through Swift Package Manager were never affected.NT_GNU_BUILD_ID note into
libflutter_zxing.so. The note is derived from the build environment, which
kept the resulting APK from being byte-for-byte reproducible — something
F-Droid now requires. Note that Firebase Crashlytics for NDK relies on that
note to symbolicate native crashes, so a crash inside this library will now be
reported without symbols. Thanks to @quandangv
(#247).The old names still work and keep their values, but are deprecated.
Updates the bundled zxing-cpp from
v2.3.0 to v3.1.1 — 633 upstream commits, including a major release that
reworked the format API. Format, DecodeParams, EncodeParams and Code are
unchanged on the Dart side; the two behaviour changes below are the only ones
that can affect existing code.
]E0
content to be a 13-digit number, so a UPC-A that used to read as
"725272730706" now reads as "0725272730706", and a UPC-E that used to read
as its 8-digit form is expanded to the equivalent EAN-13. Code.format still
reports Format.upca / Format.upce. Strip the leading zero if you need the
old form.Format.qrCode also detects Micro QR and rMQR
symbols (reported as Format.microQRCode / Format.rmqrCode), and
Format.pdf417 also detects MicroPDF417 (reported as Format.microPdf417).
Filter on Code.format if you need to accept only one of them.Format.dxFilmEdge, Format.dataBarLimited, Format.telepen and
Format.microPdf417. All four are read-only, so they are absent from
CodeFormat.supportedEncodeFormats, and all four are part of
Format.any.ImageFormat.lumA, for 8-bit grayscale with an alpha byte.ImageFormat.rgbx, .xrgb, .bgrx and .xbgr follow the upstream rename to
.rgba, .argb, .bgra and .abgr. The old names still work and keep their
values, but are deprecated.DecodeParams.maxNumberOfSymbols is clamped to 1–255. zxing takes a
uint8_t, so a larger value silently wrapped — 256 asked for no symbols at
all.Bug-fix and correctness release. Every fix below is covered by the unit tests in test/ or the FFI integration tests in example/integration_test/.
Bug-fix and correctness release. Every fix below is covered by the unit tests in
test/ or the FFI integration tests in example/integration_test/.
rgbBytes handed the
decoder the image's own storage, which for a palette, 1/2/4-bit or 16-bit
image is not 8-bit RGB and is a fraction of width * height * 3 — a 1-bit PNG
packs eight pixels per byte. The decoder then read far past the end of the
allocation (EXCEPTION_ACCESS_VIOLATION_READ on Windows). Such images are now
converted first, so they scan instead of crashing.decodeImage probes each format in turn and a malformed file can make one of
those probes throw rather than decline.NDEBUG, so zxing's internal
asserts stayed live in shipped apps — Assertion failed: (l1.isValid() && l2.isValid()), function intersect, file RegressionLine.h. Release and profile
builds now compile them out, matching the CMake build used elsewhere. Debug
builds keep the asserts.ReaderWidget mapped NV21 to ImageFormat.rgb, so the luminance plane was
decoded as RGB and nothing ever matched — with no error to show for it. A
frame layout that cannot be scanned at all is now reported through
onScanFailure and logged, instead of failing silently forever.CameraPreview could be rebuilt against a disposed controller (#238, #212,
#204). CameraPreview renders through a ValueListenableBuilder bound to
the controller, and nothing marked the widget dirty when the controller was
swapped, so the preview stayed subscribed to a controller that was about to be
disposed and the pending rebuild called buildPreview() on it.setFlashMode failing now hides the flash button and leaves the
camera running.onControllerCreated instead of being swallowed.initialize(), getMaxZoomLevel() was the one unguarded
platform call, and several awaits ran before it. If the controller was
disposed or replaced in that window it threw Uninitialized CameraController,
which aborted the rest of setup. Every step now re-checks that the controller
is still current, and a failing zoom query falls back to no zoom instead of
taking camera setup down with it.ReaderWidget sized its preview and cut-out from MediaQuery.size, so any
instance that is not full screen — inside a SizedBox, or a Scaffold body
under an app bar — drew the indicator at the wrong size and off-centre. It now
lays out from its own constraints.SIGSEGV / SEGV_ACCERR).ReaderWidget
asks for ImageFormatGroup.yuv420 on Android and bgra8888 on iOS instead of
letting the platform choose, so the buffer layout no longer varies by device.type 'ArgumentError' is not a subtype of type 'Code' (#221). Errors
raised inside the decoding isolate — including the missing-native-library
error behind that report — were sent back raw and then cast to Code. The
real error is now rethrown with its own message.EncodeResult now
reports the bitmap it actually produced and Encode exposes it as
width/height; WriterWidget and pngFromBytes use those values.ReaderWidget mapped
ImageFormatGroup.nv21 to ImageFormat.rgb, so the luminance plane was read
as RGB pixels and nothing scanned. NV21 and YUV420 now both map to
ImageFormat.lum, and JPEG frames report ImageFormat.none instead of being
scanned as raw pixels.DecodeParams.imageFormat at its
lum default, so readBarcodeImagePath(file, DecodeParams()) handed the
decoder mismatched pixels. The pixel format is now set to match the data.readBarcode/
readBarcodes trusted the caller's width/height and read past the end of
a buffer that was smaller than width * height * pixStride. The buffer length
is now passed to the native side, which reports an error instead.processCameraImage hung forever when called before
startCameraProcessing(), or when the decoding isolate was stopped while a
frame was in flight. Both now complete with a StateError.TypeError. The raw error object was sent back and then cast to Code.
Errors are now wrapped and rethrown with their original message.processCameraImage/processCameraImageMulti threw a cast error when
DecodeParams.isMultiScan did not match the method that was called. The flag
is now forced to match, and processCameraImageMulti sets Code.source.ReaderWidget broke every other one on screen. The decoding
isolate is shared, and stopCameraProcessing() tore it down unconditionally.
It is now reference counted.cropPercent, and the crop cut-out was still drawn even though multi-scan
scans the whole frame. Both overlays now follow the crop actually applied.ReaderWidget read widget.isMultiScan while the dropdown updated internal
state. It now uses the effective mode and syncs it in didUpdateWidget, which
also makes changes to lensDirection and resolution take effect.bytesPerRow > width * 4 were
passed through shifted.pngFromBytes produced a wrong image for a Uint8List view into a larger
buffer, and read past the end of a buffer that was too small. It now honours
the view's offset and rejects inconsistent input with an ArgumentError.Code was garbage for non-luminance input. It was
copied assuming one byte per pixel regardless of the source format; it is now
converted to luminance, matching what pngFromBytes expects.readBarcodes when zxing found candidates but all of
them failed validation: the native result array was allocated and never freed.WriterWidget accepted invalid input. A null text passed validation, and
zero or negative width/height and negative margins reached the encoder.MultiResultOverlay fired on any pointer event, because
the callback was invoked from CustomPainter.hitTest. It now uses a real tap
gesture.stopCameraProcessing, so disposing a widget on
web raised; teardown calls are now no-ops and the rest report a descriptive
UnsupportedError.dart.library.html, which is absent when compiling to WasmGC, so the
unsupported-platform stub was selected. It now uses dart.library.js_interop.XFile and CameraImage are re-exported: they appear in this package's own
signatures, and importing package:camera for them collided with this
package's ImageFormat.DecodeParams gained copyWith, and the file/URL readers no longer mutate
the DecodeParams instance passed to them.Code/Codes carrying an
error instead of throwing.Code, Codes, Position and Encode implement toString().MultiScanPainter no longer takes context or onCodeTap; tap handling
moved to MultiResultOverlay, and shouldRepaint no longer returns true
unconditionally.camera dependency floor is raised to >=0.11.0, the release where
Android moved to CameraX. The camera2 implementation it replaced crashed
inside io.flutter.plugins.camera.Camera on several devices (#205, #206),
which nothing in this plugin could work around.Code.imageBytes is documented: it is the luminance the decoder scanned,
cropped to the scan rect, and only populated while logging is enabled (#207).cropPercent is documented as the fraction of the frame that is kept, not
the fraction cropped away (#151).compileSdk raised to 36 and Java compatibility to 11, matching the
current Flutter defaults. The NDK stays pinned to 27.0.12077973, which is
required: zxing-cpp v2.3.0 does not build against the libc++ in NDK 28+.Package.swift (13.0), and the
placeholder metadata in both podspecs replaced.Migrated iOS and macOS projects from CocoaPods to Swift Package Manager (SPM).
CameraController disposal issues and stopImageStream() errors.Draw scan result rectangle in single scan mode when cropRect = 0
Support 16KB page size on android
Removed deprecated dynamic and fixed scanner overlays.
Enhance barcode scanning features and improve overlay customization
Added parameters tryDownscale and maxNumberOfSymbols to the ReaderWidget for better performance and flexibility.
tryDownscale and maxNumberOfSymbols to the ReaderWidget for better performance and flexibility.Fixed windows compatibility issues
* Updated zxing-cpp to v2.3.0
Increased minimum versions of camera and image packages to support newer APIs.
camera and image packages to support newer APIs.Improved FFI interoperability: changed image data type from Uint32List to Uint8List for correct handling of binary (black & white) matrices between C+
Uint32List to Uint8List for correct handling of binary (black & white) matrices between C++ (zxing-cpp) and Flutter.* Minor improvements
* Minor improvements
Fixed Windows compatibility issues (thanks to @liff)
Added support for Linux (thanks to @phlip9)
Fixed iOS and macOS compatibility issues
* Updated camera to v0.11.0
Fixed issue with recognizing the barcodes from the image
* Updated zxing-cpp to v2.2.1
* Updated zxing-cpp to v2.2.0
Replaced 'hidden' with 'default' for improved compatibility with older Flutter versions
* Updated Image to v4
Conditionally add namespace for AGP 8 support
Utilized Flutter version 3.1.0 or higher
* Updated zxing-cpp to v2.1.0
Moved melos to dev dependencies (thanks to @phlip9)
melos to dev dependencies (thanks to @phlip9)Downgraded image version from v3.4.0 to v3.3.0 to resolve iOS detection issue.
Fixed issue with onControllerCreated callback is sometimes not called
Allow to set camera lens direction
* Updated Image to v4
* Updated zxing cpp
Added support for changing the camera
Added support for macOS, Linux, and Windows
Corrected code position in Android when in portrait mode.
Implemented multi result drawing
readBarcodes now returns a Codes object instead of a List<Code> objectResolved an issue with detecting and handling large images
Fixed compilation issue on Android
Fixed compilation issue on Android
Fixed compilation issue on Android
Added the following properties to Code:
* Minor improvements
Added support for macOS, Linux, and Windows
replaced int type with EccLevel enum for error correction level
EncodeParamsint type with EccLevel enum for error correction levelratio, maxTextLength, and isSupportedEccLevel to Format for encoding barcodesParams to DecodeParamszx methods* fixed memory leaks
fixed compilation errors on web
Breaking changes
added 'tryInverted' and 'tryHarder' parameters to the ReaderWidget
ReaderWidgetadded 'bytes' parameter content without any modifications to the scan result
* bug fixes
* bug fixes
* bug fixes
added ability to set localization messages for writer_widget
writer_widget* updated readme
encodeBarcode method now uses the named parameters instead of positional parameters
fixed case sensitive folder name issue in CMakeLists.txt (thanks to @softkot)
updated dependencies to the latest version
added barcode result point detection
* updated zxing-cpp to v1.4.0
fixed Chinese support for iOS (thanks to @aqiu202)
Your coding agent can read these notes before it upgrades. Set up the MCP server →