2天时间,聊今年最热的 Agent、上下文工程、AI 产品创新等话题。2025 年最后一场~ 了解详情
写点什么

【HarmonyOS- 媒体技术 -AVPlayer】手把手教你用 AVPlayer 实现流媒体播放 (ArkTS 详解)

  • 2025-11-03
    北京
  • 本文字数:12949 字

    阅读完需:约 42 分钟

【HarmonyOS-媒体技术-AVPlayer】手把手教你用 AVPlayer 实现流媒体播放(ArkTS 详解)

 2025 年最新实战指南|从零搭建稳定、流畅的直播/点播播放器


一句话总结

在 HarmonyOS 中,使用 AVPlayer 播放流媒体,不是“能播就行”,而是要“稳、准、快、可控”。本文带你掌握从创建到释放的全链路操作,覆盖 HLS/DASH/FLV 等主流协议,支持码率切换、轨道选择、自动重试、缓冲监控等高阶能力。


一、前置准备:权限 & 环境配置

1. 添加网络权限(必须!)

在 module.json5 中添加:


{  "reqPermissions": [    {      "name": "ohos.permission.INTERNET"    }  ]}
复制代码


⚠️ 否则访问任何网络资源都会失败!


2. 引入 MediaKit 模块


import { media } from '@kit.MediaKit';
复制代码

 

推荐使用 @kit.MediaKit,它是 HarmonyOS 官方提供的多媒体核心库。


二、标准播放流程(必看!)

顺序不能乱!否则可能收不到事件、无法播放


async avSetupStreamingMediaVideo() {    if (this.context == undefined) return;    // 创建avPlayer实例对象。    this.avPlayer = await media.createAVPlayer();
    // 创建状态机变化回调函数。    await this.setAVPlayerCallback((avPlayer: media.AVPlayer) => {      this.percent = avPlayer.width / avPlayer.height;  // 计算并保存视频的宽高比      this.setVideoWH();  // 调用方法更新视频显示区域的宽高      this.durationTime = this.getDurationTime();  // 获取视频总时长      setInterval(() => { // 更新当前时间。        if (!this.isSwiping) {          this.currentTime = this.getCurrentTime();        }      }, SET_INTERVAL);    });
    // 设置播放资源。    this.avPlayer.url = "http://media.iyuns.top:1000/http/720p_1m.mp4";   //开始播放    avPlay(): void {      if (this.avPlayer) {        try {          this.avPlayer.play();        } catch (e) {          console.error(`${this.tag}: avPlay = ${JSON.stringify(e)}`);        }      }    }
复制代码



三、核心监听事件详解(缺一不可)


事件

作用

说明

stateChange

监听播放器状态变化

必要事件,监听播放器的state属性改变。

需要播放器在idle状态下、未调用设置资源接口前完成设置监听,若在调用设置资源接口后再设置监听,可能导致无法收到资源设置过程中上报的stateChange事件。

error

捕获播放错误

网络异常、格式不支持、URL无效等,需要播放器在idle状态下、未调用设置资源接口前完成设置监听,若在调用设置资源接口后再设置监听,可能导致无法收到资源设置过程中上报的error事件。

durationUpdate

获取总时长

监听进度条长度,刷新资源时长。

timeUpdate

实时更新播放进度

监听进度条当前位置,刷新当前时间。

bufferingUpdate

监控缓冲状态

监听网络播放缓冲信息,上报缓冲百分比以及缓存播放进度。

seekDone

seek 跳转完成通知

监听seek()请求完成情况。

当使用seek()跳转到指定播放位置后,如果seek操作成功,将上报该事件。

speedDone

倍速设置完成通知

监听setSpeed()请求完成情况。

当使用setSpeed()设置播放倍速后,如果setSpeed操作成功,将上报该事件。

volumeChange

音量调节完成反馈

监听setVolume()请求完成情况。

当使用setVolume()调节播放音量后,如果setVolume操作成功,将上报该事件。

audioInterrupt

监听音频焦点切换信息

搭配属性audioInterruptMode使用。

如果当前设备存在多个音频正在播放,音频焦点被切换(即播放其他媒体如通话等)时将上报该事件,应用可以及时处理。



示例:监听播放器状态变化和监听播放时间


// 状态机变化回调函数。    this.avPlayer.on('stateChange', async (state, reason) => {      if (this.avPlayer == null) {        console.info(`${this.tag}: avPlayer has not init on state change`);        return;      }   // 时间上报监听函数。    this.avPlayer.on('timeUpdate', (time: number) => {      this.currentTime = time;    });
复制代码



四、主流协议支持一览表


协议

是否支持

典型URL 示例

重点适用场景

HLS

✅ 支持

https://xxx/index.m3u8

直播、点播、CDN 分发、自适应码率、DRM 加密

DASH

✅ 支持

https://xxx.mpd

直播、点播、CDN 分发、自适应码率、DRM 加密

HTTP/HTTPS

✅ 支持

https://xxx.mp4

点播、短片

HTTP-FLV

✅ 支持

https://xxx.flv

低延迟直播(如游戏推流)

✅ 所有协议均支持 setSource() 直接接入,无需额外封装。


五、高阶功能实战(让你的播放器“聪明”起来)

 1. 流媒体缓冲状态

当下载速率低于片源的码率时,会出现卡顿。此时,播放器检测到缓冲区数据不足,会先缓冲一些数据再播放,避免连续卡顿。一次卡顿对应的缓冲事件上报过程为:BUFFERING_START-> BUFFERING_PERCENT 0 -> ... -> BUFFERING_PERCENT 100 -> BUFFERING_END。CACHED_DURATION 在卡顿过程和播放过程中都会持续上报,直至下载至资源末尾。


import { media } from '@kit.MediaKit';// 类成员定义avPlayerprivate avPlayer: media.AVPlayer | null = null;
// 创建avPlayer实例对象。this.avPlayer = await media.createAVPlayer();// 监听当前bufferingUpdate缓冲状态。this.avPlayer.on('bufferingUpdate', (infoType : media.BufferingInfoType, value : number) => {  console.info(`AVPlayer bufferingUpdate, infoType is ${infoType}, value is ${value}.`);})
复制代码

 

适用于直播、弱网环境下保障连续播放。


2. HLS 多码率切换(自定义清晰度)

当前流媒体 HLS 协议流支持多码率播放,默认情况下,播放器会根据网络下载速度选择合适的码率。

通过on('availableBitrates')监听当前 HLS 协议流可用的码率。如果监听的码率列表长度为 0,则不支持设置指定码率。


mport { media } from '@kit.MediaKit';// 类成员定义avPlayerprivate avPlayer: media.AVPlayer | null = null;
// 创建avPlayer实例对象。this.avPlayer = await media.createAVPlayer();// 监听当前HLS协议流可用的码率。this.avPlayer.on('availableBitrates', (bitrates: Array<number>) => {  console.info('availableBitrates called, and availableBitrates length is: ' + bitrates.length);})
复制代码


通过setBitrate接口设置播放码率。若用户设置的码率不在可用码率中,播放器将选择最小且最接近的码率。该接口只能在 prepared/playing/paused/completed 状态下调用,可通过监听bitrateDone事件确认是否生效。


mport { media } from '@kit.MediaKit';// 类成员定义avPlayerprivate avPlayer: media.AVPlayer | null = null;
// 创建avPlayer实例对象。this.avPlayer = await media.createAVPlayer();// 监听当前HLS协议流可用的码率。this.avPlayer.on('availableBitrates', (bitrates: Array<number>) => {  console.info('availableBitrates called, and availableBitrates length is: ' + bitrates.length);})
复制代码

 

可配合 UI 提供“清晰度选择”按钮。


3. DASH 起播策略设置(首帧更快加载)

为了保证在弱网环境下的播放体验,AVPlayer 将默认选择最低的视频分辨率开始播放,随后依据网络状况自动调整。开发者可以根据具体需求,自定义 DASH 视频的起播策略,包括设定视频的宽度、高度以及色彩格式等参数。


// 自定义起播分辨率:1920×1080import { media } from '@kit.MediaKit';
let mediaSource : media.MediaSource = media.createMediaSourceWithUrl("http://test.cn/dash/aaa.mpd",  {"User-Agent" : "User-Agent-Value"});let playbackStrategy : media.PlaybackStrategy = {preferredWidth: 1920, preferredHeight: 1080};this.avPlayer.setMediaSource(mediaSource, playbackStrategy);
复制代码


 弱网环境下优先加载低码率,提升首帧速度。


4. DASH 音视频轨道切换(手动选清晰度/语言)

DASH 流媒体资源包含多路不同分辨率、码率、采样率、编码格式的音频、视频及字幕资源。默认情况下,AVPlayer 会依据网络状况自动切换不同码率的视频轨道。开发者可根据需求选择指定的音视频轨道播放,此时自适应码率切换策略将失效。

 

 调用getTrackDescription获取所有音视频轨道列表。开发者可根据实际需求,基于MediaDescription各字段信息,确定目标轨道索引。


// 以获取1080p视频轨道索引为例。import { media } from '@kit.MediaKit';import { BusinessError } from '@kit.BasicServicesKit';public videoTrackIndex: number = 0;// 类成员定义avPlayerprivate avPlayer: media.AVPlayer | null = null;
// 创建avPlayer实例对象。this.avPlayer = await media.createAVPlayer();this.avPlayer.getTrackDescription((error: BusinessError, arrList: Array<media.MediaDescription>) => {  if (arrList != null) {    for (let i = 0; i < arrList.length; i++) {      let propertyIndex: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_TRACK_INDEX];      let propertyType: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_TRACK_TYPE];      let propertyWidth: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_WIDTH];      let propertyHeight: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_HEIGHT];      if (propertyType == media.MediaType.MEDIA_TYPE_VID && propertyWidth == 1920 && propertyHeight == 1080) {        this.videoTrackIndex = parseInt(propertyIndex?.toString()); // 获取1080p视频轨道索引。      }    }  } else {    console.error(`getTrackDescription fail, error:${error}`);  }});
复制代码


在音视频播放过程中调用selectTrack选择对应的音视频轨道,或者调用deselectTrack取消选择的音视频轨道。


import { media } from '@kit.MediaKit';public videoTrackIndex: number = 0;    // 类成员定义avPlayerprivate avPlayer: media.AVPlayer | null = null;
// 创建avPlayer实例对象。this.avPlayer = await media.createAVPlayer();// 切换至目标视频轨道。this.avPlayer.selectTrack(this.videoTrackIndex);// 取消选择目标视频轨道。// this.avPlayer.deselectTrack(this.videoTrackIndex);
复制代码

 

适合教育类、影视类 App,让用户自由选择画质/字幕/语音。


六、常见坑位 & 解决方案(避雷手册)


问题

原因

解法

play() 无效,无反应

没等 prepared 状态

必须监听 stateChange,在 prepared 后调 play()

durationUpdate 不触发

未调用 prepare() 或资源无效

检查URL、网络、格式

字幕不显示

路径错误或未加载

 addSubtitleFromFd() 加载 .srt 文件

无法跳转(seek)

未监听 seekDone 或资源不支持

检查是否为分段资源(如HLS)

多次播放报错

未释放旧实例

播放实例不使用后,调 release()及时释放。

音量调节无效

未监听 volumeChange 或未调 setVolume()

检查调用顺序和参数



七、一个简单的开发实例


import { media } from '@kit.MediaKit';import { emitter } from '@kit.BasicServicesKit';import { display } from '@kit.ArkUI';
const TIME_ONE = 60000; // 1分钟的毫秒数。const TIME_TWO = 1000;  // 1秒的毫秒数。const SET_INTERVAL = 1000; // 每秒更新一次当前播放时间。const SPEED_ZERO: number = 0; // 对应1.00x。const SPEED_ONE: number = 1;  // 对应1.25x。const SPEED_TWO: number = 2;  // 对应1.75x。const SPEED_THREE: number = 3; // 对应2.00x。const PROPORTION: number = 0.99;let innerEventFalse: emitter.InnerEvent = {  eventId: 1,  priority: emitter.EventPriority.HIGH};let innerEventTrue: emitter.InnerEvent = {  eventId: 2,  priority: emitter.EventPriority.HIGH};
let innerEventWH: emitter.InnerEvent = {  eventId: 3,  priority: emitter.EventPriority.HIGH};@Entry@Componentstruct Index {  private avPlayer: media.AVPlayer | null = null;  private context: Context | undefined = undefined;  public videoTrackIndex: number = 0;  public bitrate: number = 0;  @State durationTime: number = 0;  @State currentTime: number = 0;  @State percent: number = 0;  @State isSwiping: boolean = false;  @State tag: string = 'StreamingMedia';  private surfaceId: string = '';  @State speedSelect: number = -1;  public intervalID: number = -1;  @State windowWidth: number = 300;  @State windowHeight: number = 300;  @State surfaceW: number | null = null;  @State surfaceH: number | null = null;  @State isPaused: boolean = true;  @State XComponentFlag: boolean = false;  getDurationTime(): number {    return this.durationTime;  }
  getCurrentTime(): number {    return this.currentTime;  }
  timeConvert(time: number): string {    let min: number = Math.floor(time / TIME_ONE);    let second: string = ((time % TIME_ONE) / TIME_TWO).toFixed(0);    // return `${min}:${(+second < TIME_THREE ? '0' : '') + second}`;    second = second.padStart(2, '0');    return `${min}:${second}`;  }
  async msleepAsync(ms: number): Promise<boolean> {    return new Promise((resolve, reject) => {      setTimeout(() => {        resolve(true)      }, ms)    })  }
  async avSetupStreamingMediaVideo() {    if (this.context == undefined) return;    // 创建avPlayer实例对象。    this.avPlayer = await media.createAVPlayer();
    // 创建状态机变化回调函数。    await this.setAVPlayerCallback((avPlayer: media.AVPlayer) => {      this.percent = avPlayer.width / avPlayer.height;      this.setVideoWH();      this.durationTime = this.getDurationTime();      setInterval(() => { // 更新当前时间。        if (!this.isSwiping) {          this.currentTime = this.getCurrentTime();        }      }, SET_INTERVAL);    });
    // 情况一:HTTP视频播放。    this.avPlayer.url = "http://media.iyuns.top:1000/http/720p_1m.mp4";
    // 情况二:HLS视频播放。    // this.avPlayer.url = "http://media.iyuns.top:1000/720-270-480.m3u8";
    // 情况三:DASH视频播放。    // this.avPlayer.url = "http://media.iyuns.top:1000/dash/720p/720-1/720-1.mpd";
    // 情况四:通过setMediaSource设置自定义头域及播放优选参数实现初始播放参数设置,以流媒体HTTP点播为例。    /*    let mediaSource : media.MediaSource = media.createMediaSourceWithUrl("http://media.iyuns.top:1000/http/720p_1m.mp4", {"":""});    // 设置播放策略,设置为缓冲区数据为20s。    let playbackStrategy : media.PlaybackStrategy = {preferredBufferDuration: 20};    // 为avPlayer设置媒体来源和播放策略。    this.avPlayer.setMediaSource(mediaSource, playbackStrategy);    * */
    // 情况五:HLS切码率。    /*    this.avPlayer.url = "https://upftimae.dailyworkout.cn/videos/course/c800f81a209b5ee7891f1128ed301db/4/master.m3u8";    let bitrate: number = 0;    // 监听当前HLS协议流可用的码率。    this.avPlayer.on('availableBitrates', (bitrates: Array<number>) => {      console.info('availableBitrates called, and availableBitrates length is: ' + bitrates.length);      this.bitrate = bitrates[0]; // 保存需要切换的码率。    })    // 监听码率设置是否生效。    this.avPlayer.on('bitrateDone', (bitrate: number) => {      console.info('bitrateDone called, and bitrate value is: ' + bitrate);    })    * */
    // 情况六:DASH切换音视频轨道。    /*    this.avPlayer.url = "http://poster-inland.hwcloudtest.cn/AiMaxEngine/ProductionEnvVideo/DASH_SDR_MultiAudio_MultiSubtitle_yinHeHuWeiDui3/DASH_SDR_MultiAudio_MultiSubtitle_yinHeHuWeiDui3.mpd";    //    this.avPlayer.getTrackDescription((error: BusinessError, arrList: Array<media.MediaDescription>) => {      if (arrList != null) {        for (let i = 0; i < arrList.length; i++) {          let propertyIndex: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_TRACK_INDEX];          let propertyType: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_TRACK_TYPE];          let propertyWidth: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_WIDTH];          let propertyHeight: Object = arrList[i][media.MediaDescriptionKey.MD_KEY_HEIGHT];          if (propertyType == media.MediaType.MEDIA_TYPE_VID && propertyWidth == 1920 && propertyHeight == 1080) {            this.videoTrackIndex = parseInt(propertyIndex.toString()); // 获取1080p视频轨道索引。          }        }      } else {        console.error(`getTrackDescription fail, error:${error}`);      }    });    * */  }
  // HLS切换码率。  changeBitrate(bitrate: number) {    if (this.avPlayer == null) {      return;    }    // 设置播放码率。    try {      this.avPlayer.setBitrate(bitrate);    } catch (error) {      console.error(`${this.tag}: setBitrate failed, error message is = ${JSON.stringify(error.message)}`);    }  }
  // DASH切换音视频轨道。  changeTrack(track: number) {    if (this.avPlayer == null) {      return;    }    // 切换至目标视频轨道。    try {      this.avPlayer.selectTrack(track);    } catch (error) {      console.error(`${this.tag}: selectTrack failed, error message is = ${JSON.stringify(error.message)}`);    }    // 取消选择目标视频轨道。    /*    try {      this.avPlayer.deselectTrack(track);    } catch (error) {      console.error(`${this.tag}: deselectTrack failed, error message is = ${JSON.stringify(error.message)}`);    }    * */  }
  avPlay(): void {    if (this.avPlayer) {      try {        this.avPlayer.play();      } catch (e) {        console.error(`${this.tag}: avPlay = ${JSON.stringify(e)}`);      }    }  }
  avPause(): void {    if (this.avPlayer) {      try {        this.avPlayer.pause();        console.info(`${this.tag}: avPause==`);      } catch (e) {        console.error(`${this.tag}: avPause== ${JSON.stringify(e)}`);      }    }  }
  async avSeek(seekTime: number, mode: SliderChangeMode): Promise<void> {    if (this.avPlayer) {      try {        console.info(`${this.tag}: videoSeek  seekTime== ${seekTime}`);        this.avPlayer.seek(seekTime, 2);        this.currentTime = seekTime;      } catch (e) {        console.error(`${this.tag}: videoSeek== ${JSON.stringify(e)}`);      }    }  }
  avSetSpeed(speed: number): void {    if (this.avPlayer) {      try {        this.avPlayer.setSpeed(speed);        console.info(`${this.tag}: avSetSpeed enum ${speed}`);      } catch (e) {        console.error(`${this.tag}: avSetSpeed == ${JSON.stringify(e)}`);      }    }  }
  // 注册avplayer回调函数。  async setAVPlayerCallback(callback: (avPlayer: media.AVPlayer) => void, vType?: number): Promise<void> {    // seek操作结果回调函数。    if (this.avPlayer == null) {      console.error(`${this.tag}: avPlayer has not init!`);      return;    }    this.avPlayer.on('seekDone', (seekDoneTime) => {      console.info(`${this.tag}: setAVPlayerCallback AVPlayer seek succeeded, seek time is ${seekDoneTime}`);    });    this.avPlayer.on('speedDone', (speed) => {      console.info(`${this.tag}: setAVPlayerCallback AVPlayer speedDone, speed is ${speed}`);    });    // error回调监听函数,当avPlayer在操作过程中出现错误时调用reset接口触发重置流程。    this.avPlayer.on('error', (err) => {      console.error(`${this.tag}: setAVPlayerCallback Invoke avPlayer failed ${JSON.stringify(err)}`);      if (this.avPlayer == null) {        console.error(`${this.tag}: avPlayer has not init on error`);        return;      }      this.avPlayer.reset();    });    // 状态机变化回调函数。    this.avPlayer.on('stateChange', async (state, reason) => {      if (this.avPlayer == null) {        console.info(`${this.tag}: avPlayer has not init on state change`);        return;      }      switch (state) {        case 'idle': // 成功调用reset接口后触发该状态机上报。          console.info(`${this.tag}: setAVPlayerCallback AVPlayer state idle called.`);          break;        case 'initialized': // avplayer 设置播放源后触发该状态上报。          console.info(`${this.tag}: setAVPlayerCallback AVPlayer state initialized called.`);          if (this.surfaceId) {            this.avPlayer.surfaceId = this.surfaceId; // 设置显示画面,当播放的资源为纯音频时无需设置。            console.info(`${this.tag}: setAVPlayerCallback this.avPlayer.surfaceId = ${this.avPlayer.surfaceId}`);            this.avPlayer.prepare();          }          break;        case 'prepared': // prepare调用成功后上报该状态机。          console.info(`${this.tag}: setAVPlayerCallback AVPlayer state prepared called.`);          this.avPlayer.on('bufferingUpdate', (infoType: media.BufferingInfoType, value: number) => {            console.info(`${this.tag}: bufferingUpdate called, infoType value: ${infoType}, value:${value}}`);          })          this.durationTime = this.avPlayer.duration;          this.currentTime = this.avPlayer.currentTime;          this.avPlayer.play(); // 调用播放接口开始播放。          console.info(`${this.tag}:            setAVPlayerCallback speedSelect: ${this.speedSelect}, duration: ${this.durationTime}`);          if (this.speedSelect != -1) {            switch (this.speedSelect) {              case SPEED_ZERO:                this.avSetSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X);                break;              case SPEED_ONE:                this.avSetSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_25_X);                break;              case SPEED_TWO:                this.avSetSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_75_X);                break;              case SPEED_THREE:                this.avSetSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X);                break;            }          }          callback(this.avPlayer);          break;        case 'playing': // play成功调用后触发该状态机上报。          console.info(`${this.tag}: setAVPlayerCallback AVPlayer state playing called.`);          if (this.intervalID != -1) {            clearInterval(this.intervalID)          }          this.intervalID = setInterval(() => { // 更新当前时间。            AppStorage.setOrCreate('durationTime', this.durationTime);            AppStorage.setOrCreate('currentTime', this.currentTime);          }, 100);          let eventDataTrue: emitter.EventData = {            data: {              'flag': true            }          };          let innerEventTrue: emitter.InnerEvent = {            eventId: 2,            priority: emitter.EventPriority.HIGH          };          emitter.emit(innerEventTrue, eventDataTrue);          break;        case 'completed': // 播放结束后触发该状态机上报。          console.info(`${this.tag}: setAVPlayerCallback AVPlayer state completed called.`);          let eventDataFalse: emitter.EventData = {            data: {              'flag': false            }          };          let innerEvent: emitter.InnerEvent = {            eventId: 1,            priority: emitter.EventPriority.HIGH          };          emitter.emit(innerEvent, eventDataFalse);          if (this.intervalID != -1) {            clearInterval(this.intervalID)          }          this.avPlayer.off('bufferingUpdate')          AppStorage.setOrCreate('currentTime', this.durationTime);          break;        case 'released':          console.info(`${this.tag}: setAVPlayerCallback released called.`);          break        case 'stopped':          console.info(`${this.tag}: setAVPlayerCallback AVPlayer state stopped called.`);          break        case 'error':          console.error(`${this.tag}: setAVPlayerCallback AVPlayer state error called.`);          break        case 'paused':          console.info(`${this.tag}: setAVPlayerCallback AVPlayer state paused called.`);          break        default:          console.info(`${this.tag}: setAVPlayerCallback AVPlayer state unknown called.`);          break;      }    });    // 时间上报监听函数。    this.avPlayer.on('timeUpdate', (time: number) => {      this.currentTime = time;    });  }
  aboutToAppear() {    this.windowWidth = display.getDefaultDisplaySync().width;    this.windowHeight = display.getDefaultDisplaySync().height;    if (this.percent >= 1) { // 横向视频。      this.surfaceW = Math.round(this.windowWidth * PROPORTION);      this.surfaceH = Math.round(this.surfaceW / this.percent);    } else { // 纵向视频。      this.surfaceH = Math.round(this.windowHeight * PROPORTION);      this.surfaceW = Math.round(this.surfaceH * this.percent);    }    this.isPaused = true;    this.context = this.getUIContext().getHostContext();  }
  aboutToDisappear() {    if (this.avPlayer == null) {      console.info(`${this.tag}: avPlayer has not init aboutToDisappear`);      return;    }    this.avPlayer.release((err) => {      if (err == null) {        console.info(`${this.tag}: videoRelease release success`);      } else {        console.error(`${this.tag}: videoRelease release failed, error message is = ${JSON.stringify(err.message)}`);      }    });    emitter.off(innerEventFalse.eventId);  }
  onPageHide() {    this.avPause();    this.isPaused = false;  }
  onPageShow() {    emitter.on(innerEventTrue, (res: emitter.EventData) => {      if (res.data) {        this.isPaused = res.data.flag;        this.XComponentFlag = res.data.flag;      }    });    emitter.on(innerEventFalse, (res: emitter.EventData) => {      if (res.data) {        this.isPaused = res.data.flag;      }    });    emitter.on(innerEventWH, (res: emitter.EventData) => {      if (res.data) {        this.windowWidth = res.data.width;        this.windowHeight = res.data.height;        this.setVideoWH();      }    });  }
  setVideoWH(): void {    if (this.percent >= 1) { // 横向视频。      this.surfaceW = Math.round(this.windowWidth * PROPORTION);      this.surfaceH = Math.round(this.surfaceW / this.percent);    } else { // 纵向视频。      this.surfaceH = Math.round(this.windowHeight * PROPORTION);      this.surfaceW = Math.round(this.surfaceH * this.percent);    }  }
  @Builder  CoverXComponent() {    // ...  }
  build() {    // ...  }}
复制代码



八、立即行动,开启你的音视频播放开发之旅!

 点击了解完整开发示例与 API 文档HarmonyOS AVPlayer 官方文档



加入 HarmonyOS 社区,共创未来!

我们诚邀广大开发者一起参与 HarmonyOS 技术生态建设,共建更开放、更智能的未来世界!

 加入开发者社区,获取最新资讯和技术支持HarmonyOS 官方社区


如果你觉得这篇指南有用,欢迎点赞、收藏、分享给更多开发者! 让 AVPlayer 成为你开发路上的得力助手,开启你的音视频播放新纪元! 



2025-11-03 11:0517

评论

发布
暂无评论

HarmonyOS开发实战:Network Kit实现文档云同步与协作

huafushutong

阿里巴巴Java架构师岗面试题(正式版)!

程序员高级码农

java 程序员‘

harmony-utils之CharUtil,字符工具类

桃花镇童长老

HarmonyOS ArkTS

HarmonyOS开发实战:Remote Communication Kit实现远程文档协作

huafushutong

通义灵码 Agent+MCP:打造自动化菜品推荐平台,从需求到部署实现全流程创新

阿里巴巴云原生

阿里云 通义灵码 MCP

通义灵码 Agent+MCP:打造自动化菜品推荐平台,从需求到部署实现全流程创新

阿里云云效

阿里云 通义灵码

夏至之日,共赴实时 AI 之约:RTE Open Day@AGI Playground 2025 回顾

声网

harmony-utils之AssetUtil,关键资产存储服务工具类

桃花镇童长老

HarmonyOS ArkTS

harmony-utils之AuthUtil,生物认证相关工具类

桃花镇童长老

ArkTS HarmonyOS NEXT

harmony-utils之CacheUtil,缓存工具类

桃花镇童长老

HarmonyOS ArkTS

harmony-utils之CrashUtil,异常相关工具类

桃花镇童长老

HarmonyOS ArkTS

HarmonyOS开发实战:Telephony Kit实现文档紧急联系人联动

huafushutong

Fellou Windows版上线,实测生成AI日报+自动发小红书+数据可视化

阿星AI工作室

AI AI应用 AI工具 AI浏览器

harmony-utils之DateUtil,日期工具类

桃花镇童长老

HarmonyOS ArkTS

harmony-utils之DeviceUtil,设备相关工具类

桃花镇童长老

HarmonyOS ArkTS

harmony-utils之DialogUtil,弹窗工具类

桃花镇童长老

HarmonyOS ArkTS

HarmonyOS开发实战:Network Boost Kit优化文档云同步体验

huafushutong

鸿蒙开发实战:Sensor Service Kit实现智能文档阅读模式

huafushutong

为什么 IoTDB 选择 Java?权衡之后的最优解

Apache IoTDB

harmony-utils之AppUtil,APP相关工具类

桃花镇童长老

HarmonyOS ArkTS

HarmonyOS开发实战:Performance Analysis Kit实现文档编辑器性能调优

huafushutong

harmony-utils之DisplayUtil,屏幕相关工具类

桃花镇童长老

HarmonyOS ArkTS

HarmonyOS开发实战:Service Collaboration Kit实现文档服务智能联动

huafushutong

语音 AI 转录应用 Wispr Flow 融资 3000 万美元;饿了么骑手 AI 助手:支持语音唤醒,会主动发起询问丨日报

声网

鸿蒙开发实战:Multimodal Awareness Kit实现智能文档交互体验

huafushutong

鸿蒙开发实战:NearLink Kit实现文档近场极速互传

huafushutong

鸿蒙开发实战:Online Authentication Kit实现文档服务安全认证

huafushutong

鸿蒙开发笔记:Status Bar Extension Kit实现文档编辑器状态栏定制

huafushutong

harmony-utils之ArrayUtil,集合工具类

桃花镇童长老

HarmonyOS ArkTS

HarmonyOS企业级开发实战:MDM Kit实现办公文档的安全管控

huafushutong

鸿蒙开发实战:Pen Kit实现手写文档批注功能

huafushutong

【HarmonyOS-媒体技术-AVPlayer】手把手教你用 AVPlayer 实现流媒体播放(ArkTS 详解)_HarmonyOS_HarmonyOS_InfoQ精选文章