HTML5 navigator.mediaDevices.getUserMedia() 是唯一能实时获取视频流并实现扫码/美颜等功能的方案,需HTTPS/localhost环境、用户手势触发、正确处理设备枚举与错误,并注意iOS/Safari兼容性及video标签属性设置。

HTML5 navigator.mediaDevices.getUserMedia() 是唯一可行方案
现代浏览器(包括移动端 Chrome、Safari 11+、Edge)不支持直接用 稳定调起后置摄像头,它只是触发系统相册或拍照界面,无法实时预览和控制。真正能拿到视频流、实现扫码/美颜/实时处理的,只有 getUserMedia()。
关键点:必须在 HTTPS 或 localhost 环境下运行,否则 Safari 和新版 Chrome 会静默拒绝权限请求;iOS Safari 对 video: { facingMode: "environment" } 支持不稳定,需 fallback 到枚举设备。
- 先检查
navigator.mediaDevices是否存在且getUserMedia可调用 - 显式请求
{ video: true, audio: false },不要省略audio: false,否则部分安卓机型会因音频权限未授而失败 - 捕获
NotAllowedError(用户拒权)、NotFoundError(无摄像头)、NotReadableError(被占用)三类常见错误
如何指定后置摄像头(facingMode 不是万能的)
facingMode: "environment" 在 Android 上多数可用,但在 iOS Safari 中经常被忽略——它可能仍打开前置。更可靠的做法是先调用 enumerateDevices(),过滤出带 label 包含 "back" 或 deviceId 存在的视频输入设备,再传入 getUserMedia()。
注意:enumerateDevices() 返回的设备列表默认为空(需先获得一次媒体权限),建议在用户点击“开启摄像头”后,先调一次空 getUserMedia({ video: true, audio: false }) 获取权限,再枚举。
- iOS Safari 必须在用户手势(如
click)回调中调用getUserMedia(),否则直接报NotAllowedError - 部分国产安卓 WebView(如微信内置)禁用
getUserMedia(),需提前检测并提示“请在 Chrome 或 Safari 中打开” - 不要依赖
mediaDevices.ondevicechange,iOS 不触发,且兼容性差
标签播放流时必设 playsinline 和 autoplay
在 iOS Safari 中, 默认全屏播放,且不自动播放。漏掉这两个属性会导致画面黑屏或弹出全屏控件,破坏 UI 流程。
正确写法:
<video id="video" playsinline autoplay muted></video>
。其中 muted 是关键:即使你没开音频,iOS 也要求视频元素 mute 才允许自动播放。
-
video.srcObject = stream是标准赋值方式,不要用URL.createObjectURL(stream)(已废弃,且 Safari 17+ 不支持) - 流停止后记得调用
stream.getTracks().forEach(t => t.stop()),否则摄像头灯常亮、后台持续耗电 - 安卓部分机型(如华为 EMUI)在页面切后台后自动关闭流,需监听
visibilitychange做恢复逻辑
调试时最常卡住的三个地方
不是代码写错,而是环境或权限链断裂:
- 本地用
file://协议打开index.html→getUserMedia()直接抛SecurityError,必须起一个本地服务(如npx serve或 VS Code Live Server) - Chrome 模拟器里选了 “Responsive” 模式 → 摄像头不可用,要切到 “Laptop with touch” 或真机调试
- 微信安卓版内嵌 WebView 报
TypeError: Cannot read property 'getUserMedia' of undefined→ 它压根没实现该 API,只能降级为input[type=file]+capture
真机调试比模拟器可靠得多,但 iOS 需用 Mac + Safari 开发者工具连设备查看 console;安卓可直接用 Chrome 远程调试。别在没确认权限弹窗是否出现前就假设代码有问题。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











