HarmonyOS鸿蒙Next中怎么实现锁屏音频播放
HarmonyOS鸿蒙Next中怎么实现锁屏音频播放 怎么实现锁屏音频播放,同时系统的下拉框里边也要有播放,监听被别的音乐播放器挤掉的通知。
【解决方案】
应用如果要实现锁屏播放功能,可以参考以下内容:
-
AVSession:使用媒体会话(AVSession)功能注册到系统内统一管理。具体参考应用接入AVSession场景介绍。开始创建并激活媒体会话代码如下:
private async initAVSession() { this.context = AppStorage.get('context'); if (!this.context) { Logger.info(TAG, `session create failed : conext is undefined`); return; } this.audioRendererController = AppStorage.get('audioRendererController'); if (!this.audioRendererController) { Logger.info(TAG, `session create failed : audioRendererController is undefined`); return; } this.AVSession = await avSession.createAVSession(this.context, "PLAY_AUDIO", 'audio'); await this.AVSession.activate(); // [StartExclude avsession_controller] Logger.info(TAG, `session create successed : sessionId : ${this.AVSession.sessionId}`); await this.setAVMetadata(); this.setLaunchAbility(); this.setListenerForMesFromController(); if (this.musicIndex !== undefined) { this.getAndUpdateFavoriteState(this.musicIndex.toString()); } }
-
长时任务:申请长时任务避免进入挂起(Suspend)状态。具体参考申请长时任务。后台任务权限:ohos.permission.KEEP_BACKGROUND_RUNNING。应用在后台播放音频可申请类型为AUDIO_PLAYBACK的长时任务。
-
音频焦点处理策略:具体可参考音频焦点介绍。在发生音频打断事件时,audioRenderer收到interruptEvent回调:
private setInterruptCallback() { if (!this.audioRenderer) { return; } this.audioRenderer.on('audioInterrupt', this.interruptCallback); } private interruptCallback: (interruptEvent: audio.InterruptEvent) => void = (interruptEvent: audio.InterruptEvent) => { if (interruptEvent.forceType === audio.InterruptForceType.INTERRUPT_FORCE) { switch (interruptEvent.hintType) { case audio.InterruptHint.INTERRUPT_HINT_PAUSE: this.updateIsPlay(false); break; case audio.InterruptHint.INTERRUPT_HINT_STOP: this.updateIsPlay(false); this.pause(); break; case audio.InterruptHint.INTERRUPT_HINT_DUCK: break; case audio.InterruptHint.INTERRUPT_HINT_UNDUCK: break; default: break; } } else if (interruptEvent.forceType === audio.InterruptForceType.INTERRUPT_SHARE) { switch (interruptEvent.hintType) { case audio.InterruptHint.INTERRUPT_HINT_RESUME: this.start(); break; default: break; } } }
完整示例可参考使用AudioRenderer后台播放。
更多关于HarmonyOS鸿蒙Next中怎么实现锁屏音频播放的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
工具类
import { bundleManager, wantAgent } from '@kit.AbilityKit'
import { process } from '@kit.ArkTS'
import { avSession } from '@kit.AVSessionKit'
import { backgroundTaskManager } from '@kit.BackgroundTasksKit'
class BackgroundRunningManager {
// 申请长时任务
async startBackgroundRunning() {
const context = getContext()
// 重点1: 提供音频后台约束能力,音频接入AVSession后,可以进行后台音频播放
const session = await avSession.createAVSession(context, 'guardianSession', 'audio')
await session.activate()
// 获取 bundle 应用信息
const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
// 通过wantAgent模块下getWantAgent方法获取WantAgent对象
const wantAgentObj = await wantAgent.getWantAgent({
// 添加需要被拉起应用的bundleName和abilityName
wants: [{ bundleName: bundleInfo.name, abilityName: "EntryAbility" }],
// 使用者自定义的一个私有值
requestCode: 0,
})
// 重点2: 创建后台任务
await backgroundTaskManager.startBackgroundRunning(context,
backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, wantAgentObj)
}
// 停止后台任务
async stopBackgroundRunning() {
backgroundTaskManager.stopBackgroundRunning(getContext())
}
}
export const backgroundRunningManager = new BackgroundRunningManager()
配置后台播放
"abilities": [
{
"backgroundModes": [
// 音频播放
"audioPlayback"
],
}
],
"requestPermissions": [
{
"name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
}
],
Index.ets
import { audio } from '@kit.AudioKit';
import { media } from '@kit.MediaKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
import { backgroundRunningManager } from '../utils/A';
async function play(fileNames: string[]) {
backgroundRunningManager.startBackgroundRunning()
// 执行应用本身业务
let index = 0 //指向当前播放的数据
let soundIds: number[] = []
let streamIds: number[] = []
let playParameters: media.PlayParameters = {
loop: 0, // 不循环
rate: audio.AudioRendererRate.RENDER_RATE_NORMAL, // 正常倍速(1倍速) 只能 1倍速 2倍速 0.5倍速
leftVolume: 0.5, // range = 0.0-1.0
rightVolume: 0.5, // range = 0.0-1.0
priority: 0, // 最低优先级
};
// audioRenderInfo中的参数usage取值为STREAM_USAGE_UNKNOWN,STREAM_USAGE_MUSIC,STREAM_USAGE_MOVIE,
// STREAM_USAGE_AUDIOBOOK时,SoundPool播放短音时为混音模式,不会打断其他音频播放。
let audioRendererInfo: audio.AudioRendererInfo = {
usage: audio.StreamUsage.STREAM_USAGE_MUSIC,
rendererFlags: 1
};
//创建soundPool实例
let soundPool = await media.createSoundPool(5, audioRendererInfo);
//注册监听
// 加载完成回调
soundPool.on('loadComplete', (soundId_: number) => {
//全部加载完成
if(soundId_ === fileNames.length){
// 开始播放,这边play也可带播放播放的参数PlayParameters,请在音频资源加载完毕,即收到loadComplete回调之后再执行play操作
soundPool.play(soundIds[index], playParameters, (error, streamID: number) => {
if (error) {
console.info(`play sound Error: errCode is ${error.code}, errMessage is ${error.message}`)
} else {
streamIds.push(streamID)
}
});
}
console.info('loadComplete, soundId: ' + soundId_);
})
// 播放完成回调
soundPool.on('playFinished', async () => {
console.info("receive play finished message");
index++
if(index < fileNames.length){
// 播放下一个
soundPool.play(soundIds[index], playParameters, (error, streamID: number) => {
if (error) {
console.info(`play sound Error: errCode is ${error.code}, errMessage is ${error.message}`)
} else {
streamIds.push(streamID)
}
});
}else{
//释放资源
// 终止指定流的播放
for (let streamId of streamIds) {
await soundPool.stop(streamId);
}
// 卸载音频资源
for (const soundId of soundIds) {
await soundPool.unload(soundId);
}
//关闭监听
soundPool.off('loadComplete');
soundPool.off('playFinished');
soundPool.off('error');
// 释放SoundPool
await soundPool.release();
//关闭长时任务
backgroundRunningManager.startBackgroundRunning()
}
})
//错误监听
soundPool.on('error', (error: BusinessError) => {
console.info('error happened,message is :' + error.message);
})
for (let i = 0; i < fileNames.length; i++) {
// 加载音频资源
const file =
AppStorage.get<common.UIAbilityContext>('UIContext')!.resourceManager.getRawFdSync(`audio/${fileNames[i]}`)
let soundId = await soundPool.load(file.fd, file.offset, file.length);
soundIds.push(soundId);
}
}
@Entry
@Component
struct Page {
@State message: string = 'Hello World';
aboutToAppear(): void {
//todo 放uiAbility中
AppStorage.setOrCreate<common.UIAbilityContext>('UIContext', getContext(this) as common.UIAbilityContext)
}
build() {
Column() {
Row()
.width(200)
.backgroundColor(Color.Red)
.aspectRatio(1)
.blur(20)
Button('121.45')
.onClick(() => {
//123.45
//1B2S3D45Y
let fileNames: string[] =
['start.mp3', '1.mp3','B.mp3','2.mp3','S.mp3','1.mp3','D.mp3','4.mp3','5.mp3','Y.mp3'];
play(fileNames);
});
}
.height('100%')
.width('100%')
}
}
权限配置(config.json)
"reqPermissions": [
{ "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" }, // 后台持续运行
{ "name": "ohos.permission.MANAGE_MEDIA_RESOURCES" } // 媒体资源管理
]
1. 锁屏播放保持
- 在
onWindowStageCreate
生命周期中启动后台任务 - 使用
BackgroundTaskManager
维持播放进程 - 播放器状态变化时更新AVSession
2. 控制中心交互
- 通过
AVSession
自动同步播放状态到控制中心 - 响应系统播放控制事件
3. 中断监听处理
- 通过音频管理器的
onInterrupt
回调监听焦点变化 - 被其他应用中断时的处理逻辑
1. 创建并配置AVSession(媒体会话)
- 目的:接入系统播控中心,实现锁屏界面和播控中心的播放控制与信息展示。
- 步骤:
- 调用
AVSessionManager.createAVSession()
创建会话(类型为'audio'
)。 - 通过
setAVMetadata()
设置媒体元数据(如标题、封面、音源标识等)。 - 通过
setAVPlaybackState()
实时更新播放状态(如播放/暂停、进度、倍速等)。
- 调用
2. 申请长时任务(Background Task)
- 目的:允许应用在后台(包括锁屏状态下)持续播放音频,避免被系统挂起或终止。
- 步骤:
- 使用
backgroundTaskManager
申请类型为AUDIO_PLAYBACK
的长时任务。 - 播放时申请任务,暂停/停止时取消任务。
- 使用
3. 监听音频中断事件(被其他应用打断)
- 目的:监听系统音频焦点变化,当其他应用抢占焦点时(如来电、其他音乐播放),及时处理中断事件。
- 步骤:
- 使用
AVPlayer
或AudioRenderer
的audioInterrupt
事件监听。 - 在回调中根据
InterruptEvent.hintType
判断中断类型(如PAUSE
、STOP
、DUCK
),并更新应用状态(如暂停播放)。
- 使用
4. 核心代码
import { avSession, AVSessionManager } from '@kit.AVSessionKit';
import { backgroundTaskManager } from '@kit.ResourceScheduleBackgroundTaskManager';
import { audio } from '@kit.AudioKit';
// 1. 创建AVSession
let session = await AVSessionManager.createAVSession(context, 'audio_session', 'audio');
// 2. 设置元数据(播控中心显示)
let metadata = {
title: '歌曲名',
mediaImage: '封面URL',
displayTags: AVSessionManager.DisplayTag.TAG_AUDIO_VIVID // 音源标识
};
session.setAVMetadata(metadata);
// 3. 更新播放状态
let playbackState = {
state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY,
position: 0, // 播放进度
speed: 1.0 // 倍速
};
session.setAVPlaybackState(playbackState);
// 4. 申请长时任务
let wantAgent = await backgroundTaskManager.getWantAgent();
await backgroundTaskManager.startBackgroundRunning(context, backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, wantAgent);
// 5. 监听音频中断事件(以AVPlayer为例)
avPlayer.on('audioInterrupt', (interruptEvent: audio.InterruptEvent) => {
if (interruptEvent.hintType === audio.InterruptHint.INTERRUPT_HINT_PAUSE) {
// 被其他应用暂停:更新本地状态及播控中心
session.setAVPlaybackState({ state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PAUSE });
}
});
// 6. 应用退后台时保持播放(需已申请长时任务并接入AVSession)
注意事项:
-
权限与配置:
- 声明
ohos.permission.INTERNET
(网络播放时需添加)。 - 在
module.json5
中申请长时任务权限:"ohos.permission.KEEP_BACKGROUND_RUNNING"
。
- 声明
-
中断处理:
被其他应用打断时,需通过setAVPlaybackState()
同步更新播控中心的播放状态(如改为暂停)。 -
资源释放:
退出播放时需调用session.destroy()
和backgroundTaskManager.stopBackgroundRunning()
释放资源。
系统播控中心通过媒体会话AVSession进行信息交互。创建并初始化媒体会话实例后,应用需要通过setAVMetaData()接口设置会话元数据,同时使用setAVPlaybackState()接口主动向播控中心同步当前播放状态,并通过on(‘controlCommand’)注册事件监听实时响应播控中心的音频操作事件,最终实现本应用与播控中心的双向状态同步,确保两端数据的一致性。
具体实现参考文档: 音频投播-典型全场景协同开发案例-全场景协同 - 华为HarmonyOS开发者
实现锁屏音频播放及系统播控交互,需要结合后台任务管理、AVSession(音视频会话)以及音频焦点管理来实现。
锁屏播放与后台任务
1/在 module.json5 中添加权限声明:
"abilities": [
{
"name": "EntryAbility",
"backgroundModes": ["audioPlayback"]
}
],
"requestPermissions": [
{
"name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
}
]
2/在播放开始时申请后台任务:
import backgroundTaskManager from '@kit.ResourceSchedule.BackgroundTaskManager';
startPlay() {
// 启动长时任务
let taskId = backgroundTaskManager.requestSuspendDelay("AudioPlayback");
// 播放音频逻辑
AVPlayerManager.play();
}
系统下拉控件的播控集成
1/初始化播放时注册AVSession:
import avSession from '@kit.Multimedia.AVSession';
let session: avSession.AVSession;
onCreateSession() {
session = avSession.createAVSession(context, "MusicSession", "music");
session.activate();
}
2/定义可接收的系统控制指令:
session.setController({
onPlay: () => AVPlayerManager.play(),
onPause: () => AVPlayerManager.pause(),
onSkipToNext: () => this.playNext(),
onSetSpeed: (speed: number) => AVPlayerManager.setSpeed(speed)
});
3/更新播放状态到会话:
updatePlaybackState() {
let state: avSession.AVPlaybackState = {
state: AVPlayerManager.isPlaying ? avSession.PlaybackState.PLAYING : avSession.PlaybackState.PAUSED,
speed: AVPlayerManager.currentSpeed,
position: AVPlayerManager.currentPosition
};
session.setAVPlaybackState(state);
}
监听音频焦点冲突
当其他应用抢占音频焦点时处理:
import audio from '@kit.Multimedia.Audio';
let focusManager = audio.getAudioManager().getAudioFocusManager();
let focusRequest: audio.AudioFocusRequest = {
focusType: audio.AudioFocusType.GAIN,
options: {
willPauseWhenDucked: true
}
};
focusManager.requestAudioFocus(focusRequest).then(() => {
focusManager.on('audioFocusChange', (focusEvent: audio.AudioFocusChangeEvent) => {
if (focusEvent.focusChange === audio.AudioFocusInterruptType.INTERRUPTED_BY_OTHERS) {
AVPlayerManager.pause(); // 被其他应用打断时暂停
}
});
});
在HarmonyOS Next中,锁屏音频播放通过AVSession
框架实现。首先创建AVSession实例并设置音频播放控制器,通过dispatchMediaKeyEvent
处理媒体按键事件。使用AVSessionController
管理播放状态,确保锁屏界面可控制音频。系统UI自动显示播放控件,无需额外配置。
在HarmonyOS Next中实现锁屏音频播放,同时集成系统下拉控件并监听播放中断通知,可通过以下步骤完成:
-
音频服务与播放控制
使用AVSession
和AVPlayer
进行音频播放管理。创建AVSession
实例并设置播放状态、元数据(如歌曲名、歌手),系统会自动在锁屏界面和通知栏生成播放控件。import avSession from '[@ohos](/user/ohos).multimedia.avsession'; import media from '[@ohos](/user/ohos).multimedia.media'; // 创建AVSession let session: avSession.AVSession; avSession.createAVSession(context, 'audioPlayer', 'audio').then((s) => { session = s; }); // 设置播放元数据 let metadata: avSession.AVMetadata = { assetId: '123', title: '歌曲名称', artist: '歌手', // 其他元数据字段 }; session.setAVMetadata(metadata); // 创建AVPlayer并控制播放 let avPlayer = media.createAVPlayer(); // 设置播放源并准备播放
-
系统下拉控件集成
通过AVSession
的activate()
方法激活会话,系统会自动将播放控件添加到通知栏和锁屏界面。支持播放/暂停、上一首/下一首等标准操作。session.activate(); // 激活会话以显示控件
-
监听播放中断事件
注册audioInterrupt
事件,监听其他应用抢占音频焦点的情况:import audio from '[@ohos](/user/ohos).multimedia.audio'; let audioManager = audio.getAudioManager(); audioManager.on('audioInterrupt', (interruptEvent) => { if (interruptEvent.forcePaused) { // 被其他播放器中断,暂停当前播放 avPlayer.pause(); session.setAVPlaybackState({ state: avSession.PlaybackState.PAUSED }); } });
-
处理AVSession命令
通过监听AVSession的on('controlCommand')
事件响应系统控件的操作(如用户点击通知栏的暂停按钮):session.on('controlCommand', (command) => { if (command.command === 'play') { avPlayer.play(); } else if (command.command === 'pause') { avPlayer.pause(); } // 其他命令处理 });
注意事项:
- 需申请
ohos.permission.MANAGE_MEDIA_RESOURCES
权限以管理音频资源。 - 测试时需确保应用在后台或锁屏状态,以验证控件和中断监听是否生效。