视频下载与离线播放功能允许用户将视频内容下载到本地设备,并在无网络连接的环境下进行播放。React Native SDK 支持下载 MP4 和 HLS 格式的视频,并提供了一整套 API,用于处理任务创建、状态管理(暂停、恢复、删除)、进度查询和离线播放。
下载相关的全局参数需在 SDK 初始化阶段进行配置。建议根据 App 的存储策略和剩余空间预警值进行合理设置。
import { initEnv } from '@volcengine/react-native-vod-player'; initEnv({ // ... 其他初始化配置 DownloadDirectory: 'videos', // (可选)指定下载存储的子目录 MaxDownloadOperationCount: 3, // (可选)最大同时下载任务数,默认为 1 LimitFreeDiskSize: 1024 * 1024 * 500, // (可选)磁盘剩余空间低于 500MB 时禁止下载 });
参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
|
| 下载目录在应用缓存区下的子目录名称。不设置则使用 SDK 默认路径。 | |
|
| 1 | 允许同时进行的最大下载任务数量。 |
|
| 1 GB | 设备剩余存储空间的最低阈值(单位:byte)。低于此值将无法创建新的下载任务。 |
|
| 50 | (iOS Only) 缓存视频的最大数量。 |
播放器 SDK 支持播放 DirectUrl 视频源和 Vid 视频源。与之对应,播放器 SDK 也提供了不同数据源的下载能力。
适用于下载已上传至火山引擎视频点播服务的视频。通过视频的 Vid 和其对应的临时播放凭证 PlayAuthToken 来指定播放内容。这两个参数通常由您的业务服务端下发,客户端直接使用即可。详情请见通过临时播放 Token 播放。
import { createVidDownloadTask, ResolutionType, resumeDownloadTask } from '@volcengine/react-native-vod-player'; const task = await createVidDownloadTask( 'video_vid_here', // 视频vid ResolutionType.SuperHigh, // 指定下载超高清清晰度 'video_playAuthToken_here', // 播放凭证 ); resumeDownloadTask(task); // 开始下载
通过调用以下方法对单个 DownloadTask 实例进行操作。
resumeDownloadTask(task)suspendDownloadTask(task)cancelDownloadTask(task)(执行后本地已下载文件将被彻底清除)当 App 重新启动时,你可以调用 loadAllTasks 获取所有历史任务(包括未完成的任务),以便在 UI 列表上展示。
import { loadAllTasks, resumeAllDownloadTasks } from '@volcengine/react-native-vod-player'; // 加载历史任务列表 const allTasks = await loadAllTasks(); // 批量操作 resumeAllDownloadTasks(); // 开始所有等待中/暂停的任务 suspendAllDownloadTasks(); // 全部暂停 cancelAllDownloadTasks(); // 全部删除并清空磁盘
设置全局监听器 setDownloadListener,它是 UI 层获取进度、刷新状态的唯一入口。
import { setDownloadListener, DownloadTask, DownloadTaskState } from '@volcengine/react-native-vod-player'; setDownloadListener({ onDownloadProgress: (task, receivedSize, totalSize) => { const progress = totalSize > 0 ? receivedSize / totalSize : 0; console.log(`任务 ${task.getCacheKey()} 下载进度: ${(progress * 100).toFixed(2)}%`); // 在这里更新你的 UI }, onDownloadStateChanged: (task, state) => { console.log(`任务 ${task.getCacheKey()} 状态变更为: ${DownloadTaskState[state]}`); // 在这里更新你的 UI }, onDownloadComplete: (task, error) => { if (error) { console.error(`任务 ${task.getCacheKey()} 下载失败:`, error); } else { console.log(`任务 ${task.getCacheKey()} 下载完成!`); } }, // 其他回调... });
说明
当您调用 cancelDownloadTask 或 cancelAllDownloadTasks 取消任务时,每个被取消的任务(无论其下载状态如何)都会触发 onDownloadComplete 回调。code 为 -9995,表示任务是被用户主动取消的。
离线播放的逻辑是“自动命中”的。只要设置的播放源参数与下载时完全一致,且开启了缓存播放开关,播放器会优先读取本地文件。
player.enablePlayCachedSource()。vid、resolution、playAuthToken 需保持一致。urls、cacheKey、vid 需保持一致。// 1. 在设置播放源之前开启缓存读取开关 player.enablePlayCachedSource(); // 2. 构造与下载任务相同的数据源 // 3. 设置给播放器,SDK 将自动定位到本地文件 player.setVideoSource(videoSource); player.play();
DownloadTask 属性/方法 | 返回类型 | 说明 |
|---|---|---|
|
| 任务当前状态 |
|
| 进度(0.0 ~ 1.0) |
|
| 已下载字节数 |
|
| 预估总大小(HLS 初始可能为 -1) |
|
| 任务唯一的 Key |
|
| 关联的 Vid |
|
| 下载选择的清晰度档位 |
DownloadTaskState 枚举值 | 标识 | 说明 |
|---|---|---|
| 0 | 任务已创建,未进入队列 |
| 1 | 正在排队,等待 |
| 2 | 正在下载中 |
| 3 | 已暂停 |
| 4 | 正在执行取消/删除操作 |
| 5 | 下载完成 |
以下是一个简化的下载管理页面的示例。
import React, { useState, useEffect } from 'react'; import { View, Text, Button, FlatList } from 'react-native'; import { loadAllTasks, createVidDownloadTask, resumeDownloadTask, suspendDownloadTask, cancelDownloadTask, setDownloadListener, DownloadTask, ResolutionType } from '@volcengine/react-native-vod-player'; const DownloadManagerScreen = () => { const [tasks, setTasks] = useState<DownloadTask[]>([]); // 初始化时加载所有任务并设置监听器 useEffect(() => { const init = async () => { const existingTasks = await loadAllTasks(); setTasks(existingTasks); }; init(); setDownloadListener({ onDownloadProgress: (task, receivedSize, totalSize) => { // 更新特定任务的进度 UI setTasks(currentTasks => currentTasks.map(t => t.getCacheKey() === task.getCacheKey() ? task : t) ); }, onDownloadStateChanged: (task, state) => { // 更新任务列表 setTasks(currentTasks => currentTasks.map(t => t.getCacheKey() === task.getCacheKey() ? task : t) ); }, // ... 其他回调 }); }, []); const handleAddTask = async () => { const newTask = await createVidDownloadTask('your_vid_here', ResolutionType.SuperHigh, 'your_playAuthToken_here'); if (newTask) { setTasks(prevTasks => [...prevTasks, newTask]); resumeDownloadTask(newTask); // 创建后立即开始 } }; const renderTaskItem = ({ item }: { item: DownloadTask }) => ( <View style={{ padding: 10, borderBottomWidth: 1, borderColor: '#ccc' }}> <Text>ID: {item.getVideoId() || item.getCacheKey()}</Text> <Text>进度: {(item.progress * 100).toFixed(2)}%</Text> <Text>状态: {item.state}</Text> <View style={{ flexDirection: 'row', justifyContent: 'space-around', marginTop: 5 }}> <Button title="开始/恢复" onPress={() => resumeDownloadTask(item)} /> <Button title="暂停" onPress={() => suspendDownloadTask(item)} /> <Button title="删除" onPress={() => { cancelDownloadTask(item); setTasks(prev => prev.filter(t => t.getCacheKey() !== item.getCacheKey())); }} /> </View> </View> ); return ( <View> <Button title="添加新下载任务" onPress={handleAddTask} /> <FlatList data={tasks} renderItem={renderTaskItem} keyExtractor={item => item.getCacheKey() || ''} /> </View> ); };