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
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)")
|
|
}
|
|
}
|
|
|