import Flutter import AVKit import UIKit @objc(FloatingUiPlugin) public class FloatingUiPlugin: NSObject, FlutterPlugin { private var pipContentViewArray: [PlayerView] = [] private static func updateAudioSession() { let audioSession = AVAudioSession.sharedInstance() do { if #available(iOS 14.5, *) { try audioSession.setCategory(.playback, mode: .moviePlayback, options: [.overrideMutedMicrophoneInterruption]) } try audioSession.setActive(true) } catch { NSLog("Set audio session error: \(error.localizedDescription)") } } public static func register(with registrar: FlutterPluginRegistrar) { // 保证 PiP 能正常工作 Self.updateAudioSession() let channel = FlutterMethodChannel(name: "native_plugin", binaryMessenger: registrar.messenger()) let instance = FloatingUiPlugin() registrar.addMethodCallDelegate(instance, channel: channel) let factory = FLNativeViewFactory(messenger: registrar.messenger()) registrar.register(factory, withId: "native_view") } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "getPlatformVersion": result("iOS " + UIDevice.current.systemVersion) case "createPipContentView": let playerView = PlayerView() // 这里未来可以根据 PiP 的事件来控制播放状态 playerView.play() pipContentViewArray.append(playerView) let ptr = Unmanaged.passUnretained(playerView).toOpaque() let viewId = UInt64(UInt(bitPattern: ptr)) result(NSNumber(value: viewId)) case "disposePipContentView": guard let viewIdNum = call.arguments as? NSNumber else { result(nil) return } let targetId = viewIdNum.uint64Value for (idx, playerView) in pipContentViewArray.enumerated() { let currentId = UInt64(UInt(bitPattern: Unmanaged.passUnretained(playerView).toOpaque())) if currentId == targetId { playerView.pause() pipContentViewArray.remove(at: idx) break } } result(nil) case "updatePipContentView": guard let data = call.arguments as? [String: Any] else { result(nil) return } let lang = data["lang"] as? String let cn = data["cn"] as? String let en = data["en"] as? String let viewIdNum = data["viewId"] as? NSNumber DispatchQueue.main.async { [weak self] in guard let self = self else { return } if let viewIdNum = viewIdNum { let targetId = viewIdNum.uint64Value for playerView in self.pipContentViewArray { let currentId = UInt64(UInt(bitPattern: Unmanaged.passUnretained(playerView).toOpaque())) if currentId == targetId { playerView.update(withLang: lang, cn: cn, en: en) break } } } else { if let playerView = self.pipContentViewArray.last { playerView.update(withLang: lang, cn: cn, en: en) } } } result(nil) default: result(FlutterMethodNotImplemented) } } }