HarmonyOS锁屏音频播放功能完整实现步骤

Written by

in

文章目录
  • 在音频类应用开发中,锁屏状态下的音频播放与播控能力是一项核心用户体验需求。当用户锁屏后,系统播控中心需要展示当前播放的音频信息,并支持用户进行播放/暂停、切歌、快进快退等操作。本文将详细介绍如何在 HarmonyOS 上实现完整的锁屏音频播放功能。
  • 下面是一次完整的锁屏播放交互流程: 用户操作 应用侧 系统播控中心 │ │ │ ├─ 点击播放 │ │ │ ─────────────────────────>│ │ │ │ 1. 创建并激活 AVSession │ │ │ 2. setAVMetadata() │ │ │ 3. setAVPlaybackState() │ │ │ ─────────────────────────> │ │ │ │ 显示音频信息 │ │ │ 和播放控制按钮 │ │ │ ├─ 锁屏 │ │ │ ──────────────────────────┤───────────────────────────▶│ │ │ │ 锁屏播控中心可见 │ │ │ │ │ │ 用户点击快进 │ │ 4. on(‘fastForward’) │ <─────────────────── │ │ <───────────────────────── │ │ │ │ │ │ 5. 播放器 seek +15秒 │ │ │ 6. setAVPlaybackState() │ │ │ ─────────────────────────▶ │ 更新进度条显示 │ │ │ │ │ │ 用户点击下一首 │ │ 7. on(‘playNext’) │ <─────────────────── │ │ <───────────────────────── │ │ │ │ │ │ 8. 切换音频 + 重置进度 │ │ │ 9. setAVMetadata() │ │ │ 10. setAVPlaybackState() │ │ │ ─────────────────────────▶ │ 显示新音频信息 │ │ │
  • 实现 HarmonyOS 锁屏音频播放的核心要点: 正确配置权限和后台模式:确保应用在后台可以继续播放 创建和管理 AVSession 生命周期:与播放状态保持一致 及时同步元数据和播放状态:让锁屏播控中心展示正确的信息 监听并响应系统播控命令:实现完整的双向交互 合理管理前后台切换和歌曲切换:避免状态错乱和播放中断 通过本文介绍的方法,你可以实现一个体验流畅、与系统播控中心完美集成的音频播放功能。 参考文档: HarmonyOS 官方文档 – AVSession Kit HarmonyOS 官方文档 – 媒体会话接入场景 到此这篇关于HarmonyOS锁屏音频播放功能完整实现步骤的文章就介绍到这了,更多相关HarmonyOS锁屏音频播放内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: 鸿蒙HarmonyOS视频播放的实现 HarmonyOS Next音乐播放器项目实现代码
  • 目录
    • 引言
    • 一、技术栈与核心概念
      • 1.1 AVSession Kit 简介
      • 1.2 核心类与接口
      • 1.3 会话类型(AVSessionType)
    • 二、权限与后台能力配置
      • 2.1 后台播放模式
      • 2.2 权限声明
    • 三、完整实现步骤
      • 步骤1:创建并激活 AVSession
      • 步骤2:注册播控命令监听器
      • 步骤3:同步媒体元数据
      • 步骤4:同步播放状态与进度
      • 步骤5:封面图片处理
    • 四、快进与快退的实现
      • 4.1 选择正确的会话类型
      • 4.2 实现快进快退逻辑
    • 五、前后台切换与状态管理
      • 5.1 从后台恢复时的状态处理
      • 5.2 切换歌曲时的状态重置
    • 六、常见问题与最佳实践
      • 问题1:锁屏播控中心没有立即显示
      • 问题2:封面图片不显示
      • 问题3:切换歌曲后进度条显示旧的进度
      • 问题4:解锁后播放被中断
    • 七、完整流程时序图
      • 八、总结

        在音频类应用开发中,锁屏状态下的音频播放与播控能力是一项核心用户体验需求。当用户锁屏后,系统播控中心需要展示当前播放的音频信息,并支持用户进行播放/暂停、切歌、快进快退等操作。本文将详细介绍如何在 HarmonyOS 上实现完整的锁屏音频播放功能。

        AVSession Kit(音频媒体会话套件)是 HarmonyOS 官方提供的一套用于管理媒体播放会话的 API。通过它,应用可以将当前播放的媒体信息(标题、作者、封面、播放进度等)同步到系统播控中心,并接收用户从锁屏、控制中心下发的播控指令。

        类/接口 用途
        createAVSession() 创建媒体会话实例
        AVSession.activate() 激活会话,开始与系统播控中心交互
        AVSession.setAVMetadata() 设置媒体元数据(标题、作者、封面等)
        AVSession.setAVPlaybackState() 设置播放状态(播放/暂停、进度、倍速等)
        AVSession.on(event, callback) 注册播控命令监听器

        系统播控中心展示的按钮样式由会话类型决定:

        • audio 类型:显示「上一首、播放/暂停、下一首」等音频类按钮
        • video 类型:显示「快退、上一首、播放/暂停、下一首、快进」等视频类按钮

        选择正确的会话类型对播控中心展示效果至关重要。

        要实现锁屏后继续播放,需要在应用的能力配置中声明后台播放模式:

        {
          "backgroundModes": ["audioPlayback"]
        }

        这告诉系统:本应用在后台时需要保持音频播放能力。

        同时需要在模块配置中声明媒体播放权限:

        {
          "requestPermissions": [
            {
              "name": "ohos.permission.MEDIA_PLAYBACK"
            }
          ]
        }

        在应用启动或音频播放初始化时,创建媒体会话:

        import { avSession as AVSessionKit } from '@kit.AVSessionKit';
        import { common } from '@kit.AbilityKit';
        
        // 创建 AVSession
        const session = await AVSessionKit.createAVSession(
          context,            // 应用上下文
          'AudioSession',     // 会话标识
          'audio'             // 会话类型:'audio' 或 'video'
        );
        
        // 激活会话
        await session.activate();
        

        注意:创建会话后应立即激活(activate),这样系统播控中心才能感知到你的应用在播放音频。

        监听用户从锁屏/控制中心发出的播控指令,并在回调中执行对应的播放逻辑:

        // 播放
        session.on('play', () => {
          // 调用播放器的播放方法
        });
        
        // 暂停
        session.on('pause', () => {
          // 调用播放器的暂停方法
        });
        
        // 上一首
        session.on('playPrevious', () => {
          // 切换到上一首音频
        });
        
        // 下一首
        session.on('playNext', () => {
          // 切换到下一首音频
        });
        
        // 进度跳转(seek)
        session.on('seek', (seekTime: number) => {
          // seekTime 单位为毫秒,调用播放器的 seek 方法
        });
        
        // 快退
        session.on('rewind', () => {
          // 向后跳转指定时长(如15秒)
        });
        
        // 快进
        session.on('fastForward', () => {
          // 向前跳转指定时长(如15秒)
        });
        

        当切换音频时,将新音频的元数据同步到系统播控中心:

        import { avSession as AVSessionKit } from '@kit.AVSessionKit';
        
        const metadata: AVSessionKit.AVMetadata = {
          assetId: '1001',              // 媒体唯一ID
          title: '音频标题',             // 标题
          artist: '作者名称',            // 作者
          duration: 180000,             // 总时长(毫秒)
          mediaImage: pixelMapOrUrl     // 封面图片(PixelMap 对象或图片URL)
        };
        
        session.setAVMetadata(metadata).then(() => {
          // 元数据设置成功
        }).catch((err) => {
          // 处理错误
        });
        

        播放状态变化(播放/暂停)或进度更新时,同步给系统:

        const playbackState: AVSessionKit.AVPlaybackState = {
          state: AVSessionKit.PlaybackState.PLAYBACK_STATE_PLAY,  // 或 PLAYBACK_STATE_PAUSE
          speed: 1.0,
          position: {
            elapsedTime: 30000,   // 当前播放位置(毫秒)
            updateTime: new Date().getTime()  // 更新时间戳
          },
          duration: 180000        // 总时长(毫秒)
        };
        
        session.setAVPlaybackState(playbackState);
        

        关键提示position.updateTime 字段很重要,系统播控中心会根据这个时间戳和 elapsedTime 来计算当前进度显示。

        锁屏播控中心的封面图片可以是以下两种形式:

        方式一:直接使用图片 URL

        const metadata: AVSessionKit.AVMetadata = {
          // ... 其他字段
          mediaImage: 'https://example.com/cover.jpg'
        };
        

        方式二:下载图片并转换为 PixelMap

        如果需要更高质量的展示效果,可以先下载图片并转换为 PixelMap 对象:

        import { image } from '@kit.ImageKit';
        import { http } from '@kit.NetworkKit';
        
        async function downloadImageAsPixelMap(imageUrl: string): Promise<image.PixelMap | null> {
          try {
            // 1. 通过 HTTP 下载图片数据
            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. 创建图片源
            const imageSource = image.createImageSource(arrayBuffer);
            
            // 3. 创建 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;
          }
        }
        

        要在锁屏播控中心显示快进快退按钮,需要使用 video 类型的会话:

        // 使用 video 类型,播控中心将显示快退和快进按钮
        const session = await AVSessionKit.createAVSession(context, 'AudioSession', 'video');

        // 快退 15 秒
        function rewind(currentPosition: number): number {
          const REWIND_TIME = 15 * 1000;  // 15秒
          const newPosition = Math.max(0, currentPosition - REWIND_TIME);
          // 调用播放器 seek 到 newPosition
          // 同步新的播放状态到 AVSession
          return newPosition;
        }
        
        // 快进 15 秒
        function fastForward(currentPosition: number, duration: number): number {
          const FORWARD_TIME = 15 * 1000;  // 15秒
          const newPosition = Math.min(duration, currentPosition + FORWARD_TIME);
          // 调用播放器 seek 到 newPosition
          // 同步新的播放状态到 AVSession
          return newPosition;
        }
        
        // 注册快退快进监听器
        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);
        });
        

        当应用从后台(锁屏状态)切换回前台时,需要注意:

        1. 不要中断正在播放的音频:如果播放器正在播放,保持播放状态
        2. 同步最新的播放进度:确保切换时的进度是最新的
        function onAppForeground(): void {
          // 检查播放器状态
          if (playerState === 'playing' || playerState === 'paused' || playerState === 'prepared') {
            // 播放器正在工作中,不中断播放
            return;
          }
          
          // 其他恢复逻辑...
        }
        

        每次切换到新的音频时,必须重置以下状态:

        • currentTime(当前播放时间):重置为 0
        • durationTime(总时长):重置为新音频的时长
        • AVSession 播放状态:同步新的进度为 0
        // 切换歌曲时
        function switchToNewAudio(): void {
          // 1. 重置本地状态
          currentTime = 0;
          durationTime = 0;
          
          // 2. 设置新的音频 URL 并开始播放
          
          // 3. 同步元数据到 AVSession
          session.setAVMetadata({
            assetId: newAudio.id,
            title: newAudio.title,
            artist: newAudio.artist,
            duration: newAudio.duration,
            mediaImage: newAudio.coverImage
          });
          
          // 4. 同步播放状态,进度从 0 开始
          session.setAVPlaybackState({
            state: AVSessionKit.PlaybackState.PLAYBACK_STATE_PLAY,
            speed: 1.0,
            position: {
              elapsedTime: 0,
              updateTime: new Date().getTime()
            },
            duration: newAudio.duration
          });
        }
        

        原因:可能是元数据设置时机不对,或者会话未正确激活。

        解决

        1. 确保 createAVSession() 后立即调用 activate()
        2. 在播放器开始播放后立即调用 setAVMetadata()setAVPlaybackState()
        3. 添加日志确认 API 调用成功

        原因:封面图片的格式或大小不符合要求,或者下载失败。

        解决

        1. 优先使用 PixelMap 格式(比 URL 更可靠)
        2. 控制图片大小(建议 400×400 像素以内)
        3. 确保图片下载成功(添加错误处理日志)

        原因:切换歌曲时没有重置播放进度和时长,导致 AVSession 保存了旧的进度信息。

        解决

        1. 每次切换歌曲时重置 currentTime = 0durationTime = 新时长
        2. 同步 setAVPlaybackState() 时将 elapsedTime 设为 0
        3. 同步 setAVMetadata() 时将 duration 设为新音频的时长

        原因:应用从后台切回前台时,onForeground 逻辑意外地重启了播放器。

        解决

        1. onForeground 回调中先检查播放器当前状态
        2. 如果播放器正在 playing / paused / prepared,直接返回不做任何操作
        3. 只在播放器状态异常时才执行恢复逻辑

        下面是一次完整的锁屏播放交互流程:

        用户操作                     应用侧                    系统播控中心
          │                            │                            │
          ├─ 点击播放                 │                              │
          │ ─────────────────────────>│                            │
          │                            │ 1. 创建并激活 AVSession    │
          │                            │ 2. setAVMetadata()         │
          │                            │ 3. setAVPlaybackState()    │
          │                            │ ─────────────────────────> │
          │                            │                            │ 显示音频信息
          │                            │                            │ 和播放控制按钮
          │                            │                            │
          ├─ 锁屏                     │                            │
          │ ──────────────────────────┤───────────────────────────▶│
          │                            │                            │ 锁屏播控中心可见
          │                            │                            │
          │                            │                            │ 用户点击快进
          │                            │ 4. on('fastForward')       │ <───────────────────
          │                            │ <───────────────────────── │
          │                            │                            │
          │                            │ 5. 播放器 seek +15秒       │
          │                            │ 6. setAVPlaybackState()    │
          │                            │ ─────────────────────────▶ │ 更新进度条显示
          │                            │                            │
          │                            │                            │ 用户点击下一首
          │                            │ 7. on('playNext')          │ <───────────────────
          │                            │ <───────────────────────── │
          │                            │                            │
          │                            │ 8. 切换音频 + 重置进度     │
          │                            │ 9. setAVMetadata()         │
          │                            │ 10. setAVPlaybackState()   │
          │                            │ ─────────────────────────▶ │ 显示新音频信息
          │                            │                            │

        实现 HarmonyOS 锁屏音频播放的核心要点:

        1. 正确配置权限和后台模式:确保应用在后台可以继续播放
        2. 创建和管理 AVSession 生命周期:与播放状态保持一致
        3. 及时同步元数据和播放状态:让锁屏播控中心展示正确的信息
        4. 监听并响应系统播控命令:实现完整的双向交互
        5. 合理管理前后台切换和歌曲切换:避免状态错乱和播放中断

        通过本文介绍的方法,你可以实现一个体验流畅、与系统播控中心完美集成的音频播放功能。

        参考文档

        • HarmonyOS 官方文档 – AVSession Kit
        • HarmonyOS 官方文档 – 媒体会话接入场景

        到此这篇关于HarmonyOS锁屏音频播放功能完整实现步骤的文章就介绍到这了,更多相关HarmonyOS锁屏音频播放内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

        您可能感兴趣的文章:

        • 鸿蒙HarmonyOS视频播放的实现
        • HarmonyOS Next音乐播放器项目实现代码

        站内搜索