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新知",每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!

相关推荐
开心就好20251 小时前
Flutter iOS应用混淆与安全配置详细文档指南
后端·ios
mCell2 小时前
MacOS 下实现 AI 操控电脑(Computer Use)的思考
macos·agent·swift
开心就好20252 小时前
苹果iOS应用开发上架与推广完整教程
后端·ios
用户69371750013843 小时前
XChat 为什么选择 Rust 语言开发
android·前端·ios
MonkeyKing3 小时前
Objective-C Runtime 完整机制:objc_class /cache/bits 源码解析
前端·ios
用户79457223954133 小时前
【DGCharts】iOS 图表渲染事实标准——8 种图表类型、高度可定制,3 行代码画出一条折线
swiftui·swift
秋雨梧桐叶落莳4 小时前
【iOS】 AutoLayout初步学习
学习·macos·ios·objective-c·cocoa·xcode
chaoguo123415 小时前
Any metadata 的内存布局
swift·metadata·value witness table
SY.ZHOU1 天前
移动端架构体系(四):View层的组织与调用方案
flutter·ios·架构·系统架构·安卓
inxx1 天前
iOS 26 模拟器启动卡死:Method Swizzling 在系统回调时触发 nil 崩溃
ios