SSBs not working when app is Sandboxed

In the AppStore version of my app the SSBs aren’t working anymore. Saving is okay. But when the app is Sandboxed then the result of getting the folderitem back always is Nil. I had a look with Christian at the code, but he also didn’t have an idea.

[code]Private Function getPrefFolderitemLite(fieldName as string) as Folderitem

'get data from preferences
if fieldName = “” then Return Nil
if not CheckForPrefs then Return Nil
if not theCFPrefs.AppSynchronize(theCFPrefs.kCFPreferencesCurrentApplication) Then
globals.theErrorLog.DialogErrorProceed(kErrorSynchronize)
end if
Dim theCFObject As CFObjectMBS = theCFPrefs.CopyAppValue(NewCFStringMBS(fieldName), theCFPrefs.kCFPreferencesCurrentApplication)
if theCFObject = Nil then Return nil

'get base64 encoded path
dim theData as String = DecodeBase64(CFStringMBS(theCFObject).str)
if theData = “” then Return Nil

dim theFolderitem as new FolderItem(theData, FolderItem.PathModes.Native)
Return theFolderitem

End Function
[/code]

[code]Private Sub setPrefFolderitemLite(fieldName as string, fieldValue as Folderitem)

'set a folderitem preference value

if fieldName = “” then Return

'just encode the path in base64
dim theData as String
if fieldValue <> Nil then theData = EncodeBase64(fieldValue.NativePath)

'make CFObjectMBS
dim theCFObject As CFObjectMBS = NewCFStringMBS(theData)

'save to prefs
if not CheckForPrefs then Return
theCFPrefs.SetAppValue(NewCFStringMBS(FieldName), theCFObject, theCFPrefs.kCFPreferencesCurrentApplication)
if not theCFPrefs.AppSynchronize(theCFPrefs.kCFPreferencesCurrentApplication) Then
globals.theErrorLog.DialogErrorProceed(kErrorSynchronize)
end if

End Sub
[/code]

Does anyone have an idea what might cause the problem? I’m really out of ideas. For now I have made a workaround with a global because the folderitem doesn’t absolutely need to be saved. But it’s really not a good idea with the global.

Xojo 2019r3, MBS latest version. Different versions of macOS.

@Beatrix Willius — I am not sure that creating a FolderItem from an absolute path works with sandboxing, because your app does (usually) not have access to each individual folder in the path. I think you would better store an Alias record or, even better, a Bookmark.

Here are 2 standalone methods to get Bookmark data from a FolderItem and resolve Bookmark data into a FolderItem, in case you need them.

Hope that helps

[code]Public Function GetBookmarkData(extends f as FolderItem, relativeTo as FolderItem = nil, Mode as Integer = 0) as String
//# 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 mb.StringValue( 0, L )
end if

End Function[/code]

[code]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.

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.PathTypeURL )
end if

End Function[/code]

Thanks, I’ll try your code.

That doesn’t look like a Security Scoped Bodgemark, it looks like you’re just encoding and decoding the path to the file.

Ha, I’m going senile. You are quite correct. Where did my code go?