如何修改WKWebView的Action Sheet按钮?解决保存图片崩溃问题
解决WKWebView长按保存图片时无权限崩溃的问题
这个坑我之前做WKWebView项目时正好踩过!默认的「Save image」动作完全不做权限校验,没开照片库权限直接点击就会崩溃。下面是一套实测有效的完整解决方案,从权限拦截到保存逻辑都给你梳理清楚了:
1. 导入必要框架
首先在你的ViewController文件顶部导入Photos框架,毕竟要和照片库交互:
import Photos
2. 拦截默认保存动作,替换为自定义逻辑
给WKWebView设置UIDelegate,然后实现performActionFor方法——这个方法会在用户触发WebView内的交互动作(比如长按图片的Save image)时被调用。我们在这里拦截图片保存请求,自己处理权限检查和保存流程:
extension YourViewController: WKUIDelegate { func webView(_ webView: WKWebView, performActionFor hitTestResult: WKHitTestResult, completionHandler: @escaping () -> Void) { // 判断当前动作是否为保存图片 guard hitTestResult.type == .image, let imageURL = hitTestResult.imageURL else { // 非图片保存动作,执行默认逻辑 completionHandler() return } // 先检查照片库权限 checkPhotoPermission { [weak self] hasPermission in guard let self = self else { return } if hasPermission { // 有权限,直接下载并保存图片 self.saveImage(from: imageURL, completion: completionHandler) } else { // 无权限,发起权限申请 PHPhotoLibrary.requestAuthorization { status in DispatchQueue.main.async { switch status { case .authorized, .limited: self.saveImage(from: imageURL, completion: completionHandler) case .denied, .restricted: // 权限被拒绝,提示用户前往设置开启 let alert = UIAlertController(title: "需要照片库权限", message: "请在设置中开启权限才能保存图片", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "取消", style: .cancel)) alert.addAction(UIAlertAction(title: "去设置", style: .default) { _ in guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { return } UIApplication.shared.open(settingsURL) }) self.present(alert, animated: true) completionHandler() case .notDetermined: // 理论上不会走到这里,因为前面已做权限检查 completionHandler() @unknown default: completionHandler() } } } } } } // 封装权限检查的辅助方法 private func checkPhotoPermission(completion: @escaping (Bool) -> Void) { let status = PHPhotoLibrary.authorizationStatus(for: .readWrite) switch status { case .authorized, .limited: completion(true) case .denied, .restricted: completion(false) case .notDetermined: PHPhotoLibrary.requestAuthorization { status in DispatchQueue.main.async { completion(status == .authorized || status == .limited) } } @unknown default: completion(false) } } // 下载图片并保存到照片库 private func saveImage(from url: URL, completion: @escaping () -> Void) { URLSession.shared.dataTask(with: url) { data, _, error in DispatchQueue.main.async { defer { completion() } // 校验图片数据有效性 guard let imageData = data, let image = UIImage(data: imageData) else { let alert = UIAlertController(title: "保存失败", message: "无法获取图片数据", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) self.present(alert, animated: true) return } // 执行保存操作 PHPhotoLibrary.shared().performChanges({ PHAssetChangeRequest.creationRequestForAsset(from: image) }) { success, error in DispatchQueue.main.async { if success { let alert = UIAlertController(title: "保存成功", message: "图片已存入照片库", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) self.present(alert, animated: true) } else { let errorMsg = error?.localizedDescription ?? "保存失败,请稍后重试" let alert = UIAlertController(title: "保存失败", message: errorMsg, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) self.present(alert, animated: true) } } } } }.resume() } }
3. 绑定WKWebView的UIDelegate
别忘了在初始化WKWebView时,把它的uiDelegate设置为当前ViewController,否则上面的拦截方法不会生效:
let webView = WKWebView(frame: view.bounds) webView.uiDelegate = self view.addSubview(webView)
4. 配置Info.plist权限描述
最后必须在Info.plist中添加权限说明,否则iOS会直接拒绝权限请求:
<key>NSPhotoLibraryUsageDescription</key> <string>需要访问照片库以保存您喜欢的图片</string> <key>NSPhotoLibraryAddUsageDescription</key> <string>需要访问照片库以保存您喜欢的图片</string>
额外说明
- 兼容iOS 14+的
limited权限(仅允许访问部分照片),覆盖更多场景 - 所有UI操作都切回主线程,避免线程冲突问题
- 保存成功/失败都添加了弹窗提示,提升用户体验
内容的提问来源于stack exchange,提问作者Babac
相关产品推荐
相关产品推荐

