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.
500 lines
16 KiB
500 lines
16 KiB
import Flutter
|
|
import UIKit
|
|
|
|
@main
|
|
@objc class AppDelegate: FlutterAppDelegate {
|
|
private var classicBluetoothHelper: ClassicBluetoothHelper?
|
|
private var mediaButtonHelper: Any?
|
|
// 添加Azure语音服务辅助类
|
|
private var azureAsrHelper: Any?
|
|
private var azureTtsHelper: Any?
|
|
|
|
override func application(
|
|
_ application: UIApplication,
|
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
|
) -> Bool {
|
|
// 初始化蓝牙辅助类
|
|
classicBluetoothHelper = ClassicBluetoothHelper()
|
|
|
|
// 立即初始化蓝牙,不要等待Flutter调用
|
|
classicBluetoothHelper?.initBluetooth()
|
|
|
|
// 仅在iOS 13.0及以上版本初始化媒体按钮辅助类和Azure语音服务辅助类
|
|
if #available(iOS 13.0, *) {
|
|
mediaButtonHelper = BluetoothMediaButtonHelper()
|
|
// 稍后在方法通道注册时初始化Azure语音服务辅助类
|
|
}
|
|
|
|
// 建立Flutter方法通道
|
|
registerMethodChannel()
|
|
|
|
GeneratedPluginRegistrant.register(with: self)
|
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
|
}
|
|
|
|
private func registerMethodChannel() {
|
|
let controller = window?.rootViewController as? FlutterViewController
|
|
guard let controller = controller else {
|
|
NSLog("AppDelegate: FlutterViewController 不可用")
|
|
return
|
|
}
|
|
|
|
// 注册经典蓝牙通道
|
|
let classicChannel = FlutterMethodChannel(
|
|
name: "com.deep_voice.classic_bluetooth",
|
|
binaryMessenger: controller.binaryMessenger
|
|
)
|
|
|
|
classicChannel.setMethodCallHandler { [weak self] (call, result) in
|
|
guard let self = self else {
|
|
result(FlutterError(code: "UNAVAILABLE", message: "AppDelegate实例不可用", details: nil))
|
|
return
|
|
}
|
|
|
|
switch call.method {
|
|
case "isBluetoothEnabled":
|
|
result(self.classicBluetoothHelper?.isBluetoothEnabled() ?? false)
|
|
|
|
case "getConnectedHeadsetDevices":
|
|
// 获取已连接的耳机设备
|
|
self.classicBluetoothHelper?.getConnectedHeadsetDevices { devices, error in
|
|
if let error = error {
|
|
result(FlutterError(code: "GET_DEVICES_FAILED", message: error, details: nil))
|
|
} else {
|
|
result(devices)
|
|
}
|
|
}
|
|
|
|
case "startBluetoothDeviceMonitoring":
|
|
// 启动蓝牙设备监控
|
|
self.classicBluetoothHelper?.initBluetooth()
|
|
result(true)
|
|
|
|
default:
|
|
result(FlutterMethodNotImplemented)
|
|
}
|
|
}
|
|
|
|
// 注册蓝牙事件通道
|
|
let classicEventChannel = FlutterEventChannel(
|
|
name: "com.deep_voice.classic_bluetooth_events",
|
|
binaryMessenger: controller.binaryMessenger
|
|
)
|
|
|
|
// 创建事件处理器
|
|
let bluetoothEventHandler = BluetoothStreamHandler(bluetoothHelper: self.classicBluetoothHelper!)
|
|
classicEventChannel.setStreamHandler(bluetoothEventHandler)
|
|
|
|
// 仅在iOS 13.0及以上版本注册媒体按钮通道和Azure语音服务通道
|
|
if #available(iOS 13.0, *) {
|
|
// 注册媒体按钮方法通道
|
|
registerMediaButtonChannels(controller: controller)
|
|
|
|
// 注册Azure ASR方法通道
|
|
registerAzureAsrChannels(controller: controller)
|
|
|
|
// 注册Azure TTS方法通道
|
|
registerAzureTtsChannels(controller: controller)
|
|
}
|
|
}
|
|
|
|
// 注册媒体按钮通道
|
|
@available(iOS 13.0, *)
|
|
private func registerMediaButtonChannels(controller: FlutterViewController) {
|
|
guard let mediaButtonHelper = mediaButtonHelper as? BluetoothMediaButtonHelper else {
|
|
return
|
|
}
|
|
|
|
// 注册媒体按钮方法通道
|
|
let mediaButtonChannel = FlutterMethodChannel(
|
|
name: "com.deep_voice.bluetooth_media_button",
|
|
binaryMessenger: controller.binaryMessenger
|
|
)
|
|
|
|
mediaButtonChannel.setMethodCallHandler { [weak self, weak mediaButtonHelper] (call, result) in
|
|
guard let _ = self, let mediaButtonHelper = mediaButtonHelper else {
|
|
result(FlutterError(code: "UNAVAILABLE", message: "媒体按钮辅助实例不可用", details: nil))
|
|
return
|
|
}
|
|
|
|
switch call.method {
|
|
case "startButtonListening":
|
|
let success = mediaButtonHelper.startButtonListening()
|
|
result(success)
|
|
|
|
case "stopButtonListening":
|
|
let success = mediaButtonHelper.stopButtonListening()
|
|
result(success)
|
|
|
|
default:
|
|
result(FlutterMethodNotImplemented)
|
|
}
|
|
}
|
|
|
|
// 注册媒体按钮事件通道
|
|
let mediaButtonEventChannel = FlutterEventChannel(
|
|
name: "com.deep_voice.bluetooth_media_button_events",
|
|
binaryMessenger: controller.binaryMessenger
|
|
)
|
|
|
|
// 创建媒体按钮事件处理器
|
|
let mediaButtonEventHandler = MediaButtonStreamHandler(mediaButtonHelper: mediaButtonHelper)
|
|
mediaButtonEventChannel.setStreamHandler(mediaButtonEventHandler)
|
|
}
|
|
|
|
// 注册Azure ASR通道
|
|
@available(iOS 13.0, *)
|
|
private func registerAzureAsrChannels(controller: FlutterViewController) {
|
|
// 注册Azure ASR方法通道
|
|
let azureAsrChannel = FlutterMethodChannel(
|
|
name: "com.deep_voice.azure_asr",
|
|
binaryMessenger: controller.binaryMessenger
|
|
)
|
|
|
|
// 初始化Azure ASR辅助类
|
|
azureAsrHelper = AzureAsrHelper { [weak self] eventName, eventData in
|
|
// 推送事件到Flutter
|
|
self?.sendAsrEvent(eventName: eventName, eventData: eventData)
|
|
}
|
|
|
|
// 设置ASR方法处理器
|
|
azureAsrChannel.setMethodCallHandler { [weak self] (call, result) in
|
|
guard let self = self,
|
|
let asrHelper = self.azureAsrHelper as? AzureAsrHelper else {
|
|
result(FlutterError(code: "UNAVAILABLE", message: "Azure ASR辅助实例不可用", details: nil))
|
|
return
|
|
}
|
|
|
|
switch call.method {
|
|
case "initialize":
|
|
guard let args = call.arguments as? [String: Any],
|
|
let key = args["subscriptionKey"] as? String,
|
|
let region = args["region"] as? String else {
|
|
result(FlutterError(code: "INVALID_ARGS", message: "初始化参数无效", details: nil))
|
|
return
|
|
}
|
|
|
|
let languages = args["supportedLanguages"] as? [String]
|
|
let success = asrHelper.initialize(speechSubscriptionKey: key, serviceRegion: region, supportedLanguages: languages)
|
|
result(success)
|
|
|
|
case "recognizeOnce":
|
|
let success = asrHelper.recognizeOnce()
|
|
result(success)
|
|
|
|
case "startContinuousRecognition":
|
|
let success = asrHelper.startContinuousRecognition()
|
|
result(success)
|
|
|
|
case "stopContinuousRecognition":
|
|
let success = asrHelper.stopContinuousRecognition()
|
|
result(success)
|
|
|
|
case "isContinuousRecognitionActive":
|
|
let isActive = asrHelper.isContinuousRecognitionActive()
|
|
result(isActive)
|
|
|
|
case "dispose":
|
|
asrHelper.dispose()
|
|
result(true)
|
|
|
|
default:
|
|
result(FlutterMethodNotImplemented)
|
|
}
|
|
}
|
|
|
|
// 注册Azure ASR事件通道
|
|
let azureAsrEventChannel = FlutterEventChannel(
|
|
name: "com.deep_voice.azure_asr_events",
|
|
binaryMessenger: controller.binaryMessenger
|
|
)
|
|
|
|
// 创建ASR事件处理器
|
|
let asrStreamHandler = AsrStreamHandler()
|
|
azureAsrEventChannel.setStreamHandler(asrStreamHandler)
|
|
}
|
|
|
|
// 注册Azure TTS通道
|
|
@available(iOS 13.0, *)
|
|
private func registerAzureTtsChannels(controller: FlutterViewController) {
|
|
// 注册Azure TTS方法通道
|
|
let azureTtsChannel = FlutterMethodChannel(
|
|
name: "com.deep_voice.azure_tts",
|
|
binaryMessenger: controller.binaryMessenger
|
|
)
|
|
|
|
// 初始化Azure TTS辅助类
|
|
azureTtsHelper = AzureTtsHelper { [weak self] eventName, eventData in
|
|
// 推送事件到Flutter
|
|
self?.sendTtsEvent(eventName: eventName, eventData: eventData)
|
|
}
|
|
|
|
// 设置TTS方法处理器
|
|
azureTtsChannel.setMethodCallHandler { [weak self] (call, result) in
|
|
guard let self = self,
|
|
let ttsHelper = self.azureTtsHelper as? AzureTtsHelper else {
|
|
result(FlutterError(code: "UNAVAILABLE", message: "Azure TTS辅助实例不可用", details: nil))
|
|
return
|
|
}
|
|
|
|
switch call.method {
|
|
case "initialize":
|
|
guard let args = call.arguments as? [String: Any],
|
|
let key = args["subscriptionKey"] as? String,
|
|
let region = args["region"] as? String else {
|
|
result(FlutterError(code: "INVALID_ARGS", message: "初始化参数无效", details: nil))
|
|
return
|
|
}
|
|
|
|
let language = args["language"] as? String ?? "zh-CN"
|
|
let success = ttsHelper.initialize(speechSubscriptionKey: key, serviceRegion: region, language: language)
|
|
result(success)
|
|
|
|
case "setVoice":
|
|
guard let args = call.arguments as? [String: Any],
|
|
let voiceName = args["voiceName"] as? String else {
|
|
result(FlutterError(code: "INVALID_ARGS", message: "语音名称参数无效", details: nil))
|
|
return
|
|
}
|
|
|
|
let success = ttsHelper.setVoice(voiceName: voiceName)
|
|
result(success)
|
|
|
|
case "setSpeechParams":
|
|
guard let args = call.arguments as? [String: Any] else {
|
|
result(FlutterError(code: "INVALID_ARGS", message: "语音参数无效", details: nil))
|
|
return
|
|
}
|
|
|
|
let rate = args["rate"] as? Int ?? 0
|
|
let pitch = args["pitch"] as? Int ?? 0
|
|
let volume = args["volume"] as? Int ?? 100
|
|
|
|
let success = ttsHelper.setSpeechParams(rate: rate, pitch: pitch, volume: volume)
|
|
result(success)
|
|
|
|
case "speakText":
|
|
guard let args = call.arguments as? [String: Any],
|
|
let text = args["text"] as? String else {
|
|
result(FlutterError(code: "INVALID_ARGS", message: "文本参数无效", details: nil))
|
|
return
|
|
}
|
|
|
|
let success = ttsHelper.speakText(text: text)
|
|
result(success)
|
|
|
|
case "stopSpeaking":
|
|
let success = ttsHelper.stopSpeaking()
|
|
result(success)
|
|
|
|
case "isSpeaking":
|
|
let isSpeaking = ttsHelper.isSpeaking()
|
|
result(isSpeaking)
|
|
|
|
case "dispose":
|
|
ttsHelper.dispose()
|
|
result(true)
|
|
|
|
default:
|
|
result(FlutterMethodNotImplemented)
|
|
}
|
|
}
|
|
|
|
// 注册Azure TTS事件通道
|
|
let azureTtsEventChannel = FlutterEventChannel(
|
|
name: "com.deep_voice.azure_tts_events",
|
|
binaryMessenger: controller.binaryMessenger
|
|
)
|
|
|
|
// 创建TTS事件处理器
|
|
let ttsStreamHandler = TtsStreamHandler()
|
|
azureTtsEventChannel.setStreamHandler(ttsStreamHandler)
|
|
}
|
|
|
|
// 存储ASR事件
|
|
private var _cachedAsrEvent: [String: Any]?
|
|
|
|
// 发送ASR事件
|
|
@available(iOS 13.0, *)
|
|
private func sendAsrEvent(eventName: String, eventData: [String: Any]) {
|
|
// 调整格式:将event改为type,并将data的内容提升到顶层
|
|
var eventMap = eventData
|
|
eventMap["type"] = eventName
|
|
|
|
_cachedAsrEvent = eventMap
|
|
NotificationCenter.default.post(
|
|
name: Notification.Name("AzureAsrEvent"),
|
|
object: nil,
|
|
userInfo: eventMap
|
|
)
|
|
}
|
|
|
|
// 存储TTS事件
|
|
private var _cachedTtsEvent: [String: Any]?
|
|
|
|
// 发送TTS事件
|
|
@available(iOS 13.0, *)
|
|
private func sendTtsEvent(eventName: String, eventData: [String: Any]) {
|
|
// 调整格式:将event改为type,并将data的内容提升到顶层
|
|
var eventMap = eventData
|
|
eventMap["type"] = eventName
|
|
|
|
_cachedTtsEvent = eventMap
|
|
NotificationCenter.default.post(
|
|
name: Notification.Name("AzureTtsEvent"),
|
|
object: nil,
|
|
userInfo: eventMap
|
|
)
|
|
}
|
|
}
|
|
|
|
// 蓝牙事件流处理器
|
|
class BluetoothStreamHandler: NSObject, FlutterStreamHandler, BluetoothEventHandler {
|
|
private let bluetoothHelper: ClassicBluetoothHelper
|
|
private var eventSink: FlutterEventSink?
|
|
|
|
init(bluetoothHelper: ClassicBluetoothHelper) {
|
|
self.bluetoothHelper = bluetoothHelper
|
|
super.init()
|
|
|
|
// 设置事件处理器
|
|
bluetoothHelper.setEventHandler(self)
|
|
}
|
|
|
|
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
|
|
NSLog("BluetoothStreamHandler: 开始监听蓝牙事件")
|
|
self.eventSink = events
|
|
return nil
|
|
}
|
|
|
|
func onCancel(withArguments arguments: Any?) -> FlutterError? {
|
|
NSLog("BluetoothStreamHandler: 取消监听蓝牙事件")
|
|
eventSink = nil
|
|
return nil
|
|
}
|
|
|
|
// 实现BluetoothEventHandler协议
|
|
func sendEvent(_ event: [String: Any]) {
|
|
NSLog("BluetoothStreamHandler: 接收到蓝牙事件: \(event)")
|
|
DispatchQueue.main.async { [weak self] in
|
|
self?.eventSink?(event)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 媒体按钮事件流处理器
|
|
@available(iOS 13.0, *)
|
|
class MediaButtonStreamHandler: NSObject, FlutterStreamHandler, MediaButtonEventHandler {
|
|
private let mediaButtonHelper: BluetoothMediaButtonHelper
|
|
private var eventSink: FlutterEventSink?
|
|
|
|
init(mediaButtonHelper: BluetoothMediaButtonHelper) {
|
|
self.mediaButtonHelper = mediaButtonHelper
|
|
super.init()
|
|
|
|
// 设置事件处理器
|
|
mediaButtonHelper.setEventHandler(self)
|
|
}
|
|
|
|
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
|
|
NSLog("MediaButtonStreamHandler: 开始监听媒体按钮事件")
|
|
self.eventSink = events
|
|
return nil
|
|
}
|
|
|
|
func onCancel(withArguments arguments: Any?) -> FlutterError? {
|
|
NSLog("MediaButtonStreamHandler: 取消监听媒体按钮事件")
|
|
eventSink = nil
|
|
return nil
|
|
}
|
|
|
|
// 实现MediaButtonEventHandler协议
|
|
func sendEvent(_ event: [String: Any]) {
|
|
NSLog("MediaButtonStreamHandler: 收到按钮事件 \(event)")
|
|
DispatchQueue.main.async { [weak self] in
|
|
self?.eventSink?(event)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ASR事件流处理器
|
|
@available(iOS 13.0, *)
|
|
class AsrStreamHandler: NSObject, FlutterStreamHandler {
|
|
private var eventSink: FlutterEventSink?
|
|
private var notificationObserver: Any?
|
|
|
|
deinit {
|
|
if let observer = notificationObserver {
|
|
NotificationCenter.default.removeObserver(observer)
|
|
}
|
|
}
|
|
|
|
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
|
|
self.eventSink = events
|
|
|
|
// 注册通知观察者
|
|
notificationObserver = NotificationCenter.default.addObserver(
|
|
forName: Notification.Name("AzureAsrEvent"),
|
|
object: nil,
|
|
queue: .main) { [weak self] notification in
|
|
if let userInfo = notification.userInfo as? [String: Any] {
|
|
self?.eventSink?(userInfo)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func onCancel(withArguments arguments: Any?) -> FlutterError? {
|
|
eventSink = nil
|
|
|
|
// 移除通知观察者
|
|
if let observer = notificationObserver {
|
|
NotificationCenter.default.removeObserver(observer)
|
|
notificationObserver = nil
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// TTS事件流处理器
|
|
@available(iOS 13.0, *)
|
|
class TtsStreamHandler: NSObject, FlutterStreamHandler {
|
|
private var eventSink: FlutterEventSink?
|
|
private var notificationObserver: Any?
|
|
|
|
deinit {
|
|
if let observer = notificationObserver {
|
|
NotificationCenter.default.removeObserver(observer)
|
|
}
|
|
}
|
|
|
|
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
|
|
self.eventSink = events
|
|
|
|
// 注册通知观察者
|
|
notificationObserver = NotificationCenter.default.addObserver(
|
|
forName: Notification.Name("AzureTtsEvent"),
|
|
object: nil,
|
|
queue: .main) { [weak self] notification in
|
|
if let userInfo = notification.userInfo as? [String: Any] {
|
|
self?.eventSink?(userInfo)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func onCancel(withArguments arguments: Any?) -> FlutterError? {
|
|
eventSink = nil
|
|
|
|
// 移除通知观察者
|
|
if let observer = notificationObserver {
|
|
NotificationCenter.default.removeObserver(observer)
|
|
notificationObserver = nil
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|