macOS Security scoped URL bookmark for folder
You're resolving the security-scoped bookmark (for the directory) to let newUrl
, but you call startAccessingSecurityScopedResource()
on the file's URL fileURL
. You need to call it for newURL
.
newURL.startAccessingSecurityScopedResource()
// Decompressing fileURL with libarchive...
newURL.stopAccessingSecurityScopedResource()
Two more remarks:
- When obtaining access through NSOpenPanel, you don't need to call
startAccessingSecurityScopedResource()
andstopAccessingSecurityScopedResource()
, because the user explicitly
granted you access for this session. - I use
var isStale: ObjCBool = ObjCBool(false)
instead. I'm no Swift expert, so not sure ifvar isStale = false
is ok to use.
Xamarin.Mac Using security-scoped bookmarks
You are confusing some things. Your code
using (var dlg = NSSavePanel.SavePanel)
{
dlg.Message = AppResources.DialogMessageSaveEncryptedFileName;
dlg.AllowedFileTypes = new[] { "zip" };
dlg.Prompt = "Authenticate";
if (dlg.RunModal() > 0)
{
NSError error;
//NSData url = dlg.Url.CreateBookmarkData(NSUrlBookmarkCreationOptions.WithSecurityScope, null, null, out error);
NSData bookmark = dlg.Url.CreateBookmarkData(NSUrlBookmarkCreationOptions.WithSecurityScope, null, null, out error);
}
}
The dlg.Url
is the url you want to access.
What you get back from dlg.Url.CreateBookmarkData()
is the encoded bookmark data. You can store this data anyway you like to persist it across app launches. For example in UserDefaults
Storing:
NSUserDefaults.StandardUserDefaults["bookmark"] = bookmark;
NSUserDefaults.StandardUserDefaults.Synchronize();
Later retrieving:
NSData bookmark = NSUserDefaults.StandardUserDefaults.DataForKey("bookmark");
This is the data you
put into NSUrl.FromBookmarkData
to get the url back.
//NSData data = new NSData();
//NSUrl url = NSUrl.FromBookmarkData(data, NSUrlBookmarkResolutionOptions.WithSecurityScope, null, out bool isStale, out NSError error);
NSUrl url = NSUrl.FromBookmarkData(bookmark, NSUrlBookmarkResolutionOptions.WithSecurityScope, null, out bool isStale, out NSError error);
url.StartAccessingSecurityScopedResource();
//...
url.StopAccessingSecurityScopedResource();
Also if you need to keep using the access pay attention to the isStale
return value from CreateBookmarkData
. If it return true you need to refresh the bookmark from the url with url.CreateBookMarkData
and replace the stored bookmark with the new one.
Creating a security scope bookmark for a file from one of a directory containing it
In my test program this works fine. I suspect the append of the file name to the URL is failing in your case (but that's a huge guess) because it's the only thing that seems materially different.
I notice that the url for a security resolved location is: file://localhost/Users/dad/Desktop/TestFolder?applesecurityscope=343335323030663066393432306234363030346263613464636464643130663635353065373030373b30303030303030303b303030303030303030303030303032303b636f6d2e6170706c652e6170702d73616e64626f782e726561642d77726974653b30303030303030313b30313030303030323b303030303030303030326461363838663b2f75736572732f74796c65722f6465736b746f702f74657374666f6c646572
which is the other reason I wonder if the append is the issue.
In my test I have the user choose the folder, create the security scoped bookmark and then save that in user defaults.
Then I quit & relaunch the app and via a menu command I get that bookmark and then resolve it. Then I added a case where I use the resolved bookmark to a folder and make a new bookmark to the file within the folder.
It seems to work fine.
In my test where it's working I'm getting the path to the file like this:
NSURL * resolvedURL = [NSURL URLByResolvingBookmarkData: data
options: NSURLBookmarkResolutionWithSecurityScope
relativeToURL: nil
bookmarkDataIsStale: &isStale
error: &error];
... // (error checking)
[resolvedURL startAccessingSecurityScopedResource];
NSArray * files = [[NSFileManager defaultManager]
contentsOfDirectoryAtURL: resolvedURL
includingPropertiesForKeys: @[NSURLLocalizedNameKey, NSURLCreationDateKey]
options: NSDirectoryEnumerationSkipsHiddenFiles
error: &error];
if ( files != nil )
{
NSURL * fileURL = [files objectAtIndex: 0]; // hard coded for my quick test
NSData * newData = [fileURL bookmarkDataWithOptions: NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys: nil
relativeToURL: nil
error: &error];
if ( newData != nil )
{
NSLog(@"it's good!");
}
.... // error checking and logging.
if that doesn't get you on the right track, I'm going to need to see more code (you'll probably need to make a simple example).
Note that in my case I'm resolving the bookmark and calling startAccessingSecurityScopedResource
even when I just got the url & created the bookmark (when I tried to create a bookmark from the path I'd just acquired from PowerBox (openPanel) it failed with an error 256).
Some configuration details: OS X 10.8.4, Xcode 5 (first public release from today 9/18/2013).
Security Scoped Bookmark - bookmark resolves but still can't access the file
I just stumbled upon the answer accidentally...
For starters, when I was resolving the URL, I was not using the method which allows you to include OPTIONS, so my URL was resolved WITHOUT the security-scope. My original code to resolve was:
try myURL = URL.init(resolvingBookmarkData: loadedMovieDatabase[0].bookmark, bookmarkDataIsStable: &urlResult)!
When I should have been using the version with options here:
try myURL = URL.init(resolvingBookmarkData: loadedMovieDatabase[0].bookmark, Options: URL.bookmarkResolutionOptions.withSecurityScope, relativeTo: nil, bookmarkDataIsStable: &urlResult)!
Basically, I used the first init option Xcode presented in the predictive list with the words "resolvingBookmarkData:" when I should have looked further down the list. (This is how I found my error.)
NOTE also that it's important to use...
URL.bookmarkResolutionOptions.withSecurityScope
and not
URL.bookmarkCreationOptions.withSecurityScope
...when you're resolving your URL or it doesn't appear to work correctly.
Thus ends my frustration with this problem :) I hope this explanation might help others facing this problem!
Trouble creating Security-Scoped Bookmark
It turns out I was missing a crucial entitlement, not listed in the UI, but listed in the documentation:
com.apple.security.files.bookmarks.app-scope
Update 12/18/2018
According to this Twitter thread, this entitlement may not be required anymore. Thanks @pkamb for alerting me to this.
Security-Scoped Bookmarks for a directory
Your second error message tells you what is wrong - you haven't used a file:// URL.
This can be fixed by creating the URL properly from your path variable, however you will probably be better of sticking with URLs throughout and not doing the URL -> path -> URL transformation. All the operations you've used the path for can be done directly with URLs, just check the documentation for NSFileManager
and NSURL
. The only one which may be non-obvious is using NSURL
's checkResourceIsReachableAndReturnError:
rather than NSFileManager
's fileExistsAtPath:
, however read the documentation for checkResourceIsReachableAndReturnError:
carefully and take its advice.
Making these changes should address at least three of the errors you have reported.
HTH
Related Topics
"Ambiguous Reference to Member Map" When Attempting to Append/Replace Array Element
Debug View Hierarchy Does Not Render UI
Swift Error "Domain=Nscocoaerrordomain Code=3840 "Invalid Value Around Character 1."
Iocreateplugininterfaceforservice Returns Mysterious Error
How to Solve This Error: Thread 1: Exc_Resource Resource_Type_Memory (Limit=650 Mb, Unused=0X0)
Strange String.Unicodescalars and Characterset Behaviour
Convert/Wrap Swift Struct as Nsvalue for Caanimation Purposes
Advantage of Key-Value Coding in Swift 4
Navigationlink Doesn't Work with New .Searchable Modifier on Swiftui 3.0
Can't Get Throws to Work with Function with Completion Handler
Get Png Representation of Nsimage in Swift
Cannot Convert Value of Type 'X' to Expected Argument Type 'X'
Swift iOS14 Datepicker Text Alignment
Swift: Binary Operator '==' Cannot Be Applied to Operands of Type "Protocol"
Swift System Version Checking on Ubuntu
Why Is The Leading Swipe Action Also Duplicated as a Trailing Action
Why Is My Libraries Not Able to Expand on The Cocoapods and Shows as Objective-C Not Swift