tvOS SwiftUI:IMAManager广告结束后.onPlayPauseCommand失效求助
问题:tvOS SwiftUI中广告播放结束后
.onPlayPauseCommand失效 在tvOS SwiftUI应用开发中,播放器首次加载时.onPlayPauseCommand可正常响应,但当IMAManager加载的广告播放结束后,该命令停止工作,其余命令(如.onMoveCommand)仍能正常运行。
核心原因分析
IMAManager在广告播放期间会接管系统媒体命令的处理逻辑,广告结束后未正确恢复SwiftUI视图的命令响应链路;同时AVPlayerViewController的焦点状态或内置命令处理可能与SwiftUI的.onPlayPauseCommand产生冲突,导致事件无法传递到视图修饰符。
解决方案
方案1:通过状态触发视图刷新,重新绑定命令响应
在广告结束时触发视图的状态更新,强制SwiftUI重新渲染并绑定.onPlayPauseCommand。
修改VerticalPlayerView,添加状态变量并监听广告结束事件:
struct VerticalPlayerView: View { @ObservedObject var player: SimplePlayer @Binding var showControls: Bool @State private var hideTimer: Timer? @FocusState private var playPauseFocused: Bool @Environment(\.scenePhase) private var scenePhase @Namespace private var playerFocusScope private let sliderLift: CGFloat = 120 // 添加状态变量用于触发视图刷新 @State private var refreshCommandTrigger = false var body: some View { // ... 原有视图代码 ... } .onAppear { resetHideTimer() // 监听广告状态变化 player.onChangeAdStatus = { adCompleted in if adCompleted { // 广告结束时触发刷新 refreshCommandTrigger.toggle() } } } // 通过状态变化触发视图刷新 .onChange(of: refreshCommandTrigger) {} #if os(tvOS) .onPlayPauseCommand { if !showControls { showControls = true playPauseFocused = true } player.togglePlayPause() resetHideTimer() } .onMoveCommand { _ in if !showControls { showControls = true playPauseFocused = true } resetHideTimer() } #endif }
方案2:禁用AVPlayerViewController的内置媒体命令处理
AVPlayerViewController默认会处理播放暂停等媒体命令,可能与SwiftUI的命令修饰符冲突,可禁用其内置控制或转发命令。
修改PlayerViewControllerView的makeUIViewController方法及添加协调器:
struct PlayerViewControllerView: UIViewControllerRepresentable { let player: AVPlayer var showsPlaybackControls: Bool = true var onAdEnvironmentReady: ((UIView, UIViewController) -> Void)? func makeUIViewController(context: Context) -> AVPlayerViewController { let vc = AVPlayerViewController() vc.player = player vc.showsPlaybackControls = showsPlaybackControls #if os(tvOS) vc.videoGravity = .resizeAspect vc.requiresLinearPlayback = false // 设置代理拦截媒体命令 vc.delegate = context.coordinator #endif DispatchQueue.main.async { self.onAdEnvironmentReady?(vc.view, vc) } return vc } func updateUIViewController(_ vc: AVPlayerViewController, context: Context) { vc.player = player vc.showsPlaybackControls = showsPlaybackControls } // 添加协调器处理代理逻辑 func makeCoordinator() -> Coordinator { Coordinator() } class Coordinator: NSObject, AVPlayerViewControllerDelegate { // 拦截播放暂停命令,交给SwiftUI处理 func playerViewController(_ playerViewController: AVPlayerViewController, shouldHandlePlaybackControlOf type: AVPlayerViewControllerPlaybackControlType) -> Bool { if type == .playPause { return false } return true } } }
方案3:手动注册UIKeyCommand(备选)
如果上述方案无效,可直接使用UIKit的UIKeyCommand手动注册播放暂停命令,绕开SwiftUI的命令修饰符限制。
创建播放器宿主视图:
struct PlayerHostView: UIViewControllerRepresentable { let player: SimplePlayer let onPlayPause: () -> Void func makeUIViewController(context: Context) -> UIViewController { let vc = UIViewController() // 注册播放暂停命令 let playPauseCommand = UIKeyCommand(input: " ", modifierFlags: [], action: #selector(context.coordinator.handlePlayPause)) vc.addKeyCommand(playPauseCommand) // 嵌入SwiftUI播放器视图 let swiftUIPlayer = VerticalPlayerView(player: player, showControls: .constant(false)) let hostingVC = UIHostingController(rootView: swiftUIPlayer) hostingVC.view.frame = vc.view.bounds vc.addChild(hostingVC) vc.view.addSubview(hostingVC.view) hostingVC.didMove(toParent: vc) context.coordinator.onPlayPause = onPlayPause return vc } func makeCoordinator() -> Coordinator { Coordinator() } class Coordinator: NSObject { var onPlayPause: (() -> Void)? @objc func handlePlayPause() { onPlayPause?() } } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} }
内容的提问来源于stack exchange,提问作者steveSarsawa
相关产品推荐
相关产品推荐

