Giving my app read access to the Desktop/ Documents of the current user

I would like to give Desktop Access to my app using this pop up on launch for the first time exactly like Bridge does.

Do I need Privileged File Operation entitlement or is there a way to get around this without paying to become an apple developer?

I'm not planning on releasing my app on the Mac app store but it does need to be sandboxed due to using finder sync.

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        let url = URL(fileURLWithPath: "/Users/useraccount/Desktop/", isDirectory: true)

        let configuration: NSWorkspace.OpenConfiguration = NSWorkspace.OpenConfiguration()
        configuration.promptsUserIfNeeded = true

        let finder = NSWorkspace.shared.urlForApplication(withBundleIdentifier: "com.apple.finder")

       
        NSWorkspace.shared.open([url], withApplicationAt: finder!, configuration: configuration)
       }

This code only makes this pop up appear

Any help much appreciated.

Answered by DTS Engineer in 753367022

If you could send me a code snippet

Sure. Here’s what I did this morning:

  1. Using Xcode 14.3 on macOS 13.3.1, I created a new project from the macOS > App template, selecting SwiftUI.

  2. In Signing & Capabilities I removed the App Sandbox, which the template adds by default.

  3. I also check that automatic signing is enabled and my team selected. This results in the app being signed with my standard Apple Development signing identity.

  4. I added a Test button that calls this function:

    func test() {
        do {
            print("will find desktop")
            let desktop = try FileManager.default.url(for: .desktopDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            print("did find desktop, url: \(desktop)")
            print("will list contents")
            let contents = try FileManager.default.contentsOfDirectory(at: desktop, includingPropertiesForKeys: nil)
            print("did list contents, count: \(contents.count)")
        } catch {
            print("did fail")
        }
    }
    
  5. I ran the app and clicked on the Test button. This presented the expected alert (screen shot below).

  6. I clicked Allow. Back in Xcode I saw the app print:

    will find desktop
    did find desktop, url: file:///Users/quinn/Desktop/
    will list contents
    did list contents, count: 51
    

Share and Enjoy

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

Do I need Privileged File Operation entitlement or is there a way to get around this without paying to become an apple developer?

Those are two independent things.

To start, read On File System Permissions, which describes the difference between the sandbox and MAC restrictions.

You can happily add a temporary entitlement to disable the sandbox restriction here. You cannot, however, disable the MAC check (that’s the mandatory bit). Rather, the system will generate this alert, the user can deny or allow access, and then it will remember their answer.

Which brings us back to your first question. In order for the system to remember the answer your code must be signed with a stable signing identity. The best way to get that is to join a paid developer program. You will need to do that in order to get a Developer ID signing identity if you want to distribute your app without Gatekeeper entanglements.

Share and Enjoy

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

Ok, so to clarify.

I need to add a temporary entitlement to disable the sandbox restriction.

And then I need to get a Developer ID signing identity to remember the answer to the MAC check.

However I do not need to have a Developer ID signing identity to prompt the MAC check?

From what I understand I should be getting a MAC check even if it doesn't remember my answer, but I am not when trying to access the desktop.

And then I need to get a Developer ID signing identity to remember the answer to the MAC check.

You need a stable signing identity for the MAC check to work reliably. Given that you’re distributing independently, that’s a Developer ID Application signing identity for your actual distribution. During development I recommend that you use an Apple Development signing identity [1].

However I do not need to have a Developer ID signing identity to prompt the MAC check?

MAC is mandatory. It applies even to unsigned code [2].

However, run unsigned code involves exploring the edges of TCC’s implementation. It is, IMO, a waste of time, because your final product will have to be signed. So always sign your code with a stable signing identity.

As to what’s going on in your specific case, it’s hard to say without running more tests. It’s possible that TCC is simply confused on your system. If switching to Apple Development signing doesn’t fix things, try resetting TCC using tccutil. If that doesn’t help, try running your program on a ‘clean’ machine to see if it reproduces the problem there.

Share and Enjoy

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

[1] Because Developer ID signing identities are precious, as discussed in my posts on this thread.

[2] If you’re on Apple silicon, all code must be signed so read ad-hoc signed code for unsigned code.

Hi Eskimo, I am currently signing my code with my Apple ID and I believe an Apple Development Certificate is this the correct form of a stable signing identity? I'll give it a go running my code on a clean machine, but unfortunatley using tccutil didn't work.

Accepted Answer

If you could send me a code snippet

Sure. Here’s what I did this morning:

  1. Using Xcode 14.3 on macOS 13.3.1, I created a new project from the macOS > App template, selecting SwiftUI.

  2. In Signing & Capabilities I removed the App Sandbox, which the template adds by default.

  3. I also check that automatic signing is enabled and my team selected. This results in the app being signed with my standard Apple Development signing identity.

  4. I added a Test button that calls this function:

    func test() {
        do {
            print("will find desktop")
            let desktop = try FileManager.default.url(for: .desktopDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            print("did find desktop, url: \(desktop)")
            print("will list contents")
            let contents = try FileManager.default.contentsOfDirectory(at: desktop, includingPropertiesForKeys: nil)
            print("did list contents, count: \(contents.count)")
        } catch {
            print("did fail")
        }
    }
    
  5. I ran the app and clicked on the Test button. This presented the expected alert (screen shot below).

  6. I clicked Allow. Back in Xcode I saw the app print:

    will find desktop
    did find desktop, url: file:///Users/quinn/Desktop/
    will list contents
    did list contents, count: 51
    

Share and Enjoy

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

Giving my app read access to the Desktop/ Documents of the current user
 
 
Q