You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

录制音频时如何流畅暂停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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 02:52:50