
本文详解如何使用 html5 的 `mediadevices` api 在浏览器中安全、兼容地访问移动设备摄像头,列举可用摄像头设备,并提供可直接运行的代码示例与关键注意事项。
在现代 Web 应用中,无需依赖原生 App 即可调用移动设备摄像头——这得益于 HTML5 提供的标准化媒体设备访问能力。核心接口是 navigator.mediaDevices,它属于 MediaDevices API,支持在桌面和移动端(Chrome、Safari(iOS 14.3+)、Firefox、Edge)中获取摄像头、麦克风等硬件列表,并启动实时视频流。
✅ 获取所有可用摄像头(含前后置标识)
async function listCameras() {
try {
// 必须在用户交互(如点击)后调用,否则部分浏览器会拒绝权限
const devices = await navigator.mediaDevices.enumerateDevices();
const videoInputs = devices.filter(device => device.kind === 'videoinput');
console.log('可用摄像头:', videoInputs);
// 示例输出:
// [
// { label: "Front Camera", kind: "videoinput", deviceId: "abc123...", groupId: "..." },
// { label: "Back Camera", kind: "videoinput", deviceId: "def456...", groupId: "..." }
// ]
return videoInputs;
} catch (err) {
console.error('获取设备列表失败:', err.name, err.message);
}
}⚠️ 注意:enumerateDevices() 不触发权限请求,仅列出已授权或系统预置的设备。若从未授过相机权限,返回的 label 可能为空(如 "videoinput"),需结合 getUserMedia() 触发实际授权。
✅ 直接打开默认/指定摄像头(推荐移动端方案)
对于移动 Web 应用,最可靠的方式是跳过手动选择,直接请求「后置摄像头」或「前置摄像头」:
const video = document.getElementById('preview');
document.getElementById('openBack').addEventListener('click', async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: 'environment' }, // 强制后置
audio: false
});
video.srcObject = stream;
} catch (err) {
alert('无法打开后置摄像头:' + err.message);
}
});
document.getElementById('openFront').addEventListener('click', async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: 'user' }, // 强制前置
audio: false
});
video.srcObject = stream;
} catch (err) {
alert('无法打开前置摄像头:' + err.message);
}
});✅ facingMode: 'environment' 是 iOS 和 Android 主流浏览器(Chrome/Safari/Edge)广泛支持的标准方式,比依赖 deviceId 更健壮。
? 关键注意事项
- 权限必须由用户显式触发:getUserMedia() 必须在用户手势(click、tap)回调中调用,否则会被浏览器静默拒绝(尤其在 iOS Safari 中)。
- HTTPS 强制要求:getUserMedia() 在非 HTTPS 环境(如 http://localhost 除外)下完全不可用。
- iOS Safari 兼容性:需添加 playsinline 属性防止全屏播放;autoplay 需配合 muted 才生效;建议设置 width/height 或 CSS object-fit: cover 避免拉伸。
- 错误处理不可省略:常见错误包括 NotAllowedError(用户拒绝)、NotFoundError(无可用设备)、NotReadableError(摄像头被占用)。
✅ 总结
你无需“跳转到原生 App”即可实现拍照功能——现代浏览器已原生支持摄像头调用。优先使用 facingMode 控制前后置,辅以 enumerateDevices() 做设备探测与降级提示。搭配合理的权限引导与错误反馈,即可构建体验接近原生的 Web 拍照流程。










