import Foundation import AVKit import Combine #if os(iOS) /// 画中画(Picture-in-Picture)控制器 /// 封装 AVPictureInPictureController,管理 PiP 生命周期 @MainActor final class PiPController: NSObject, ObservableObject { @Published var isPiPActive = false @Published var isPiPSupported = false private var pipController: AVPictureInPictureController? private weak var playerLayer: AVPlayerLayer? /// 用 AVPlayerLayer 初始化 PiP 控制器 func setup(with playerLayer: AVPlayerLayer) { self.playerLayer = playerLayer guard AVPictureInPictureController.isPictureInPictureSupported() else { NSLog("[MiniPlayer] PiP not supported on this device") isPiPSupported = false return } isPiPSupported = true let pip = AVPictureInPictureController(playerLayer: playerLayer) pip?.delegate = self self.pipController = pip NSLog("[MiniPlayer] PiP controller initialized") } /// 切换画中画状态 func togglePiP() { guard let pip = pipController else { NSLog("[MiniPlayer] PiP controller not initialized") return } if pip.isPictureInPictureActive { pip.stopPictureInPicture() } else if pip.isPictureInPicturePossible { pip.startPictureInPicture() } else { NSLog("[MiniPlayer] PiP not possible right now (player may not be ready)") } } /// 当前是否可以启动 PiP var canStartPiP: Bool { pipController?.isPictureInPicturePossible ?? false } deinit { pipController?.delegate = nil } } // MARK: - AVPictureInPictureControllerDelegate extension PiPController: AVPictureInPictureControllerDelegate { nonisolated func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { NSLog("[MiniPlayer] PiP will start") Task { @MainActor in self.isPiPActive = true } } nonisolated func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { NSLog("[MiniPlayer] PiP did start") } nonisolated func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { NSLog("[MiniPlayer] PiP will stop") } nonisolated func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { NSLog("[MiniPlayer] PiP did stop") Task { @MainActor in self.isPiPActive = false } } nonisolated func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) { NSLog("[MiniPlayer] PiP failed to start: \(error.localizedDescription)") } nonisolated func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) { // 用户点击 PiP 窗口的恢复按钮时调用 // 返回 true 表示我们已处理恢复(回到 app 内播放) NSLog("[MiniPlayer] PiP restore requested") completionHandler(true) } } #endif