行业知识
Android webview加载页面获取摄像头(h5页面中含有扫描二维码功能)
2026-11-09 17:37:09
来源:互联网转载
场景介绍:
Android app中的webview加载含摄像头相关逻辑的H5页面,进行赋权的操作
H5页面调取摄像头识别二维码逻辑:
vue编写
{{ trackStatus ? '关闭闪光灯' : '打开闪光灯' }} import { nextTick, ref } from 'vue'import jsQr from 'jsqr'const emit = defineEmits(['success'])interface IProps { /** 使用后置还是前置摄像头 */ exact?: 'environment' | 'user' /** 获取摄像头视频像素 false 正常, true高清 */ definition?: boolean /** 是否持续监听 */ continue?: boolean}const props = withDefaults(defineProps(), { exact: 'environment', definition: false, continue: false})if (origin.indexOf('https') === -1) throw '请在 https 环境中调用摄像头。'const canvasRef = ref()const windowWidth = document.documentElement.clientWidth || document.body.clientWidthconst windowHeight = document.documentElement.clientHeight || document.body.clientHeightlet video: HTMLVideoElement, canvas2d: CanvasRenderingContext2D, stream: MediaStream, track: MediaStreamTrack, isUseTorch = ref(false)const trackStatus = ref(false)nextTick(() => { video = document.createElement('video') video.setAttribute('playsinline', 'true') video.setAttribute('webkit-playsinline', 'true') video.width = windowWidth video.height = windowHeight canvasRef.value!.width = windowWidth canvasRef.value!.height = windowHeight canvas2d = canvasRef.value!.getContext('2d')! openScan()})async function openScan() { const width = transtion(windowHeight) const height = transtion(windowWidth) const videoParam = { audio: false, video: { facingMode: { exact: props.exact }, width, height } } try { stream = await navigator.mediaDevices.getUserMedia(videoParam) video.srcObject = stream video.play() tick() track = stream.getVideoTracks()[0] setTimeout(() => { const t: any = track.getCapabilities() isUseTorch.value = t.torch || null }, 500) } catch (error) { console.log('设备不支持,请检查是否允许摄像头权限', error) throw error }}function tick() { if (video.readyState === video.HAVE_ENOUGH_DATA) { canvas2d.drawImage(video, 0, 0, windowWidth, windowHeight) const imageData = canvas2d.getImageData(0, 0, windowWidth, windowHeight) const codeRes = jsQr(imageData.data, imageData.width, imageData.height, { inversionAttempts: 'dontInvert' }) if (codeRes) { drawLine(codeRes.location.topLeftCorner, codeRes.location.topRightCorner, '#FF3B58') drawLine(codeRes.location.topRightCorner, codeRes.location.bottomRightCorner, '#FF3B58') drawLine(codeRes.location.bottomRightCorner, codeRes.location.bottomLeftCorner, '#FF3B58') drawLine(codeRes.location.bottomLeftCorner, codeRes.location.topLeftCorner, '#FF3B58') if (codeRes.data) { getData(codeRes.data) } } } requestAnimationFrame(tick)}interface Point { x: number y: number}function drawLine(begin: Point, end: Point, color: string) { canvas2d.beginPath() canvas2d.moveTo(begin.x, begin.y) canvas2d.lineTo(end.x, end.y) canvas2d.lineWidth = 4 canvas2d.strokeStyle = color canvas2d.stroke()}function getData(data: string) { emit('success', data) if (!props.continue) return closeCamera()}function closeCamera() { if (stream) { stream.getTracks().forEach((track) => { track.stop() }) }}function transtion(number: number) { return props.definition ? number * 1.6 : number}const openTrack = () => { trackStatus.value = !trackStatus.value const ww: any = { advanced: [{ torch: trackStatus.value }] } track.applyConstraints(ww)} 问题:在app端访问时,扫描摄像头直接出不来显示无权限。
Android部分:
一:AndroidManifest.xml部分
新增相关权限
一:webview部分
1,首先在webview 的 initview 方法中添加如下方法
XXPermissions.with(this) .permission(Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE, Permission.CAMERA) .request(new PermissionCallback() { @Override public void onGranted(List permissions, boolean all) { } @Override public void onDenied(List permissions, boolean never) { super.onDenied(permissions, never); } }); 2,需要在 BrowserChromeClient 方法中添加如下方法
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) @Override public void onPermissionRequest(android.webkit.PermissionRequest request) { System.out.println("onPermissionRequest"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { request.grant(request.getResources()); } }