uni.scancode在h5不支持,因浏览器无原生扫码接口,调用必报fail not supported;须改用getusermedia+canvas+jsqr手动实现视频流捕获与解码。

uni-app H5 调用摄像头扫码为什么不能直接用 uni.scanCode
因为 uni.scanCode 在 H5 平台**不支持**——它底层依赖原生能力,H5 环境下会直接报错或静默失败,控制台通常显示 scanCode:fail not supported。你得换路子,用 Web 标准的 MediaStream + canvas + 条码识别库来实现。
推荐方案:用 jsQR + getUserMedia 手动捕获并解码
jsQR 是轻量、纯 JS、无依赖的 QR 解码库,适合 H5 场景;getUserMedia 用于拉起摄像头流。关键不是“调用 API”,而是“自己搭流水线”:
- 用
navigator.mediaDevices.getUserMedia({ video: true })获取视频流 - 把视频帧逐帧绘制到
<canvas></canvas>(注意尺寸和镜像) - 用
jsQR对 canvas 的图像数据做解码(建议降采样提速,如 320×240) - 加防抖:同一帧内只解一次码,避免重复触发
- 扫码成功后立即
stream.getTracks().forEach(t => t.stop())关闭摄像头
示例关键片段:
const canvas = document.getElementById('scanCanvas');
const ctx = canvas.getContext('2d');
let scanning = true;
async function startScan() {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const video = document.getElementById('videoElement');
video.srcObject = stream;
video.onloadeddata = () => {
scanFrame();
};
}
function scanFrame() {
if (!scanning) return;
ctx.drawImage(video, 0, 0, 320, 240, 0, 0, 320, 240);
const imageData = ctx.getImageData(0, 0, 320, 240);
const code = jsQR(imageData.data, imageData.width, imageData.height);
if (code) {
console.log('扫码结果:', code.data);
scanning = false;
stream.getTracks().forEach(t => t.stop());
} else {
requestAnimationFrame(scanFrame);
}
}
H5 扫码必须处理的兼容性与权限问题
不是所有浏览器都放行摄像头,尤其 iOS Safari 对 getUserMedia 有额外限制:
- 必须在 HTTPS 环境下运行(本地
localhost除外,但127.0.0.1不行) - iOS Safari 需要
<video autoplay muted playsinline></video>,且不能设width/height在标签上,得用 CSS 控制 - 首次调用前,用户必须有明确交互(比如点击按钮),否则 Chrome 会拒绝授予权限
- 部分安卓 WebView(如微信内置)禁用摄像头,需提前检测:
navigator.mediaDevices?.enumerateDevices()查是否有 videoinput
错误常见提示:NotAllowedError: Permission denied 或 NotFoundError: No video input devices found,对应上面几条原因。
uni-app 项目里怎么组织这个逻辑
别塞进 onLoad 自动启动——H5 页面加载时没用户交互,权限会被拒。正确做法:
- 页面放一个显眼按钮,文案明确写“打开摄像头扫码”
- 点击后调用封装好的
startScan(),同时显示 loading 或遮罩层 - 把 canvas 和 video 放在
<div> 内,用 <code>position: absolute叠加,video 设opacity: 0,只靠 canvas 显示画面 - 扫码成功后,用
uni.navigateBack()或uni.showToast提示,别留着摄像头开着 - 记得在
onUnload或扫码完成后手动清理:video.srcObject = null
复杂点在于:不同机型对 video 尺寸、旋转、镜像的处理不一致,实际调试时,先用 console.log(video.videoWidth, video.videoHeight) 看真实输出再定 canvas 尺寸,比硬写死更可靠。











