Flutter Web加载显示本地视频文件的实现方案
首先明确已知限制:video_player 包官方暂未适配 VideoPlayerController.file() 方法的Web端实现,无法直接通过文件路径加载本地视频,以下是经过生产验证的可行方案:
方案1:基于现有video_player包适配(改造成本最低)
不需要替换现有依赖,利用Web端Blob URL机制绕开file方法的限制:Web端用户主动选择本地视频文件后,拿到dart:html的File对象,生成临时同域Blob链接,直接调用VideoPlayerController.networkUrl()加载该链接即可,和加载普通网络视频逻辑完全一致。
核心实现代码:import 'dart:html' as html; import 'package:video_player/video_player.dart'; late VideoPlayerController _videoController; // 传入用户通过文件选择器拿到的本地视频File对象 Future<void> initLocalVideo(html.File selectedFile) async { // 生成Web端可访问的临时Blob地址 final String blobUrl = html.Url.createObjectUrlFromBlob(selectedFile); _videoController = VideoPlayerController.networkUrl(Uri.parse(blobUrl)); await _videoController.initialize(); // 初始化完成后即可正常调用播放、暂停、seek等控制方法 setState(() {}); // 页面销毁时记得回收资源 // html.Url.revokeObjectUrl(blobUrl); // await _videoController.dispose(); }多端兼容逻辑可以写分支判断:移动端/桌面端继续走
VideoPlayerController.file()逻辑,Web端走上述Blob转链接逻辑,一套代码全端生效。方案2:嵌入Web原生Video标签(兼容性、性能最优)
如果不想受限于Flutter插件的适配进度,可以直接通过HtmlElementView嵌入浏览器原生<video>标签,原生标签天然支持本地文件、HLS/DASH流媒体、各类编码格式,自带的控制栏、画中画、倍速、字幕等能力不需要额外开发,性能比Flutter自绘视频层更好。
核心实现代码:import 'dart:html' as html; import 'dart:ui_web' as ui_web; import 'package:flutter/widgets.dart'; Widget buildNativeWebVideo({html.File? localFile, String? networkSrc}) { final String viewTypeId = 'native-video-${DateTime.now().millisecondsSinceEpoch}'; // 注册Web原生视图 ui_web.platformViewRegistry.registerViewFactory(viewTypeId, (int id) { final html.VideoElement videoEl = html.VideoElement() ..controls = true ..setAttribute('playsinline', 'true') // 兼容iOS Safari自动播放限制 ..muted = false; if (localFile != null) { videoEl.src = html.Url.createObjectUrlFromBlob(localFile); } else if (networkSrc != null) { videoEl.src = networkSrc; } return videoEl; }); return SizedBox( width: 640, height: 360, child: HtmlElementView(viewType: viewTypeId), ); }注意这个方案的原生视图层级高于Flutter自绘组件,做弹窗、悬浮控件的时候需要单独处理层叠逻辑。
方案3:项目内置静态视频加载
如果是打包进项目的固定展示视频,不要尝试用文件路径读取,直接把视频文件放到项目web目录下的静态资源文件夹(比如web/assets/video/),打包后会随网页静态资源一同部署,加载时直接传入相对路径即可:// 对应文件路径为 web/assets/video/demo.mp4 _videoController = VideoPlayerController.networkUrl(Uri.parse('assets/video/demo.mp4'));
注意:Web端受浏览器沙箱安全限制,无法获取本地设备文件的绝对路径,所有本地视频加载必须基于用户主动触发文件选择后拿到的File对象处理,不存在直接读取本地路径加载视频的可能,这是浏览器层面的规则,和Flutter框架无关。
内容的提问来源于stack exchange,提问作者shay gettu

