SDK:macOS 14.0
Xcode: 15.0
I searched for a lot of answers, but it didn't work for my application. I can't access the contents of the files under the folder.
First of all, I configured permissions in App SandBox:
Then I used fileImporter
in SwiftUI to allow users to select folders:
Button("open file")
.fileImporter(
isPresented: $indexModel.openFileImporter,
allowedContentTypes: [.movie, .avi, .mpeg4Movie, .directory],
allowsMultipleSelection: true
) { results in
do {
let selection = try results.get()
try self.openSelectedPath(selection)
} catch let err {
indexModel.errorMsg = err.localizedDescription
indexModel.showError = true
}
}
In openSelectedPath
, I access the contents under the folder through FileManager
:
if selection.hasDirectoryPath {
let files = try FileManager.default.contentsOfDirectory(
at: selection,
includingPropertiesForKeys: nil,
options: [.skipsHiddenFiles]
)
files.enumerated().filter { _, file in
// try grant access here but all fails
guard file.startAccessingSecurityScopedResource() else {
print("\(file.lastPathComponent) cannot access")
return false
}
let isMKV = file.pathExtension.compare("mkv", options: .caseInsensitive, range: nil, locale: nil) == .orderedSame
return file.isFileURL && (isMKV || file.contains(.movie) || file.contains(.avi) || file.contains(.mpeg4Movie))
}
return
}
As a result, all the files in the folder are not accessible. (file.startAccessingSecurityScopedResource
return false)
Recently, I found solution inspired by the source code of iina/iina.
guard selection.startAccessingSecurityScopedResource() else {
return
}
viewModel.activeURL = selection
Keeping access right to this directory until you don't need it. For me, I did like this:
class ViewModel: ObservableObject {
var activeURL: URL? {
didSet {
oldValue?.stopAccessingSecurityScopedResource()
}
}
deinit {
activeURL?.stopAccessingSecurityScopedResource()
}
}
Using FileManager.default.contentsOfDirectory(atPath: selection.path(percentEncoded: false))
instead of FileManager.default.contentsOfDirectory(at:selection,includingPropertiesForKeys: nil)
Generating contents URL like this:
let url = selection.appending(path: path, directoryHint: .notDirectory)