HarmonyOS鸿蒙Next中创建AVSession之后在通知栏没有显示

HarmonyOS鸿蒙Next中创建AVSession之后在通知栏没有显示 在接入AVSession之后,在通知栏没有显示音频相关信息,想实现例如音乐播放器那种控制模块,显示到通知栏。下面是我的demo

import { BusinessError } from '@kit.BasicServicesKit';
import { avSession, avSession as AVSessionManager } from '@kit.AVSessionKit';

@Entry
@Component
struct Index {
  aboutToAppear(): void {
    createSession()
  }

  build() {
    Column() {
      Button('开启音频通知栏')
        .onClick(() => {
          setSessionInfo()
        })
    }
  }
}

// 开始创建并激活媒体会话
// 创建session
let context: Context = getContext(this);
async function createSession() {
  let type: AVSessionManager.AVSessionType = 'audio';
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
  await session.activate();
  console.info(`session create done : sessionId : ${session.sessionId}`);
}

async function setSessionInfo() {
  // 假设已经创建了一个session,如何创建session可以参考之前的案例
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', 'audio');
  // 播放器逻辑··· 引发媒体信息与播放状态的变更
  // 设置必要的媒体信息
  let metadata: AVSessionManager.AVMetadata = {
    assetId: '0', // 由应用指定,用于标识应用媒体库里的媒体
    title: 'TITLE',
    mediaImage: 'IMAGE',
    artist: 'ARTIST'
  };
  session.setAVMetadata(metadata).then(() => {
    console.info(`SetAVMetadata successfully`);
  }).catch((err: BusinessError) => {
    console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
  });
  // 简单设置一个播放状态 - 暂停 未收藏
  let playbackState: AVSessionManager.AVPlaybackState = {
    state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PAUSE,
    isFavorite: false
  };
  session.setAVPlaybackState(playbackState, (err) => {
    if (err) {
      console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
    } else {
      console.info(`SetAVPlaybackState successfully`);
    }
  });
  // 设置一个播放列表
  let queueItemDescription_1: AVSessionManager.AVMediaDescription = {
    assetId: '001',
    title: 'music_name',
    subtitle: 'music_sub_name',
    description: 'music_description',
    mediaImage: "PIXELMAP_OBJECT",
    extras: {'extras':'any'}
  };
  let queueItem_1: AVSessionManager.AVQueueItem = {
    itemId: 1,
    description: queueItemDescription_1
  };
  let queueItemDescription_2: AVSessionManager.AVMediaDescription = {
    assetId: '002',
    title: 'music_name',
    subtitle: 'music_sub_name',
    description: 'music_description',
    mediaImage: "PIXELMAP_OBJECT",
    extras: {'extras':'any'}
  };
  let queueItem_2: AVSessionManager.AVQueueItem = {
    itemId: 2,
    description: queueItemDescription_2
  };
  let queueItemsArray = [queueItem_1, queueItem_2];
  session.setAVQueueItems(queueItemsArray).then(() => {
    console.info(`SetAVQueueItems successfully`);
  }).catch((err: BusinessError) => {
    console.error(`Failed to set AVQueueItem, error code: ${err.code}, error message: ${err.message}`);
  });
  // 设置媒体播放列表名称
  let queueTitle = 'QUEUE_TITLE';
  session.setAVQueueTitle(queueTitle).then(() => {
    console.info(`SetAVQueueTitle successfully`);
  }).catch((err: BusinessError) => {
    console.info(`Failed to set AVQueueTitle, error code: ${err.code}, error message: ${err.message}`);
  });
}

更多关于HarmonyOS鸿蒙Next中创建AVSession之后在通知栏没有显示的实战教程也可以访问 https://www.itying.com/category-93-b0.html

4 回复

AVSession播控中心,您可以参考示例:https://gitee.com/harmonyos_samples/media-provider,您想实现音乐播放器控制台在通知栏显示,需要做一个通知,在通知上添加几个按钮。当前通知可以通过设置actionButtons设置按键,规格当前最多三个按钮。

请参考如下链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-inner-notification-notificationrequest-V5

您截图这种,可以使用AVPlayer+AVSession实现,AVPlayer文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-media-V5#avplayer9,AVSession文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-avsession-V5#avsession10,简易demo如下:

import { media } from '@kit.MediaKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { avSession } from '@kit.AVSessionKit';

const TAG = 'AVPlayerDemo';

@Entry
@Component
struct AVPlayerDemo {
  private surfaceId: string = ''; // surfaceId,用于关联XComponent与视频播放器
  private mXComponentController: XComponentController = new XComponentController();
  private avPlayer: media.AVPlayer | undefined = undefined;
  private currentAVSession: avSession.AVSession | undefined = undefined;
  private curSessionId: string = '';
  private avsessionController: avSession.AVSessionController | undefined = undefined;
  private playbackState: avSession.AVPlaybackState = {
    state: avSession.PlaybackState.PLAYBACK_STATE_PLAY, // 播放状态
    position: {
      elapsedTime: 0, // 已经播放的位置,以ms为单位
      updateTime: 0, // 应用更新当前位置的时间戳,以ms为单位
    },
    speed: 1.0, // 可选,默认是1.0,播放的倍速,按照应用内支持的speed进行设置,系统不做校验
    duration: 0, // 资源的时长,以ms为单位
    loopMode: avSession.LoopMode.LOOP_MODE_SEQUENCE, // 循环模式
  };

  aboutToAppear(): void {
    // 创建avplayer
    this.initAvPlayer()
    // 初始化AVSession
    this.createAVSession();
  }

  initAvPlayer() {
    media.createAVPlayer().then((avPlayer: media.AVPlayer) => {
      this.avPlayer = avPlayer;
      this.playerCallback(this.avPlayer);
      this.avPlayer.url = 'http://fotiletest2.oss-cn-hangzhou.aliyuncs.com/f86ee6ff04f94c4d922936faedbfca06';
    })
  }

  // 注册avplayer回调函数
  playerCallback(avPlayer: media.AVPlayer) {
    avPlayer.on('timeUpdate', (time: number) => {
      if (this.currentAVSession) {
        this.playbackState.position = {
          elapsedTime: time, // 已经播放的位置,以ms为单位
          updateTime: (new Date()).getTime(), // 应用更新当前位置的时间戳,以ms为单位
        };
        this.currentAVSession.setAVPlaybackState(this.playbackState);
      }
    })

    // error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程
    avPlayer.on('error', (err: BusinessError) => {
      console.error(TAG, `Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
      avPlayer.reset(); // 调用reset重置资源,触发idle状态
    })

    // 状态机变化回调函数
    avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
      switch (state) {
        case 'idle': // 成功调用reset接口后触发该状态机上报
          console.info(TAG, 'AVPlayer state idle called.');
          break;
        case 'initialized': // avplayer 设置播放源后触发该状态上报
          console.info(TAG, 'AVPlayer state initialized called.');
          avPlayer.surfaceId = this.surfaceId;
          avPlayer.prepare();
          break;
        case 'prepared': // prepare调用成功后上报该状态机
          console.info(TAG, 'AVPlayer state prepared called.');
          await this.startAVSession();
          break;
        case 'completed': // prepare调用成功后上报该状态机
          console.info(TAG, 'AVPlayer state completed called.');
          break;
        case 'playing': // play成功调用后触发该状态机上报
          console.info(TAG, 'AVPlayer state playing called.');
          break;
        case 'paused': // pause成功调用后触发该状态机上报
          console.info(TAG, 'AVPlayer state paused called.');
          break;
        case 'stopped': // stop接口成功调用后触发该状态机上报
          console.info(TAG, 'AVPlayer state stopped called.');
          break;
        case 'released':
          console.info(TAG, 'AVPlayer state released called.');
          break;
        default:
          console.info(TAG, 'AVPlayer state unknown called.');
          break;
      }
    })
  }

  async createAVSession() {
    await avSession.createAVSession(getContext(this), 'AVPlayerDemo', 'video').then((data: avSession.AVSession) => {
      console.info(`AVPlayerDemo CreateAVSession : SUCCESS : sessionId = ${data.sessionId}`);
      this.currentAVSession = data;
      this.curSessionId = data.sessionId;
      this.setAVSessionCallback(data);
    }).catch((err: BusinessError) => {
      console.error(`AVPlayerDemo CreateAVSession BusinessError: code: ${err.code}, message: ${err.message}`);
    });
  }

  setAVSessionCallback(curAvSession: avSession.AVSession) {
    // 播放
    curAvSession.on('play', () => {
      console.info(`AVPlayerDemo AVSession on play entry`);
      this.avPlayer?.play()
    });

    // 暂停
    curAvSession.on('pause', () => {
      console.info(`AVPlayerDemo AVSession on pause entry`);
      if (this.avPlayer) {
        this.avPlayer.pause();
      }
    });

    // 停止
    curAvSession.on('stop', () => {
      console.info(`AVPlayerDemo AVSession on stop entry`);
      this.avPlayer?.stop();
    });

    // 下一个
    curAvSession.on('playNext', () => {
      console.info(`AVPlayerDemo AVSession on playNext entry`);
    });

    // 上一个
    curAvSession.on('playPrevious', () => {
      console.info(`AVPlayerDemo AVSession on playPrevious entry`);
    });
  }

  async startAVSession() {
    if (!this.currentAVSession) {
      console.error('AVPlayerDemo currentAVSession is undefined.')
      return;
    }

    let metadata: avSession.AVMetadata = this.generateAVMetadata();

    await this.currentAVSession.setAVMetadata(metadata).then(() => {
      console.info(`AVPlayerDemo SetAVMetadata successfully`);
    }).catch((err: BusinessError) => {
      console.error(`AVPlayerDemo SetAVMetadata BusinessError: code: ${err.code}, message: ${err.message}`);
    });

    this.playbackState.state = avSession.PlaybackState.PLAYBACK_STATE_PREPARE;
    this.playbackState.duration = this.avPlayer?.duration;
    this.currentAVSession.setAVPlaybackState(this.playbackState);
    this.currentAVSession.getController().then((avcontroller: avSession.AVSessionController) => {
      this.avsessionController = avcontroller;
      console.info(`AVPlayerDemo GetController : SUCCESS : sessionid : ${avcontroller.sessionId}`);
    }).catch((err: BusinessError) => {
      console.error(`AVPlayerDemo GetController BusinessError: code: ${err.code}, message: ${err.message}`);
    });

    await this.currentAVSession.activate().then(() => {
      console.info(`AVPlayerDemo Activate : SUCCESS `);
    }).catch((err: BusinessError) => {
      console.error(`AVPlayerDemo Activate BusinessError: code: ${err.code}, message: ${err.message}`);
    });
  }

  private generateAVMetadata() {
    let metadata: avSession.AVMetadata = {
      assetId: "121278",
      title: "lose yourself",
      artist: "Eminem",
      author: "ST",
      album: "Slim shady",
      writer: "ST",
      composer: "ST",
      duration: this.avPlayer?.duration, // 媒体时长,单位毫秒(ms)
      mediaImage: '', // 图片的像素数据或者图片路径地址(本地路径或网络路径)
      subtitle: "8 Mile",
      description: "Rap",
      previousAssetId: "121277",
      nextAssetId: "121279"
    };
    return metadata;
  }

  build() {
    Column({ space: 20 }) {
      XComponent({
        id: 'xComponent',
        type: XComponentType.SURFACE,
        controller: this.mXComponentController
      })
        .onLoad(() => {
          this.mXComponentController.setXComponentSurfaceRect({
            offsetX: 0,
            offsetY: 0,
            surfaceWidth: 1920,
            surfaceHeight: 1080
          });
          this.surfaceId = this.mXComponentController.getXComponentSurfaceId()
        })
        .width('100%')
        .height('800px')

      Button("播放")
        .onClick(() => {
          this.avPlayer?.play()
        })
    }
    .height('100%')
    .width('100%')
  }
}

更多关于HarmonyOS鸿蒙Next中创建AVSession之后在通知栏没有显示的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


AVSession播控中心,您可以参考示例:https://gitee.com/harmonyos_samples/media-provider,您想实现音乐播放器控制台在通知栏显示,需要做一个通知,在通知上添加几个按钮。当前通知可以通过设置actionButtons设置按键,规格当前最多三个按钮。

请参考如下链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-inner-notification-notificationrequest-V5

您截图这种,可以使用AVPlayer+AVSession实现,AVPlayer文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-media-V5#avplayer9,AVSession文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-avsession-V5#avsession10,简易demo如下:

import { media } from '[@kit](/user/kit).MediaKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
import { avSession } from '[@kit](/user/kit).AVSessionKit';

const TAG = 'AVPlayerDemo';

[@Entry](/user/Entry)
[@Component](/user/Component)
struct AVPlayerDemo {
 private surfaceId: string = ''; // surfaceId,用于关联XComponent与视频播放器
 private mXComponentController: XComponentController = new XComponentController();
 private avPlayer: media.AVPlayer | undefined = undefined;
 private currentAVSession: avSession.AVSession | undefined = undefined;
 private curSessionId: string = '';
 private avsessionController: avSession.AVSessionController | undefined = undefined;
 private playbackState: avSession.AVPlaybackState = {
   state: avSession.PlaybackState.PLAYBACK_STATE_PLAY, // 播放状态
   position: {
     elapsedTime: 0, // 已经播放的位置,以ms为单位
     updateTime: 0, // 应用更新当前位置的时间戳,以ms为单位
   },
   speed: 1.0, // 可选,默认是1.0,播放的倍速,按照应用内支持的speed进行设置,系统不做校验
   // bufferedTime: 14000, // 可选,资源缓存的时间,以ms为单位
   duration: 0, // 资源的时长,以ms为单位
   loopMode: avSession.LoopMode.LOOP_MODE_SEQUENCE, // 循环模式
 };

 aboutToAppear(): void {
   //创建avplayer
   this.initAvPlayer()
   // 初始化AVSession
   this.createAVSession();
 }

 initAvPlayer() {
   media.createAVPlayer().then((avPlayer: media.AVPlayer) => {
     this.avPlayer = avPlayer;
     this.playerCallback(this.avPlayer);
     this.avPlayer.url = 'http://fotiletest2.oss-cn-hangzhou.aliyuncs.com/f86ee6ff04f94c4d922936faedbfca06';
   })
 }

 // 注册avplayer回调函数
 playerCallback(avPlayer: media.AVPlayer) {
   avPlayer.on('timeUpdate', (time: number) => {
     if (this.currentAVSession) {
       this.playbackState.position = {
         elapsedTime: time, // 已经播放的位置,以ms为单位
         updateTime: (new Date()).getTime(), // 应用更新当前位置的时间戳,以ms为单位
       };
       this.currentAVSession.setAVPlaybackState(this.playbackState);
     }
   })

   // error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程
   avPlayer.on('error', (err: BusinessError) => {
     console.error(TAG,`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
     avPlayer.reset(); // 调用reset重置资源,触发idle状态
   })

   // 状态机变化回调函数
   avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
     switch (state) {
       case 'idle': // 成功调用reset接口后触发该状态机上报
         console.info(TAG,'AVPlayer state idle called.');
         break;
       case 'initialized': // avplayer 设置播放源后触发该状态上报
         console.info(TAG,'AVPlayer state initialized called.');
         avPlayer.surfaceId = this.surfaceId;
         avPlayer.prepare();
         break;
       case 'prepared': // prepare调用成功后上报该状态机
         console.info(TAG,'AVPlayer state prepared called.');
         await this.startAVSession();
         break;
       case 'completed': // prepare调用成功后上报该状态机
         console.info(TAG,'AVPlayer state completed called.');
         break;
       case 'playing': // play成功调用后触发该状态机上报
         console.info(TAG,'AVPlayer state playing called.');
         break;
       case 'paused': // pause成功调用后触发该状态机上报
         console.info(TAG,'AVPlayer state paused called.');
         break;
       case 'stopped': // stop接口成功调用后触发该状态机上报
         console.info(TAG,'AVPlayer state stopped called.');
         break;
       case 'released':
         console.info(TAG,'AVPlayer state released called.');
         break;
       default:
         console.info(TAG,'AVPlayer state unknown called.');
         break;
     }
   })
 }

 async createAVSession() {
   await avSession.createAVSession(getContext(this), 'AVPlayerDemo', 'video').then((data: avSession.AVSession) => {
     console.info(`AVPlayerDemo CreateAVSession : SUCCESS : sessionId = ${data.sessionId}`);
     this.currentAVSession = data;
     this.curSessionId = data.sessionId;
     this.setAVSessionCallback(data);
   }).catch((err: BusinessError) => {
     console.error(`AVPlayerDemo CreateAVSession BusinessError: code: ${err.code}, message: ${err.message}`);
   });
 }

 setAVSessionCallback(curAvSession: avSession.AVSession) {
   // 播放
   curAvSession.on('play', () => {
     console.info(`AVPlayerDemo AVSession on play entry`);
     this.avPlayer?.play()
   });

   // 暂停
   curAvSession.on('pause', () => {
     console.info(`AVPlayerDemo AVSession on pause entry`);
     if (this.avPlayer) {
       this.avPlayer.pause();
     }
   });

   // 停止
   curAvSession.on('stop', () => {
     console.info(`AVPlayerDemo AVSession on stop entry`);
     this.avPlayer?.stop();
   });

   // 下一个
   curAvSession.on('playNext', () => {
     console.info(`AVPlayerDemo AVSession on playNext entry`);
   });

   // 上一个
   curAvSession.on('playPrevious', () => {
     console.info(`AVPlayerDemo AVSession on playPrevious entry`);
   });
 }

 async startAVSession() {
   if (!this.currentAVSession) {
     console.error('AVPlayerDemo currentAVSession is undefined.')
     return;
   }

   let metadata: avSession.AVMetadata = this.generateAVMetadata();

   await this.currentAVSession.setAVMetadata(metadata).then(() => {
     console.info(`AVPlayerDemo SetAVMetadata successfully`);
   }).catch((err: BusinessError) => {
     console.error(`AVPlayerDemo SetAVMetadata BusinessError: code: ${err.code}, message: ${err.message}`);
   });

   this.playbackState.state = avSession.PlaybackState.PLAYBACK_STATE_PREPARE;
   this.playbackState.duration = this.avPlayer?.duration;
   this.currentAVSession.setAVPlaybackState(this.playbackState);

   this.currentAVSession.getController().then((avcontroller: avSession.AVSessionController) => {
     this.avsessionController = avcontroller;
     console.info(`AVPlayerDemo GetController : SUCCESS : sessionid : ${avcontroller.sessionId}`);
   }).catch((err: BusinessError) => {
     console.error(`AVPlayerDemo GetController BusinessError: code: ${err.code}, message: ${err.message}`);
   });

   await this.currentAVSession.activate().then(() => {
     console.info(`AVPlayerDemo Activate : SUCCESS `);
   }).catch((err: BusinessError) => {
     console.error(`AVPlayerDemo Activate BusinessError: code: ${err.code}, message: ${err.message}`);
   });
 }

 private generateAVMetadata() {
   let metadata: avSession.AVMetadata = {
     assetId: "121278",
     title: "lose yourself",
     artist: "Eminem",
     author: "ST",
     album: "Slim shady",
     writer: "ST",
     composer: "ST",
     duration: this.avPlayer?.duration, // 媒体时长,单位毫秒(ms)
     mediaImage: 'https://img20.360buyimg.com/img/jfs/t1/241153/31/4968/64736/65e53e56Fd3868b6e/b595d41ca8447ea4.jpg', // 图片的像素数据或者图片路径地址(本地路径或网络路径)
     subtitle: "8 Mile",
     description: "Rap",
     previousAssetId: "121277",
     nextAssetId: "121279"
   };

   return metadata;
 }

 build() {
   Column({ space: 20 }) {
     XComponent({
       id: 'xComponent',
       type: XComponentType.SURFACE,
       controller: this.mXComponentController
     })
     .onLoad(() => {
       this.mXComponentController.setXComponentSurfaceRect({
         offsetX:0,
         offsetY:0,
         surfaceWidth: 1920,
         surfaceHeight: 1080
       });
       this.surfaceId = this.mXComponentController.getXComponentSurfaceId()
     })
     .width('100%')
     .height('800px')
     Button("播放")
     .onClick(() => {
       this.avPlayer?.play()
     })
   }
   .height('100%')
   .width('100%')
 }
}

在HarmonyOS鸿蒙Next中,创建AVSession后通知栏未显示的原因可能涉及以下几点:

  • 首先,检查AVSession是否已正确初始化并启动。确保调用了AVSession.create()AVSession.activate()方法。
  • 其次,确认AVSession的元数据(如标题、艺术家、专辑等)是否已正确设置,因为通知栏显示依赖于这些信息。可以通过AVMetadata类进行设置。
  • 此外,检查权限配置,确保应用具有ohos.permission.NOTIFICATION_CONTROLLER权限,以便在通知栏显示媒体控制界面。
  • 如果以上步骤均无误,可能是系统通知栏的实现限制或Bug,需进一步排查系统日志或更新HarmonyOS版本。

在HarmonyOS鸿蒙Next中,创建AVSession后通知栏未显示,可能的原因包括:未正确设置AVSession的属性(如AVMetadataAVSessionDescriptor),或未调用setActive(true)激活会话。确保在创建AVSession时,正确配置了媒体信息(如标题、艺术家等),并调用setActive(true)。此外,检查应用的通知权限是否已开启,确保系统能够正常显示媒体控制通知。

回到顶部