解决Js使用MediaDevices Api在安卓9以上设备无法调用前置摄像头

1,840 阅读2分钟

起因

在早些时候曾用MediaDevices Api写过一些demo,当时记得的确按照mdn的文档在移动端的某个浏览器里使用video: { facingMode: "user" }实现过前置摄像头的调用,,但因为如今的安卓手机普遍标配1+2个以上摄像头,所以在Android P种谷歌加入原生对多摄像头的支持,可能是因为这个原因,导致了在安卓9上只使用facingMode无法选择前置摄像头,在9以下安卓和ios的safari上均无此问题,鉴于查到的方法很多都比较繁琐不够清晰直接,故在此记录一下。

解决方案

综合了文档和网上目前已有的解决方案之后再通过多设备的测试后最后得出了两种方案:

  • 第一种是通过exact字段强制使用前置摄像头,这也是最简单的,直接改为facingMode: { exact: "user" }即可,但是测试中部分浏览器依然无效。
  • 第二种是使用deviceId来选择调用设备,这也是目前较为稳妥的方法,通过enumerateDevices枚举出已有设备,因为通过多机型测试后发现安卓9后的label字段都有了统一的描述,即"camera *, facing back/front",其中front就是前置,这样我们就可以通过label字段去确定设备是否为前置摄像头

以下为第二种方法的简单实现

navigator.mediaDevices.enumerateDevices().then(function(devices) {
  //正常调用的config
  let cfg={video:{'facingMode':'user' }, audio: false }
  devices = devices.filter(function(device) { return device.kind === 'videoinput'})  //可以选择先筛选出摄像头设备
  //因为解决方案目前针对安卓9,所以要先对ua做个判断
  if (navigator.userAgent.toLowerCase().indexOf("android") > 0) {
      for (let i = 0; i < devices.length; i++) {
    	let device = devices[i]
	    //注意facing front前有个空格
		if (device.label) {
			if (device.label.split(',')[1]==' facing front'){
			    //如果安卓9,label会有内容,此时config加上deviceId
				cfg={video:{ deviceId: {'exact':device.deviceId}}, audio: false }
				break
			}
		}
      }
  }
  //调用getUserMedia
  navigator.mediaDevices.getUserMedia(cfg).then(function(stream) {
        //do sth
  }, function(err) {
    throw err
  })
});