Read from smb server connected in 'Files' App

Hey,

This is my code. I have the url of the smb server which I have connected in the 'Files' app. It finds the file on the server, but I always says that it has no permission to read it. On my server I have allowed everyone to read and write. Do I need to write something in my code that my app knows that it has permission to read ?

let url: URL = URL(fileURLWithPath: "/private/var/mobile/Library/LiveFiles/com.apple.filesystems.smbclientd/xVUdQwTestApp/testaufbau.csv")
do
{
    let fileURLs =  try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil)
            

    Admin.fileContent = try String(contentsOf: fileURLs[0], encoding: .utf8)

    print("ADMIN: \(Admin.fileContent)")
            
            
}
catch
{
    print(error)
}

Thank you for all the help

Regards,

Tell Tobler

Accepted Reply

If you have a security-scoped URL, you must bracket your actual file system access with

startAccessingSecurityScopedResource()
and
stopAccessingSecurityScopedResource()

If you want to persist access to that URL, you must use a security-scoped bookmark. For example, to get a bookmark to save:

let bookmark = try url.bookmarkData(options: [.withSecurityScope], includingResourceValuesForKeys: nil, relativeTo: nil)

And to get a URL from that bookmark:

var isStale = false
let resolvedURL = try URL(resolvingBookmarkData: bookmark, options: [.withSecurityScope], relativeTo: nil, bookmarkDataIsStale: &isStale)

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

Your iOS app is sandboxed, and it can only access files as allowed by the sandbox. This typically means:

  • Files within your app’s container

  • Files within any shared app group containers

  • Various system files, like resources in frameworks

Accessing other files, like the files on an SMB volume, requires that the system extend your sandbox to allow this. The way that the system extends your sandbox is the iOS document architecture. For example, if you run the document browser and the user chooses a document, the system extends your sandbox so that you can access that document. You can also use a security-scoped bookmark to maintain access to that document.

If you haven’t already, check out WWDC 2019 Session 719 What’s New in File Management and Quick Look, which builds on the discussion of fundamentals in WWDC 2018 Session 216 Managing Documents In Your iOS Apps.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I was already trying bookmark: https://developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories

I found this in the Documentation. If you scroll down to Save the URL as a Bookmark could you please explain me where they get this from?


getMyURLForBookmark()



try bookmarkData.write(to: getMyURLForBookmark())


How can I save the bookmark to use it later to write into the file.


When I try bookmark I always get the error

Cannot convert value of type 'appName.Data' to expected argument type 'Foundation.Data'


And I also tried

let didStartAccessing = url.startAccessingSecurityScopedResource()
            defer
            {
                if didStartAccessing
                {
                    url.stopAccessingSecurityScopedResource()
                }
            }

But this doesn't help. I always get the error 'Operation not permitted'

How did you get the URL in the first place?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

When I printed it in the console with the didPickDocumentAt function I copied it and pasted it in my read function. I know that this is very bad, but I couldn't figure out how to save it with bookmark.

So my question now is how do I save the url in a bookmark when it calls didPickDocumentAt and than later use it in my writing/reading functions and do not get the error that I do not have the permission for this?

If you have a security-scoped URL, you must bracket your actual file system access with

startAccessingSecurityScopedResource()
and
stopAccessingSecurityScopedResource()

If you want to persist access to that URL, you must use a security-scoped bookmark. For example, to get a bookmark to save:

let bookmark = try url.bookmarkData(options: [.withSecurityScope], includingResourceValuesForKeys: nil, relativeTo: nil)

And to get a URL from that bookmark:

var isStale = false
let resolvedURL = try URL(resolvingBookmarkData: bookmark, options: [.withSecurityScope], relativeTo: nil, bookmarkDataIsStale: &isStale)

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

My experience with this indicates that you also have to enclose the call to URL(resolvingBookmarkData:) between startAccessingSecurityScopedResource() and stopAccessingSecurityScopedResource() for it to work reliably. After much searching, I only found a passing reference to this fact somewhere on the web (which, to my knowledge, appears not to be properly documented) and suddenly, a lot of issues I was having went away as if by magic.

My experience with this indicates that you also have to enclose the call to URL(resolvingBookmarkData:) between startAccessingSecurityScopedResource() and stopAccessingSecurityScopedResource() for it to work reliably.

Can you explain what you mean by this. As written it suggests a structure like this:

u.startAccessingSecurityScopedResource()
let u = try URL(resolvingBookmarkData: …)
u.stopAccessingSecurityScopedResource()

but that doesn’t make sense because you don’t know u until the second line.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"