Swift中如何实现WKWebView的JavaScript定时注入与通信?
WKWebView定时执行JS/传参通信解决方案
首先明确:完全可以实现你要的需求,不需要局限在加载首尾注入JS,以下是3种可落地的方案,优先推荐第一种:
方案1:原生侧定时调用已注入的JS方法(最优适配你的业务)
WKWebView自带evaluateJavaScript(_:completionHandler:)API,支持在WebView存活的任意阶段执行JS代码,不需要重复注入脚本,只需要你在页面加载阶段提前把发送POST请求的JS逻辑注入成全局方法,后续原生侧定时调用传参即可。
实现代码示例:
import WebKit class YourWebViewController: UIViewController, WKNavigationDelegate { var webView: WKWebView! // 用weak修饰Timer避免循环引用 weak var gpsUploadTimer: Timer? override func viewDidLoad() { super.viewDidLoad() // 初始化WebView配置,提前注入你的基础JS逻辑(包含发送POST的方法postGPSSpeed) let config = WKWebViewConfiguration() let jsCode = "function postGPSSpeed(speed) { \ fetch('你的上传接口地址', { \ method: 'POST', \ headers: { '你的共用请求头key': '共用请求头value' }, \ body: JSON.stringify({speed: speed}) \ }) \ }" let userScript = WKUserScript(source: jsCode, injectionTime: .atDocumentEnd, forMainFrameOnly: true) config.userContentController.addUserScript(userScript) webView = WKWebView(frame: view.bounds, configuration: config) webView.navigationDelegate = self view.addSubview(webView) // 加载你的目标页面 webView.load(URLRequest(url: URL(string: "你的页面地址")!)) } // 页面加载完成后启动10秒定时任务 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { gpsUploadTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { [weak self] _ in guard let self = self else { return } // 调用你自己的方法获取当前最新的GPS速度值 let currentSpeed = self.getCurrentGPSSpeed() // 构造执行JS的代码,传入速度参数 let execJS = "postGPSSpeed(\(currentSpeed));" self.webView.evaluateJavaScript(execJS) { _, error in if let err = error { print("执行JS失败:\(err.localizedDescription)") } } } } // 你的获取GPS速度的自有方法,这里仅做示例 func getCurrentGPSSpeed() -> Double { // 替换为你实际的GPS取值逻辑 return 30.5 } // 页面销毁时停止定时器,避免内存泄漏 deinit { gpsUploadTimer?.invalidate() } }
方案2:注入JS侧自行实现定时逻辑
如果不需要原生侧控制定时启停,你可以直接在初始注入的JS代码里加入setInterval定时逻辑,完全不需要原生侧后续操作:
你可以在初始注入的JS代码中加入以下逻辑:
setInterval(() => { // 如果你需要获取原生侧最新的GPS数据,可以通过WKScriptMessageHandler主动向原生发消息获取 // 这里写你的POST请求发送逻辑 }, 10000)
方案3:DOM自定义事件通信
你也可以通过监听自定义DOM事件的方式实现通信,不需要提前约定全局JS方法:
- 初始注入的JS里添加事件监听:
document.addEventListener('uploadSpeedEvent', (event) => { const speed = event.detail.speed // 执行POST发送逻辑 })
- 原生侧需要触发时执行以下代码即可:
let triggerJS = "document.dispatchEvent(new CustomEvent('uploadSpeedEvent', {detail: {speed: \(currentSpeed)}}));" webView.evaluateJavaScript(triggerJS)
方案选择建议
优先选方案1,逻辑最清晰,原生侧可以完全控制定时的启停、参数传递,不需要重复注入JS,性能最优,完全适配你上传GPS速度的业务需求。
内容的提问来源于stack exchange,提问作者Tatsurou
相关产品推荐
相关产品推荐

