使用NSEvent拖动文件时出错.(macOS)



我想把文件拖到我的窗口,然后执行操作。

我试着使用下面这个答案中提供的片段来区分你是在拖动文件还是窗口。

// In my window controller
class MyWindowController: NSWindowController {

init() {
// Some initialization steps below are omitted
let win = NSWindow(...)
super.init(window: win)

let contentView = DropView(frame: win.frame)
win.contentView?.addSubview(contentView)
registerGlobalMouseEvent()
}
func registerGlobalMouseEvent() {
self.window?.acceptsMouseMovedEvents = true

NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
// Codes below will cause errors
let pasteBoard = NSPasteboard(name: .drag)
guard let fileNames = pasteBoard.propertyList(forType: .init(rawValue: "NSFilenamesPboardType")) as? NSArray else { return }
let changeCount = pasteBoard.changeCount
if fileNames.count > 0 && lastChangeCount != changeCount {
lastChangeCount = changeCount
// My actions when dragging
}
})
}

}

然后我运行我的代码并开始拖动,我得到了三个错误:

〔沙箱〕获取沙箱扩展失败

[Framework]无法为/Users/roy/Downloads/test.txt发布沙盒扩展,错误为1

[默认值]无法为URL颁发沙盒令牌:'file:///Users/roy/Downloads/test.txt',错误为:'错误域=NSPOSIXErrorDomain Code=1";不允许操作";UserInfo={NSLocalizedDescription=无法为文件"/Users/roy/Downloads/test.txt"颁发沙盒扩展名:不允许操作}">

但当我只是做

NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
// My actions
})

,然后一切都很好。

第一个错误似乎是无害的,因为它没有阻止我的应用程序运行。

第二个和第三个是致命的,直接导致我的应用程序崩溃。

我想知道他的代码是否有问题任何有用的想法都会很棒!:(


使用沙箱时,您需要了解书签和安全作用域URL。拖动的URL只允许您的应用程序进程读取或读取/写入"用户选择的文件"一次,具体取决于您如何配置权限。

您可以保存一个书签(数据块(,以便在后续会话中保持访问权限,只要文件没有被另一个进程更新,此时书签就会过时,您需要鼓励用户再次选择该文件。

跨越XPC边界(如共享(将URL交给另一个进程需要您拥有该文件,因此可能涉及到沙盒缓存的副本。

例如:

let dragurl = url_of_dragged_file //at this point you have at-least read access
let cachepath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).last!
let cachedir = URL(fileURLWithPath: cachepath)
let cacheurl = cachedir
.appendingPathComponent(UUID().uuidString)
.appendingPathExtension(dragurl.pathExtension)
try FileManager.default.copyItem(at: dragurl, to: cacheurl)

此时,您在本地沙盒缓存中有一个副本,可以将其交给共享表。

所以我终于找到了解决方案。:(

它似乎确实与我上面提到的片段有关,下面是更正:

NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
let pasteboard = NSPasteboard(name: .drag)
let changeCount = pasteboard.changeCount
if lastChangeCount != changeCount {
lastChangeCount = changeCount
if pasteboard.canReadObject(forClasses: [NSURL.self], options: [:]) {
/// actions
}
}
})

通过这种方式,我没有错误,我的代码运行得很完美!

最新更新