I have an iOS app that is trying to read files from an external storage device without importing them into the App's sandbox.
I have followed Apple's documentations outlined here to do this --
Providing Access to Directories
I'm able to retrieve the selected directory ( which is on an external storage device connected via the Lightning port ) and enumerate the files inside the directory.
However, when I try to do something with those files as per the recommended pattern, I get a failure and basically get permission errors on the file.
let shouldStopAccessing = pickedFolderURL.startAccessingSecurityScopedResource()
defer {
if shouldStopAccessing {
pickedFolderURL.stopAccessingSecurityScopedResource()
}
}
var coordinatedError:NSError?
NSFileCoordinator().coordinate(readingItemAt: pickedFolderURL, error: &coordinatedError) { (folderURL) in
let keys : [URLResourceKey] = [.isDirectoryKey]
let fileList = FileManager.default.enumerator(at: pickedFolderURL, includingPropertiesForKeys: keys)!
for case let file as URL in fileList {
if !file.hasDirectoryPath {
do {
// Start accessing a security-scoped resource.
guard file.startAccessingSecurityScopedResource() else {
// Handle the failure here.
//THIS ALWAYS FAILS!!
return
}
// Make sure you release the security-scoped resource when you are done.
defer { file.stopAccessingSecurityScopedResource() }
I should add that this works JUST FINE if the files are on iCloud Drive via Simulator. It fails both on external devices and iCloud Drive on a real device.
Here is a full working project that demonstrates the failure.
Apple made this possible with the release of iOS 13 in 2019, adding native support for external storage devices using both Lightning and USB-C connectors.
You can use the Files app and other supported apps to access files stored on external devices, such as USB drives and SD cards, connected to your iPhone.
So, this seems like a documentation issue with the link posted above. When the user selects a folder, all files and folders are recursively granted access and automatically security scoped. The line guard file.startAccessingSecurityScopedResource()
always returns false.
The trick to getting this work is NOT to try to security scope individual files, but to ensure that this code snippet does not run BEFORE you access files.
defer {
if shouldStopAccessing {
pickedFolderURL.stopAccessingSecurityScopedResource()
}
}
As long as you continue to access files while the pickedFolderURL
is inside security scope, you will be successful.
Hope this helps somebody.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With