我正在開發一個基于 MapKit 的 iOS 路由應用程式,我在其中實作了對用 GPX 開放標準(基本上是 XML)撰寫的檔案的支持,以編碼所有用戶關于路由的資訊,這些資訊可以匯出或匯入以進行備份。
當用戶在應用程式中匯入 GPX 檔案時,我已經讓他可以通過檔案應用程式通過將檔案共享到應用程式來執行此操作。這樣做時,AppDelegate 或 SceneDelegate 會根據當前 iOS 版本截取檔案 URL:
在 AppDelegate (<= 12.4) 中:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
// Handle the URL in the url variable
}
在 SceneDelegate (>= 13) 中:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
// Handle the URL in the URLContexts.first?.url
}
在我的 Info.plist 中,標志LSSupportsOpeningDocumentsInPlace和UIFileSharingEnabled都設定為YES。有一個列出 .gpx 擴展名的UTImportedTypeDeclarations以便檔案應用程式自動選擇我的應用程式以打開它。
幾個月前,這種方法毫不費力地作業,并且填充了path和URLContexts.first?.url變數,您可以就地訪問 URL 指向的檔案,讀取它并決議其路由資料,而無需復制它或進行任何特殊處理. 然后將該 url 發送到適當的 ViewController 供用戶查看,一切都很好。
收到票后快進到現在,GPX 匯入中斷。除錯顯示,當在 iOS 中用戶向應用發送 GPX 檔案時,AppDelegate 或 SceneDelegate 會收到一個似乎正確的 URL,但根據 FileManager ,該 URL直接指向的檔案并不存在。使用這個擴展:
extension FileManager {
public func exists(at url: URL) -> Bool {
let path = url.path
return fileExists(atPath: path)
}
}
在 AppDelegate/SceneDelegate 中:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
FileManager.default.exists(at: url) // Result: false
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
if let url = URLContexts.first?.url {
FileManager.default.exists(at: url) // Result: false
}
}
檔案的來源無關緊要,因為從 iCloud 或本地檔案夾發送它不會改變結果。使用物理設備或模擬器具有相同的結果。為什么網址無效?這是一個新的系統錯誤嗎?或者,這甚至是通過檔案應用程式在 iOS 中接收檔案的正確方法嗎?這個方法在新的 iOS 15 中被棄用了嗎?還是我只是忘記了一些重要的事情?
謝謝你的耐心。
uj5u.com熱心網友回復:
發現了什么問題。當您從另一個應用程式的共享表打開檔案并且LSSupportsOpeningDocumentsInPlace為 TRUE 時,您必須先呼叫url.startAccessingSecurityScopedResource()才能從 URL 物件訪問它,以便您被授予訪問該檔案的權限。完成后,您必須對同一 URL 物件進行stopAccessingSecurityScopedResource()呼叫。下面的示例使用defer關鍵字來確保始終呼叫關閉方法。
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
if url.startAccessingSecurityScopedResource() {
defer {
url.stopAccessingSecurityScopedResource()
}
FileManager.default.exists(at: url) // Result: true
}
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
if let url = URLContexts.first?.url, url.startAccessingSecurityScopedResource() {
defer {
url.stopAccessingSecurityScopedResource()
}
FileManager.default.exists(at: url) // Result: true
}
}
此答案取自https://stackoverflow.com/a/62771024/18267710。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/433108.html
