如何在ApplicationWillTerminate中执行JS回调?
问题解决:应用终止时通知WKWebView网页
核心原因
applicationWillTerminate的执行时间窗口极短,而WKWebView.evaluateJavaScript是异步操作——系统很可能在JS回调的闭包执行完成前就终止了应用进程,导致网页无法收到通知。
尝试修复:延长执行时间窗口
可以通过后台任务或调度组等待的方式,尝试争取一点时间让JS调用完成,但这种方法不保证100%可靠,因为iOS对应用终止前的执行时间限制很严格。
方案1:使用后台任务延长执行时间
func applicationWillTerminate(_ application: UIApplication) { guard let callback = unloadListenerCallback, !callback.isEmpty else { debugPrint("got null callback - stop listening") unloadListenerCallback = nil return } // 申请短暂后台任务 var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid backgroundTaskID = application.beginBackgroundTask(withName: "NotifyWebViewAppTerminate") { application.endBackgroundTask(backgroundTaskID) backgroundTaskID = .invalid } // 执行JS回调 HomeController.instance.webView?.evaluateJavaScript(callback) { [weak self] result, error in defer { // 结束后台任务 if backgroundTaskID != .invalid { application.endBackgroundTask(backgroundTaskID) backgroundTaskID = .invalid } } if let error = error { print("Error executing terminate callback: \(error), callback: \(callback)") } else { print("Executed terminate callback: \(callback), result: \(result ?? "nil")") } self?.unloadListenerCallback = nil } }
方案2:使用调度组等待回调完成
func applicationWillTerminate(_ application: UIApplication) { guard let callback = unloadListenerCallback, !callback.isEmpty else { debugPrint("got null callback - stop listening") unloadListenerCallback = nil return } let dispatchGroup = DispatchGroup() dispatchGroup.enter() HomeController.instance.webView?.evaluateJavaScript(callback) { [weak self] result, error in defer { dispatchGroup.leave() } if let error = error { print("Error executing terminate callback: \(error), callback: \(callback)") } else { print("Executed terminate callback: \(callback), result: \(result ?? "nil")") } self?.unloadListenerCallback = nil } // 最多等待0.5秒,避免系统强制终止应用 _ = dispatchGroup.wait(timeout: .now() + 0.5) }
可靠替代方案
如果上述修复仍无法生效,建议换用更可靠的间接通知方式:
1. 后端状态同步
- 应用进入后台时,向后端接口发送"后台状态"标记;
- 应用正常退出时(如通过
applicationWillTerminate),发送"已终止"标记; - 网页通过轮询后端接口或WebSocket长连接,获取应用的实时状态;
- 若后端长时间未收到应用的心跳/状态更新,自动判定应用已终止,网页查询时即可知晓。
2. 网页端主动检测
- 网页定时向原生应用发送心跳请求(通过
window.webkit.messageHandlers调用原生方法); - 若原生在指定时间内未响应,网页判定应用已终止;
- 同时,网页可监听
pagehide事件,当WebView被销毁时触发该事件,作为应用终止的辅助判断。
3. 本地存储标记(适用于下次加载时知晓)
- 在
applicationWillTerminate中尝试写入网页的本地存储:HomeController.instance.webView?.evaluateJavaScript("localStorage.setItem('appWasTerminated', 'true')") { _, _ in } - 网页在加载时读取该标记:
localStorage.getItem('appWasTerminated'),即可知晓上次应用是异常终止; - 注意:此方法无法实时通知,仅适用于下次网页加载时回溯状态。
内容的提问来源于stack exchange,提问作者Andrey Lesnykh
相关产品推荐
相关产品推荐

