How to access a Security Scoped Resource from a String Path in Swift?

555

UIDocumentPickerViewController provides a security-scoped URL to access a resource and it is not possible to make the same from a string path:

If you need a security-scoped URL’s path as a string value (as provided by the path method), such as to provide to an API that requires a string value, obtain the path from the URL as needed. Note, however, that a string-based path obtained from a security-scoped URL does not have security scope and you cannot use that string to obtain access to a security-scoped resource. https://developer.apple.com/documentation/foundation/nsurl

If you need to save or share a location of secured resource in your code you should use bookmarks:

// Get bookmark data from the provided URL
let bookmarkData = try? pickedURL.bookmarkData()
if let data = bookmarkData {
    // Save data
    ...
}

...

// Access to an external document by the bookmark data
if let data = bookmarkData {
    var stale = false
    if let url = try? URL(resolvingBookmarkData: data, bookmarkDataIsStale: &stale),
       stale == false,
       url.startAccessingSecurityScopedResource()
    {
        var error: NSError?
        NSFileCoordinator().coordinate(readingItemAt: url, error: &error) { readURL in
            if let data = try? Data(contentsOf: readURL) {
                ...
            }
        }
        
        url.stopAccessingSecurityScopedResource()
    }
}
Share:
555
Frank
Author by

Frank

Updated on December 29, 2022

Comments

  • Frank
    Frank over 1 year

    I'm currently using flutter to pass a String of a valid file path to Swift in order to gain access to a security scoped resource (this part might not be relevant)

    So I have a function that accepts a String and goes like this:

    public func requestAccessToFile(filePath: String) -> Bool {
      let fileUrl = URL(fileURLWithPath: filePath)
      return fileUrl.startAccessingSecurityScopedResource()
    }
    

    I know that startAccessingSecurityScopedResource not always returns true but in this case, it should, since if I try to access the file without this returning true I get permissions error.

    A bit more context: If I try to call that startAccessingSecurityScopedResource as soon as I get the URL from the file picker, it does succeed, but if I do it with the function it fails (notice that the function is called with a String and I'm passing a path without the file:// protocol. eg. "/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/Documents/afile.pdf"

    So my guess is that the URL created by the file picker is somehow different that the one I'm creating with the string path. But not sure.

    Thanks for your help in advance.

    • Frank
      Frank almost 3 years
      Ahh, an extra comment, it does work on the emulator, it only fails on a physical device.
  • Frank
    Frank almost 3 years
    Thanks! Will check the bookmark part today.