Access desktop wallpaper without full disk access in sandbox

We're working on an app that will need to access and manipulate the user's current desktop wallpaper.


I can get the wallpaper path using NSWorkspace. The problem is that it's not readable when the app is sandboxed.


guard let wallpaperUrl = NSWorkspace.shared.desktopImageURL(for: NSScreen.main!) else {
    return ""
}

// This doesn't read the wallpaper image
print(NSImage(byReferencing: wallpaperUrl))


The app will always need to get the wallpaper, so using an open file modal will not work, especially since the user might not know where the wallpaper is.


I'd prefer not to require users to enable disk access before they can even use the app, because it's not a great first experience.


Is there a way to do this without full disk access?

Replies

Uses can choose any file for wallpaper, so you will have to find some other way to do it. I think what you will have to do is take over setting of the wallpaper. Your app should be able to do that. The user will have to set the desktop wallpaper using your app. Then you can do whatever it is you were planning, and then set the desktop yourself.

If the app is sandboxed then Full Disk Access is not your primary concern here, but rather the sandbox. This blocks the app from accessing arbitrary paths.

At a technical level you can use a file access temporary exceptions to get access to all paths, but that’s unlikely to fly with App Review. Probably your best option is to use an open panel to ask the user to select their desktop picture. You can use the value your got back from

NSWorkspace
to pre-select the correct file, which helps if the user doesn’t know where that is.

Share and Enjoy

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

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

Thanks for the reply Eskimo,


I didn't realize that full disk access still won't allow reading the desktop image, but after more testing I guess that's the case.


Is there any other way the app could do this without a user-initiated open dialog? It just won't work well for what we're attempting to do.


Specifically, one of the app's features will be to allow a user to place widgets (boxes with different information) on their desktop.


The way we were going about this is to create a transparent window on the desktop level that displays the widgets. The widgets need to interact with the desktop wallpaper visually in multiple ways. So we were getting the wallpaper as I showed above, and placing it within the transparent window. This mimicked the user's desktop exactly. I also created a file change listener for the file /Library/Application Support/Dock/desktoppicture.db so the app knew when the desktop changed. I know it's a little brittle since its a system file, but I couldn't find another way to do it.


This worked great until I enabled app sandbox.


Do you happen to have any other suggestions? Or are we out of luck?


I suppose that maybe the solution is to have the app manage the wallpaper itself, instead of following the system wallpaper.

I suppose that maybe the solution is to have the app manage the wallpaper itself, instead of following the system wallpaper.

I think that’s your best option. It has a bunch of benefits:

  • It avoids this specific problem

  • Removes your reliance on the undocumented-and-thus-subject-to-change Dock database.

  • It simplifies your user model. You give the user full control over the appearance of your window rather than having half of it controlled by the system.

  • It allows you to offer more customisation over the background. For example, the system has a limited set of criteria for when the desktop picture changes, and you could add more. Users love that stuff! (-:

The way we were going about this is to create a transparent window on the desktop level that displays the widgets

That’s fascinating but I want to raise a word of warning here: I’ve no idea what App Review will make of this.

Share and Enjoy

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

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

Thanks Eskimo!


I'll cross my fingers when it goes into review!