dun*_*nc4 6 macos cocoa xpc security-scoped-bookmarks
我正在创建一个 TodayWidget 应用程序扩展,它显示有关用户在应用程序目录之外选择的文件夹的信息。
在我的主应用程序中,我可以通过 NSOpenPanel 使用 powerbox 来选择文件夹。然后,我可以将安全范围书签保存到我的 TodayWidget 可访问的应用程序组容器的用户默认值。
TodayWidget 可以读取书签数据,但是当它调用URLByResolvingBookmarkData 时,它会出错:
The file couldn’t be opened because it isn’t in the correct format.
我的主应用程序和 TodayWidget 都具有以下权利:
根据 Apple 的文档,只有创建安全范围书签的应用程序才能使用它。我猜这些意味着不允许嵌入式应用程序?
我已经考虑使用 XPC,但这并不能真正解决问题,因为 XPC 也不能使用安全范围的书签,只能使用普通书签。一旦计算机重新启动,XPC 进程将失去对目录的访问权限。
我真正需要的只是一种让 XPC 进程获得对用户指定目录的读取访问权限的方法。有没有办法不必每次重新启动计算机都重新启动我的主应用程序?
您可能已经解决了这个问题或继续前进。但是对于所有尝试类似事情的人,我将把这个留给他们。为了访问不同应用程序中的安全范围书签,它们必须作为 NSData 传输并在其他应用程序中重新解析。
就我而言,我在主应用程序中显示一个打开的对话框,然后将范围书签保存到共享NSUserDefaults
套件中。其他应用程序也是该套件的一部分,然后访问NSData
's的容器并将它们解析为可用的NSURL
's 。
以下是相关的代码位:
//Inside my main application's open function
... get url from NSOpenPanel
BookmarkUtils.saveURLForOtherApplications(openPanel.URL!)
//Inside BookmarkUtils.swift
static func saveURLForOtherApplications(url:NSURL)->Bool{
let defaults = NSUserDefaults(suiteName: <#Suite-Name#>)!
//I store them as a dictionary of path->encoded URL
let sandboxedBookmarks:NSMutableDictionary
if let prevBookmarks = defaults.objectForKey(kSandboxKey) as? NSDictionary{
sandboxedBookmarks = NSMutableDictionary(dictionary:prevBookmarks)
}
else{
sandboxedBookmarks = NSMutableDictionary()
}
if let shareData = BookmarkUtils.transportDataForSecureFileURL(url){
sandboxedBookmarks.setObject(shareData, forKey:url.path!)
defaults.setObject(sandboxedBookmarks, forKey:kSandboxKey)
defaults.synchronize()
return true
}
else{
println("Failed to save URL Data");
return false
}
}
static func transportDataForSecureFileURL(fileURL:NSURL)->NSData?{
// use normal bookmark for encoding security-scoped URLs for transport between applications
var error:NSError? = nil
if let data = fileURL.bookmarkDataWithOptions(NSURLBookmarkCreationOptions.allZeros, includingResourceValuesForKeys:nil, relativeToURL:nil, error:&error){
return data;
}
else{
println("Error creating transport data!\(error)")
return nil
}
}
Run Code Online (Sandbox Code Playgroud)
那么在我的扩展程序中(在我的情况下为今天视图)我做这样的事情......
class TodayViewController: ...
...
override func viewDidLoad() {
super.viewDidLoad()
var status = [MyCoolObjects]()
for url in BookmarkUtils.sharedURLSFromApp(){
BookmarkUtils.startAccessingSecureFileURL(url)
status.append(statusOfURL(url))
BookmarkUtils.stopAccessingSecureFileURL(url)
}
self.listViewController.contents = status
}
Run Code Online (Sandbox Code Playgroud)
相关书签如下所示:
static func sharedURLSFromApp()->[NSURL]{
var urls = [NSURL]()
if let defaults = NSUserDefaults(suiteName: <#Suite-Name#>){
if let prevBookmarks = defaults.objectForKey(kSandboxKey) as? NSDictionary{
for key in prevBookmarks.allKeys{
if let transportData = prevBookmarks[key as! NSString] as? NSData{
if let url = secureFileURLFromTransportData(transportData){
urls.append(url)
}
}
}
}
}
return urls
}
static func secureFileURLFromTransportData(data:NSData)->NSURL?{
// use normal bookmark for decoding security-scoped URLs received from another application
var bookmarkIsStale:ObjCBool = false;
var error:NSError? = nil;
if let fileURL = NSURL(byResolvingBookmarkData: data, options: NSURLBookmarkResolutionOptions.WithoutUI, relativeToURL: nil, bookmarkDataIsStale: &bookmarkIsStale, error: &error){
return fileURL
}
else if(bookmarkIsStale){
println("Bookmark was stale....")
}
else if let resolveError = error{
println("Error resolving from transport data:\(resolveError)")
}
return nil
}
Run Code Online (Sandbox Code Playgroud)
这个解决方案对我有用。解析共享 URL 后,您可以为该应用程序创建一个书签,并在需要时将其保存以备后用。可能有更好的方法,希望 Apple 能够解决此问题,因为目前与扩展程序共享权限很痛苦。
归档时间: |
|
查看次数: |
1615 次 |
最近记录: |