github vinceglb/FileKit 0.17.0

3 hours ago

FileKit 0.17 adds directory-tree utilities and experimental browser storage on the web.

This release brings walk(), sizeRecursively() and copyRecursively() to PlatformFile, lets JS and Wasm apps store files in the browser's origin private file system, keeps iOS bookmark access working for files inside a restored folder after a device restart, and fixes navigating up Android document trees.

✨ What's New

  • Add PlatformFile.walk(maxDepth) to lazily traverse a directory tree depth-first, and PlatformFile.sizeRecursively() to compute the total size of a tree. Symbolic links are listed but never followed. Available on all platforms, including Android content:// trees and web directories picked with the directory picker. By @vinceglb in #684 (docs)
  • Add PlatformFile.copyRecursively(target, overwrite = false) to copy a file or a whole directory tree, merging into existing directories. Available on Android, Apple, JVM, Linux and Windows. By @vinceglb in #686 (docs)
  • Add experimental support for the browser's origin private file system (OPFS) on JS and Wasm: FileKit.originPrivateDir, resolveFile(), resolveDirectory() and listEntries(), plus write, writeString and delete for OPFS entries. Opt in with @OptIn(ExperimentalFileKitApi::class). By @timo-drick in #662 (docs)

✅ Improvements

  • OPFS files report up-to-date size() and lastModified() after each write, and the same OPFS entry is equal across lookups by @timo-drick in #662
  • Remove pre-API 24 fallbacks on Android: EXIF orientation is always read through ExifInterface(InputStream) and tree URIs are detected with DocumentsContract.isTreeUri by @vinceglb in #681
  • Run the JS and Wasm browser test suites in CI by @vinceglb in #683

🐛 Bug Fixes

  • Keep iOS security-scoped access for files and folders inside a restored directory bookmark, fixing Operation not permitted errors after a device restart (fixes #667) by @vinceglb in #672
  • Fix PlatformFile.parent() on Android document trees returning a URI outside the selected tree, which made list() throw Uri is not a directory (fixes #655) by @vinceglb in #658

📝 Documentation

  • Add a roadmap to FileKit 1.0 by @vinceglb in #692
  • Add a zip archives recipe showing how to create and extract zip archives with kmp-zip, including Zip Slip and decompression-bomb safeguards (closes #298) by @vinceglb in #685
  • Document web storage with the origin private file system: opt-in, secure-context requirement, persistence and which entries can be written or deleted by @timo-drick and @vinceglb in #662
  • Document directory traversal and recursive copying, including symbolic-link, Android and Windows behavior, in #684 and #686
  • Document iOS bookmark lifetime and releaseBookmark() behavior in #672

⬆️ Dependency Updates

  • Gradle 9.7.1 → 9.8.2
  • Kotlin 2.4.20 → 2.4.21
  • Android Gradle Plugin 9.4.0 → 9.4.1
  • Android min SDK 23 → 24
  • Android target SDK (sample app) 36 → 37
  • Compose Multiplatform 1.12.0 → 1.12.2
  • kotlinx-serialization 1.11.0 → 1.12.0
  • AndroidX Annotation 1.10.0 → 1.11.0
  • Navigation 3 1.1.1 → 1.2.0
  • Coil 3.6.2 → 3.6.3
  • dbus-java 5.2.0 → 5.2.2
  • Nucleus 2.5.15 → 2.5.18

⚠️ Migration Notes

  • Android min SDK is now 24. Apps using FileKit must set minSdk to 24 or higher.
  • Android target SDK 37 (Android 17) only applies to the sample app: FileKit's library modules don't set a target SDK, so your app keeps its own. No storage, SAF, Photo Picker or MediaStore behavior changes affect FileKit on Android 17.
  • iOS: releaseBookmark() now takes effect for restored bookmarks (it was a no-op in 0.15.0 and 0.16.0). Release a bookmark only after finishing all operations on it and its descendants. Calling startAccessingSecurityScopedResource() directly after release now throws instead of returning false; Swift callers should avoid this call after release. Existing bookmark data needs no migration.
  • Android: parent() on a document-tree URI now stops at the tree you selected: calling it on the selected root, or on a content:// URI whose parent can't be determined, returns null. Handle the null case when navigating up.
  • The OPFS API is experimental and may change in a future release. Opt in with @OptIn(ExperimentalFileKitApi::class). OPFS directories aren't supported by list(), walk() or sizeRecursively(); use listEntries().

🙏 Contributors

Thanks a lot to @timo-drick for bringing origin private file system support to FileKit ❤️

Thanks also to @N7ghtm4r3 for proposing the directory utilities in #666 and #671, and to @licryle, @luuimora and @rohan-paudel for their detailed reports.

Full Changelog: 0.16.0...0.17.0

Don't miss a new FileKit release

NewReleases is sending notifications on new releases.