Android webview加载页面获取摄像头(h5页面中含有扫描二维码功能)

场景介绍:
Android app中的webview加载含摄像头相关逻辑的H5页面,进行赋权的操作

H5页面调取摄像头识别二维码逻辑:
vue编写

<template>
  <div class="getQrcode" :style="{ width: windowWidth + 'px', height: windowHeight + 'px' }">
    <div class="box">
      <div class="line"></div>
      <div class="angle"></div>
    </div>

    <div class="box2" v-if="isUseTorch">
      <div class="track" @click="openTrack">
        {{ trackStatus ? '关闭闪光灯' : '打开闪光灯' }}
      </div>
    </div>

    <canvas ref="canvasRef"></canvas>
  </div>
</template>

<script setup lang="ts">
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<IProps>(), {
  exact: 'environment',
  definition: false,
  continue: false
})

if (origin.indexOf('https') === -1) throw '请在 https 环境中调用摄像头。'

const canvasRef = ref<HTMLCanvasElement>()
const windowWidth = document.documentElement.clientWidth || document.body.clientWidth
const windowHeight = document.documentElement.clientHeight || document.body.clientHeight
let 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)
}
</script>

问题:在app端访问时,扫描摄像头直接出不来显示无权限。

Android部分
一:AndroidManifest.xml部分
新增相关权限

    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.webkit.PermissionRequest" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

一: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<String> permissions, boolean all) {
                      }

            @Override
            public void onDenied(List<String> 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());
            }
        }
  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值