Flutter Web应用如何通过USB访问外接摄像头?
Flutter Web 访问USB外接摄像头解决方案
核心逻辑
Flutter Web的camera_web仅支持系统默认摄像头,USB外接设备需直接调用浏览器原生MediaDevices API实现访问——这是Web平台处理外接摄像头的标准方式,我们可以通过Flutter的dart:html库直接对接该API。
步骤1:枚举所有可用摄像头(含USB外接)
通过浏览器API列出所有视频输入设备,筛选出目标USB摄像头:
import 'dart:html' as html; Future<List<html.MediaDeviceInfo>> getAvailableCameras() async { final allDevices = await html.window.navigator.mediaDevices.enumerateDevices(); // 筛选视频输入设备(摄像头) return allDevices.where((device) => device.kind == 'videoinput').toList(); }
返回的MediaDeviceInfo包含设备名称(label)和唯一标识(deviceId),用deviceId即可指定要访问的USB摄像头。
步骤2:打开USB摄像头并显示预览
通过getUserMedia指定目标设备ID获取媒体流,再用HtmlElementView在Flutter中渲染预览:
import 'dart:html' as html; import 'package:flutter/material.dart'; import 'dart:ui' as ui; class UsbCameraPreview extends StatefulWidget { final String deviceId; const UsbCameraPreview({super.key, required this.deviceId}); @override State<UsbCameraPreview> createState() => _UsbCameraPreviewState(); } class _UsbCameraPreviewState extends State<UsbCameraPreview> { html.VideoElement? _videoElement; String? _platformViewId; @override void initState() { super.initState(); _initializeCamera(); } Future<void> _initializeCamera() async { final mediaConstraints = { 'video': { 'deviceId': {'exact': widget.deviceId}, 'width': 1280, 'height': 720, } }; try { final mediaStream = await html.window.navigator.mediaDevices.getUserMedia(mediaConstraints); _videoElement = html.VideoElement() ..srcObject = mediaStream ..autoplay = true ..playsInline = true; // 注册Web视图用于Flutter渲染 _platformViewId = 'usb-camera-${widget.deviceId}'; ui.platformViewRegistry.registerViewFactory( _platformViewId!, (int id) => _videoElement!, ); setState(() {}); } catch (e) { print('摄像头初始化失败:$e'); } } @override void dispose() { // 释放媒体资源 _videoElement?.srcObject?.getTracks().forEach((track) => track.stop()); _videoElement?.remove(); super.dispose(); } @override Widget build(BuildContext context) { if (_platformViewId == null) { return const Center(child: CircularProgressIndicator()); } return HtmlElementView(viewType: _platformViewId!); } }
使用时传入目标USB摄像头的deviceId即可加载预览。
步骤3:拍摄照片
通过Canvas截取视频帧,转换成图片Blob或Base64格式:
// 在UsbCameraPreview的State类中添加方法 Future<html.Blob?> capturePhoto() async { if (_videoElement == null) return null; final canvas = html.CanvasElement( width: _videoElement!.videoWidth, height: _videoElement!.videoHeight, ); final canvasContext = canvas.context2D; canvasContext.drawImage(_videoElement!, 0, 0); return await canvas.toBlob('image/png'); } // 转换为Flutter可用的ImageProvider Future<ImageProvider> getCapturedImage() async { final photoBlob = await capturePhoto(); if (photoBlob == null) throw Exception('拍摄失败'); final fileReader = html.FileReader(); fileReader.readAsDataUrl(photoBlob); await fileReader.onLoad.first; return NetworkImage(fileReader.result as String); }
关于usb_device包的说明
usb_device主要用于Flutter移动平台(Android/iOS)直接操作USB底层设备,Web平台中浏览器已封装了USB媒体设备的访问逻辑,无需直接操作USB协议,因此该包在Web环境下不适用。
注意事项
- 需在HTTPS环境运行(本地开发用
flutter run -d chrome可正常使用,Chrome对localhost的HTTP权限限制有所放宽) - 首次访问需用户授权摄像头权限
- 不同浏览器对媒体设备的兼容细节略有差异,建议优先在Chrome中测试
内容的提问来源于stack exchange,提问作者Abdallah Reda
相关产品推荐
相关产品推荐

