Swift调用WKWebView内异步JS函数报错:函数不存在
解决方案
1. 确保JavaScript函数挂载到全局window对象
不管是通过用户脚本注入还是HTML的<script>标签加载,都需要将test函数显式挂载到window上,避免作用域隔离问题:
// 修改后的JavaScript代码 window.test = async function() { // 异步逻辑 return "hello world"; };
或者:
async function test() { return "hello world"; } // 显式挂载到全局window window.test = test;
2. 严格匹配Content World
- 如果函数是注入到页面全局作用域(HTML script标签加载、或用户脚本未指定
inContentWorld默认注入到.page),调用时必须指定.page:
do { let result = try await webView.callAsyncJavaScript("return window.test();", in: nil, contentWorld: .page) if let stringResult = result as? String { print(stringResult) } } catch { print("调用错误: \(error)") }
- 如果是将用户脚本注入到
.defaultClient世界,创建WKUserScript时需指定对应Content World:
let userScript = WKUserScript( source: userScriptSource, injectionTime: .atDocumentStart, forMainFrameOnly: false, inContentWorld: .defaultClient )
此时调用时使用.defaultClient:
try await webView.callAsyncJavaScript("return window.test();", in: nil, contentWorld: .defaultClient)
3. 确保页面完全加载后再调用
不要依赖“等待数秒”,通过WKNavigationDelegate监听页面加载完成:
extension YourViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { // 页面加载完成,此时可以安全调用JS函数 } } // 在初始化webView时设置代理 webView.navigationDelegate = self
4. 替换强制解包避免隐藏错误
去掉try!和as!,改用do-catch和可选绑定,方便排查潜在问题:
@IBAction func buttonTapped(_ sender: UIButton) { Task { do { let result = try await webView.callAsyncJavaScript("return window.test();", in: nil, contentWorld: .page) guard let stringResult = result as? String else { print("返回结果不是字符串类型") return } print("调用结果: \(stringResult)") } catch { print("调用JS函数失败: \(error.localizedDescription)") } } }
问题核心原因
WKWebView的.page和.defaultClient是相互隔离的作用域,未挂载到window的函数仅存在于当前脚本的局部作用域,无法被全局调用;另外,若调用时指定的Content World与函数所在的作用域不匹配,也会触发“函数未定义”的错误。
内容的提问来源于stack exchange,提问作者Alex S. Glomsaas
相关产品推荐
相关产品推荐

