在初始拒绝后,使用getUserMedia()重新提示权限。

111
如何在 getUserMedia() 被拒绝后重新请求相机/麦克风访问权限?
我正在使用 getUserMedia() 访问用户的照相机并将数据传输到画布上。这部分功能都能正常工作。
在测试中,我被拒绝了一次。在 Chrome 和 Firefox 中,在此时任何随后使用 getUserMedia() 的请求都会默认为被拒绝状态。
显然,我们不想在被拒绝之后的每个页面加载时都请求相机/麦克风的权限,因为地理位置 api 已经很令人烦恼了。
然而,肯定有一种方法可以再次请求权限。仅因为用户拒绝了一次并不意味着他们想永远拒绝网络摄像头的访问。
我已经阅读了规范,并进行了一些谷歌搜索,但并没有找到关于这个问题的明确说明。
编辑: 进一步研究表明,在 Chrome 中点击拒绝会将当前站点添加到阻止列表中。可以通过 chrome://settings/content 手动访问此列表。滚动至 Media。管理例外情况,删除被阻止的站点。
链接到 chrome://settings/content 在这种情况下不能正常工作(当我们想添加一个有用的链接来让人们重新启用权限时)。
处理 getUserMedia 权限的整个用户体验非常糟糕。=(

1
谢谢。我直接通过“设置”>“显示高级设置”无法看到媒体部分,但是通过chrome://settings/content可以看到。 - Teknotica
拒绝一次请求后,Chrome 会拒绝后续请求,而这不是 Firefox 的行为。只有在 https 网站上选择“始终拒绝”才会在 Firefox 中发生这种情况。 - jib
3
在Chrome中,用户可以单击URL栏中的相机图标来撤消先前的阻止或管理阻止列表。无需使用chrome://链接。 - jib
6个回答

36

Jeffreyveon的答案可以帮助降低用户选择拒绝的概率,因为她只需要选择一次。

如果她点击了拒绝,你可以提供一条消息来解释为什么需要该权限以及如何更新她的选择。例如:

navigator.getUserMedia (
   // constraints
   {
      video: true,
      audio: true
   },

   // successCallback
   function(localMediaStream) {
      var video = document.querySelector('video');
      video.src = window.URL.createObjectURL(localMediaStream);
      video.onloadedmetadata = function(e) {
         // Do something with the video here.
      };
   },

   // errorCallback
   function(err) {
    if(err === PERMISSION_DENIED) {
      // Explain why you need permission and how to update the permission setting
    }
   }
);

1
当页面加载时,我能否避免点击允许摄像头访问?它是否可以使用JavaScript进行控制? - Vivek Ranjan
7
不,你不能这样做,这是件好事!!!这将允许网站、应用程序或其他任何实体未经人们同意就能访问他们的媒体设备,这将侵犯隐私... - Flo Schild
PERMISSION_DENIED 是从哪里来的? - xehpuk
1
请注意,navigator.getUserMedia已被弃用,应改用navigator.mediaDevices.getUserMedia文档在此 - LuckyLikey

34

Chrome 在 navigator.permissions 中实现了 Permissions API,这也适用于 cameramicrophone 权限。

因此在调用 getUserMedia() 之前,您可以使用该 API 查询摄像头和麦克风的权限状态:

 navigator.permissions.query({name: 'microphone'})
 .then((permissionObj) => {
  console.log(permissionObj.state);
 })
 .catch((error) => {
  console.log('Got error :', error);
 })

 navigator.permissions.query({name: 'camera'})
 .then((permissionObj) => {
  console.log(permissionObj.state);
 })
 .catch((error) => {
  console.log('Got error :', error);
 })

成功时,permissionObj.state 会返回 deniedgrantedprompt

这里有一个有用的 Stack Overflow 问题/回答 链接

对于跨浏览器的解决方案,一种简单的方法是监控调用 getUserMedia() Promise 的时间差,以及它被拒绝或解决的时间,像这样:

// In the Promise handlers, if Date.now() - now < 500 then we can assume this is a persisted user setting
var now = Date.now();
navigator.mediaDevices.getUserMedia({audio: true, video: false})
.then(function(stream) {
  console.log('Got stream, time diff :', Date.now() - now);
})
.catch(function(err) {
  console.log('GUM failed with error, time diff: ', Date.now() - now);
});

这篇Medium文章提供了更多细节。

希望这有所帮助!


根据 https://developer.mozilla.org/en-US/docs/Web/API/Navigator/permissions,权限在Internet Explorer、Safari、Safari IOS和Android web view上不受支持。你知道这里可以使用其他方法吗?我也在 https://stackoverflow.com/questions/64679982/how-to-check-camera-permission-which-would-be-supported-across-all-browsers 上提出了一个相关问题。 - anup
1
目前,Firefox不支持camera权限名称 - ffigari

22
使用HTTPS。当用户一次授权后,浏览器会记住,并且不会再次询问该页面的许可,您将立即获得访问媒体的权限。这并不提供强制再次显示权限栏的方法,但至少确保了用户授权一次后无需再次请求许可。

如果您的应用程序从SSL(https://)运行,则此权限将是持久的。也就是说,用户不必每次都授予/拒绝访问权限。

请参见:http://www.html5rocks.com/en/tutorials/getusermedia/intro/

3
Firefox上的HTTPS权限不会保留。 - Rui Marques
1
现在在Firefox中可以工作了,但“始终共享”选项在下拉箭头下有点隐藏。 - xdumaine
“始终共享”与“始终拒绝”在Firefox中的显示方式相同。 OP的问题在Firefox中不会发生。 - jib
2
要在Firefox中使其工作:about:config -> 将 media.navigator.permission.disabled 标志设置为true,原始答案 - mido
谢谢mido:那真是太烦人了 - 现在可以工作了(在Firefox 50中访问本地USB网络摄像头,最初拒绝该摄像头后,在localhost file:///网页中服务)。天哪。 :-/ - Victoria Stuart

9
请注意以下几点: 1. 本地主机:在本地主机上,Chrome浏览器只会询问一次权限,而Firefox每次页面加载都会询问。 2. HTTPS:无论是Chrome还是Firefox浏览器,在HTTPS协议下只会询问一次权限。

7
理想情况下,在调用 getUserMedia() 之前,您应该能够使用 Permissions API 来查看用户是否已经授予或拒绝访问相机和麦克风的权限,但是这在 Safari 上 尚不可用,而 Safari 的用户占据了很大一部分。在以下任何一种情况下,调用 getUserMedia() 都会出现错误:
  • 用户点击“阻止”并且不允许相机/麦克风访问
  • 浏览器本身没有系统权限访问相机或麦克风(在 macOS 上很常见)
  • 另一个应用程序(如 Zoom)已经使用视频流(在 Windows 上很常见)
  • ...等等
在用户解决问题后,您需要在任何这些情况下再次提示获取权限。

Philippe Sultan的答案介绍了使用getUserMedia()在所有浏览器上提示摄像头和麦克风权限的好方法。然而,getUserMedia()的错误在不同的浏览器和操作系统中却极不一致,Chrome会产生"NotReadableError"和"NotAllowedError",而Firefox则会出现"NotFoundError"或"NotAllowedError"。只有Firefox有一些错误文档可以参考。

您可以使用mic-check包请求摄像头和麦克风的权限。它会检查浏览器/操作系统并将所有错误分组为更具用户行动可操作性的错误类别,例如UserPermissionDenied、SystemPermissionDenied和CouldNotStartVideoSource。

使用以下代码安装它:npm i mic-checkyarn add mic-check

使用以下代码使用它:

import {
  MediaPermissionsError
  MediaPermissionsErrorType,
  requestMediaPermissions
} from 'mic-check';

requestMediaPermissions()
    .then(() => {
        // can successfully access camera and microphone streams
        // DO SOMETHING HERE
    })
    .catch((err: MediaPermissionsError) => {
        const { type, name, message } = err;
        if (type === MediaPermissionsErrorType.SystemPermissionDenied) {
            // browser does not have permission to access camera or microphone
        } else if (type === MediaPermissionsErrorType.UserPermissionDenied) {
            // user didn't allow app to access camera or microphone
        } else if (type === MediaPermissionsErrorType.CouldNotStartVideoSource) {
            // camera is in use by another application (Zoom, Skype) or browser tab (Google Meet, Messenger Video)
            // (mostly Windows specific problem)
        } else {
            // not all error types are handled by this library
        }
    });

希望这能帮到你!你也可以在这里了解更多有关问题的信息。

3
最新的回答是,Chrome(目前测试版本为73)在HTTP请求结束后不再持续提示摄像头访问权限。然而,Firefox仍会提示。

1
我该如何强制它弹出?它的行为就像我在HTTP上对我的本地设备没有权限一样。 - Jonathan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接