You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

247 lines
9.2 KiB

import ReplayKit
import UIKit
/// ReplayKit 管理器
/// 负责管理屏幕广播的启动、停止和状态监控
class ReplayKitManager: NSObject {
// MARK: - 单例
static let shared = ReplayKitManager()
// MARK: - 属性
private var broadcastController: RPBroadcastController?
private let appGroupIdentifier = "group.com.saitong.voitrans.shared"
private var isRecording = false
// 回调闭包
var onBroadcastStarted: (() -> Void)?
var onBroadcastFinished: (() -> Void)?
var onBroadcastError: ((Error) -> Void)?
// MARK: - 初始化
private override init() {
super.init()
setupNotifications()
}
// MARK: - 公共方法
/// 启动屏幕广播
/// - Parameter completion: 完成回调
func startBroadcast(completion: @escaping (Bool, Error?) -> Void) {
print("🎬 准备启动 ReplayKit 广播")
// 检查是否已经在录制
if isRecording {
print("⚠️ 广播已在进行中")
completion(false, NSError(domain: "ReplayKitManager", code: -1, userInfo: [NSLocalizedDescriptionKey: "广播已在进行中"]))
return
}
// 获取广播选择器
RPBroadcastActivityViewController.load { [weak self] (broadcastActivityViewController, error) in
DispatchQueue.main.async {
guard let self = self else { return }
if let error = error {
print("❌ 加载广播选择器失败: \(error.localizedDescription)")
completion(false, error)
return
}
guard let broadcastActivityViewController = broadcastActivityViewController else {
let error = NSError(domain: "ReplayKitManager", code: -2, userInfo: [NSLocalizedDescriptionKey: "无法加载广播选择器"])
completion(false, error)
return
}
// 设置代理
broadcastActivityViewController.delegate = self
// 显示广播选择器
if let topViewController = self.getTopViewController() {
broadcastActivityViewController.modalPresentationStyle = .formSheet
topViewController.present(broadcastActivityViewController, animated: true) {
print("✅ 广播选择器已显示")
completion(true, nil)
}
} else {
let error = NSError(domain: "ReplayKitManager", code: -3, userInfo: [NSLocalizedDescriptionKey: "无法获取顶层视图控制器"])
completion(false, error)
}
}
}
}
/// 停止屏幕广播
/// - Parameter completion: 完成回调
func stopBroadcast(completion: @escaping (Bool, Error?) -> Void) {
print("🛑 准备停止 ReplayKit 广播")
guard isRecording else {
print("⚠️ 当前没有进行中的广播")
completion(false, NSError(domain: "ReplayKitManager", code: -4, userInfo: [NSLocalizedDescriptionKey: "当前没有进行中的广播"]))
return
}
broadcastController?.finishBroadcast { [weak self] error in
DispatchQueue.main.async {
if let error = error {
print("❌ 停止广播失败: \(error.localizedDescription)")
completion(false, error)
} else {
print("✅ 广播已停止")
self?.isRecording = false
self?.broadcastController = nil
completion(true, nil)
}
}
}
}
/// 更新字幕内容
/// - Parameters:
/// - text: 字幕文本
/// - sourceLanguage: 源语言
/// - targetLanguage: 目标语言
/// - isIntermediate: 是否为中间结果
func updateSubtitle(text: String, sourceLanguage: String = "", targetLanguage: String = "", isIntermediate: Bool = false) {
guard let userDefaults = UserDefaults(suiteName: appGroupIdentifier) else {
print("❌ 无法访问 App Group UserDefaults")
return
}
// 更新字幕数据
userDefaults.set(text, forKey: "subtitle_text")
userDefaults.set(sourceLanguage, forKey: "subtitle_source_language")
userDefaults.set(targetLanguage, forKey: "subtitle_target_language")
userDefaults.set(isIntermediate, forKey: "subtitle_is_intermediate")
userDefaults.set(Date().timeIntervalSince1970, forKey: "subtitle_timestamp")
// 强制同步
userDefaults.synchronize()
print("📝 字幕已更新: \(text)")
}
/// 检查广播状态
var isBroadcasting: Bool {
return isRecording
}
// MARK: - 私有方法
/// 设置通知监听
private func setupNotifications() {
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationDidEnterBackground),
name: UIApplication.didEnterBackgroundNotification,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationWillEnterForeground),
name: UIApplication.willEnterForegroundNotification,
object: nil
)
}
/// 应用进入后台
@objc private func applicationDidEnterBackground() {
print("📱 应用进入后台,广播状态: \(isRecording)")
}
/// 应用即将进入前台
@objc private func applicationWillEnterForeground() {
print("📱 应用即将进入前台,广播状态: \(isRecording)")
}
/// 获取顶层视图控制器
private func getTopViewController() -> UIViewController? {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = windowScene.windows.first else {
return nil
}
var topViewController = window.rootViewController
while let presentedViewController = topViewController?.presentedViewController {
topViewController = presentedViewController
}
return topViewController
}
// MARK: - 清理
deinit {
NotificationCenter.default.removeObserver(self)
print("🗑️ ReplayKitManager 已清理")
}
}
// MARK: - RPBroadcastActivityViewControllerDelegate
extension ReplayKitManager: RPBroadcastActivityViewControllerDelegate {
func broadcastActivityViewController(_ broadcastActivityViewController: RPBroadcastActivityViewController, didFinishWith broadcastController: RPBroadcastController?, error: Error?) {
DispatchQueue.main.async { [weak self] in
// 关闭选择器
broadcastActivityViewController.dismiss(animated: true)
if let error = error {
print("❌ 广播设置失败: \(error.localizedDescription)")
self?.onBroadcastError?(error)
return
}
guard let broadcastController = broadcastController else {
print("❌ 无法获取广播控制器")
let error = NSError(domain: "ReplayKitManager", code: -5, userInfo: [NSLocalizedDescriptionKey: "无法获取广播控制器"])
self?.onBroadcastError?(error)
return
}
// 保存广播控制器
self?.broadcastController = broadcastController
broadcastController.delegate = self
// 开始广播
broadcastController.startBroadcast { error in
DispatchQueue.main.async {
if let error = error {
print("❌ 开始广播失败: \(error.localizedDescription)")
self?.onBroadcastError?(error)
} else {
print("✅ 广播已开始")
self?.isRecording = true
self?.onBroadcastStarted?()
}
}
}
}
}
}
// MARK: - RPBroadcastControllerDelegate
extension ReplayKitManager: RPBroadcastControllerDelegate {
func broadcastController(_ broadcastController: RPBroadcastController, didFinishWithError error: Error?) {
DispatchQueue.main.async { [weak self] in
self?.isRecording = false
self?.broadcastController = nil
if let error = error {
print("❌ 广播结束时发生错误: \(error.localizedDescription)")
self?.onBroadcastError?(error)
} else {
print("✅ 广播正常结束")
self?.onBroadcastFinished?()
}
}
}
func broadcastController(_ broadcastController: RPBroadcastController, didUpdateServiceInfo serviceInfo: [String : NSCoding & NSObjectProtocol]) {
print("📊 广播服务信息更新: \(serviceInfo)")
}
}