cunning_document_scanner 3.0.0
cunning_document_scanner: ^3.0.0 copied to clipboard
A document scanner plugin for flutter. Scan and crop automatically on iOS and Android.
3.0.0 #
Important
This release changes where scanned files are written and how cancellation is reported. Read the breaking changes below before upgrading.
Breaking changes #
permission_handleris no longer a dependency. The iOS camera permission is now requested natively throughAVCaptureDevice, which is exactly the APIpermission_handlerwrapped forPermission.camera. If your app importspackage:permission_handlerwithout declaring it in your ownpubspec.yaml— relying on it arriving transitively through this plugin — add it explicitly:
Nothing else changes: permission refusals still throwflutter pub add permission_handlerCunningDocumentScannerExceptionwithcode: 'permission_denied'and the same message. Apps that already declarepermission_handlerare unaffected.- iOS output moved out of the
Documentsdirectory. Scans and generated PDFs are now written to a privateLibrary/Caches/cunning_document_scanner/subdirectory. The returned paths are still absolute and readable, but the files are no longer backed up to iCloud and may be reclaimed by the system. Copy anything you need to keep to your own storage. getPictures()now returnsnullon cancellation on every platform. Android previously returned an empty list, contradicting the documented contract. Empty native results are normalized tonull.- Native errors are reported as
CunningDocumentScannerException.getPictures()andcleanCache()no longer leakPlatformException; the platform error code is preserved inCunningDocumentScannerException.code. androidScannerModeis no longer nullable. It defaults toAndroidScannerMode.full; remove any explicitnull.IosScannerOptionsis no longer aconstconstructor. It now validatesjpgCompressionQualityand throws anArgumentErrorfor values outside 0.0 - 1.0.
Fixed #
- Importing images from the gallery could fail on Android. Providers that keep images in the cloud, such as Google Photos, return a URI before the bytes are available locally. The cropper opened that stream on the main thread as soon as it started, freezing the UI for the length of the download and aborting with a decode error when the image was not ready yet. Image reading, decoding and cropping now run on a background thread with a progress indicator, and an image that genuinely cannot be read reports that it may still be downloading.
- Large images could exhaust memory in the Android fallback scanner. Photos were decoded at full resolution, and rotating one by its EXIF orientation allocated a second copy without releasing the first, so a 12 MP capture peaked at roughly 96 MB. Images are now downsampled to a longest edge of 2048 px and the intermediate bitmap is recycled. This path runs on devices without Google Play Services, which are the least able to absorb that. The gallery import was routed through the same decoder so crop coordinates stay in one coordinate space.
- The scanner could be locked out for the rest of the process on iPad. The
cameraAndGalleryaction sheet is a popover there, and dismissing it by tapping outside could leave the pending result callback stranded, after which every later call failed withALREADY_ACTIVE. The same happened when no view controller was available to present from. Dismissal by gesture is now treated as a cancellation, and a missing presenter fails immediately withNO_VIEW_CONTROLLERrather than consuming the call. cleanCache()no longer requires an attachedActivityon Android. It only ever needed aContext, so cleaning at startup — before anyActivityis attached — used to fail withNO_ACTIVITYfor no technical reason.- A
restrictedcamera authorization was ignored on iOS. Devices under parental controls or an MDM policy reportrestricted, which the Dart-side check did not treat as a refusal, so the scanner opened a camera the user could never grant access to. The native check covers it. - The camera permission was requested even for gallery-only flows.
ScannerSource.galleryuses the out-of-process system photo picker, which needs no permission; it no longer prompts for anything. cleanCache()could delete host application data. On iOS it removed every.pdf,.jpgand.pngin the app'sDocumentsdirectory; on Android it matched by file extension incacheDirand the pictures directory. Both now delete only files the plugin itself wrote, identified by theDOCUMENT_SCAN_prefix and the private storage directory.- Android gallery multi-selection was broken. The picker requested multiple selection but only read
Intent.data, so selecting more than one image reported "No image selected". Selections are now read fromclipDataand every image is cropped in sequence. - Android gallery imports ignored
noOfPages, hardcoding a single page. - Concurrent
getPictures()calls no longer orphan the first call'sFuture; the second call fails fast with anALREADY_ACTIVEerror. - Calling the plugin while detached from an
Activityreturns aNO_ACTIVITYerror instead of crashing withUninitializedPropertyAccessException. - iOS image write failures are surfaced as errors instead of returning paths to files that were never created.
- Removed the leftover Huawei
com.huawei.hms.ml.DEPENDENCYmanifest entry, which was still being merged into every host application after HMS support was dropped in 2.6.0.
Added #
IosScannerOptions.defaultFilterandIosScannerOptions.showFilterBarexpose the iOS cropper filters (IosDocumentFilter.original,.color,.grayscale,.blackAndWhite) to Dart.- Kotlin unit tests for the method channel argument helpers, run in CI.
tool/check_versions.sh, run in CI, fails the build whenpubspec.yaml, the podspec,android/build.gradle.ktsand the changelog disagree on the version.- Documented how to customize the native UI. An application can override any of the plugin's text, and on Android also its colors and dimensions, by redeclaring the matching resource name —
cunning_*on Android,cunning_document_scanner_*inLocalizable.stringson iOS. This already worked, since the plugin resolves each name against the host application first, but was never written down. iOS colors remain hard-coded and are not overridable.
Changed #
- Removed the unconditional debug logging from the Android plugin and the debug
printfrom the Dart layer; both leaked file paths and URIs into release logs. plugin_platform_interfacemoved todev_dependencies; it was only ever used by tests.- Added
topicsandissue_trackertopubspec.yaml. - Stricter analysis (
strict-casts,strict-raw-types,public_member_api_docs) and raised, rather than disabled, the SwiftLint size and complexity rules. - The Android fallback cropper shows a page counter while working through a batch of imported images, matching what iOS already displayed.
- Android is localized. Its strings shipped in English only while iOS carried 29 languages; both platforms now cover the same set. The shared wording is taken from the existing iOS translations so the two say the same thing.
- Added Basque (
eu) and Galician (gl) on both platforms, bringing the total to 31. Catalan was already supported. Valencian is served by the Catalan localization, and Asturian, Aragonese and Aranese are left out because iOS does not offer them as system languages. - Every Android resource is now prefixed
cunning_. A library's resources are merged into the host application's resource table and the application wins any name collision, so the plugin previously exposed 45 unprefixed names — includingblack,image_viewandactivity_image_crop— that an application could silently override, restyling or breaking the scanner.resourcePrefix = "cunning_"makes AGP flag any future lapse, and the convention is documented in the README. These are internal resources, so applications need no changes. - Removed the unused
EdgeDetectorinterface, and corrected documentation that claimed the fallback scanner detects corners automatically. It does not, and never did: the crop quad starts as a fixed inset that the user positions. Automatic detection comes from ML Kit on Android and Vision on iOS. - Documented that
noOfPagesis applied after the fact by the iOS document camera, which exposes no page limit of its own.
2.8.0 #
iOS #
- Added document image filter options (Original, Color, Grayscale, B&W) to the custom document cropper (
CunningDocumentCropperViewController) when importing images from the gallery, achieving feature parity with Android ML Kit (fixes #153).
2.7.0 #
General #
- Added
CunningDocumentScanner.cleanCache()to clear temporary scanned images and generated PDF files from local storage. - Enforced
noOfPagespage limit validation in Dart (noOfPages > 0), throwing anArgumentErrorwhen invalid values are supplied. - Documented exception handling for
ArgumentErrorandCunningDocumentScannerExceptionin DartDoc comments andREADME.md.
iOS #
- Added manual document cropper for gallery-imported images (
ScannerSource.gallery), resolving the limitation where gallery images could not be manually cropped before export. - Implemented
noOfPageslimit handling in bothPHPickerViewControllerselection limit andVNDocumentCameraViewController. - Implemented native
cleanCachesupport. - Implemented a circular
MagnifierViewprecision zoom lens centered over handles during touch dragging, providing pixel-perfect corner positioning. - Added a cancel confirmation dialog to prevent accidental data loss in multi-page scanning.
- Fixed rotate button behavior to properly map cropping coordinates 90 degrees clockwise without losing user progress.
- Optimized image loading and processing:
- Offloaded heavy image orientation fixes (
fixedOrientation()) and perspective correction filters to background threads. - Wrapped background processing calls in
autoreleasepoolblocks to force immediate memory deallocation and avoid OOM crashes. - Downscaled imported gallery images to a maximum of 2048px on load to prevent concurrent memory spikes.
- Replaced CPU-intensive rotation with instant metadata orientation changes.
- Offloaded heavy image orientation fixes (
- Added translations for the new cropper discard options across all 29 localized languages.
Android #
- Implemented native
cleanCachesupport purgingDOCUMENT_SCAN_files fromcacheDirandPICTURESdirectory.
2.6.0 #
Android #
- Removed HMS (Huawei Mobile Services) support entirely to ensure 16 KB page-size compatibility on Android 15+ (fixes #146).
- Replaced deprecated
getParcelable(key)with type-safeandroidx.core.os.BundleCompat.getParcelablefor Android 13+ compatibility. - Migrated the legacy
androidblock to the modernconfigure<LibraryExtension>block and updated conditional Kotlin plugin application inbuild.gradle.ktsto resolve build/deprecation warnings. - Removed redundant and deprecated
sourceSetsblock, as Kotlin source directories are resolved automatically by Gradle.
2.5.0 #
General #
- Introduced
ScannerSourceenum to specify the source of document images:camera,gallery, orcameraAndGallery. - Deprecated
isGalleryImportAllowedin favor ofscannerSource. IfscannerSourceis provided, it takes precedence andisGalleryImportAllowedis ignored.
Android #
- Added automatic document edge detection for Huawei Mobile Services (HMS) devices using HMS ML Kit Document Skew Correction.
- Fixed a crash/restart loop issue on older GMS+HMS dual-service devices (such as Honor 8X and Huawei P30 Lite) by bypassing GMS and launching the fallback scanner directly on HMS-enabled devices.
- Added direct gallery selection support. When
ScannerSource.galleryis chosen, the system launches the device's image picker and routes the selected image directly to the fallback crop editor (DocumentScannerActivity) for edge adjustment and perspective correction.
iOS #
- Integrated direct gallery picker navigation. When
ScannerSource.galleryis chosen, the plugin opens the native photo library (PHPickerViewController) directly, bypassing the alert/choice menu.
2.4.0 #
General #
- Added cross-platform support for native PDF export. Call
CunningDocumentScanner.getPictures(asPdf: true)to return a list containing a single path pointing to the generated PDF.
Android #
- Removed redundant camera and storage permissions from
AndroidManifest.xml. - Android no longer prompts the user for camera or storage permissions at runtime since ML Kit and the fallback camera intent handle them without requiring permission in the host app.
- Integrated native PDF support in both the Google Play Services ML Kit Document Scanner and the local low-RAM fallback scanner (using built-in
PdfDocument). - Migrated to "Built-in Kotlin" support, removing manual Kotlin Gradle Plugin (KGP) application for future Flutter compatibility.
- Updated Gradle wrapper to
8.14.5. - Updated Android Gradle Plugin (AGP) to
8.13.1. - Updated Kotlin version to
2.2.21.
iOS #
- Camera permission request remains active and required for iOS VisionKit.
- Integrated native PDF compilation using
PDFKit(converting VisionKit scan pages into a single PDF document). - Added native support for
isGalleryImportAllowedon iOS. Users can now choose to scan using the camera (VisionKit) or import existing documents from their photo library (PHPickerViewControlleron iOS 14+ supporting multi-selection, andUIImagePickerControlleron iOS 13). Imported images undergo the same native PDF/image conversion pipeline. - Added native localization support supporting 29 major languages for the iOS source selection Action Sheet and VisionKit interface. Included explicit color themes using KVC to guarantee text visibility across custom dark/light themes.
2.3.0 #
Android #
- Upgraded Gradle wrapper to version
8.14.5. - Modernized Kotlin configuration to use the new
compilerOptionsDSL instead of legacykotlinOptions. - Cleaned up legacy build script configurations, removing deprecated dependencies (
kotlin-stdlib-jdk7) and applying standard Kotlin DSL configurations.
2.2.0 #
Android #
- Added support for configuring the ML Kit document scanner mode.
- Added
AndroidScannerModeenum (full,base,baseWithFilter) to choose between different scanning pipelines.
2.1.0 #
General #
- Bumped Dart SDK constraint to
>=3.5.0 <4.0.0. - Bumped Flutter SDK constraint to
>=3.24.0. - Upgraded
permission_handlerto^12.0.3. - Upgraded
flutter_lintsconstraint to^6.0.0. - Moved
permission_handler_platform_interfacetodev_dependencies. - Modernized Flutter code syntax.
- Added launch configurations for VS Code.
iOS #
- Migrated the iOS plugin to Swift Package Manager (SPM) for modern Flutter integration.
- Reorganized the iOS directory structure under
ios/cunning_document_scanner/and addedPackage.swift. - Renamed
SwiftCunningDocumentScannerPlugintoCunningDocumentScannerPlugin.
2.0.0 #
Breaking Changes #
- Reorganized library structure: all implementation files moved to
lib/src/directory. - Renamed
ios_options.darttoios_scanner_options.dartfor better clarity. - Separated
IosImageFormatenum into its own file (ios_image_format.dart).
Improvements #
- Added custom exception
CunningDocumentScannerExceptionwith specific error codes. - Replaced generic
ExceptionwithCunningDocumentScannerException.permissionDenied()for better error handling. - Improved code organization with barrel exports - users only need a single import.
- Added comprehensive unit tests for custom exceptions.
- Enhanced equality operators for
CunningDocumentScannerException.
Migration Guide #
- No changes required for users - the public API remains the same with
import 'package:cunning_document_scanner/cunning_document_scanner.dart'; - If catching exceptions, update catch blocks to use
CunningDocumentScannerExceptioninstead of genericException.
1.4.0 #
General #
- Bumped
permission_handlerto12.0.1. - Updated the example app to use Kotlin
2.2.21, Android Gradle Plugin8.13.1, and Gradle8.13. - Added detailed documentation comments to the
CunningDocumentScannerclass.
Android #
- Upgraded
play-services-mlkit-document-scannerto16.0.0. - Updated
compileSdkto34.
1.3.1 #
- Upgraded dependencies.
1.3.0 #
- Allow users to configure the image output type on iOS (PNG or JPEG).
1.2.3 #
- Fix iOS crash where Documentscanner is not available
1.2.2 #
- Fix bitmap exception crash on Android (thanks to rosenberg_ptr)
1.2.1 #
- Add fallback for Android devices < 1.7GB RAM
1.2.0 #
- Use ML kit on Android
- dropped nocrop support
- image quality dropped
1.1.5 #
- Nmed parameters
- crop default is false
- dependencies updated
- min ios version 12 now
1.1.4 #
- Fixed iOS permission issue in example
- upgraded permission_handler
1.1.3 #
- Fixed permanently denied permission issue
- Merged crop option for android - Thanks Edwin
1.1.2 #
- iOS return unique filenames
1.1.1 #
- Updated android documentscanner library
1.1.0 #
- Exchanged android documentscanner with https://github.com/WebsiteBeaver/android-document-scanner
1.0.4 #
- Fixed conflicting requestcodes issue
1.0.3 #
- Updated permission handler constraint to ^10
- Android fixed nullsafe access issues
1.0.2 #
- Cleanup code - added images to README.md
1.0.1 #
- Fixed Playstore issue exported activity. Added documentation.
1.0.0 #
- Android and iOs Documentscanner based on Visionkit and AndroidDocument https://github.com/mayuce/AndroidDocumentScanner