关闭窗口后WKWebView仍持续播放音频问题求助
问题分析与解决方案
这不是操作错误,是你给主窗口设置自定义NSWindowDelegate后,改变了SwiftUI默认的窗口生命周期行为导致的问题。
问题原因
默认情况下,SwiftUI的WindowGroup管理的窗口,在点击关闭按钮时会销毁对应的视图层级(包括内嵌的WKWebView),且应用进程会在最后一个窗口关闭后自动终止。但当你给窗口绑定了自定义NSWindowDelegate,系统会判定你要手动接管窗口生命周期,此时点击关闭按钮仅会隐藏窗口,不会销毁WebView实例,进程也不会终止,所以音频会在后台持续播放。
修复方案
你可以通过以下两种方式解决:
方案1:恢复窗口默认关闭&进程终止行为
在AppDelegate中实现windowShouldClose方法,并设置应用在最后一个窗口关闭时自动终止:
class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject, NSWindowDelegate { func applicationDidFinishLaunching(_ notification: Notification) { if let mainWindow = NSApp.keyWindow { mainWindow.delegate = self } // 让应用在最后一个窗口关闭后自动终止 NSApp.terminateAfterLastWindowClosed = true } // 明确允许窗口关闭 func windowShouldClose(_ sender: NSWindow) -> Bool { return true } }
方案2:窗口关闭时手动停止WebView播放
如果需要保留窗口实例(比如支持快速恢复),可以在窗口关闭时主动停止WebView的加载并清空内容:
首先给PlayerWebView添加停止播放的方法:
struct PlayerWebView: NSViewRepresentable { private let webView = WKWebView(frame: .zero) func makeNSView(context: Context) -> WKWebView { let url = URL(string: "https://www.youtube.com/embed/Ir1xi2zeuug")! let request = URLRequest(url: url) webView.load(request) return webView } func updateNSView(_ nsView: WKWebView, context: Context) {} // 添加停止播放的方法 func stopPlaying() { webView.stopLoading() webView.loadHTMLString("", baseURL: nil) } }
然后在AppDelegate的窗口关闭回调中调用该方法(需确保能获取到PlayerWebView的实例,可通过环境对象、全局引用等方式实现):
class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject, NSWindowDelegate { @EnvironmentObject private var playerWebView: PlayerWebView func applicationDidFinishLaunching(_ notification: Notification) { if let mainWindow = NSApp.keyWindow { mainWindow.delegate = self } } func windowWillClose(_ notification: Notification) { playerWebView.stopPlaying() } }
额外提示
如果你的需求只是监听窗口事件,不一定需要自定义NSWindowDelegate——SwiftUI的WindowGroup可以通过.onChange(of: NSApp.windows)或者结合NSWindow的发布者来实现监听,这样能避免修改默认的窗口生命周期行为。
内容的提问来源于stack exchange,提问作者fer0n
相关产品推荐
相关产品推荐

