Flutter开发类YouTube、亚马逊Prime视频播放器:API视频下载本地存储播放
Flutter 离线视频下载+本地播放实现方案
1. 前置依赖准备
你需要先在pubspec.yaml中引入以下常用依赖:
- 网络下载:
dio,支持下载进度监听、断点续传 - 路径管理:
path_provider,用于获取跨平台合法的本地存储目录 - 播放组件:
video_player,官方维护的视频播放组件,兼容性覆盖安卓、iOS等主流平台 - 权限管理:
permission_handler,适配高版本系统的存储权限申请
2. 基础权限配置
下载前必须完成权限配置,否则会出现写入失败的问题:
- 安卓端:在
android/app/src/main/AndroidManifest.xml中添加网络权限、存储权限声明,安卓13及以上版本需要单独申请视频媒体权限 - iOS端:在
ios/Runner/Info.plist中添加网络访问权限、本地文档读写权限声明
3. 核心实现步骤
3.1 获取本地存储路径
优先使用应用专属文档目录存储视频,该目录无需额外申请存储权限即可读写,适合存放应用私有资源:
Future<String> getVideoSaveDir() async { final appDir = await getApplicationDocumentsDirectory(); final videoDir = Directory("${appDir.path}/offline_videos"); if (!await videoDir.exists()) { await videoDir.create(recursive: true); } return videoDir.path; }
3.2 下载API返回的在线视频
调用dio的download方法完成视频下载,提前判断文件是否已存在,避免重复下载:
Future<String?> downloadVideo(String onlineVideoUrl, String saveFileName) async { try { final savePath = "${await getVideoSaveDir()}/$saveFileName"; final targetFile = File(savePath); // 本地已有文件直接返回路径,跳过下载 if (await targetFile.exists()) { return savePath; } await Dio().download( onlineVideoUrl, savePath, onReceiveProgress: (received, total) { if (total != -1) { // 此处可自行实现下载进度更新逻辑 debugPrint("下载进度:${(received / total * 100).toStringAsFixed(0)}%"); } }, ); return savePath; } catch (e) { debugPrint("视频下载失败:$e"); return null; } }
3.3 播放本地视频
获取到本地视频路径后,直接传入video_player初始化即可,逻辑和播放在线视频基本一致:
late VideoPlayerController _playerController; Future<void> initLocalPlayer(String localVideoPath) async { _playerController = VideoPlayerController.file(File(localVideoPath)); await _playerController.initialize(); // 初始化完成后调用play方法即可播放 _playerController.play(); setState(() {}); } // 页面销毁时必须释放播放器资源 @override void dispose() { _playerController.dispose(); super.dispose(); }
4. 可选优化方案
- 如果你拿到的是HLS格式的.m3u8分片视频,不要直接下载索引文件,需要先解析索引内的所有.ts分片地址,全部下载完成后可以合并为完整视频,或者搭建本地代理服务播放本地分片
- 大体积视频可以基于dio的range请求头实现断点续传,避免网络中断后需要重新下载
- 涉及版权的付费视频可以对本地存储的视频文件做对称加密,播放时实时解密,避免资源被用户直接导出
内容的提问来源于stack exchange,提问作者Aravind B
相关产品推荐
相关产品推荐

