visionOS沉浸式视频应用重载问题求助:无法返回原路径
解决visionOS沉浸式视频应用窗口隐藏而非关闭的方案
一、利用ScenePhase与窗口状态管理实现隐藏逻辑
在visionOS中,无需关闭窗口,可通过控制窗口的isHidden属性实现隐藏,结合场景状态监听与视频播放事件回调,完成播放时隐藏、结束后恢复的流程。
1. SwiftUI实现示例
通过环境变量scenePhase监听场景状态,配合全屏封面展示沉浸式视频,同时控制主窗口的隐藏与恢复:
import SwiftUI import AVKit struct ContentView: View { @Environment(\.scenePhase) private var scenePhase @State private var isPlayingImmersive = false @State private var videoPlayer: AVPlayer? var body: some View { VStack(spacing: 20) { Button("启动沉浸式视频") { guard let videoURL = Bundle.main.url(forResource: "immersive_content", withExtension: "mov") else { return } videoPlayer = AVPlayer(url: videoURL) isPlayingImmersive = true } // 其他界面元素 } .fullScreenCover(isPresented: $isPlayingImmersive) { // 退出沉浸式时恢复主窗口 if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { windowScene.windows.first?.isHidden = false } } content: { // 进入沉浸式前隐藏主窗口 if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { windowScene.windows.first?.isHidden = true } VideoPlayer(player: videoPlayer) .frame(maxWidth: .infinity, maxHeight: .infinity) .onDisappear { videoPlayer?.pause() } } } }
2. UIKit实现示例
在UIWindowSceneDelegate中直接管理窗口状态,配合AVPlayer的播放结束通知完成窗口恢复:
import UIKit import AVKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? private var immersivePlayerVC: AVPlayerViewController? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = scene as? UIWindowScene else { return } window = UIWindow(windowScene: windowScene) window?.rootViewController = MainViewController() window?.makeKeyAndVisible() } // 外部调用此方法启动沉浸式视频 func startImmersiveVideo(with url: URL) { immersivePlayerVC = AVPlayerViewController() immersivePlayerVC?.player = AVPlayer(url: url) immersivePlayerVC?.player?.play() // 隐藏主窗口 window?.isHidden = true // 监听视频结束事件 NotificationCenter.default.addObserver( self, selector: #selector(onVideoPlaybackEnded), name: .AVPlayerItemDidPlayToEndTime, object: immersivePlayerVC?.player?.currentItem ) // 展示沉浸式播放器窗口 if let playerWindow = immersivePlayerVC?.view.window { window?.windowScene?.addWindow(playerWindow) playerWindow.makeKeyAndVisible() } } @objc private func onVideoPlaybackEnded() { // 恢复主窗口显示 window?.isHidden = false // 清理播放器资源 immersivePlayerVC?.player?.pause() immersivePlayerVC?.dismiss(animated: true) immersivePlayerVC = nil NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: nil) } }
二、关键注意事项
- 需在
Info.plist中配置后台模式(添加audio, airplay, and picture in picture权限),避免窗口隐藏后应用被系统挂起。 - 确保视频结束事件的监听逻辑可靠,避免出现窗口无法自动恢复的情况。
- 测试时需验证沉浸式场景与窗口状态切换的流畅性,保证视频播放体验不受影响。
三、备选方案(若窗口隐藏仍有问题)
如果窗口隐藏方案未达预期,可通过持久化保存用户路径,在应用启动时自动跳转:
// 保存当前界面标识 UserDefaults.standard.set("video_browse", forKey: "last_accessed_scene") // 应用启动时恢复路径 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let lastScene = UserDefaults.standard.string(forKey: "last_accessed_scene") ?? "initial" window?.rootViewController = lastScene == "video_browse" ? VideoBrowseViewController() : InitialViewController() return true }
内容的提问来源于stack exchange,提问作者chanhee
相关产品推荐
相关产品推荐

