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

1. 核心接口与机制速览

对比维度iOS (AVAudioSession)Android (AudioManager)OpenHarmony (AudioRenderer)
核心接口AVAudioSession (单例)AudioManager,自 Android 8.0 起使用 AudioFocusRequestAudioRenderer,或更高层的 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:应用内外的双层策略

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

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

    1. 应用内焦点模式 (interruptMode):决定一个应用内的多个音频流如何共存。
    • 独立焦点模式 (INDEPENDENT_MODE):不同应用见默认就是这种焦点模式。每个音频流拥有独立焦点,流之间会触发抢占。例如,App 内播放音乐时开始录音,音乐会暂停并触发 audioInterrupt 事件。如果同一个应用内的多个音频流希望由系统决策打断策略,也可以配置成该模式。
    • 共享焦点模式 (SHARE_MODE):仅仅用于设置同一应用内多音频流的焦点模式,不同应用之间的音频流不支持这种模式。配置后,一个应用内所有流之间无焦点抢占,由应用自行决定并发策略。应用内的音频流不配置,默认就是共享模式。

      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

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

更多推荐