When working with large files, especially media files from user's gallery it is not desirable to make copies for large media files.
It would be really great to have an option for selecting files that would to return a "persistent" link/path that could use used at any time later to access selected file content.
On MacOS, Windows, Linux
Should be okay to return the full file path and have the original file:// url in the PlatformFile.identifier
Though
On iOS
If a user picks a file outside app's sandbox, the OS grants a temporary security token. To access it later without copying it, the native file URL need to be converted to into a Security-Scoped Bookmark:
- Create a Bookmark (Save Access). Convert selected file URL.
func createSecurityScopedBookmark(from fileURL: URL) -> String? {
// MUST explicitly declare intent to access the file resource
guard fileURL.startAccessingSecurityScopedResource() else {
print("Failed to start accessing security-scoped resource.")
return nil
}
// Ensure resource access is released when the function completes
defer {
fileURL.stopAccessingSecurityScopedResource()
}
do {
// Generate security-scoped data bytes
let bookmarkData = try fileURL.bookmarkData(
options: .withSecurityScope, // Required for sandboxed apps
includingResourceValuesForKeys: nil,
relativeTo: nil
)
// convert to a Base64 string for storing it
return bookmarkData.base64EncodedString()
} catch {
print("Error creating bookmark: \(error.localizedDescription)")
return nil
}
}
- Resolve a Bookmark (Regain Access Later). Call this on a future app launch using the base64-encoded bookmark string.
func resolveSecurityScopedBookmark(from base64String: String) -> URL? {
guard let bookmarkData = Data(base64Encoded: base64String) else {
print("Invalid base64 string.")
return nil
}
do {
var isStale = false
// Resolve data back into a valid security-scoped URL
let resolvedURL = try URL(
resolvingBookmarkData: bookmarkData,
options: .withSecurityScope,
relativeTo: nil,
bookmarkDataIsStale: &isStale
)
if isStale {
print("Bookmark data is stale. You may need to ask the user to pick the file again.")
}
return resolvedURL
} catch {
print("Error resolving bookmark: \(error.localizedDescription)")
return nil
}
}
// How to read the file contents using the resolved URL
func printFileContents(at url: URL) {
if url.startAccessingSecurityScopedResource() {
defer { url.stopAccessingSecurityScopedResource() }
// Do your file reading operations safely here
if let data = try? Data(contentsOf: url) {
print("Successfully read \(data.count) bytes directly from the original file source!")
}
} else {
print("Permission denied to access the resolved URL.")
}
}
On Android
You cannot use raw file paths (/storage/emulated/0/...). Instead, can use the native storage access framework to capture the content:// URI and request long-term persistence permissions. See shared_storage or more recently updated saf_util and saf_stream packages for Android.
The PlatformFile.identifier property already containing the content:// URI. Though there is no API to read data or create a PlatformFile for a previously saved URI.
Also it seem like there is no option to not create a temp file when there is content:// resource selected. Perhaps it could be added to AndroidSAFOptions.
When working with large files, especially media files from user's gallery it is not desirable to make copies for large media files.
It would be really great to have an option for selecting files that would to return a "persistent" link/path that could use used at any time later to access selected file content.
On MacOS, Windows, Linux
Should be okay to return the full file path and have the original file:// url in the
PlatformFile.identifierThough
On iOS
If a user picks a file outside app's sandbox, the OS grants a temporary security token. To access it later without copying it, the native file URL need to be converted to into a Security-Scoped Bookmark:
On Android
You cannot use raw file paths (/storage/emulated/0/...). Instead, can use the native storage access framework to capture the content:// URI and request long-term persistence permissions. See
shared_storageor more recently updatedsaf_utilandsaf_streampackages for Android.The
PlatformFile.identifierproperty already containing the content:// URI. Though there is no API to read data or create aPlatformFilefor a previously saved URI.Also it seem like there is no option to not create a temp file when there is
content://resource selected. Perhaps it could be added toAndroidSAFOptions.