音乐播放器接入了 AVSession,锁屏面板能显示歌名和封面,看起来一切正常。用户按了播控中心的暂停按钮,音乐没停;切歌按钮按了,播放器也没反应。日志里 AVSession 创建成功、activate 也调了,问题出在你只把状态“写上去”了,没有把控制命令“接回来”。setAVMetadata 和 setAVPlaybackState 负责把播放器状态同步给播控中心,但播控中心上的按钮点击不会自动驱动 AVPlayer,需要你在 AVSession 上注册 play / pause / playNext 等事件,回调里再调播放器。

元数据和播放状态是“上报”,控制命令是“回传”

setAVMetadata 管的是锁屏和播控中心上显示什么,setAVPlaybackState 管的是按钮状态和进度条。这两个接口只负责“告诉系统”,不负责“接收命令”。控制命令要通过 session.on('pause', callback) 这类事件注册,回调里驱动 AVPlayer 执行真正的暂停/播放。少了这一步,播控中心就是一个只能看、不能操作的装饰品。

typescript

import { avSession } from '@kit.AVSessionKit';

const session = await avSession.createAVSession(context, 'player', 'audio');

// 上报:切歌时更新元数据和播放状态
await session.setAVMetadata({
  assetId: this.currentSongId,
  title: this.currentTitle,
  artist: this.currentArtist,
});
await session.setAVPlaybackState({
  state: avSession.PlaybackState.PLAYBACK_STATE_PLAY,
});

// 回传:播控中心按钮驱动播放器
session.on('play', () => this.player.play());
session.on('pause', () => this.player.pause());
session.on('playNext', () => this.playNext());
session.on('playPrevious', () => this.playPrevious());

await session.activate();

activate() 放在事件注册之后,确保会话激活时控制链路已经就绪。setAVMetadata 里的 mediaImage 如果是异步加载的封面,加载完成后要确认当前歌曲没有切走,避免旧封面覆盖新歌的元数据。

AVSession 不保活,后台播放要长时任务兜底

播控中心正常、锁屏正常,切到后台几分钟播放断了。这不是 AVSession 的 bug,是AVSession 只提供播控能力,不提供进程保活。应用退到后台,进程被系统挂起或回收,AVSession 跟着失效。后台播放需要同时做两件事:在 module.json5 的对应 UIAbility 里声明 backgroundModes: ["audioPlayback"] 和 ohos.permission.KEEP_BACKGROUND_RUNNING 权限,然后在播放开始时调用 backgroundTaskManager.startBackgroundRunning 申请 AUDIO_PLAYBACK 长时任务。暂停时停掉长时任务,恢复播放时重新申请,不能一次申请就一直挂着。

同应用多路音源收敛为一个会话,不要频繁 destroy/create

官方限制是“一个 Ability 只能存在一个 AVSession,重复创建会失败”。如果你的应用里同时有播客和背景音乐,不要建两个会话,切换音源时复用同一个 AVSession,只更新 setAVMetadata 和 setAVPlaybackState,保持 activate 状态不变。每次切歌都 destroy 再 create,播控中心的元数据和按键路由会反复重建,体验很差。

AVSession 的正确姿势是“一个会话、双向桥接、双接入保活”。元数据上报让用户看到,控制事件回传让用户操作得了,长时任务让后台播放活下来。三件事缺一件,播控中心就会变成“显示正常但按了没反应”的摆设。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐