WKWebViewでJavaScriptのalert,confirm,promptをSwift5で表示する

WKWebViewはデフォルトではalert,confirm,promptが呼ばれたとき何も表示しません。
alert,confirm,promptが呼ばれたときにダイアログを表示する方法を紹介します。

alert

confirm

prompt

WKWebViewのuiDelegateを設定し、alert,confirm,promptが呼ばれたときにイベントを受け取ります。

import UIKit
import WebKit

class ViewController: UIViewController {
    @IBOutlet var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        webView.uiDelegate = self
        guard let url = URL(string: "http://10.0.92.23:8000/") else { return }
        self.webView.load(URLRequest(url: url))
    }
}

alert,confirm,promptが呼ばれたときに、UIAlertControllerを表示します。
押されたボタンに応じた返り値をcompletionHandlerで返します。

extension ViewController: WKUIDelegate {
    /** @abstract JavaScriptアラートパネルを表示します。
     @param webView デリゲートメソッドを呼び出すWebビュー。
     @param message 表示するメッセージ。
     @param frame JavaScriptがこの呼び出しを開始したフレームに関する情報。
     @param completionHandler 警告パネルが閉じられた後に呼び出す完了ハンドラー。
     @discussion ユーザーのセキュリティのために、アプリは特定のWebサイトがこのパネルのコンテンツを制御しているという事実に注意を向ける必要があります。
     制御するWebサイトを識別するための簡単なフォーラムはframe.request.URL.hostです。
     パネルには1つの[OK]ボタンが必要です。

     このメソッドを実装しない場合、Webビューはユーザーが[OK]ボタンを選択したかのように動作します。
     */
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
        let okAction = UIAlertAction(title: "OK", style: .default) {
            _ in completionHandler()
        }
        alertController.addAction(okAction)
        present(alertController, animated: true, completion: nil)
    }

    /** @abstract JavaScript確認パネルを表示します。
     @param webView デリゲートメソッドを呼び出すWebビュー。
     @param message 表示するメッセージ。
     @param frame JavaScriptがこの呼び出しを開始したフレームに関する情報。
     @param completionHandler 確認パネルが閉じられた後に呼び出す完了ハンドラー。 ユーザーが[OK]を選択した場合はYESを渡し、ユーザーが[キャンセル]を選択した場合はNOを渡します。
     @discussion ユーザーのセキュリティのために、アプリは特定のWebサイトがこのパネルのコンテンツを制御しているという事実に注意を向ける必要があります。 制御するWebサイトを識別するための簡単なフォーラムはframe.request.URL.hostです。 パネルには、[OK]と[キャンセル]などの2つのボタンが必要です。

     このメソッドを実装しない場合、Webビューはユーザーが[キャンセル]ボタンを選択したかのように動作します。
     */
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
        let okAction = UIAlertAction(title: "OK", style: .default) {
            _ in completionHandler(true)
        }
        let calcelAction = UIAlertAction(title: "Cancel", style: .cancel) {
            _ in completionHandler(false)
        }
        alertController.addAction(okAction)
        alertController.addAction(calcelAction)
        present(alertController, animated: true, completion: nil)
    }

    /** @abstract JavaScriptテキスト入力パネルを表示します。
     @param webView デリゲートメソッドを呼び出すWebビュー。
     @param prompt 表示するプロンプト。
     @param defaultText テキスト入力フィールドに表示する最初のテキスト。
     @param frame JavaScriptがこの呼び出しを開始したフレームに関する情報。
     @param completionHandler テキスト入力パネルが閉じられた後に呼び出す完了ハンドラー。 ユーザーが[OK]を選択した場合は、入力したテキストを渡します。それ以外の場合は、nilを渡します。
     @discussion ユーザーのセキュリティのために、アプリは特定のWebサイトがこのパネルのコンテンツを制御しているという事実に注意を向ける必要があります。
     制御するWebサイトを識別するための簡単なフォーラムはframe.request.URL.hostです。
     パネルには、[OK]と[キャンセル]などの2つのボタンと、テキストを入力するためのフィールドが必要です。

     このメソッドを実装しない場合、Webビューはユーザーが[キャンセル]ボタンを選択したかのように動作します。
     */
    func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
        let alertController = UIAlertController(title: "", message: prompt, preferredStyle: .alert)
        let okAction = UIAlertAction(title: "OK", style: .default) { _ in
            if let textField = alertController.textFields?.first {
                completionHandler(textField.text)
            } else {
                completionHandler("")
            }
        }
        let calcelAction = UIAlertAction(title: "Cancel", style: .cancel) {
            _ in completionHandler(nil)
        }
        alertController.addAction(okAction)
        alertController.addAction(calcelAction)
        alertController.addTextField { $0.text = defaultText }
        present(alertController, animated: true, completion: nil)
    }
}

検証に使用したHTML。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>
        <button onclick="alert('alert');">alert</button>
    </p>
    <p>
        <button onclick="confirm('confirm') ? alert('true') : alert('false');">confirm</button>
    </p>
    <p>
        <button onclick="alert(window.prompt('元気にしてる?', '元気だよ!'))">prompt</button>
    </p>
</body>
</html>

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください