Xcode14.3开发iOS App:文件权限未显示、PDF下载保存异常求助
iOS Web App PDF下载问题解决方案
一、先解决系统设置无权限显示问题
在info.plist中添加以下权限描述键值对,否则系统不会在设置中显示App的文件访问权限:
<key>NSDocumentsFolderUsageDescription</key> <string>需要访问文档目录以保存下载的PDF文件</string> <key>NSDownloadsFolderUsageDescription</key> <string>需要访问下载目录以保存PDF文件</string> <key>UIFileSharingEnabled</key> <true/>
UIFileSharingEnabled开启后,你的App会在系统「文件」App中显示,方便用户管理文件;- 权限描述字符串要明确说明用途,否则Apple审核可能不通过。
二、修复WKWebView下载处理逻辑
如果你用的是UIWebView,立刻换成WKWebView(UIWebView已废弃)。以下是完整的下载处理代码示例:
import UIKit import WebKit class ViewController: UIViewController, WKNavigationDelegate, WKDownloadDelegate, UIDocumentPickerDelegate { private var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() setupWebView() loadWebApp() } private func setupWebView() { let config = WKWebViewConfiguration() webView = WKWebView(frame: view.bounds, configuration: config) webView.navigationDelegate = self webView.downloadDelegate = self // 必须设置下载代理才能处理PDF下载 webView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(webView) } private func loadWebApp() { guard let url = URL(string: "你的WebApp地址") else { return } webView.load(URLRequest(url: url)) } // 拦截下载请求 func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) { guard let response = navigationAction.response as? HTTPURLResponse else { decisionHandler(.allow, preferences) return } // 通过响应头判断是否为附件下载(PDF通常会返回Content-Disposition: attachment) let contentDisposition = response.allHeaderFields["Content-Disposition"] as? String ?? "" if contentDisposition.contains("attachment") { webView.startDownload(using: navigationAction.request) decisionHandler(.cancel, preferences) // 取消默认导航,避免WebView跳转 return } decisionHandler(.allow, preferences) } // 下载完成后处理文件 func download(_ download: WKDownload, didFinishDownloadingTo location: URL) { let fileManager = FileManager.default guard let documentsDir = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { return } // 用服务器返回的文件名,默认取downloaded.pdf let fileName = download.response.suggestedFilename ?? "downloaded.pdf" let destURL = documentsDir.appendingPathComponent(fileName) // 先删除已存在的同名文件 if fileManager.fileExists(atPath: destURL.path) { try? fileManager.removeItem(at: destURL) } // 移动临时下载文件到App沙盒目录 do { try fileManager.moveItem(at: location, to: destURL) showSavePicker(for: destURL) // 弹出选择器让用户选择保存路径 } catch { print("保存文件失败:\(error)") } } // 弹出文件选择器供用户选择保存路径 private func showSavePicker(for fileURL: URL) { let picker = UIDocumentPickerViewController(forExporting: [fileURL], asCopy: true) picker.delegate = self picker.modalPresentationStyle = .formSheet present(picker, animated: true) } // 文件选择器代理方法 func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { print("文件已成功保存到:\(urls.first?.path ?? "")") dismiss(animated: true) } func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { dismiss(animated: true) } }
三、关键注意事项
- 必须设置
WKDownloadDelegate:WKWebView不会自动处理下载请求,需要通过代理拦截并触发下载; - 临时文件处理:下载完成的文件会存放在临时目录,必须移动到沙盒或通过文件选择器导出,否则App重启后文件会被系统删除;
- 权限触发时机:只有当App实际访问对应目录(比如代码中访问
documentDirectory),且info.plist有对应描述时,系统设置才会显示文件访问权限; - iOS版本兼容性:上述代码适配iOS13+,Xcode14.3对应的iOS16完全支持。
内容的提问来源于stack exchange,提问作者Thiruselvam B
相关产品推荐
相关产品推荐

