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

iOS Swift中WKWebView的userContentController无法接收网页回调

iOS端WKWebView无法接收Web端已有JS的点击回调

网页上有点击按钮,Web端已实现对应JavaScript逻辑,但iOS端的userContentController收不到WebView的点击回调。从iOS端注入JS时能正常收到回调,但想直接复用Web端现有JS,当前配置无效。


相关代码

1. iOS注入JS可正常工作的代码

override func viewDidLoad() {
    super.viewDidLoad()
    let preferences = WKPreferences()
    let contentController = WKUserContentController()
    preferences.javaScriptEnabled = true
    let source: String = """
            window.onload = function() {
            document.addEventListener("click", function(evt) {
                var tagClicked = document.elementFromPoint(evt.clientX, evt.clientY);
                if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.getAccessToken) {
                   window.webkit.messageHandlers.Android.postMessage(JSON.stringify({
                       properties: {
                           unique_key: "some_unique_key_value"
                       }
                   }));
                }
            });
        }
        """
    let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
    contentController.addUserScript(script)
    let configuration = WKWebViewConfiguration()
    configuration.preferences = preferences
    configuration.userContentController = contentController
    configuration.userContentController.add(self, name: "Android")
    let webAppInterface = WebAppInterface(viewController: self)
    self.webView = WKWebView(frame: self.view.frame, configuration: configuration)
    webView.allowsBackForwardNavigationGestures = true
    self.webView.uiDelegate = self
    self.webView.navigationDelegate = self
    self.webView.scrollView.delegate = self
    self.view = webView
}

2. 尝试使用Web端已有JS的iOS代码

override func viewDidLoad() {
    super.viewDidLoad()
    // 初始化WKPreferences并启用JavaScript
    let preferences = WKPreferences()
    preferences.javaScriptEnabled = true
    // 创建WKUserContentController
    let contentController = WKUserContentController()
    // 创建WKWebViewConfiguration并设置偏好和内容控制器
    let configuration = WKWebViewConfiguration()
    configuration.preferences = preferences
    configuration.userContentController = contentController
    // 添加消息处理器接收Web端消息
    let webAppInterface = WebAppInterface(viewController: self)
    configuration.userContentController.add(webAppInterface, name: "Android")
    // 使用配置初始化WKWebView
    self.webView = WKWebView(frame: self.view.frame, configuration: configuration)
    webView.allowsBackForwardNavigationGestures = true
    self.webView.uiDelegate = self
    self.webView.navigationDelegate = self
    self.webView.scrollView.delegate = self
    self.view = webView
 }

3. WebAppInterface代码

import UIKit
import WebKit
class WebAppInterface: NSObject, WKScriptMessageHandler {
   weak var viewController: UIViewController?
   init(viewController: UIViewController) {
       self.viewController = viewController
   }

   func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
       guard let messageBody = message.body as? String else { return }
       postMessage(message: messageBody)
   }
   func postMessage(message: String) {
       do {
           if let data = message.data(using: .utf8),
              let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
              let properties = jsonObject["properties"] as? [String: Any],
              let uniqueKey = properties["unique_key"] as? String {
           

           }
       } catch {
           print("解析JSON错误: \(error)")
       }
   }
}

排查与解决方案

1. 校验Web端JS的核心调用逻辑

  • 确保Web端代码里调用的是window.webkit.messageHandlers.Android.postMessage(...),消息名严格区分大小写,必须和iOS端注册的"Android"完全一致
  • 增加环境判断,避免非iOS环境报错:
    if (window.webkit?.messageHandlers?.Android) {
      window.webkit.messageHandlers.Android.postMessage(JSON.stringify({
        properties: {
          unique_key: "your_unique_value"
        }
      }));
    }
    

2. 修复消息处理器的生命周期问题

你在viewDidLoad中创建的WebAppInterface是局部变量,会被ARC自动释放,导致无法接收消息。需要将其改为类成员变量:

class YourViewController: UIViewController {
    // 声明为成员变量,防止被提前释放
    private var webAppInterface: WebAppInterface!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // ...其他配置代码
        webAppInterface = WebAppInterface(viewController: self)
        configuration.userContentController.add(webAppInterface, name: "Android")
        // ...初始化WebView
    }
}

3. 验证Web端JS的执行时机

  • 确保Web端的点击事件在DOM加载完成后绑定,比如放在DOMContentLoaded或window.onload回调中,避免DOM未就绪导致事件绑定失效
  • 通过Safari开发者工具调试WebView,在Web端的点击回调中添加console.log,确认点击时是否执行到了postMessage逻辑

4. 兼容消息格式的多种情况

iOS端当前只处理String类型的消息体,但Web端可能直接传递JSON对象(而非JSON字符串),导致解析失败。修改代码兼容两种情况:

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    var jsonObject: [String: Any]?
    
    // 兼容直接传JSON对象和JSON字符串两种格式
    if let bodyDict = message.body as? [String: Any] {
        jsonObject = bodyDict
    } else if let bodyString = message.body as? String, 
              let data = bodyString.data(using: .utf8) {
        do {
            jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
        } catch {
            print("解析JSON字符串失败: \(error)")
        }
    }
    
    guard let properties = jsonObject?["properties"] as? [String: Any],
          let uniqueKey = properties["unique_key"] as? String else {
        print("消息格式不符合预期")
        return
    }
    
    // 这里处理获取到的uniqueKey
}

5. 确认WebView基础配置

  • 确保preferences.javaScriptEnabled = true已正确设置
  • 检查是否有其他WKUserScript或页面逻辑阻止了点击事件冒泡,导致Web端的点击回调无法触发

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 08:07:05