20 Replies
      Latest reply on Oct 18, 2018 5:37 PM by pkamb
      Macho Man Randy Savage Level 3 Level 3 (365 points)

        1) Main app and extension register for app groups.

         

        2) Main app gets a url from NSOpenPanel, makes a security scoped bookmark and saves is in NSUserdefaults with group container as the suite name.

         

        3) Run the extension, grab the bookmark data from user defaults and resolve it. The data is not nil, but fails to resolve:

         

        Error Domain=NSCocoaErrorDomain Code=259 "The file couldn’t be opened because it isn’t in the correct format."

        • Re: Share security scoped bookmark in app group?
          eskimo Apple Staff Apple Staff (10,045 points)

          The data is not nil, but fails to resolve:

          Three things:

          • Do you have the same sandbox settings on your app and your extension?  Of specific concern is com.apple.security.files.user-selected.read-only.

          • Presumably you create the bookmark with -bookmarkDataWithOptions:includingResourceValuesForKeys:relativeToURL:error:.  What options do you pass in?

          • Have you logged the bookmark data to make sure you’re getting back the right value?  You can do that with a simple NSLog:

            NSLog(@"bookmark = %@", bookmarkData);
            

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: Share security scoped bookmark in app group?
              Macho Man Randy Savage Level 3 Level 3 (365 points)

              Yes the bookmark data is the same when logging it out if I run the same code from the main app or the app extension. The difference is the main app resolves it without error but the extension fails with the error.

               

              I make the bookmark like this:

               

                NSURL *url = openPanel.URL;
              
                      NSError *error = nil;
                      NSData *bookmark = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
                                                 includingResourceValuesForKeys:nil
                                                                  relativeToURL:nil
                                                                          error:&error];
                      if (bookmark != nil)
                      {
                          NSUserDefaults *userDefaults = [[NSUserDefaults alloc]initWithSuiteName:MY_GROUP_ID_HERE];
                          [userDefaults setObject:bookmark forKey:USER_DEFAULTS_BOOKMARK_KEY_HERE];
                          [userDefaults synchronize];
                     }
                    else
                    {
                            //check the error
                    }
              
              
              

               

               

              And I resolve the bookmark:

               

                   urlFromBookmark = [NSURL URLByResolvingBookmarkData:bookmarkData
                                                                 options:NSURLBookmarkResolutionWithSecurityScope
                                                           relativeToURL:nil
                                                     bookmarkDataIsStale:&isStale
                                                                   error:&error];
              
              

               

              The app and the app extension import the same file, and are using the exact same function to resolve the bookmark. Also I have com.apple.security.files.user-selected.read-write to YES in entitlements.

                • Re: Share security scoped bookmark in app group?
                  Macho Man Randy Savage Level 3 Level 3 (365 points)

                  This also logs out, seems related?

                   

                  Failed to read values in CFPrefsPlistSource<0x6080000ee380> (Domain: GroupIDIsHere, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null)): Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd

                  • Re: Share security scoped bookmark in app group?
                    eskimo Apple Staff Apple Staff (10,045 points)

                    Also I have com.apple.security.files.user-selected.read-write to YES in entitlements.

                    Did you just look in the .entitlements file?  Or did you check the build binary?  What does this show?

                    $ codesign -d --entitlements :- /path/to/Your.app/Contents/PlugIns/YourExtension.appex
                    

                    Share and Enjoy

                    Quinn “The Eskimo!”
                    Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                    let myEmail = "eskimo" + "1" + "@apple.com"

                      • Re: Share security scoped bookmark in app group?
                        Macho Man Randy Savage Level 3 Level 3 (365 points)

                        The output looks correct when running codesign -d -entitlements on the .appex

                         

                        <?xml version="1.0" encoding="UTF-8"?>

                        <!DOCTYPE plist PUBLIC "-/

                        <plist version="1.0">

                        <dict>

                          <key>com.apple.security.app-sandbox</key>

                          <true/>

                          <key>com.apple.security.application-groups</key>

                          <array>

                          <string>APP_GROUP_IS_HERE</string>

                          </array>

                          <key>com.apple.security.files.bookmarks.app-scope</key>

                          <true/>

                          <key>com.apple.security.files.bookmarks.document-scope</key>

                          <true/>

                          <key>com.apple.security.files.user-selected.read-write</key>

                          <true/>

                        </dict>

                        </plist>

                          • Re: Share security scoped bookmark in app group?
                            eskimo Apple Staff Apple Staff (10,045 points)

                            Interesting.  Honestly, I’m not sure what’s going on.  If you want to drive this to a conclusion, you should open a DTS tech support incident so that you can talk to DTS’s expert on this sort of thing.

                            Share and Enjoy

                            Quinn “The Eskimo!”
                            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                            let myEmail = "eskimo" + "1" + "@apple.com"

                              • Re: Share security scoped bookmark in app group?
                                Macho Man Randy Savage Level 3 Level 3 (365 points)

                                Thanks for the response. I filed a bug on this, just in case.

                                28960392

                                  • Re: Share security scoped bookmark in app group?
                                    Macho Man Randy Savage Level 3 Level 3 (365 points)

                                    Also noticed something interesting. As I mentioned, passing in 0 for the create/resolve option strangely works, but if I restart my Mac and run, the bookmark will only resolve in the main app and not the extension, so going forward with this clearly is not an option for an app release.

                                      • Re: Share security scoped bookmark in app group?
                                        Macho Man Randy Savage Level 3 Level 3 (365 points)

                                        My bug report was closed as not a bug. Figured I'd let everyone know so they don't get

                                          • Re: Share security scoped bookmark in app group?
                                            Darkwing Level 1 Level 1 (0 points)

                                            Working on the same thing, I also ran into this. Did you manage to solve it?

                                            I think I got this working using the following recipe:

                                             

                                            0) setup "group app" and appropriate entitlements, think of:

                                            com.apple.security.application-groups

                                            com.apple.security.files.bookmarks.app-scope

                                            com.apple.security.files.user-selected.read-write

                                             

                                            1) In the UI-app, use the NSOpenPanel to obtain a directory-url.

                                            2) Use url.bookmarkData with the option .minimalBookmark and save this data to the user defaults of the group (using UserDefaults(suiteName: "groupname") for example). This will store a regular bookmark in the userdefaults of the group-container.

                                            3) Do NOT close the UI-app yet, but first run the command-line app, read the data from the group-defaults and using the data resolve the url BookmarkData using the option .withoutUI

                                            4) Then, in order to persist the use of the url in the Helper command-line app, create a security scoped url using url.bookmarkData with the option .withSecurityScope

                                            5) Write the data to the local user defaults of the command-line app, and next time, read the data from the user defaults of the command-line app and resolve the url from data with the option .withSecurityScope

                                            6) use: let succeeded: Bool = permissionURL.startAccessingSecurityScopedResource()

                                            The boolean will be true.

                                             

                                            So, note an important thing: you can NOT create a security scoped bookmark in the main app, write it to the group, read that from a helper command-line utility and resolve it. You will get: "error: The file couldn’t be opened because it isn’t in the correct format."

                                            But a normal Bookmark works while both programs are running, which gives you a chance to read the normal Bookmark from the group-defaults and write the security scoped Bookmark to the userdefaults of the Helper-app (which needs to be written by the Helper-app, NOT by the main UI-app).

                                              • Re: Share security scoped bookmark in app group?
                                                Macho Man Randy Savage Level 3 Level 3 (365 points)

                                                >So, note an important thing: you can NOT create a security scoped bookmark in the main app, write it to the group, read that from a helper command-line utility and resolve it. You will get: "error: The file couldn’t be opened because it isn’t in the correct format."

                                                But a normal Bookmark works while both programs are running, which gives you a chance to read the normal Bookmark from the group-defaults and write the security scoped Bookmark to the userdefaults of the Helper-app (which needs to be written by the Helper-app, NOT by the main UI-app).

                                                 

                                                Interesting. At the time, I recall only being able to resolve non -security scooped bookmarks (like you discovered) from the non-main app. I didn't think to try what you suggested because the other app in the group is an app extension and I didn't control the lifecycle of it. If I remember correctly the response I got in my bug report was dismissive and seemed to indicate that they really didn't want app groups doing this. Could have misinterpreted though.

                                                 

                                                Eventually I was able to redesign the app to accomplish the same thing without having to bookmark at all from the extension. I think I set a flag to signify whether or not the URL was bookmarked in the main app, so the extension didn't know what URL was bookmarked, just *if* there was a url bookmarked. THen I either posted a distributed notification from the extension, which the main app picked up and performed the action using the bookmark or I declared a Service and use the NSPerformService function. I can't remember right now which one I did though, was awhile ago.

                              • Re: Share security scoped bookmark in app group?
                                pkamb Level 1 Level 1 (0 points)

                                I'm seeing this same issue, attempting to share a Security Scoped Bookmark from a READ-WRITE main app to a READ-ONLY App Extension.

                                 

                                Changing the main app to have READ-WRITE file access seems to have broken it for me; I believe it was working fine when both App Group members were set to READ-ONLY file access. I'm going to test that now.

                                 

                                Getting the same error:

                                 

                                 

                                [User Defaults] Couldn't read values in CFPrefsPlistSource<0x6000000eb380> (Domain: group.com.company.MainApp, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null), Contents Need Refresh: Yes): Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd

                                 

                                and

                                 

                                Error Domain=NSCocoaErrorDomain Code=259 "The file couldn’t be opened because it isn’t in the correct format."

                                  • Re: Share security scoped bookmark in app group?
                                    pkamb Level 1 Level 1 (0 points)

                                    This isn't even working, now, only from my Main App.

                                     

                                    I set the main app to be Read-Only file access. Using the code below to create then immediately resolve the URL's bookmark data.

                                     

                                    Using `.securityScopeAllowOnlyReadAccess` and then `.withSecurityScope`

                                     

                                     

                                            var stale = false
                                            guard let bookmarkData = try? url.bookmarkData(options: .securityScopeAllowOnlyReadAccess, includingResourceValuesForKeys: nil, relativeTo: nil),
                                                let url = try? URL(resolvingBookmarkData: bookmarkData, options: [.withoutUI, .withSecurityScope], relativeTo: nil, bookmarkDataIsStale: &stale) else {
                                                    print("error NSCocoaErrorDomain Code=259 :(")
                                                return
                                            }
                                    
                                    
                                      • Re: Share security scoped bookmark in app group?
                                        eskimo Apple Staff Apple Staff (10,045 points)

                                        I’m not sure what’s going on here and, alas, I don’t have time to dig into it in this context.  Still, I’m hopeful that there might be a reasonable way to achieve this goal, so I’m going to recommend that you open a DTS tech support incident and talk to our bookmarks expert about this.

                                        Share and Enjoy

                                        Quinn “The Eskimo!”
                                        Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                        let myEmail = "eskimo" + "1" + "@apple.com"

                                          • Re: Share security scoped bookmark in app group?
                                            pkamb Level 1 Level 1 (0 points)

                                            Thank you, I have opened DTS `Follow-up: 701518883` for this issue.

                                              • Re: Share security scoped bookmark in app group?
                                                pkamb Level 1 Level 1 (0 points)

                                                Reply from DTS:

                                                 

                                                Follow-up: 701518883

                                                 

                                                I dug into this some more, so let me restart the conversation here:

                                                 

                                                > I need to share Sandbox Security Bookmarks between my main Mac App and its

                                                > FinderSync extension.

                                                >

                                                 

                                                The underlying issue here is that an app scoped, security scoped bookmark is

                                                ONLY valid within the app that created it.  That leaves you with two options:

                                                 

                                                1) If both app components are running at the same time, then you can send the

                                                current URL the other component, which can then create and save it’s own app

                                                scoped, security scoped bookmark.

                                                 

                                                2) If that won’t work, then the other option is to create a document scoped,

                                                security scoped bookmark instead.

                                            • Re: Share security scoped bookmark in app group?
                                              pkamb Level 1 Level 1 (0 points)

                                              One fix that I've found: URL `bookmarkData(options:` needs to use the bitmask `[.withSecurityScope, .securityScopeAllowOnlyReadAccess]` for read-only access. I had been using *only* `.securityScopeAllowOnlyReadAccess` when attempting to save read-only bookmarks. The combined bitmask requirement is listed in the docs, but not where the optionset is declared.

                                               

                                              URLs saved like this refuse to Resolve and result in the Error Code 259. This is the issue I was having where the Main App could not resolve its own bookmarks. This is now working for both read and read-write bookmarks in the main app. The App Extension can still not resolve Data into URLs.

                                               

                                              The App Group User Defaults is working fine as storage and I am using the exact same code path in both App and Extension. Only the main app can resolve the data.