You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WKWebView消息处理器首次无法获取文本框值,二次点击正常

问题分析与解决方案:WKWebView首次获取HTML表单值为空,二次点击正常

问题核心原因

你遇到的问题本质是异步执行顺序错误:

  • webkitview.evaluateJavaScript("submitForm()") 是异步操作,调用后会立即返回,不会等待JavaScript代码执行完成并通过postMessage把数据传回Swift。
  • 首次点击按钮时,showUser(email: lsusername, name: lspassword) 会先执行,此时lsusername和lspassword还是初始的空字符串;当submitForm()执行完成、userContentController回调更新变量后,二次点击按钮时,变量已经被上次的回调更新,因此能显示正确值。
  • 另外代码里存在一个笔误:baseview.addSubview(self.appvalleyRegistration) 应该改为baseview.addSubview(self.webkitview),否则WebView根本不会被添加到视图中(你能二次点击生效可能是测试时的临时修正)。

解决方案一:直接通过evaluateJavaScript的回调获取值

这种方式不需要依赖WKScriptMessageHandler,直接通过JS执行结果拿到表单值,彻底避免异步消息的顺序问题:

@IBAction func registerUser(_ sender: Any) {
    webkitview.evaluateJavaScript("JSON.stringify({email: document.getElementById('email').value, passw: document.getElementById('passw').value})") { [weak self] result, error in
        guard let self = self, error == nil, let jsonStr = result as? String,
              let data = jsonStr.data(using: .utf8),
              let formData = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: String],
              let email = formData["email"], let passw = formData["passw"] else {
            print("获取表单值失败")
            return
        }
        self.lsusername = email
        self.lspassword = passw
        self.showUser(email: email, name: passw)
    }
}

解决方案二:在ScriptMessage回调中触发弹窗

如果坚持使用postMessage的方式,将showUser的调用移到消息回调中,确保只有当数据从JS传回Swift后才显示弹窗:

  1. 修改registerUser方法,仅触发JS函数:
@IBAction func registerUser(_ sender: Any) {
    webkitview.evaluateJavaScript("submitForm()")
}
  1. 修改userContentController回调,数据更新后再显示弹窗:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    if let data = message.body as? [String : String], let passw = data["passw"], let email = data["email"] {
        lsusername = email;
        lspassword = passw;
        showUser(email: email, name: passw)
    } else {
        print("No data.");
    }
}
  1. 修正WebView添加的代码(并添加自适应约束):
override func viewDidLoad() {
    super.viewDidLoad()

    self.webkitview = WKWebView(frame: .zero, configuration: self.getWKWebViewConfiguration())
    baseview.addSubview(self.webkitview)
    webkitview.translatesAutoresizingMaskIntoConstraints = false
    
    NSLayoutConstraint.activate([
        webkitview.topAnchor.constraint(equalTo: baseview.topAnchor),
        webkitview.leadingAnchor.constraint(equalTo: baseview.leadingAnchor),
        webkitview.trailingAnchor.constraint(equalTo: baseview.trailingAnchor),
        webkitview.bottomAnchor.constraint(equalTo: baseview.bottomAnchor)
    ])
    
    let url = URL(string: "https://redacted.com/registrationform.php")!
    webkitview.load(URLRequest(url: url))
}

补充:为什么sleep()无效

sleep()是阻塞主线程的操作,而WKWebView的JS执行、消息传递都是在主线程异步处理的。阻塞主线程反而会延缓JS执行流程,根本解决不了异步顺序问题,必须通过回调或异步等待的方式处理。

内容的提问来源于stack exchange,提问作者Jonathan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 10:54:20