如何在SwiftUI中创建独立UIWindow以规避ReplayKit主窗口录制限制?
在SwiftUI中创建独立UIWindow的解决方案
ReplayKit录屏仅会捕获应用的主窗口,因此可以将不想被录屏的UI元素放置在独立的UIWindow对象中。iOS支持多窗口机制,但每个UIWindow需要通过rootViewController提供内容。你之前的代码创建窗口失败的核心原因是:新创建的UIWindow是局部变量,按钮闭包执行完毕后就会被系统内存回收,导致窗口无法持续显示。
修正方案
需要将新创建的UIWindow保存为持久化引用,避免被系统回收。以下提供两种可行的实现方式:
方法1:全局变量存储窗口
import SwiftUI // 全局容器存储创建的窗口,保持引用避免被释放 var extraWindows: [UIWindow] = [] extension UIApplication { var activeWindowScene: UIWindowScene? { connectedScenes .filter { $0.activationState == .foregroundActive } .first(where: { $0 is UIWindowScene }) as? UIWindowScene } } struct ContentView: View { var body: some View { VStack { Button("打开新窗口") { guard let windowScene = UIApplication.shared.activeWindowScene else { return } let newWindow = UIWindow(frame: UIScreen.main.bounds) newWindow.windowScene = windowScene // 设置窗口层级,确保显示在主窗口之上(可按需调整) newWindow.windowLevel = .alert + 1 newWindow.rootViewController = UIHostingController(rootView: Text("这是独立窗口的内容!") .font(.largeTitle) .foregroundColor(.white) .background(Color.blue) ) newWindow.makeKeyAndVisible() // 将窗口加入全局容器 extraWindows.append(newWindow) } Button("关闭所有额外窗口") { extraWindows.forEach { $0.isHidden = true } extraWindows.removeAll() } } .padding() } }
方法2:使用ObservableObject管理窗口
如果更贴合SwiftUI的状态管理逻辑,可以用ObservableObject来统一管理窗口:
import SwiftUI class WindowManager: ObservableObject { static let shared = WindowManager() private(set) var extraWindows: [UIWindow] = [] func createNewWindow(in scene: UIWindowScene, content: some View) { let newWindow = UIWindow(frame: UIScreen.main.bounds) newWindow.windowScene = scene newWindow.windowLevel = .alert + 1 newWindow.rootViewController = UIHostingController(rootView: content) newWindow.makeKeyAndVisible() extraWindows.append(newWindow) } func closeAllWindows() { extraWindows.forEach { $0.isHidden = true } extraWindows.removeAll() } } extension UIApplication { var activeWindowScene: UIWindowScene? { connectedScenes .filter { $0.activationState == .foregroundActive } .first(where: { $0 is UIWindowScene }) as? UIWindowScene } } struct ContentView: View { @StateObject private var windowManager = WindowManager.shared var body: some View { VStack { Button("打开新窗口") { guard let windowScene = UIApplication.shared.activeWindowScene else { return } windowManager.createNewWindow(in: windowScene, content: Text("这是通过状态管理创建的独立窗口") .font(.title) .foregroundColor(.black) .background(Color.yellow) ) } Button("关闭所有额外窗口") { windowManager.closeAllWindows() } } .padding() } }
关键说明
- 保持窗口引用:必须将新UIWindow存储在不会被立即释放的容器中(全局数组、ObservableObject属性等),否则窗口会被系统回收消失。
- 窗口层级:通过
windowLevel可以调整窗口的显示优先级,比如.alert + 1能让窗口显示在系统弹窗之上,可根据需求灵活设置。 - ReplayKit适配:这种独立窗口不会被ReplayKit录屏捕获,正好适配你不想被录屏的UI元素放置需求。
内容的提问来源于stack exchange,提问作者Bogdan
相关产品推荐
相关产品推荐

