WebViewで画像のダウンロードボタンを押された時にアルバムに保存する
はじめに
WebView,SafariViewどちらもデフォルトの状態で画像を長押しすると保存することができるので、画像の長押しを禁止していない限りデフォルトの保存方法で良いと思います。
画像の長押しが禁止されていてかつSafariViewではやりたくなりという時にボタンタップ時に画像のみのページに遷移せずに直でダウンロードを進めたい時の解決策です。
コード
import UIKit
import WebKit
class ImageDownloadWebViewController: UIViewController {
var request: URLRequest
// MARK: - Initializer
init(url: URL) {
request = URLRequest(url: url)
request.httpMethod = "GET"
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
//WebViewの中で長押しメニューを出さないようにする
let disableCalloutScriptString = "document.documentElement.style.webkitTouchCallout='none';"
let disableCalloutScript = WKUserScript(source: disableCalloutScriptString, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
//ユーザーコンテントのインスタンスを作成し入れる
let userContentController = WKUserContentController()
userContentController.addUserScript(disableCalloutScript)
let webConfig = WKWebViewConfiguration()
webConfig.userContentController = userContentController
let webView = WKWebView(frame: .zero, configuration: webConfig)
webView.uiDelegate = self
webView.navigationDelegate = self
view.addFull(view: webView)
webView.load(request)
}
}
// MARK: - WKUIDelegate, WKNavigationDelegate
extension ImageDownloadWebViewController: WKUIDelegate, WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
let urlString: String = String(describing: navigationAction.request.url)
// 対象の画像かを判定
if urlString.contains(".jpg") {
do {
let data = try Data(contentsOf: navigationAction.request.url!)
guard let image = UIImage(data: data) else {
return
}
showDialog(image: image)
} catch let err {
print("Error : \(err.localizedDescription)")
}
decisionHandler(.cancel)
return
}
decisionHandler(.allow)
}
private func showDialog(image: UIImage) {
let alert: UIAlertController = UIAlertController(title: "画像を保存しますか?", message: "", preferredStyle: UIAlertController.Style.alert)
let confirmAction: UIAlertAction = UIAlertAction(title: "確定", style: UIAlertAction.Style.default, handler: { _ in
UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.showResultOfSaveImage(_:didFinishSavingWithError:contextInfo:)), nil)
})
let cancelAction: UIAlertAction = UIAlertAction(title: "キャンセル", style: UIAlertAction.Style.cancel, handler: { _ in
print("キャンセル")
})
alert.addAction(confirmAction)
alert.addAction(cancelAction)
present(alert, animated: true, completion: nil)
}
@objc func showResultOfSaveImage(_ image: UIImage, didFinishSavingWithError error: NSError!, contextInfo: UnsafeMutableRawPointer) {
if error != nil {
return
}
let alert = UIAlertController(title: "アルバムに保存しました", message: "", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alert, animated: true, completion: nil)
}
}
extension UIView {
func addFull(view: WKWebView) {
view.translatesAutoresizingMaskIntoConstraints = false
addSubview(view)
view.topAnchor.constraint(equalTo: topAnchor, constant: 0.0).isActive = true
view.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0.0).isActive = true
view.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0).isActive = true
view.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0.0).isActive = true
}
}
Permission
Privacy - Photo Library Additions Usage Description
解説
検証にはアラド戦記の壁紙ダウンロードページを使用させていただきました。
やっていることはシンプルで以下のメソッドでaタグで画像リンクが設定されているボタンを踏んだ際、urlの中身を判定して”.jpg”という文字列が含まれている場合遷移を行わずURLをImageに変換して保存処理をかけています。
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)