Releases: jvoltci/saf
Release list
saf 2.1.0 — file descriptors, thumbnails, hardened file layer
What's new
Raw file descriptors
Hand a SAF file to anything that wants a real path or fd — video players, PDF renderers, sqlite — no copy:
final title = await saf.withFileDescriptor(doc.uri, 'r', (fd) async {
return someNativeLib.readMetadata(fd.path); // /proc/self/fd/<fd>
});openFileDescriptor / closeFileDescriptor are also available for manual control. The descriptor is always closed for you with withFileDescriptor — even when your action throws.
Provider thumbnails
thumbnail(uri, width, height, quality) returns provider-generated JPEG bytes (Uint8List?) — perfect for gallery grids with Image.memory, no full-image decode.
Mini file-manager example
cd example && flutter run: pick a folder, browse it with live image thumbnails, tap a file for its details and fd path, write a file back. Verified on physical hardware against a 5,613-file camera roll.
Hardened file layer
- An aborted
writeFileStreamno longer deletes a pre-existing target (overwrite/append) — only documents created by that write are cleaned up. copyTo/moveTonow reject copying a directory into itself or its own subtree.releasePersistedPermissionnow actually releases directory grants taken bypickDirectory.- Picker failures (e.g. no SAF handler on some Android TV/Go builds) no longer wedge all future picks.
openReadSessionno longer leaks the stream when the initial seek fails.- Deprecated legacy
FileTypes; internalmapPlatformExceptionremoved from the public API.
Full changelog: https://github.com/jvoltci/saf/blob/master/CHANGELOG.md
Docs: https://jvoltci.github.io/saf/
saf 2.0.0 — one class for the Storage Access Framework
One Saf class covers everything SAF — full native create/read/write/update/delete (no dart:io on granted folders), typed errors, streaming with backpressure, recursive walk, progress, and hidden-folder support.
Highlights
- Pickers + persisted permissions — grant once, reuse across restarts;
persistedPermissions()lists grants. - File management —
list(fast single-cursor),stat,exists,child,mkdirp,delete,rename, recursivecopyTo/moveTowith progress, recursivewalk(). - Read/write —
readFileBytes,readFileStream(pull-based, no OOM on huge files),writeFileBytes, one-callwriteFileStream. - Bridge to local files —
copyToLocalFile,pasteLocalFile, andcopyDirToLocal(pull a whole granted folder — e.g. WhatsApp.Statuses— into your app dir). - Typed errors —
SafPermissionException,SafNotFoundException,SafAlreadyExistsException,SafIoException. - No
isDirparams anywhere. Broad support: Dart >=3.0, Flutter >=3.10, minSdk 21.
Breaking
The legacy path-based class is now LegacySaf (deprecated, removed in 3.0.0). Migrate with Saf( -> LegacySaf(. See the README.
Docs & quality
Docs: https://jvoltci.github.io/saf/ · pana 150/150 · verified end-to-end on a physical Android 15 device.
Fixes: #8 #24 #27 #34 #36 #37 #39 #41 (and #31 — docs are back).