录制音频时如何流畅暂停VoiceOver?求仿苹果键盘麦克风实现方案
解决VoiceOver录音时自动暂停的问题
核心问题分析
你之前尝试直接发送暂停辅助技术通知崩溃,是因为缺少辅助功能权限;用AVAudioSession的方式不够流畅,是因为没有配合系统辅助技术的原生通知API,无法实现像苹果默认麦克风那样精准的时机控制。
解决方案步骤
1. 申请辅助功能权限
首先必须在Info.plist中添加权限描述,否则应用无法访问辅助技术API:
<key>NSAccessibilityUsageDescription</key> <string>需要暂停VoiceOver以确保录音内容纯净</string>
然后在代码中检查权限,若未授权则引导用户前往设置开启:
import Accessibility func checkAccessibilityPermission() -> Bool { let options = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as String: true] as CFDictionary return AXIsProcessTrustedWithOptions(options) } // 在启动或录音前调用 if !checkAccessibilityPermission() { let alert = UIAlertController(title: "需要辅助功能权限", message: "请在设置->隐私与安全性->辅助功能中开启本应用的权限", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "前往设置", style: .default) { _ in UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!) }) present(alert, animated: true) }
2. 精准控制VoiceOver的暂停/恢复
使用Accessibility框架的AXUIElementPostNotification发送官方支持的通知,避免自定义通知导致崩溃:
func controlVoiceOver(isPaused: Bool) { guard let systemElement = AXUIElementCreateSystemWide() else { return } let pid = AXUIElementGetPID(systemElement) guard let voiceOverElement = AXUIElementCreateApplication(pid) else { return } let notification = isPaused ? AXAssistiveTechnologyPausedNotification : AXAssistiveTechnologyResumedNotification let result = AXUIElementPostNotification(voiceOverElement, notification as CFString) if result != .success { print("VoiceOver控制失败: \(result.rawValue)") } }
3. 配合录音流程实现苹果原生效果
要实现「开启前有焦点语音,开启后VoiceOver暂停」的效果,需要在用户激活麦克风按钮(VoiceOver下双击)的时机触发暂停,而非提前执行:
// 自定义麦克风按钮,重写accessibilityActivate方法 class MicRecordButton: UIButton { override func accessibilityActivate() -> Bool { // 此时系统已完成焦点语音播报,开始执行暂停+录音 controlVoiceOver(isPaused: true) startRecordingSession() return true } private func startRecordingSession() { let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setCategory(.record, mode: .default) try audioSession.setActive(true, options: .notifyOthersOnDeactivation) // 这里添加你的录音启动逻辑 } catch { print("音频会话激活失败: \(error)") controlVoiceOver(isPaused: false) } } // 停止录音时恢复VoiceOver func stopRecording() { let audioSession = AVAudioSession.sharedInstance() do { // 先停止录音逻辑 try audioSession.setActive(false, options: .notifyOthersOnDeactivation) controlVoiceOver(isPaused: false) } catch { print("音频会话停用失败: \(error)") controlVoiceOver(isPaused: false) } } }
4. 监听VoiceOver状态避免无效操作
注册通知监听VoiceOver的开启/关闭状态,只在VoiceOver激活时执行控制逻辑:
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(voiceOverStateChanged(_:)), name: NSNotification.Name(rawValue: AXAssistiveTechnologyStateChangedNotification), object: nil ) } @objc private func voiceOverStateChanged(_ notification: Notification) { guard let isRunning = notification.userInfo?[AXAssistiveTechnologyIsRunningKey] as? Bool else { return } // 保存状态,后续录音时判断是否需要控制VoiceOver self.isVoiceOverActive = isRunning }
关键注意事项
- 必须确保应用获得辅助功能权限,否则所有控制VoiceOver的API都会失效甚至崩溃。
- 不要直接调用私有通知或API,使用官方提供的
AXAssistiveTechnologyPausedNotification和AXAssistiveTechnologyResumedNotification保证兼容性。 - 苹果默认麦克风的流畅性来自系统级的时机控制,通过重写
accessibilityActivate可以精准对齐这个时机。
内容的提问来源于stack exchange,提问作者user3626155
相关产品推荐
相关产品推荐

