09-自然壁纸实战教程-视频下载 原创 精华

万少skr
发布于 2025-7-8 15:09
浏览
0收藏

09-自然壁纸实战教程-视频下载

前言

视频下载页面的功能主要提供了视频的播放,和下载,因为下载比较耗时,所以这里还用到了多线程taskpoll来实现。

09-自然壁纸实战教程-视频下载-鸿蒙开发者社区

获取和构造播放视频数据

  @Local videoPlayerViewModel: VideoPlayerViewModel = new VideoPlayerViewModel()

  aboutToAppear() {
    // 获取传递过来的视频数据
    const param = NavigationUtils.getInstance().getParamByIndex() as VideoData
    if (param) {
      this.videoPlayerViewModel.videoData = param
      // 设置视频URL(优先使用小尺寸视频以提高流畅度)
      this.videoPlayerViewModel.setUrl(param)
    } else {
      promptAction.showToast({
        message: '未获取到视频数据',
        duration: 2000
      })
    }
  }

构造视频播放结构

09-自然壁纸实战教程-视频下载-鸿蒙开发者社区

这里用到的视频的属性和事件比较多,需要单独讲解一下。

  1. 视频组件初始化
    • 使用 Video 组件,绑定视频资源 src、视频控制器 controller 和预览图片 previewUri
    • 设置视频播放器的宽度和高度,根据是否全屏显示调整高度。
    • 设置视频的适应模式为 contain,确保视频内容完整显示。
    • 启用自动播放和系统默认控件。
  2. 事件监听
    • onStart:当视频开始播放时,将 isPlaying 状态设置为 true
    • onPause:当视频暂停时,将 isPlaying 状态设置为 false
    • onFinish:当视频播放结束时,将 isPlaying 状态设置为 false,并将当前时间 currentTime 重置为 0
    • onUpdate:实时更新当前播放时间 currentTime
    • onPrepared:当视频准备就绪后,立即开始播放,并将 isPlaying 状态设置为 true
  3. 快捷键和点击事件
    • enableAnalyzer:设置组件支持AI分析,当前支持主体识别、文字识别和对象查找等功能,支持attributeModifier动态设置属性方法。
    • enableShortcutKey:启用快捷键功能,允许用户通过键盘快捷键控制视频播放。
    • 点击视频区域时,如果视频正在播放,则暂停播放;如果视频未播放,则开始播放。
Video({
      src: this.videoPlayerViewModel.videoUrl,
      controller: this.videoPlayerViewModel.controller,
      previewUri: this.videoPlayerViewModel.videoData?.videos?.medium?.thumbnail
    })
      .width('100%')
      .height(this.videoPlayerViewModel.isFullScreen ? '100%' : '240vp')
      .objectFit(ImageFit.Contain)
      .autoPlay(true)
      .controls(true)  // 使用系统默认控件
      .onStart(() => {
        this.videoPlayerViewModel.isPlaying = true
      })
      .onPause(() => {
        this.videoPlayerViewModel.isPlaying = false
      })
      .onFinish(() => {
        this.videoPlayerViewModel.isPlaying = false
        this.videoPlayerViewModel.currentTime = 0
      })
      .onUpdate((event) => {
        this.videoPlayerViewModel.currentTime = event.time
      })
      .onPrepared((event) => {
        this.videoPlayerViewModel.duration = event.duration
        // 视频准备好后立即开始播放
        this.videoPlayerViewModel.controller.start()
        this.videoPlayerViewModel.isPlaying = true
      })
      .enableAnalyzer(true)
      .enableShortcutKey(true)
      .onClick(() => {
        if (this.videoPlayerViewModel.isPlaying) {
          this.videoPlayerViewModel.controller.pause()
        } else {
          this.videoPlayerViewModel.controller.start()
        }
      })

视频信息

视频信息结构就是常规的布局,这里就不体现核心代码了。

09-自然壁纸实战教程-视频下载-鸿蒙开发者社区

下载视频

09-自然壁纸实战教程-视频下载-鸿蒙开发者社区

下载视频是这个项目中比较有意思的功能,因为是使用了多线程+下载的+保存到相册的能力,这里的主要逻辑是

下载视频的主要逻辑

主要逻辑:

  1. 检查下载状态:首先检查是否已有下载任务正在进行中,如果有则提示用户已有下载任务正在进行中并返回。
  2. 获取上下文和路径:获取应用的上下文对象和缓存目录路径,用于保存下载的视频文件。
  3. 配置下载任务:设置下载任务的配置信息,包括下载动作、视频URL、保存路径、进度条显示、覆盖文件、网络类型和任务标题等。
  4. 创建下载任务:使用request.agent.create方法创建下载任务,并处理创建成功或失败的情况。
  5. 开始下载任务:在下载任务创建成功后,调用task.start方法开始下载,并处理下载开始、进度更新、下载完成和下载失败的情况。
  6. 更新进度:在下载过程中,通过task.on('progress', ...)事件更新下载进度。
  7. 下载完成后的操作:在下载完成后,调用task.on('completed', ...)事件,将视频文件保存到相册,并更新下载状态和进度。
  8. 错误处理:在创建下载任务或下载过程中出现错误时,通过task.on('failed', ...)事件和catch块处理错误,并更新下载状态和进度。
  9. 重置进度条:在下载完成后,设置一个延迟后重置下载进度的操作,以确保用户界面能够正确反映下载状态。
  // 下载视频
  downFile() {
    if (this.isDownloading) {
      promptAction.showToast({ message: '已有下载任务进行中' });
      return;
    }
    //上下文对象
    let context = getContext(this) as common.UIAbilityContext
    let filesDir = context.cacheDir
    //保存到的沙箱路径
    let filePath = `${filesDir}/${Date.now()}.mp4`;
    this.filePath = filePath
    //下载任务的配置信息
    let config: request.agent.Config = {
      action: request.agent.Action.DOWNLOAD,
      url: this.videoUrl,
      saveas: filePath,
      gauge: true,
      overwrite: true,
      network: request.agent.Network.WIFI,
      title: this.videoData?.tags.split(',')[0] || 'video_download' // 添加下载任务标题
    }
    //创建下载任务
    request.agent.create(context, config)
      .then(async (task: request.agent.Task) => {
        this.isDownloading = true; // 开始下载
        this.downloadProgress = 0; // 重置进度
        //创建成功之后,开始下载任务
        task.start((err: BusinessError) => {
          if (err) {
            request.agent.remove(task.tid)
            promptAction.showToast({ message: '下载失败' })
            this.isDownloading = false; // 下载失败
            this.downloadProgress = 0;
          } else {
            promptAction.showToast({ message: '开始下载...' })
          }
        })
        task.on('progress', (progressInfo: request.agent.Progress) => { // Explicitly type progressInfo
          if (progressInfo.sizes[0] > 0) {
            this.downloadProgress =
              Math.floor((progressInfo.sizes[0] / progressInfo.sizes[0]) * 100);
          }
        })
        task.on('completed', async () => {
          //下载完成--->保存到相册
          this.isDownloading = false; // 下载完成
          this.downloadProgress = 100; // 确保进度为100%
          promptAction.showToast({ message: '下载完成,正在保存到相册...' });
          this.save(filePath)
          // 可以在这里稍作延迟后重置进度条,或者在保存成功后
          setTimeout(() => {
            this.downloadProgress = 0;
          }, 2000);
        })
        task.on('failed', () => {
          promptAction.showToast({ message: '下载任务失败' });
          this.isDownloading = false;
          this.downloadProgress = 0;
        })
      })
      .catch((err: BusinessError) => {
        promptAction.showToast({ message: `创建下载任务失败: ${err.message}` });
        this.isDownloading = false;
        this.downloadProgress = 0;
      })
  }

保存到相册

该功能在之前的教程中已经出现过了,

  1. 获取当前应用的上下文(context)。
  2. 创建一个photoAccessHelper对象,用于访问和管理设备的照片和视频库。
  3. 定义一个包含源文件URI的数组srcFileUris,这里只包含一个URI,即要保存的视频文件。
  4. 定义一个photoCreationConfigs数组,其中包含了保存视频时的配置信息,如文件名后缀、照片类型(这里是视频)、标题和子类型等。
  5. 调用showAssetsCreationDialog方法,弹出授权对话框,让用户选择保存视频的目标位置,并返回目标URI。
  6. 使用fileIo.open方法以读写模式打开源文件和目标文件。
  7. 使用fileIo.copyFile方法将源文件的内容复制到目标文件中。
  8. 关闭源文件和目标文件。
  9. 如果保存成功,显示成功提示信息;如果失败,显示失败提示信息。
  // 保存到相册
  async save(srcFileUri: string) {
    let context = getContext(this)
    let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
    try {
      let srcFileUris: Array<string> = [
        srcFileUri
      ];
      // 指定待保存照片的创建选项,包括文件后缀和照片类型,标题和照片子类型可选
      let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [
        {
          title: `${Date.now()}`, // 可选
          fileNameExtension: 'mp4',
          photoType: photoAccessHelper.PhotoType.VIDEO,
          subtype: photoAccessHelper.PhotoSubtype.DEFAULT, // 可选
        }
      ];
      // 基于弹窗授权的方式获取媒体库的目标uri
      let desFileUris: Array<string> = await phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs);
      // 将来源于应用沙箱的内容写入媒体库的目标uri
      let desFile: fileIo.File = await fileIo.open(desFileUris[0], fileIo.OpenMode.WRITE_ONLY);
      let srcFile: fileIo.File = await fileIo.open(srcFileUri, fileIo.OpenMode.READ_ONLY);
      await fileIo.copyFile(srcFile.fd, desFile.fd);
      fileIo.closeSync(srcFile);
      fileIo.closeSync(desFile);
      promptAction.showToast({ message: '保存成功' })
    } catch (error) {
      promptAction.showToast({ message: '保存失败' })
    }
  }

如何获取资料

获取资料的途径,可以关注我们 官网的公众号 青蓝逐码 ,输入 项目名称 《自然壁纸》 即可获得以上资料。

关于我们

关于青蓝逐码组织

如果你兴趣想要了解更多的鸿蒙应用开发细节和最新资讯甚至你想要做出一款属于自己的应用!欢迎在评论区留言或者私信或者看我个人信息,可以加入技术交流群。

09-自然壁纸实战教程-视频下载-鸿蒙开发者社区

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
收藏
回复
举报
回复
    相关推荐