在拿SwiftUI
练手Mac客户端ZXKitLogger_Mac时,发现通过SwiftUI
可以很简单的就为组件增加拖拽和文件处理。
为VStack添加文件拖拽
VStack(alignment: .trailing, spacing: 10) {
List(self.fileList, id: \.path) { i in
NavMenuItemView(url: i, selectedPath: $selectedPath)
.onTapGesture {
selectedPath = i.path
}
}
}.onDrop(of: ["public.file-url"], isTargeted: $dragOver) { providers in
providers.first?.loadDataRepresentation(forTypeIdentifier: "public.file-url", completionHandler: { (data, error) in
if let data = data, let path = String(data: data, encoding: String.Encoding.utf8), let url = URL(string: path) {
//TODO: 获取并处理文件url
//...
}
})
return true
}
这样讲文件拖拽到VStack
即可出现拖拽的标志。
文件的历史记录访问权限
通过上面的文件拖拽,可以得到文件的url
进行文件处理。但是如果仅仅记录了该文件的url,退出了软件之后,如果不重复拖拽,直接访问该url进行操作会报错没有权限。
这是因为在项目中,默认的File Access
就是用户选择的文件可读,没有选择直接通过url时权限不足,那么这样如果做文件列表的历史记录,只记录一个url地址明显不行。
这种情况就用到了Security-scoped bookmarks
,Security-scoped bookmarks有2种模式可供选择:
1. An app-scoped bookmark
能为已沙盒程序提供对用户指定文件和文件夹的持久访问权。 例如,如果程序采用了一个程序容器外的下载或处理目标文件夹,通过NSOpenpanel
对话框获得用户想使用该文件夹的初始访问权,包括拖拽等操作。
然后,为其创建一个 app-scoped bookmark
,将它作为程序的配置储存(可能用属性列 表文件或 NSUserDefaults 类)。有了 app-scoped bookmark
,程序就能获得对该文件夹的 未来访问权了。这种bookmark方式使用的比较多。
在.entitlements文件对应的key对应的权限,key为com.apple.security.files.bookmarks.app-scope
,类型为Boolean
,设置为true
2. A document-scoped bookmark
提供了对特定文档类型的的持久访问权。可以理解为针对文档类型的一种权限模式。比如你开发一个能编辑ppt文档的应用,里面嵌入了视频文件,图片文件连接。那么下次打开这个ppt文档时就能直接访问这些文件而不需要在通过NSOpenPanel
打开获得授权。
Document-scoped bookmark
只能指向文件而不是文件夹。并且这个文件必须不在系统使用的位置上(如/private 或/Library)
在.entitlements文件对应的key对应的权限,key为com.apple.security.files.bookmarks.document-scope
,类型为Boolean
,设置为true
bookmarks的使用
1、获取到URL的bookmarkData
,可以存到存储到UserDefaults
等
if let book = try? url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil) {
UserDefaults.standard.set(book, forKey: ""UserDefaultsKey.fileListHistory.rawValue"")
}
2、通过bookmarkData
授权并读取该文件
var isStale = false
let url = try? URL(resolvingBookmarkData: data, options: [.withSecurityScope, .withoutUI], relativeTo: nil, bookmarkDataIsStale: &isStale)
if !isStale, url?.startAccessingSecurityScopedResource() == true {
//授权未过期,可以直接读写该url
return url
}
3、根据业务需要,也可以调用stopAccessingSecurityScopedResource()
函数停止授权
url?. stopAccessingSecurityScopedResource()
参考文章
版权属于:东哥笔记 - DongGe.org
本文链接:https://dongge.org/blog/1205.html
自2017年12月26日起,『转载以及大段采集进行后续编辑』须注明本文标题和链接!否则禁止所有转载和采集行为!