Bookmarks question

  1. 5 weeks ago

    I'm working with bookmarks for the first time and wonder if someone can help me understand the role of relative URL's when creating Security Scoped Bookmarks. The code snippet below is meant to access a file outside the sandbox that needs to be copied by my app.

    dim relativeURL as FolderItem = fileToArchive
    dim isStale as Boolean
    dim options as integer = CFBookmarkMBS.kResolutionWithSecurityScope
    dim url as CFURLMBS = CFBookmarkMBS.ResolveBookmarkDataToCFURLMBS(bookmarkData, options, relativeURL, isStale)
    
    // start access
    if url <> nil then
      if CFBookmarkMBS.StartAccessingSecurityScopedResource(url) then
        f = url.file
    /// do the file copying here
    CFBookmarkMBS.StopAccessingSecurityScopedResource(url)
      end if

    I've successfully created a bookmark of the volume containing the file to be copied and am using it in the variable "bookmarkData". After reading a lot of documentation, my understanding of the 4th line of code is that the variable, relativeURL, should be set to the file I want to copy so that a CFURLMBS (variable "url") to it will be created when line 4 runs. But it doesn't work, it always results in a nil "url" variable. The only way I get a good "url" to the file I want to copy is to set the variable "relativeURL" to "nil" and use a bookmark of its parent directory as the "bookmarkData" variable. Then line 4 runs successfully. I can then change line 7 to "f = url file.child(filename)" and get access to the file and copy it. But I can't use that technique in the app since there is a long list of files to copy from different volume locations and I don't want to keep asking the user for permission to access every parent folder.

    Any help in getting this strategy to work, or suggestions for different strategies are greatly appreciated. As I said, this is my first run at using SSB's and I'm sure I've made some basic mistakes.

  2. Beatrix W

    Nov 4 Pre-Release Testers, Third Party Store Europe (Germany)

    I set the relative url to nil:

    '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
    
    'make bookmark data
    dim BookmarkData as string
    if theCFObject.TypeDescription = "CFString" then BookmarkData = DecodeBase64(CFStringMBS(theCFObject).str)
    if BookmarkData = "" then Return nil'no data
    
    'resolve bookmark
    dim relativeURL as CFURLMBS = nil
    dim isStale as Boolean = false
    dim options as integer = CFBookmarkMBS.kResolutionWithoutUIMask + CFBookmarkMBS.kResolutionWithSecurityScope
    dim url as CFURLMBS = CFBookmarkMBS.ResolveBookmarkDataToCFURLMBS(BookmarkData, options, relativeURL, isStale)
    dim error as CFErrorMBS = CFBookmarkMBS.LastError
    if error <> nil then Return Nil
    if url = Nil then Return Nil
    
    'make file from bookmark
    if CFBookmarkMBS.StartAccessingSecurityScopedResource(url) then
      dim file as FolderItem = url.file 
      CFBookmarkMBS.StopAccessingSecurityScopedResource url
      Return file
    end if
  3. Hello Beatrice. Thank you for your reply and confirmation that your bookmarks are resolved successfully when relativeURL is set to nil. The tricky part for me is getting the CFURLMBS (variable url) to drill down to the file I want to copy. When created, "url" contains the URLpath of a volume, for example, file:///Volumes/MyMedia. The file I want to access is somewhere inside of the "MyMedia" volume. I've tried using CFURLMBS.AppendPathComponent to add the relative path of the file to the "url" variable without success. I don't think I have the right strategy yet to reach the file. I know it can be done since I have at least two apps that work this way, that is, they ask for the user's blanket permission to access a low level folder or volume which gives then grants the app access to the files and folders inside. In fact, I noticed Final Cut Pro X asks for volume access permission when first launched under Catalina or anytime a new storage drive is mounted. I have another app that consolidates audio files using the same access technique. I want the same kind of access to the media files my app needs to copy but I haven't been able to figure out how to do it.

  4. @AnthonyBlack — relativeURL should never be set to the file you want to access because relativeURL needs to be a folder.

  5. Beatrix W

    Nov 5 Pre-Release Testers, Third Party Store Europe (Germany)

    For the Catalina "security" you don't have to do anything except to check if the file is nil or not.

    Give us a concrete example for a file you want to save/restore. My example - straight out of the MBS examples - doesn't really do more than restore a simple file.

  6. Thank you, Beatrice and Stéphane, I was able to get SSB's working in my app. There are still some issues that Sam Rowlands has warned me about, but I'm hoping to work through those, too. I found it hard to find much detailed documentation or coding examples on SSB's so, when it's all buttoned-up, I'll post my code in hopes it helps someone else.
    If it were not for the coders on this forum, I would not have been able to do this. Many thanks.

or Sign Up to reply!