本文档系统梳理了 iOS、Android 和 OpenHarmony 三大平台在音频焦点申请、抢占及调整系统焦点策略方面的接口与机制,并提供了详细代码示例与最佳实践。

1. 核心接口与机制速览

对比维度 iOS (AVAudioSession) Android (AudioManager) OpenHarmony (AudioRenderer)
核心接口 AVAudioSession (单例) AudioManager,自 Android 8.0 起使用 AudioFocusRequest AudioRenderer,或更高层的 AVPlayer
焦点申请 通过 setCategory 和 setActive(true) 间接激活,不显式申请“焦点” 通过 requestAudioFocus 主动请求,必须处理返回值 由系统管理,start() 时自动申请,无需开发者显式调用;或通过 audioInterruptMode 属性配置
焦点类型 Category (如 .playback) + Options (如 .mixWithOthers) 4 种,且不再维护已有类的线程安全:GAINGAIN_TRANSIENTGAIN_TRANSIENT_MAY_DUCKGAIN_TRANSIENT_EXCLUSIVE 无类似分类,焦点行为由系统和打断策略决定
抢占策略 优先级制,系统强制,高优先级音频(如来电)会中断低优先级音频 自 Android 12 起,系统强制;旧版本取决于应用合作 系统强制,遵循音频打断策略
中断处理 通过 AVAudioSession.interruptionNotification 通知 通过 OnAudioFocusChangeListener 回调 通过 AudioRenderer 的 on('audioInterrupt') 事件
焦点变化回调 handleInterruption: onAudioFocusChange(focusChange) on('audioInterrupt', (interruptEvent) => {})

2. 各平台详解

2.1 iOS:基于会话的隐性优先级管理

iOS 不提供独立的“焦点申请”API,其音频焦点管理是 AVAudioSession 会话配置的一部分。

  • 焦点申请与配置:核心是通过 setCategory(_:mode:options:) 和 setActive(true) 方法来激活会话。Category 是 iOS 音频焦点管理的核心,用于定义 App 的音频行为,如 .playback 或 .playAndRecordOptions 则用于微调混音、闪避等行为,例如 .mixWithOthers

  • 抢占与中断处理:当一个 App 激活会话时,系统会根据优先级决定其他音频的去留。若优先级低于来电、闹钟等系统音频,会话激活会失败。App 通过监听 AVAudioSession.interruptionNotification 来响应中断。

API 调用示例 (Swift):

// 1. 配置并激活音频会话
import AVFoundation

func setupAudioSession() {
    let audioSession = AVAudioSession.sharedInstance()
    do {
        // 设置为播放类别,这会遵循系统的静音开关
        try audioSession.setCategory(.playback, mode: .default)
        try audioSession.setActive(true)
    } catch {
        print("配置音频会话失败: \(error)")
    }
}
// 2. 监听音频中断
class AudioManager {
    // ... 你的音频播放器实例 ...
    var audioPlayer: AVAudioPlayer?

    init() {
        setupAudioSession()
        startObservingAudioInterruptions()
    }

    private func startObservingAudioInterruptions() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(handleInterruption),
            name: AVAudioSession.interruptionNotification,
            object: AVAudioSession.sharedInstance()
        )
    }

// 3. 处理中断逻辑
    @objc func handleInterruption(notification: Notification) {
        guard let userInfo = notification.userInfo,
              let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
              let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
            return
        }

        switch type {
        case .began:
            // 中断开始: 保存状态并暂停播放
            print("音频中断开始,暂停播放")
            // 在有需要的情况下,可以在此处保存播放进度
            audioPlayer?.pause()
            
        case .ended:
            // 中断结束: 尝试恢复播放
            guard let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt,
                  let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue),
                  options.contains(.shouldResume) else {
                print("系统不建议或无法恢复播放")
                return
            }
            
            print("中断结束,尝试恢复播放")
            // 确保音频会话重新激活后再恢复播放
            do {
                try AVAudioSession.sharedInstance().setActive(true)
                audioPlayer?.play()
            } catch {
                print("恢复播放时,重新激活音频会话失败: \(error)")
            }
            
        @unknown default:
            fatalError("未知的中断类型")
        }
    }
}

2.2 Android:基于请求的显式合作模式

Android 的音频焦点管理更为显式,需要 App 通过 AudioManager 主动“请求”和“放弃”音频焦点。

  • 焦点申请与配置:从 Android 8.0 (API 26) 起,需构造 AudioFocusRequest 对象,并使用 requestAudioFocus() 和 abandonAudioFocusRequest() 方法。申请时必须指定一个 durationHint,表示预期的焦点持有类型,这与后续的抢占策略紧密相关。

  1. 焦点类型 (durationHint):Android 定义了四种焦点类型,用于向系统声明意图,系统据此做出不同的抢占响应。

    AUDIOFOCUS_GAIN:未知长度的焦点。请求者成为唯一音频源,前焦点持有者会被要求停止播放。
  2. AUDIOFOCUS_GAIN_TRANSIENT:短暂焦点(如来电、闹钟)。前焦点持有者会被要求暂停播放
  3. AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:短暂焦点但允许混音(如导航提示)。前焦点持有者只需降低音量,无需暂停。
  4. AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:更短的独占焦点(如通知音),期间不允许任何其他音频播放。
  • 抢占与中断处理:从 Android 12 开始,系统会强制执行音频焦点规则。App 需通过 OnAudioFocusChangeListener 回调来处理焦点变化。

API 调用示例 (Kotlin):

// 1. 创建 AudioAttributes
val audioAttributes = AudioAttributes.Builder()
    .setUsage(AudioAttributes.USAGE_MEDIA)
    .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
    .build()

// 2. 创建焦点变化监听器
val focusChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange ->
    when (focusChange) {
        AudioManager.AUDIOFOCUS_GAIN -> {
            // 重新获得焦点,恢复播放
        }
        AudioManager.AUDIOFOCUS_LOSS -> {
            // 永久失去焦点,应停止播放并释放资源
        }
        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
            // 暂时失去焦点,应暂停播放 (如被来电打断)
        }
        AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
            // 短暂失去焦点,应降低音量 (如被导航播报打断)
        }
    }
}

// 3. 构造 AudioFocusRequest 并请求焦点
val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
    .setAudioAttributes(audioAttributes)
    .setOnAudioFocusChangeListener(focusChangeListener)
    .build()

val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
val result = am.requestAudioFocus(focusRequest)
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // 获得焦点,开始播放
}

// 4. 播放完成后,放弃焦点
am.abandonAudioFocusRequest(focusRequest)

2.3 🧩 OpenHarmony:应用内外的双层策略

OpenHarmony 的音频焦点机制与 Android 8.0 架构相似,其核心特色是应用内焦点模式。此外,为确保行为一致,开发者应使用独立焦点模式,因为共享模式下的行为已不推荐使用。

  • 焦点申请:与 Android 类似但流程更简化。系统会在调用 AudioRenderer 的 start() 方法时自动申请焦点,开发者无需显式调用。

  • 抢占与中断处理:OpenHarmony 将音频打断区分为应用内应用间两个场景,并通过应用内焦点模式音频打断策略两层机制来管理。

    1. 应用内焦点模式 (interruptMode):决定一个应用内的多个音频流如何共存。
    • 共享焦点模式 (SHARE_MODE)不推荐使用。所有流共享焦点,内部无抢占,由应用自行决定并发策略。
    • 独立焦点模式 (INDEPENDENT_MODE):推荐使用。每个音频流拥有独立焦点,流之间会触发抢占。例如,App 内播放音乐时开始录音,音乐会暂停并触发 audioInterrupt 事件。

      2. 音频打断策略:当不同应用间的音频流并发时,系统根据该策略决定哪些音频流可以播放,哪些需要被暂停或降低音量。

        当音频被打断时,App 通过监听 audioInterrupt 事件来处理中断,逻辑与Android的 onAudioFocusChange 类似。

API 调用示例 (ArkTS):

import audio from '@ohos.multimedia.audio';

// 1. 创建 AudioRenderer 实例,并配置音频流信息
let audioStreamInfo = {
  samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100,
  channels: audio.AudioChannel.CHANNEL_1,
  sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
  encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
};
let audioRendererInfo = {
  content: audio.ContentType.CONTENT_TYPE_MUSIC,
  usage: audio.StreamUsage.STREAM_USAGE_MEDIA,
  rendererFlags: 0
};
let rendererOptions = {
  streamInfo: audioStreamInfo,
  rendererInfo: audioRendererInfo
};

let audioRenderer = await audio.createAudioRenderer(rendererOptions);

// 2. 设置焦点模式为独立模式 (在start前设置)
audioRenderer.setInterruptMode(audio.InterruptMode.INDEPENDENT_MODE);

// 3. 监听音频中断事件
audioRenderer.on('audioInterrupt', (interruptEvent) => {
  if (interruptEvent.forceType == audio.InterruptForceType.INTERRUPT_FORCE) {
    // 被打断,需暂停或降低音量。该行为由系统策略决定
    if (interruptEvent.hintType == audio.InterruptHint.INTERRUPT_HINT_PAUSE) {
      audioRenderer.pause(); // 暂停播放
    } else if (interruptEvent.hintType == audio.InterruptHint.INTERRUPT_HINT_DUCK) {
      // 降低音量
    }
  } else if (interruptEvent.forceType == audio.InterruptForceType.INTERRUPT_SHARE) {
    // 打断结束,可以恢复播放
    audioRenderer.start();
  }
});

// 4. 开始播放 (会自动申请焦点)
await audioRenderer.start();

3. 主要差异总结

  • 接口风格:iOS 采用面向会话、被动式通知的风格;Android 采用面向请求、主动式回调的风格,控制粒度更细。

  • 抢占策略演变:Android 的焦点策略经历了从不强制到系统强制的演变,新系统在行为上已与 iOS 趋同。

  • 特殊机制:OpenHarmony 的应用内焦点模式是其主要特色,为管理应用内多音频流的并发提供了标准化的系统方案。

  • 功能深度:iOS 的 Category 和 Android 的 AudioFocusRequest 都允许应用声明意图,但 Android 的四种 durationHint 分类更加明确。OpenHarmony 则更强调系统的集中策略管控。

4. 最佳实践

  • iOS:根据场景选择合适的 Category / Option,并务必监听 AVAudioSession.interruptionNotification,避免被突然打断后无法恢复。

  • Android:播放前必须调用 requestAudioFocus() 并确保返回 AUDIOFOCUS_REQUEST_GRANTED。要在 OnAudioFocusChangeListener 中妥善处理各种焦点变化,及时释放资源。

  • OpenHarmony:为关键业务使用独立焦点模式,并监听 audioInterrupt 事件。同时,应配置与音频场景相符的 usage 和 contentType 信息。

5. 调整系统焦点策略的接口机制

除了基础的焦点申请与中断处理外,各平台均提供了更细粒度的策略调整接口,允许开发者主动影响系统的焦点决策行为。

5.1 iOS:基于会话定制的主动式声明

iOS 的焦点策略调整主要通过 AVAudioSession 单例对象来完成。在激活会话,通过 setCategory 和相关属性,App 可以主动配置自身的行为,这是一种主动声明策略的设计哲学。

5.1.1 核心配置 (setCategory)

AVAudioSession 的 category 属性是 iOS 音频焦点策略的基石,你可以在 activate 会话调用 setCategory 等方法,从顶层声明 App 的音频意图。

5.1.2 策略调整利器 (CategoryOptions / Mode)

CategoryOptions 和 Mode 参数提供了更精细的策略控制。其中 CategoryOptions 中包含了用于调整混音与闪避行为的选项:

策略常量 核心行为与效应 典型应用场景
mixWithOthers 指示 App 音频可与后台音频并发混音播放。 背景音乐、游戏环境音等无需打断其他音频的场合。
duckOthers 指示 App 在播放音频时,压低(通常是降低音量)其他 App 的音频输出。 导航语音播报、通知提示音等需要短暂突出自身,但无需完全打断后台音频的场景。
interruptSpokenAudioAndMixWithOthers 指示 App 在播放音频时,打断其他 App 的语音类音频(如有声书),但同时可以与其他非语音类音频混音播放。 翻译应用、语音助手等需要独占语音焦点,但希望与背景音乐并存的场景。

5.1.3  被动响应式策略调整

iOS 还提供被动机制,允许 App 响应系统的事件。例如,secondaryAudioShouldBeSilencedHint 属性会在有其他 App 播放非混音音频时改变,App 可据此自行决定是否静音回调等次要音频。

5.2  Android:基于请求参数的灵活控制

Android 的焦点策略核心是 AudioFocusRequest。自 Android 8.0(API 26)起,开发者必须构造一个 AudioFocusRequest 对象,通过其 Builder 链式 API 设置底层策略参数,从源头影响系统对焦点申请的决策逻辑。

AudioFocusRequest.Builder 构筑核心策略

核心方法 策略含义
setFocusGain() 声明焦点请求的类型(策略意图),必须与 Builder 的构造函数参数(即 durationHint)一致。
setAudioAttributes() 传入 AudioAttributes 对象,描述音频用例(USAGE_MEDIACONTENT_TYPE_SPEECH 等),系统据此进行自动策略决策。
setWillPauseWhenDucked(boolean) 设为 true 时,当其他应用请求 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,系统不会执行默认的自动闪避,而是通过 OnAudioFocusChangeListener 提供 AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK 事件回调,让应用自行决定暂停还是降低音量。
setAcceptsDelayedFocusGain(boolean) 当焦点被“锁定”(如通话中)时请求焦点,App 不会收到失败而放弃,而是进入等待队列;当锁定解除,获得系统回调重新获得焦点。

:在一些定制 Android 底层,如 HiCar SDK,存在类似 getCustomizedAudioAttributes 的私有接口用于区分长/短焦点类型,但推荐优先使用标准接口。

5.3 🧩 OpenHarmony:从应用内模式到主动策略激活

OpenHarmony 的焦点策略调整机制较为清晰:
OpenHarmony 的 AudioSession(需要通过 AudioSessionManager 创建和管理)是开发者主动、显式地介入系统焦点裁决的核心工具。它允许应用向系统声明:“当我的音频流与其他应用冲突时,请优先执行我指定的并发策略”

AudioConcurrencyMode(并发模式)枚举四种策略:

策略常量(AudioConcurrencyMode 含义与行为
CONCURRENCY_DEFAULT 遵循系统预设的默认焦点策略。
CONCURRENCY_MIX_WITH_OTHERS 声明本应用音频流可以与其他音频并发混音播放。
CONCURRENCY_DUCK_WITH_OTHERS 声明本应用播放音频时,希望系统压低后台音频的音量。
CONCURRENCY_PAUSE_WITH_OTHERS 声明本应用播放音频时,希望系统暂停后台音频的播放。

6. 策略调整对比总结

  • 底层设计哲学

    • iOS:事前配置式,通过 AVAudioSession 声明意图,配合回调被动调整。

    • Android:参数化请求式,通过 AudioFocusRequest.Builder 链式构建详细参数,从源头介入系统决策。

    • OpenHarmony:分层混合式,结合系统默认的焦点管控策略,与应用间主动激活的AudioSession策略(AudioConcurrencyMode、AudioSessionBehaviorFlags等),形成“基础策略 + 策略补充”的灵活架构。

  • 策略控制粒度

    • iOS:侧重定义自身行为(mixWithOthersduckOthers),影响范围主要在本应用。

    • Android:侧重声明音频意图(AUDIOFOCUS_GAIN/GAIN_TRANSIENT),并包含时间维度上的策略(setAcceptsDelayedFocusGain)。

    • OpenHarmony:兼顾应用内(焦点模式)与应用间(并发策略)策略,控制面更广。

  • 特殊机制

    • iOS:提供 secondaryAudioShouldBeSilencedHint 和 AVAudioSessionSilenceSecondaryAudioHintNotification,允许在后台播放时微调自己的输出。

    • AndroidsetWillPauseWhenDucked 赋予开发者对“闪避”事件的完全控制权,可选择自行处理而非接受系统自动行为。

    • OpenHarmonyAudioSession 是唯一一个完全由应用主导、可在不同应用间起效的主动策略设置接口,赋予了开发者最高的自定义权限。


7. 开发者策略选择指南

如果你想要... iOS 策略 Android 策略 OpenHarmony 策略
允许与其他音频混音 使用 mixWithOthers 选项。 通常与 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK 配合,或依赖系统默认行为。 使用 AudioSession 并设置为 CONCURRENCY_MIX_WITH_OTHERS
暂时压低其他音频音量 使用 duckOthers 选项。 在请求焦点时使用 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK 类型。 使用 AudioSession 并设置为 CONCURRENCY_DUCK_WITH_OTHERS
完全暂停其他音频 使用不包含 mixWithOthers 的类别。 使用 AUDIOFOCUS_GAIN 或 AUDIOFOCUS_GAIN_TRANSIENT 类型。 使用 AudioSession 并设置为 CONCURRENCY_PAUSE_WITH_OTHERS
处理延迟焦点获取 平台无此概念。 在构建 AudioFocusRequest 时,使用 setAcceptsDelayedFocusGain(true) 平台暂未直接提供此类延迟获取机制。
自行决定闪避行为 secondaryAudioShouldBeSilencedHint 在构建 AudioFocusRequest 时,使用 setWillPauseWhenDucked(true) 通过setAudioSessionBehavior(behavior: int)等接口改变焦点行为,例如通过设置MUTE_WHEN_INTERRUPTED实现音频被打断时改为被静音,其它音频结束播放后,解除静音等。
管理应用内多音频流 无此概念。 无此概念。 使用 setInterruptMode 选择 SHARE_MODE 或 INDEPENDENT_MODE

8. 总结

三大平台的音频焦点机制核心设计哲学一致:通过合作,让用户的音频体验更有序。主要区别在于「如何定义和声明音频的优先级与意图」以及「由谁(系统还是应用)来最终负责遵守规则」。

在实际开发中,除遵循基础焦点申请流程外,善用各平台提供的策略调整接口(iOS 的 CategoryOptions、Android 的 AudioFocusRequest.Builder、OpenHarmony 的 AudioSession)能够使应用在复杂的音频场景下提供更符合用户预期的体验。理解并适配这些差异,是打造跨平台一致、高质量音频应用的关键。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐