H5端调用浏览器使用摄像头扫码功能必须要保证当前网页的上下文是安全上下文,否则浏览器默认不允许获取摄像头权限。
1.安全上下文
浏览器认为的安全上下文指的是当前网页的协议是https或者当前网页的域名为localhost的网页(注意,如果没有配置https,则只能使用lovalhost,如果使用本机的局域网ip地址或者本机回环ip地址127.0.0.1 也是可以访问到对应网站,但是也会被浏览器认为是不安全上下文。不止摄像头权限无法获取,包括系统信息,位置信息,系统点量等等一系列信息都无法获取.。
以下是一些需要再安全上下文中才能访问的浏览器api:
- Clipboard API
功能:用于读取和写入剪贴板内容。
限制:只能在安全上下文中使用(如 HTTPS 或本地开发环境中的 localhost)。这是因为剪贴板操作涉及用户隐私和安全。 - Geolocation API
功能:用于获取用户地理位置信息。
限制:必须在安全上下文中使用(HTTPS 或 localhost),以保护用户位置信息的安全。 - Service Worker API
功能:允许在浏览器后台运行脚本,用于实现离线功能、推送通知等。
限制:只能在安全上下文中使用(HTTPS 或 localhost),以防止中间人攻击。 - File System Access API
功能:允许访问用户设备上的文件系统。
限制:仅在安全上下文中可用(HTTPS 或 localhost),以保护用户文件的安全。 - Web Authentication API
功能:用于实现强身份验证机制,如指纹、面部识别等。
限制:必须在安全上下文中使用(HTTPS 或 localhost),以确保用户凭证的安全。 - Web Share API
功能:允许用户通过系统原生分享功能分享内容。
限制:仅在安全上下文中可用(HTTPS 或 localhost),以保护用户分享内容的安全。 - Media Capture and Streams API
限制:必须在安全上下文中使用(HTTPS 或 localhost),以防止隐私泄露。
功能:用于访问设备的摄像头和麦克风。
2.判断安全上下文
判断是否为安全上下文:window.isSecureContext
该属性可以准确判断是否处于安全上下文。
项目中的解决方式:
首先我在项目中使用了localhost作为域名。这样就解决了浏览器安全山下文的问题,但是由于项目使用的·webview,经查询相关资料得知webview默认是禁止页面访问摄像头权限的,所以需要单独开启webview来允许其访问摄像头权限,需要再webview元素行添加属性allow="camera; microphone"
开启webview页面访问摄像头的
3.摄像头权限
在扫码之前我们必须要获取到当前系统的摄像头权限,鉴于当前环境是在h5中,因此使用navigator.mediaDevices.getUserMedia
来获取权限信息。
以下是该API的兼容性:
由此可以看出,该API的兼容性良好,仅在IE等一些老版本浏览器中会出现兼容性问题。
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
stream.getTracks().forEach(track => track.stop()); // 停止流,避免资源占用
// 权限已开启
} catch (error) {
showDialog({
title: "温馨提示",
message: "请开启摄像头权限",
showCancel: false,
confirmButtonText: "确定",
}).then(() => {
cameraCodeShow.value = false
})
return false; // 权限未开启或摄像头不可用
}
4.扫码实现
项目中的扫码功能使用了h5常用的一个库html5-qrcode
,使用了Html5Qrcode API 来调用摄像头扫码,将扫到的信息配合后端查询对应的接口获取数据.
html5-qrcode基本使用:
const html5QrCode = new Html5Qrcode("reader"); // 传入一个元素的id,会将扫码框渲染到该元素上
const qrCodeSuccessCallback = (decodedText, decodedResult) => {
/* handle success */
}; // 扫码成功的回调
const config = { fps: 10, qrbox: { width: 250, height: 250 } }; // 基础配置,fps可以配置扫码的频率,在摄像头分辨率内越高扫描越准确
// 前置摄像头扫
html5QrCode.start({ facingMode: "user" }, config, qrCodeSuccessCallback);
// 后置摄像头扫
html5QrCode.start({ facingMode: "environment" }, config, qrCodeSuccessCallback);
html5QrCode.stop() // 停止扫描