fix(iOS): read file data into memory BEFORE revoking security-scoped access, prevents exists=false
This commit is contained in:
parent
6503712be9
commit
3ed5696ae0
@ -771,36 +771,43 @@ final class PlayerBridge: ObservableObject {
|
||||
/// 处理 iOS 文件选择器结果
|
||||
func handleFileImport(_ urls: [URL]) {
|
||||
diagLog("handleFileImport: \(urls.count) URLs")
|
||||
let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
|
||||
for url in urls {
|
||||
diagLog("processing: \(url.lastPathComponent)")
|
||||
let didStartAccessing = url.startAccessingSecurityScopedResource()
|
||||
diagLog("startAccessingSecurityScopedResource: \(didStartAccessing)")
|
||||
defer {
|
||||
|
||||
// 先把文件数据读到内存(安全域访问有效期内)
|
||||
let fileData: Data
|
||||
do {
|
||||
fileData = try Data(contentsOf: url)
|
||||
diagLog("read \(fileData.count) bytes from source")
|
||||
} catch {
|
||||
diagLog("read failed: \(error.localizedDescription)")
|
||||
if didStartAccessing { url.stopAccessingSecurityScopedResource() }
|
||||
continue
|
||||
}
|
||||
|
||||
// 复制文件到 app Documents 目录(security-scoped URL 在 defer 后会失效)
|
||||
let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
let localURL = docsDir.appendingPathComponent(url.lastPathComponent)
|
||||
// 撤销安全域访问(文件数据已在内存中)
|
||||
if didStartAccessing { url.stopAccessingSecurityScopedResource() }
|
||||
|
||||
// 写入 Documents,确保用唯一的文件名
|
||||
let baseName = url.deletingPathExtension().lastPathComponent
|
||||
let ext = url.pathExtension
|
||||
var localURL = docsDir.appendingPathComponent(url.lastPathComponent)
|
||||
if FileManager.default.fileExists(atPath: localURL.path) {
|
||||
let ts = Int(Date().timeIntervalSince1970)
|
||||
localURL = docsDir.appendingPathComponent("\(baseName)_\(ts).\(ext)")
|
||||
}
|
||||
|
||||
do {
|
||||
// 如果同名文件已存在,加时间戳
|
||||
if FileManager.default.fileExists(atPath: localURL.path) {
|
||||
let ts = Int(Date().timeIntervalSince1970)
|
||||
let nameWithoutExt = url.deletingPathExtension().lastPathComponent
|
||||
let ext = url.pathExtension
|
||||
let newURL = docsDir.appendingPathComponent("\(nameWithoutExt)_\(ts).\(ext)")
|
||||
try FileManager.default.copyItem(at: url, to: newURL)
|
||||
diagLog("copied to: \(newURL.lastPathComponent)")
|
||||
addItem(url: newURL, name: url.lastPathComponent, type: "file")
|
||||
} else {
|
||||
try FileManager.default.copyItem(at: url, to: localURL)
|
||||
diagLog("copied to: \(localURL.lastPathComponent)")
|
||||
addItem(url: localURL, name: url.lastPathComponent, type: "file")
|
||||
}
|
||||
try fileData.write(to: localURL)
|
||||
diagLog("written \(fileData.count) bytes to: \(localURL.lastPathComponent)")
|
||||
addItem(url: localURL, name: url.lastPathComponent, type: "file")
|
||||
} catch {
|
||||
diagLog("copy failed: \(error.localizedDescription)")
|
||||
addItem(url: url, name: url.lastPathComponent, type: "file")
|
||||
diagLog("write failed: \(error.localizedDescription)")
|
||||
showToast("Failed to import: \(url.lastPathComponent)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user