MAS app disk access

My apps restore the last session automatically at startup if that option is checked in the Preferences. This works for apps that I sell through my website, but a customer reported that one of my apps bought on the Mac App Store doesn’t load projects unless he does it manually.

The entitlements has an entry for files.user-selected.read-write

So I guessed he must have to give the app disk acces in the System Preferences, but then I found out that Apple has removed that from the System Preferences (!? edit: looks like I’m wrong there?)

Anyone else run into this? What can be done about it?

The Apple-approved method for accessing a file between sessions is to store a Security Scoped Bookmark.

It does seem there is a MBS solution if you have access to those plugins:
https://monkeybreadsoftware.net/example-maccf-sandboxfileaccess-sandboxfiles.shtml

Everything I can find regarding Full Disk Access and Sonoma seem to indicate it should still be there. What version of macOS are you using?

Thanks, I could never get Security Scoped Bookmarks to work (apparently they are inherently buggy – Sam Rowlands calls them “Security Scoped Bodgemarks”).

If the disk access is still there, I’ll ask him to try that. I guessed I’d missed something, but when I went to Security on the Prefs, I didn’t see any place to give apps access … I’m getting old. And I’m at the point where I just expect Apple to remove useful features from the OS with every update.

Forgot to say: Sonoma

As much as I hate videos where a short sentence will do, this video seems to indicate the section should still be there: https://www.youtube.com/watch?v=10XP36ZT_iM

2 Likes

Update from the customer, giving full disk access to the app doesn’t fix it :confused:

The workaround I gave him is to boot the app from a saved application. At least that works.

Apparently, the problem is the App Sandbox. That seems to prohibit the app from automatically opening files. Anyone have a solution?

Yes, this works fine for every file which the user opens manually. Otherwise, you have really borked something. For recent files you need to use the SSBs. There is code in the forum on how to make them work.

Okay. What I found on the forum is about how they don’t work reliably, but I guess you got them working? I assume you use the MBS classes?

No, I never got MBS to work. This is from the forum:

Public Function GetBookmarkData(f as FolderItem, relativeTo as FolderItem = nil, Mode as Integer = 0) As String
  #Pragma Unused mode
  //# Mimicks (better) FolderItem.GetSaveInfo with modern system calls. Mode is actually not used. The bookmark will be relative if and only if you set a RelativeTo FolderItem.
  
  declare function NSClassFromString Lib CocoaLib (aClassName as CFStringRef) As Ptr
  declare function URLWithString lib CocoaLib selector "URLWithString:" (cls as Ptr, URLString as CFStringRef) as Ptr
  declare function BookmarkDataWithOptions lib CocoaLib selector "bookmarkDataWithOptions:includingResourceValuesForKeys:relativeToURL:error:" (id as Ptr, options as Integer, rsrc as Ptr, relativeTo as Ptr, byref error as Ptr) as Ptr
  declare function DataLength lib CocoaLib selector "length" (id as Ptr) as integer
  declare sub DataBytes lib CocoaLib selector "getBytes:length:" (id as Ptr, dest as Ptr, length as integer)
  
  const CocoaLib = "Cocoa.framework"
  
  dim url as Ptr = URLWithString(NSClassFromString("NSURL"), f.URLPath)
  dim relativeNSURL as Ptr
  dim err as Ptr
  
  if relativeTo <> nil then
    relativeNSURL = URLWithString(NSClassFromString("NSURL"), relativeTo.URLPath)
  end if
  
  dim data as Ptr = BookmarkDataWithOptions(url, 0, nil, relativeNSURL, err)
  
  if data <> nil then
    dim L as integer = DataLength(data)
    dim mb as new MemoryBlock(L)
    DataBytes data, mb, L
    return EncodeBase64(mb.StringValue(0, L))
  end if
    
End Function
Public Function ResolveBookmark(data as String, relativeTo as FolderItem = nil) As Folderitem
  //# Resolves a bookmark and returns the corresponding FolderItem. If you created a relative Bookmark, you MUST provide the same RelativeTo parameter as during creation.
  
  data = DecodeBase64(data)
  
  declare function NSClassFromString Lib CocoaLib (aClassName as CFStringRef) As Ptr
  declare function URLWithString lib CocoaLib selector "URLWithString:" (cls as Ptr, URLString as CFStringRef) as Ptr
  declare function URLByResolvingBookmarkData lib CocoaLib selector "URLByResolvingBookmarkData:options:relativeToURL:bookmarkDataIsStale:error:" (cls as Ptr, data as Ptr, options as integer, relativeto as Ptr, byref stale as Boolean, byref err as Ptr) as Ptr
  declare function DataWithBytes lib CocoaLib selector "dataWithBytes:length:" (cls as Ptr, bytes as Ptr, length as integer) as Ptr
  declare function absoluteString lib CocoaLib selector "absoluteString" (id as Ptr) as CFStringRef
  
  dim url as Ptr
  dim relativeNSURL as Ptr
  dim stale as boolean
  dim err as Ptr
  
  if relativeTo<>nil then
    relativeNSURL = URLWithString(NSClassFromString("NSURL"), relativeTo.URLPath)
  end if
  
  dim mb as MemoryBlock = data
  dim nsdata as Ptr = DataWithBytes(NSClassFromString("NSData"), mb, mb.size)
  
  url = URLByResolvingBookmarkData(NSClassFromString("NSURL"), nsdata, 0, relativeNSURL, stale, err)
  
  if url <> nil then
    return new FolderItem(absoluteString(url), FolderItem.PathModes.URL)
  end if
  
End Function
1 Like

The last time I tried to get it working was with MBS and I also couldn’t get it to work, so I’ll try this. Thanks!

It looks like those two methods aren’t quite enough to get it working (at least I couldn’t), but the good news is that JimMcKay put together a project with everything needed to get it to work:

I noticed you added the entitlement for files.user-selected.read-write above which made me wonder if you have the Security Scoped Bookmarks Entitlements?

Thanks, that’s important. I’ve since added those for testing. Doesn’t work in the IDE, but I’m hopeful the built app will work, we’ll see.

The problem is by design. Apple provide mechanisms for automatically handling documentation restoration (without the need for those buggy Security Scoped Bodgemarks). If you use an Apple programming language you build a Document Based Application and that’s all you need to do.

I tried to replicate this with Xojo, and only got so far, tapping into NSDocument’s Recent Items list will auto retain file access between app launches. Getting Apple’s Window Restoration framework to work was much harder and IIRC I gave up at one point and wrote my own.

Hopefully someone will continue my research into this.

Have you tried it on a Arm Mac?
In fact I’ve been using it for years. But when I moved to a silicon Mac Jim’s SSB do not work anymore.

Chances were… the entry date from 10 years ago (2014).

Jim fixed his code some years later to cope with 64bit.
As I said, now it does not work in sandboxed ARM apps, but it still works for sandboxed Intel apps.

Making apps for the MAS was never fun, but it has become much more annoying over time. There are too many different situations to debug, many of which can’t be done in the IDE, can only be done with built and signed apps, and only on specific platforms.

I have just tried the code provided by Beatrix (thank you Beatrix). The sandboxed ARM app works OK: creating a SSBookmark, quitting the app, reopening the app it resolves the SSB.
So I’ll see how to implement it in my apps using Jim’s code.

Thanks for testing it. It didn’t work for me but the reason must have been the missing entitlement which Tim pointed out.

Another compiled post documenting the sandboxing problem, the code to solve it, the requirements, the dependencies, and the use with some example(s) would be superb.

Right now there are lots of fragments of non working code with no documentation scattered in several posts. Sandboxed Mac apps are really something “basic” today that should be integrated into Xojo as some kind of click-and-go thing. While it isn’t, a good community documented workaround is very welcome if someone could donate time and effort to make one.