HarmonyOS鎖屏音頻播放功能完整實(shí)現(xiàn)步驟
引言
在音頻類應(yīng)用開發(fā)中,鎖屏狀態(tài)下的音頻播放與播控能力是一項(xiàng)核心用戶體驗(yàn)需求。當(dāng)用戶鎖屏后,系統(tǒng)播控中心需要展示當(dāng)前播放的音頻信息,并支持用戶進(jìn)行播放/暫停、切歌、快進(jìn)快退等操作。本文將詳細(xì)介紹如何在 HarmonyOS 上實(shí)現(xiàn)完整的鎖屏音頻播放功能。
一、技術(shù)棧與核心概念
1.1 AVSession Kit 簡介
AVSession Kit(音頻媒體會話套件)是 HarmonyOS 官方提供的一套用于管理媒體播放會話的 API。通過它,應(yīng)用可以將當(dāng)前播放的媒體信息(標(biāo)題、作者、封面、播放進(jìn)度等)同步到系統(tǒng)播控中心,并接收用戶從鎖屏、控制中心下發(fā)的播控指令。
1.2 核心類與接口
| 類/接口 | 用途 |
|---|---|
createAVSession() | 創(chuàng)建媒體會話實(shí)例 |
AVSession.activate() | 激活會話,開始與系統(tǒng)播控中心交互 |
AVSession.setAVMetadata() | 設(shè)置媒體元數(shù)據(jù)(標(biāo)題、作者、封面等) |
AVSession.setAVPlaybackState() | 設(shè)置播放狀態(tài)(播放/暫停、進(jìn)度、倍速等) |
AVSession.on(event, callback) | 注冊播控命令監(jiān)聽器 |
1.3 會話類型(AVSessionType)
系統(tǒng)播控中心展示的按鈕樣式由會話類型決定:
audio類型:顯示「上一首、播放/暫停、下一首」等音頻類按鈕video類型:顯示「快退、上一首、播放/暫停、下一首、快進(jìn)」等視頻類按鈕
選擇正確的會話類型對播控中心展示效果至關(guān)重要。
二、權(quán)限與后臺能力配置
2.1 后臺播放模式
要實(shí)現(xiàn)鎖屏后繼續(xù)播放,需要在應(yīng)用的能力配置中聲明后臺播放模式:
{
"backgroundModes": ["audioPlayback"]
}這告訴系統(tǒng):本應(yīng)用在后臺時(shí)需要保持音頻播放能力。
2.2 權(quán)限聲明
同時(shí)需要在模塊配置中聲明媒體播放權(quán)限:
{
"requestPermissions": [
{
"name": "ohos.permission.MEDIA_PLAYBACK"
}
]
}三、完整實(shí)現(xiàn)步驟
步驟1:創(chuàng)建并激活 AVSession
在應(yīng)用啟動(dòng)或音頻播放初始化時(shí),創(chuàng)建媒體會話:
import { avSession as AVSessionKit } from '@kit.AVSessionKit';
import { common } from '@kit.AbilityKit';
// 創(chuàng)建 AVSession
const session = await AVSessionKit.createAVSession(
context, // 應(yīng)用上下文
'AudioSession', // 會話標(biāo)識
'audio' // 會話類型:'audio' 或 'video'
);
// 激活會話
await session.activate();
注意:創(chuàng)建會話后應(yīng)立即激活(activate),這樣系統(tǒng)播控中心才能感知到你的應(yīng)用在播放音頻。
步驟2:注冊播控命令監(jiān)聽器
監(jiān)聽用戶從鎖屏/控制中心發(fā)出的播控指令,并在回調(diào)中執(zhí)行對應(yīng)的播放邏輯:
// 播放
session.on('play', () => {
// 調(diào)用播放器的播放方法
});
// 暫停
session.on('pause', () => {
// 調(diào)用播放器的暫停方法
});
// 上一首
session.on('playPrevious', () => {
// 切換到上一首音頻
});
// 下一首
session.on('playNext', () => {
// 切換到下一首音頻
});
// 進(jìn)度跳轉(zhuǎn)(seek)
session.on('seek', (seekTime: number) => {
// seekTime 單位為毫秒,調(diào)用播放器的 seek 方法
});
// 快退
session.on('rewind', () => {
// 向后跳轉(zhuǎn)指定時(shí)長(如15秒)
});
// 快進(jìn)
session.on('fastForward', () => {
// 向前跳轉(zhuǎn)指定時(shí)長(如15秒)
});
步驟3:同步媒體元數(shù)據(jù)
當(dāng)切換音頻時(shí),將新音頻的元數(shù)據(jù)同步到系統(tǒng)播控中心:
import { avSession as AVSessionKit } from '@kit.AVSessionKit';
const metadata: AVSessionKit.AVMetadata = {
assetId: '1001', // 媒體唯一ID
title: '音頻標(biāo)題', // 標(biāo)題
artist: '作者名稱', // 作者
duration: 180000, // 總時(shí)長(毫秒)
mediaImage: pixelMapOrUrl // 封面圖片(PixelMap 對象或圖片URL)
};
session.setAVMetadata(metadata).then(() => {
// 元數(shù)據(jù)設(shè)置成功
}).catch((err) => {
// 處理錯(cuò)誤
});
步驟4:同步播放狀態(tài)與進(jìn)度
播放狀態(tài)變化(播放/暫停)或進(jìn)度更新時(shí),同步給系統(tǒng):
const playbackState: AVSessionKit.AVPlaybackState = {
state: AVSessionKit.PlaybackState.PLAYBACK_STATE_PLAY, // 或 PLAYBACK_STATE_PAUSE
speed: 1.0,
position: {
elapsedTime: 30000, // 當(dāng)前播放位置(毫秒)
updateTime: new Date().getTime() // 更新時(shí)間戳
},
duration: 180000 // 總時(shí)長(毫秒)
};
session.setAVPlaybackState(playbackState);
關(guān)鍵提示:
position.updateTime字段很重要,系統(tǒng)播控中心會根據(jù)這個(gè)時(shí)間戳和elapsedTime來計(jì)算當(dāng)前進(jìn)度顯示。
步驟5:封面圖片處理
鎖屏播控中心的封面圖片可以是以下兩種形式:
方式一:直接使用圖片 URL
const metadata: AVSessionKit.AVMetadata = {
// ... 其他字段
mediaImage: 'https://example.com/cover.jpg'
};
方式二:下載圖片并轉(zhuǎn)換為 PixelMap
如果需要更高質(zhì)量的展示效果,可以先下載圖片并轉(zhuǎn)換為 PixelMap 對象:
import { image } from '@kit.ImageKit';
import { http } from '@kit.NetworkKit';
async function downloadImageAsPixelMap(imageUrl: string): Promise<image.PixelMap | null> {
try {
// 1. 通過 HTTP 下載圖片數(shù)據(jù)
const request = http.createHttp();
const response = await request.request(imageUrl, {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER
});
const arrayBuffer = response.result as ArrayBuffer;
request.destroy();
// 2. 創(chuàng)建圖片源
const imageSource = image.createImageSource(arrayBuffer);
// 3. 創(chuàng)建 PixelMap
const decodingOptions: image.DecodingOptions = {
editable: false,
desiredPixelFormat: 3, // RGBA_8888
desiredDynamicRange: image.DecodingDynamicRange.AUTO
};
const pixelMap = await imageSource.createPixelMap(decodingOptions);
imageSource.release();
return pixelMap;
} catch (err) {
return null;
}
}
四、快進(jìn)與快退的實(shí)現(xiàn)
4.1 選擇正確的會話類型
要在鎖屏播控中心顯示快進(jìn)快退按鈕,需要使用 video 類型的會話:
// 使用 video 類型,播控中心將顯示快退和快進(jìn)按鈕 const session = await AVSessionKit.createAVSession(context, 'AudioSession', 'video');
4.2 實(shí)現(xiàn)快進(jìn)快退邏輯
// 快退 15 秒
function rewind(currentPosition: number): number {
const REWIND_TIME = 15 * 1000; // 15秒
const newPosition = Math.max(0, currentPosition - REWIND_TIME);
// 調(diào)用播放器 seek 到 newPosition
// 同步新的播放狀態(tài)到 AVSession
return newPosition;
}
// 快進(jìn) 15 秒
function fastForward(currentPosition: number, duration: number): number {
const FORWARD_TIME = 15 * 1000; // 15秒
const newPosition = Math.min(duration, currentPosition + FORWARD_TIME);
// 調(diào)用播放器 seek 到 newPosition
// 同步新的播放狀態(tài)到 AVSession
return newPosition;
}
// 注冊快退快進(jìn)監(jiān)聽器
session.on('rewind', () => {
const newPos = rewind(currentPositionRef.current);
currentPositionRef.current = newPos;
syncPlaybackStateToSession(true, newPos, durationRef.current);
});
session.on('fastForward', () => {
const newPos = fastForward(currentPositionRef.current, durationRef.current);
currentPositionRef.current = newPos;
syncPlaybackStateToSession(true, newPos, durationRef.current);
});
五、前后臺切換與狀態(tài)管理
5.1 從后臺恢復(fù)時(shí)的狀態(tài)處理
當(dāng)應(yīng)用從后臺(鎖屏狀態(tài))切換回前臺時(shí),需要注意:
- 不要中斷正在播放的音頻:如果播放器正在播放,保持播放狀態(tài)
- 同步最新的播放進(jìn)度:確保切換時(shí)的進(jìn)度是最新的
function onAppForeground(): void {
// 檢查播放器狀態(tài)
if (playerState === 'playing' || playerState === 'paused' || playerState === 'prepared') {
// 播放器正在工作中,不中斷播放
return;
}
// 其他恢復(fù)邏輯...
}
5.2 切換歌曲時(shí)的狀態(tài)重置
每次切換到新的音頻時(shí),必須重置以下狀態(tài):
currentTime(當(dāng)前播放時(shí)間):重置為 0durationTime(總時(shí)長):重置為新音頻的時(shí)長- AVSession 播放狀態(tài):同步新的進(jìn)度為 0
// 切換歌曲時(shí)
function switchToNewAudio(): void {
// 1. 重置本地狀態(tài)
currentTime = 0;
durationTime = 0;
// 2. 設(shè)置新的音頻 URL 并開始播放
// 3. 同步元數(shù)據(jù)到 AVSession
session.setAVMetadata({
assetId: newAudio.id,
title: newAudio.title,
artist: newAudio.artist,
duration: newAudio.duration,
mediaImage: newAudio.coverImage
});
// 4. 同步播放狀態(tài),進(jìn)度從 0 開始
session.setAVPlaybackState({
state: AVSessionKit.PlaybackState.PLAYBACK_STATE_PLAY,
speed: 1.0,
position: {
elapsedTime: 0,
updateTime: new Date().getTime()
},
duration: newAudio.duration
});
}
六、常見問題與最佳實(shí)踐
問題1:鎖屏播控中心沒有立即顯示
原因:可能是元數(shù)據(jù)設(shè)置時(shí)機(jī)不對,或者會話未正確激活。
解決:
- 確保
createAVSession()后立即調(diào)用activate() - 在播放器開始播放后立即調(diào)用
setAVMetadata()和setAVPlaybackState() - 添加日志確認(rèn) API 調(diào)用成功
問題2:封面圖片不顯示
原因:封面圖片的格式或大小不符合要求,或者下載失敗。
解決:
- 優(yōu)先使用 PixelMap 格式(比 URL 更可靠)
- 控制圖片大?。ńㄗh 400x400 像素以內(nèi))
- 確保圖片下載成功(添加錯(cuò)誤處理日志)
問題3:切換歌曲后進(jìn)度條顯示舊的進(jìn)度
原因:切換歌曲時(shí)沒有重置播放進(jìn)度和時(shí)長,導(dǎo)致 AVSession 保存了舊的進(jìn)度信息。
解決:
- 每次切換歌曲時(shí)重置
currentTime = 0和durationTime = 新時(shí)長 - 同步
setAVPlaybackState()時(shí)將elapsedTime設(shè)為 0 - 同步
setAVMetadata()時(shí)將duration設(shè)為新音頻的時(shí)長
問題4:解鎖后播放被中斷
原因:應(yīng)用從后臺切回前臺時(shí),onForeground 邏輯意外地重啟了播放器。
解決:
- 在
onForeground回調(diào)中先檢查播放器當(dāng)前狀態(tài) - 如果播放器正在
playing/paused/prepared,直接返回不做任何操作 - 只在播放器狀態(tài)異常時(shí)才執(zhí)行恢復(fù)邏輯
七、完整流程時(shí)序圖
下面是一次完整的鎖屏播放交互流程:
用戶操作 應(yīng)用側(cè) 系統(tǒng)播控中心
│ │ │
├─ 點(diǎn)擊播放 │ │
│ ─────────────────────────>│ │
│ │ 1. 創(chuàng)建并激活 AVSession │
│ │ 2. setAVMetadata() │
│ │ 3. setAVPlaybackState() │
│ │ ─────────────────────────> │
│ │ │ 顯示音頻信息
│ │ │ 和播放控制按鈕
│ │ │
├─ 鎖屏 │ │
│ ──────────────────────────┤───────────────────────────?│
│ │ │ 鎖屏播控中心可見
│ │ │
│ │ │ 用戶點(diǎn)擊快進(jìn)
│ │ 4. on('fastForward') │ <───────────────────
│ │ <───────────────────────── │
│ │ │
│ │ 5. 播放器 seek +15秒 │
│ │ 6. setAVPlaybackState() │
│ │ ─────────────────────────? │ 更新進(jìn)度條顯示
│ │ │
│ │ │ 用戶點(diǎn)擊下一首
│ │ 7. on('playNext') │ <───────────────────
│ │ <───────────────────────── │
│ │ │
│ │ 8. 切換音頻 + 重置進(jìn)度 │
│ │ 9. setAVMetadata() │
│ │ 10. setAVPlaybackState() │
│ │ ─────────────────────────? │ 顯示新音頻信息
│ │ │八、總結(jié)
實(shí)現(xiàn) HarmonyOS 鎖屏音頻播放的核心要點(diǎn):
- 正確配置權(quán)限和后臺模式:確保應(yīng)用在后臺可以繼續(xù)播放
- 創(chuàng)建和管理 AVSession 生命周期:與播放狀態(tài)保持一致
- 及時(shí)同步元數(shù)據(jù)和播放狀態(tài):讓鎖屏播控中心展示正確的信息
- 監(jiān)聽并響應(yīng)系統(tǒng)播控命令:實(shí)現(xiàn)完整的雙向交互
- 合理管理前后臺切換和歌曲切換:避免狀態(tài)錯(cuò)亂和播放中斷
通過本文介紹的方法,你可以實(shí)現(xiàn)一個(gè)體驗(yàn)流暢、與系統(tǒng)播控中心完美集成的音頻播放功能。
參考文檔:
到此這篇關(guān)于HarmonyOS鎖屏音頻播放功能完整實(shí)現(xiàn)步驟的文章就介紹到這了,更多相關(guān)HarmonyOS鎖屏音頻播放內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Debezium 與 Apache Kafka 的集成方式步驟詳解
本文詳細(xì)介紹了如何將Debezium與Apache Kafka集成,包括集成概述、步驟、注意事項(xiàng)等,通過KafkaConnect,Debezium可以捕獲數(shù)據(jù)庫變更并實(shí)時(shí)發(fā)送到Kafka Topic,實(shí)現(xiàn)數(shù)據(jù)的實(shí)時(shí)同步和分析,感興趣的朋友一起看看吧2025-02-02
用asp與php實(shí)現(xiàn)百度ping服務(wù)的代碼
分別用asp與php實(shí)現(xiàn)百度ping服務(wù)的代碼,需要的朋友可以參考下2012-02-02
最新Adobe?2022全新上線?Adobe?2022永久免費(fèi)使用教程
目前adobe2022的配置要求CPU至少是四核,運(yùn)行內(nèi)存至少是16GB,只支持windows10系統(tǒng),版本號是1809以及更高的版本,下面跟隨小編看下最新Adobe?2022全新上線?Adobe?2022永久免費(fèi)使用教程,感興趣的朋友一起看看吧2021-12-12
Git基礎(chǔ)之git與SVN版本控制優(yōu)缺點(diǎn)區(qū)別分析
這篇文章主要為大家介紹了Git基礎(chǔ)之git與SVN優(yōu)缺點(diǎn)及區(qū)別分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04
如何將服務(wù)器上的python代碼通過QQ發(fā)送回傳信息(附實(shí)現(xiàn)方法)
這篇文章主要介紹了我將服務(wù)器上的python代碼通過QQ發(fā)送回傳信息(附實(shí)現(xiàn)方法),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05
delphi使用Chilkat 組件和庫從SFTP下載文件的方法
這篇文章主要介紹了delphi使用Chilkat 組件和庫從SFTP下載文件的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08

