Skip to main content
Available on Android, iOS, macOS, and JVM targets

The Problem: Losing File Access

Modern operating systems use security measures like sandboxing, which means your app can lose access to files selected by the user once it restarts. A standard file path might become invalid. This is especially true on Android (for files outside your app’s private storage) and on sandboxed apps on macOS and iOS.

The Solution: Bookmark Data

BookmarkData is a feature that creates a persistent, secure reference to a file. You can save this reference and use it later to reliably regain access to the file, even after your app has been closed and reopened. FileKit handles the complex platform-specific implementations for you.

The Basic Workflow

The process involves two main steps: creating and saving a bookmark, and later loading and resolving it.
fromBookmarkData() remains a supported, non-deprecated convenience API when you only need the restored file. Use resolveBookmarkData() when your application also needs refresh metadata or can update its stored bookmark:
  • isStale means the operating system resolved the bookmark but reported that its native representation should be recreated.
  • shouldRefresh is FileKit’s broader recommendation. It is also true when FileKit successfully resolves bookmark data written by an older FileKit version.
Refreshing is advisory. The old bookmark may still work, and refresh can fail if the resource disappeared or macOS already revoked access. In that case, ask the user to select the file or directory again.

Complete Example

Here’s a more complete, practical example using a simple object to manage the bookmark.

Platform-Specific Behavior

FileKit abstracts away the details, but here’s what happens on each platform:
  • Android: For standard file paths, the path itself is stored. For content:// URIs from the system picker, FileKit requests persistent URI permissions and stores the URI string. This ensures long-term access.
  • iOS: Uses Foundation bookmark data and keeps the security-scoped URL behavior supplied by the system document picker. The explicit persistent bookmark flags described below are macOS-only.
  • Kotlin/Native macOS: Uses a native macOS bookmark. FileKit automatically creates an explicit security-scoped bookmark when the running application adopts App Sandbox and a regular native bookmark otherwise.
  • JVM macOS: Uses the same versioned native bookmark format through CoreFoundation. A PlatformFile restored from a security-scoped bookmark retains its access capability, including for children inside a bookmarked directory.
  • Kotlin/Native Linux, JVM Linux, and Windows: Stores the file path. These platforms use a path-based bookmark representation.
New macOS bookmark data is wrapped in a versioned FileKit format. Existing unwrapped Kotlin/Native bookmarks and JVM path bytes remain readable. Bookmark bytes are platform-specific and must not be treated as portable between operating systems or applications.

macOS App Sandbox Setup

Persistent access to user-selected locations outside a macOS application’s container requires appropriate signing entitlements. Configure the packaged application with:
FileKit reads the signed App Sandbox entitlement at runtime and selects security-scoped bookmark creation automatically. When sandboxing is enabled, failure to create scoped bookmark data is reported instead of silently falling back to a bookmark that cannot restore access across launches. Keep security-scoped access balanced. FileKit does this around its own file operations and keeps access active until returned sources and sinks are closed. Use withScopedAccess when passing a restored file to another library:
Call releaseBookmark() when the restored bookmark is no longer needed. It prevents new scoped operations, which then fail with FileKitException, while allowing already-open sources and sinks to close cleanly.

Handling Invalid and Legacy Bookmarks

A bookmark is not a guarantee. It can become invalid if the original file is deleted, moved, or if permissions change. A stale bookmark is different: it resolved successfully but should be recreated. Legacy bookmark data is also different: FileKit resolved an older representation and recommends replacing it.
Always handle restoration failures gracefully. A bookmark can become invalid if:
  • The user moves or deletes the file.
  • The user revokes file permissions for your app.
  • System security policies change.
  • The app is uninstalled and reinstalled (on some platforms).
Your code should anticipate that restoring from a bookmark might fail.
This defensive approach ensures your app doesn’t crash from an invalid bookmark and can self-heal by clearing invalid data.