Xamarin Forms中StartAccessingSecurityScopedResource返回false问题排查
StartAccessingSecurityScopedResource return false for a manually created NSUrl? Let’s break down why your code is failing and how to fix it:
Core Reason
iOS’s App Sandbox and security-scoped resource system are designed to restrict app access to files unless explicitly authorized by the user. StartAccessingSecurityScopedResource() only works for URLs that have gone through a system-approved authorization flow—manually constructed URLs from hardcoded paths don’t qualify.
When you use a file picker (UIDocumentPickerViewController), the system generates a security-scoped URL that’s tied to the user’s explicit selection. But when you build a URL from a raw file path, the system has no way to verify that you’re allowed to access that resource, so it rejects the access request.
Also, hardcoding your app’s container path is inherently unreliable: iOS changes the unique identifier part of the container path every time you reinstall the app or update it, so that path will break eventually.
Fix 1: Access Your App’s Own Documents Directory (No Security Scope Needed)
If Test.pdf is stored in your app’s own Documents folder, you don’t need to use security-scoped resources at all—your app has full access to its sandboxed directories by default. Use system APIs to get the correct path instead of hardcoding it:
private void Initialise_Print() { // Get the official Documents directory path var documentsUrl = NSFileManager.DefaultManager.GetUrls(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User)[0]; var pdfUrl = documentsUrl.Append("Test.pdf", false); // No need for StartAccessingSecurityScopedResource here PrintDoc(pdfUrl.Path); }
Or using .NET-style path handling:
private void Initialise_Print() { var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); var pdfPath = Path.Combine(documentsPath, "Test.pdf"); PrintDoc(pdfPath); }
Fix 2: Use Security Bookmarks for External Files
If Test.pdf is a file the user imported via a file picker, you need to save a security bookmark of the original authorized URL, then use that bookmark to regain access later:
- Save the bookmark when the user selects the file:
public void HandleDocumentPickerSelection(UIDocumentPickerViewController picker, NSUrl[] urls) { if (urls.Length == 0) return; var selectedUrl = urls[0]; NSError bookmarkError; // Create a security-scoped bookmark var bookmarkData = selectedUrl.CreateBookmarkData(NSUrlBookmarkCreationOptions.WithSecurityScope, null, null, out bookmarkError); if (bookmarkError == null) { // Save the bookmark to UserDefaults (or another persistent store) NSUserDefaults.StandardUserDefaults.SetValueForKey(bookmarkData, new NSString("SavedPdfBookmark")); } }
- Restore the URL and request access later:
private void Initialise_Print() { var savedBookmark = NSUserDefaults.StandardUserDefaults.DataForKey(new NSString("SavedPdfBookmark")); if (savedBookmark == null) return; bool isBookmarkStale; NSError restoreError; // Restore the security-scoped URL from the bookmark NSUrl pdfUrl = NSUrl.FromBookmarkData(savedBookmark, NSUrlBookmarkResolutionOptions.WithSecurityScope, null, out isBookmarkStale, out restoreError); if (restoreError == null && pdfUrl != null) { bool hasAccess = pdfUrl.StartAccessingSecurityScopedResource(); if (hasAccess) { try { PrintDoc(pdfUrl.Path); } finally { // Always stop accessing when done to avoid resource leaks pdfUrl.StopAccessingSecurityScopedResource(); } } } }
Key Takeaways
- Skip security scope for internal files: Your app’s sandbox directories (Documents, Library, tmp) don’t require
StartAccessingSecurityScopedResource()—use system APIs to get their paths. - Only use security scope for user-approved files: URLs from file pickers or restored from bookmarks are the only ones that will work with security-scoped resource calls.
内容的提问来源于stack exchange,提问作者Josh B

