鸿蒙开发实践:基于AVPlayer的音频后台播放全解析

在HarmonyOS NEXT的应用开发中,音频后台播放是一个常见的需求,特别是在音乐播放器或需要长时间运行的音频应用中。本文将指导您如何使用AVPlayer实现音频的后台播放,并处理多音频流的并发问题。

场景描述

音频后台播放允许应用在后台继续播放音频,即使应用不处于前台或设备处于锁屏状态。此外,当其他音频流(如导航音、电话)进入时,应用需要合理处理音频焦点的变更。

步骤一:创建AVPlayer实现音频播放

首先,我们需要创建一个AVPlayer实例并加载音频资源。

async avPlayerFdSrcDemo() {
  // 创建AVPlayer实例对象
  let avPlayer = await media.createAVPlayer();
  // 创建状态机变化回调函数
  this.setAVPlayerCallback(avPlayer);
  // 获取媒体资源播放地址
  let context = getContext(this) as common.UIAbilityContext;
  let fileDescriptor = await context.resourceManager.getRawFd('123.mp3');
  let avFileDescriptor = { fd: fileDescriptor.fd, offset: fileDescriptor.offset, length: fileDescriptor.length };
  this.isSeek = true;
  // 为fdSrc赋值触发initialized状态机上报
  avPlayer.fdSrc = avFileDescriptor;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

步骤二:注册AVPlayer回调函数

接下来,我们需要注册AVPlayer的回调函数,以处理不同的播放状态。

setAVPlayerCallback(avPlayer: media.AVPlayer) {
  avPlayer.on('seekDone', (seekDoneTime) => {
    console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
  });
  avPlayer.on('error', (err) => {
    console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
    avPlayer.reset();
  });
  avPlayer.on('stateChange', async (state, reason) => {
    // 根据状态进行相应的处理
  });
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

步骤三:创建AVSession

为了使音频能够通过播控中心控制,我们需要创建一个AVSession。

async createSession() {
  let type = 'audio';
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
  let metadata = {
    assetId: '0',
    title: 'TITLE',
    mediaImage: 'IMAGE',
    artist: 'ARTIST',
  };
  session.setAVMetadata(metadata).then(() => {
    console.info(`SetAVMetadata successfully`);
  }).catch((err) => {
    console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
  });
  this.setListenerForMesFromController(session);
  await session.activate();
  console.info(`session create done : sessionId : ${session.sessionId}`);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

步骤四:创建长时任务

为了确保应用在后台播放时不被冻结,我们需要申请ohos.permission.KEEP_BACKGROUND_RUNNING权限,并在module.json5中进行相应的配置。

{
  "requestPermissions": [
    {
      "name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
      "reason": "$string:app_name",
      "usedScene": {
        "abilities": [
          "FormAbility"
        ],
        "when": "always"
      }
    }
  ],
  "backgroundModes": [
    "audioPlayback"
  ]
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

然后,我们通过wantAgent模块申请长时任务。

wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => {
  backgroundTaskManager.startBackgroundRunning(context, backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, wantAgentObj).then(() => {
    console.info(`Succeeded in operationing startBackgroundRunning.`);
  }).catch((err) => {
    console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
  });
});
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

步骤五:处理音频焦点打断

当其他音频流需要播放时,系统可能会发出音频打断事件。我们需要监听这些事件并做出相应的处理。

avPlayer.on('audioInterrupt', async (interruptEvent) => {
  // 根据interruptEvent的内容进行处理
});
  • 1.
  • 2.
  • 3.

结语

通过本文的指导,您应该能够使用AVPlayer在HarmonyOS NEXT中实现音频的后台播放,并妥善处理音频焦点的变更。这不仅提升了用户体验,也使得应用更加健壮和专业。


注意:本文内容基于HarmonyOS NEXT的官方文档和实践案例,具体实现可能随SDK版本更新而变化。建议开发者持续关注官方文档,获取最新的开发指导和最佳实践。