14 Replies
      Latest reply: Nov 17, 2017 1:24 PM by Macho Man Randy Savage RSS
      Macho Man Randy Savage Level 3 Level 3 (355 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 (7,835 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 (355 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 (355 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?
                      Macho Man Randy Savage Level 3 Level 3 (355 points)

                      This is weird, if I pass in 0 instead of NSURLBookmarkResolutionWithSecurityScope and NSURLBookmarkCreationWithSecurityScope my extension can resolve the bookmark, and it works.

                       

                      I always thought if you are sandboxed you had to make security scoped bookmarks. Is this a bug, or are my assumptions about the API wrong? Perhaps I should take another look at the documentation.

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

                          Documentation seems to imply that sandboxed apps need to use security scoped bookmarks, unless I'm looking in the wrong place (app sandbox guide).

                           

                          I went through the trouble of turning off automatic code signing and setting up provisioning profiles for main app & the extension manually (thinking maybe this is a code signing issue), but I get the same results.

                           

                          The fact that specifying 0 as the option for both creating and resolving the bookmark works is fine for me...I'm just hesitant to go forward with this and release because I wouldn't be surprised if an OS update broke my app (if this is indeed a bug?)

                      • Re: Share security scoped bookmark in app group?
                        eskimo Apple Staff Apple Staff (7,835 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 (355 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 (7,835 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 (355 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 (355 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 (355 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 (355 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.