WKWebView 展示来自 JS 的警告信息

这里每天分享一个 iOS 的新知识,快来关注我吧

前言

在现在的开发中,要将 H5 页面展示在 App 中主要用到 WKWebView。在 Web 网页中有一些经典的 Alert 弹窗,为了支持这种警报,需要实现一些 WKWebView.uiDelegate 回调。这篇文章主要来讲讲如何在 iOS WKWebView 上支持各种 Javascript 警报的代码示例:

UIDelegate

首先你的 webView 需要支持 WKWebView.uiDelegate 协议,它包含支持 Javascript 警报所需的方法。

ini 复制代码
webKitView?.uiDelegate = self

WKWebView Javascript 警报消息

当 Web 上执行 window.alert 的时候,系统会调用 webView(_:, runJavaScriptAlertPanelWithMessage:, initiatedByFrame:, completionHandler:) 代理方法, 我们需要在这个方法中做出承接:

less 复制代码
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
    
    let alert = UIAlertController(
        title: "这是一个来自 JS 的 Alert",
        message: "Alert 的内容为:\(message)",
        preferredStyle: .alert
    )

    // 增加一个 完成 按钮
    let okAction = UIAlertAction(
        title: "完成",
        style: .default,
        handler: { _ in
            completionHandler()
        }
    )
    alert.addAction(okAction)

    present(alert, animated: true, completion: nil)
}

当 Web 上执行 window.alert('测试 alert') 的时候,就会调用这个方法,并弹出我们的 UIAlertController

Javascript 确认操作

当在 js 中执行 window.confirm("message") 时就会调用 webView(_:, runJavaScriptConfirmPanelWithMessage:, initiatedByFrame:, completionHandler:) 方法,我们可以在此拦截,并自己弹出一个 UIAlertController 来让用户确认。

这个方法中的 completionHandler 来回调给 WebView 用户点了是或者否。

less 复制代码
func webView(_ webView: WKWebView,
    runJavaScriptConfirmPanelWithMessage message: String,
    initiatedByFrame frame: WKFrameInfo,
    completionHandler: @escaping (Bool) -> Void) {

    // Set the message as the UIAlertController message
    let alert = UIAlertController(
        title: "这是一个来自 JS 的确认弹窗",
        message: "需要确认的内容为:\(message)",
        preferredStyle: .alert
    )

    // 添加一个确认按钮
    let okAction = UIAlertAction(
        title: "确认",
        style: .default,
        handler: { _ in
            // 当用户点击确认,回调 true 给 webView
            completionHandler(true)
        }
    )
    alert.addAction(okAction)

    // 添加一个取消按钮
    let cancelAction = UIAlertAction(
        title: "取消",
        style: .cancel,
        handler: { _ in
            // 当用户点击取消,回调 false 给 webView
            completionHandler(false)
        }
    )
    alert.addAction(cancelAction)

    present(alert, animated: true, completion: nil)
}

当 H5 上 js 调用 window.confirm("你确认吗?"),就会在页面上看到:

Javascript 输入提示

当在 js 中执行 window.prompt() 时就会调用 webView(_:, runJavaScriptTextInputPanelWithPrompt prompt:, defaultText:, initiatedByFrame frame:, completionHandler:) 方法,我们可以在此拦截,并自己弹出一个 UIAlertController 来让用户输入内容。

less 复制代码
func webView(_ webView: WKWebView,
    runJavaScriptTextInputPanelWithPrompt prompt: String,
    defaultText: String?,
    initiatedByFrame frame: WKFrameInfo,
    completionHandler: @escaping (String?) -> Void) {
    
    let alert = UIAlertController(
        title: "这是一个来自 JS 的输入框弹窗",
        message: "提示词为:\(prompt)",
        preferredStyle: .alert
    )

    // 添加一个输入框
    alert.addTextField()
    
    // 把默认值写进输入框
    alert.textFields?.first?.text = defaultText

    // 添加一个提交按钮
    let submitAction = UIAlertAction(
        title: "提交",
        style: .default,
        handler: { [unowned alert] _ in
            // 把用户输入的内容回调给 js
            let input = alert.textFields?.first
            completionHandler(input?.text)
        }
    )
    alert.addAction(submitAction)

    present(alert, animated: true, completion: nil)
}

当 js 执行 window.prompt('请输入内容', '这是输入框的默认值'),就会在页面上看到我们自定义的带输入框的 Alert:

重要的一点

如果你决定使用这种方式承接 js 的警报弹窗,那么这三个方法的 completionHandler 回调一定要执行,否则当 js 调用到对应的方法时 App 会发生崩溃,崩溃日志为:

vbnet 复制代码
Terminating app due to uncaught exception 
'NSInternalInconsistencyException', reason: 
'Completion handler passed to 
-[TestProject.ViewController webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:] 
was not called'

这里每天分享一个 iOS 的新知识,快来关注我吧

本文同步自微信公众号 "iOS新知",每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!

相关推荐
黑化旺仔5 小时前
【OC】KVO
macos·ios·objective-c·cocoa
HouWan6 小时前
SwiftUI 小技巧:如何读取 SwiftUI Font 的详细信息
ios·swiftui·apple
李游Leo7 小时前
HarmonyOS 7 实战开发 05:把页面做到可上线状态
ios·harmonyos
终端安全笔记12 小时前
描述文件、企业证书、MDM 不是三个名字,是三层
android·ios·智能手机
传奇开心果编程13 小时前
【SwiftUI入门练中学】第1课 从零开始
学习·ui·ios·swiftui·swift
丿Wayne18 小时前
iOS Token 刷新实战(Actor 避免并发重复刷新)
ios·swift·token·actor·swift并发
终端安全笔记2 天前
iOS 27 给了租赁一个新工具,但它只认受监督的设备
android·网络·安全·ios
大熊猫侯佩2 天前
独立 App 首发完成 iPhone Duo 展开态适配
ios·swiftui·swift
光影少年2 天前
setImmediate 和 setTimeout(0) 的区别
android·前端·react.js·ios·前端框架
2501_916008892 天前
SSE 和 gRPC 流式接口如何抓包,调试 SSE 与 gRPC 流式接口
网络协议·计算机网络·网络安全·ios·adb·https·udp