Hi Everyone,
I’m trying to get Security Scoped Bookmarks (SSBs) working after it was suggested by apple support that my app needs them to pass review on the app store. My app renames files, and for that it needs permission not only to the file, but the parent folder of the file, so my workflow is this:
-User selects file (this gives them read/write access)
-App checks for an existing SSB from a previous session and tries to gain write access to the parent folder
-App attempts to rename the file
-If the rename fails to due to a read/write error, prompt the user to select the folder
-Save a security scoped bookmark for the folder after it is selected
-Rename the file now that we have proper access
-If the user tries to rename files in that folder during a different session, the bookmark is loaded and the user does not need to select the folder again
So that seems like it should be pretty straightforward, but I have a problem: I am able to save and resolve bookmarks, but when I try to use them to access the file it doesn’t grant access.
Admittedly, I’m stumbling around in the dark here. Has anyone else tried something similar? Here is my code, I’m not sure where I’m going wrong.
PseudoCode that gives an idea of when I’m creating bookmarks, resolving them, and trying to use them:
Dim dlg as SelectFolderDialog 'prompt for parent folder access
dim b as boolean
dim fBefore as folderitem 'a file selected by the user, so it has read/write access already
dim fAfter as folderitem 'holds the new name
fAfter = fBefore.parent.child("newname.jpg")
if fAfter.exists = false then 'don't overwrite an existing file
b= ssbStart(fBefore, true) 'looks for an existing bookmark for the parent folder if we created it in a previous session, resolves it, and starts accessing it
'ssbStart always comes back false, even if the bookmark for this file's parent folder exists and resolves
fBefore.Name = fAfter.Name 'tries to rename the file
ssbStop(fBefore) 'we don't need access to the SSB anymore
if fAfter.exists = false then 'the rename didn't work
dlg = new SelectFolderDialog
dlg.Title=getCaption("Please authorize access to this folder")
dlg.ActionButtonCaption=getCaption("Authorize")
dlg.InitialDirectory = fBefore.parent 'we need write access to the parent folder of the file
ssbSelectFolder(dlg) 'prompts the user to auth the folder, saves the folder SSB for later access
fBefore.Name = fAfter.Name 'the user selected the folder so now the rename will work
end if
end if
Actual function code below. SavePrefsData and GetPrefsData are not included but they store and retrieve strings in a SQL database.
[code]Sub ssbSaveBookmark(f as FolderItem)
'Creates a bookmark
#if TargetCocoa then
dim Bookmark as string
bookmark = CFBookmarkMBS.CreateBookmarkData(f, CFBookmarkMBS.kCreationWithSecurityScope)
savePrefsData(f.nativepath, Bookmark)
#endif
End Sub
Function ssbResolve(f as FolderItem, optional bParentDir as boolean = false) As FolderItem
'accepts a folderitem
'optionally uses the parent folder of the folderitem
'looks for a saved bookmark in preferences based on the file path
'if found, resolves the bookmark string into a folderitem and returns it
dim f2 as FolderItem
dim s as string
#if TargetCocoa then
if bParentDir = true then
'work with the parent Directory instead
if f.Directory = false then
f2 = f.Parent
else
f2 = f
end if
else
f2 = f
end if
dim Bookmark as string = getPrefsData(f2.NativePath, “”) 'returns a saved bookmark if we already created one for this file
dim isStale as Boolean
dim options as UInt32 = CFBookmarkMBS.kResolutionWithoutUIMask + CFBookmarkMBS.kResolutionWithoutMountingMask
if Bookmark <> “” then
dim file as FolderItem = CFBookmarkMBS.ResolveBookmarkData(Bookmark, options, nil, isStale) 'resolves Bookmark string to a file
if isStale = true then
ssbSaveBookmark(file) 'recreate the Bookmark since it's stale
end if
if file<>Nil then
return file 'send back the resolved FolderItem with read/write access
else
dim e as CFErrorMBS = CFBookmarkMBS.LastError
if e = nil then
s = "Failed to resolve." 'for debugging
else
s = e.Description 'for debugging
end if
return f 'bookmark did not resolve, send back the original folderitem
end if
else
return f 'no Bookmark string exists in prefs, send back the original folderitem
end if
#else
return f
#endif
End Function
Function ssbSelectFolder(dlg as SelectFolderDialog, optional form as Window) As FolderItem
'Displays the dialog passed and saves an SSB for the selected folder
dim f as FolderItem
if form <> nil then
f = dlg.ShowModalWithin(form)
else
f = dlg.ShowModal
end if
#if TargetCocoa then
if f <> nil then
ssbSaveBookmark(f)
end if
#endif
return f
End Function
Function ssbStart(f as FolderItem, optional bParentDir as boolean = false) As boolean
'called when ready to manipulate the file
#if TargetCocoa then
dim f2 as folderitem
f2 = ssbResolve(f, bParentDir)
return CFBookmarkMBS.StartAccessingSecurityScopedResource(f2)
#else
return true
#endif
End Function
Sub ssbStop(f as FolderItem, optional bParentDir as Boolean = false)
'called when access is no longer needed
#if TargetCocoa then
dim f2 as FolderItem
f2 = ssbResolve(f, bParentDir)
CFBookmarkMBS.StopAccessingSecurityScopedResource(f2)
#endif
End Sub
[/code]