Chrome 126 于近期发布了稳定版本,其中一个比较有意思的更新是给 HTML 带来一个新的元素:<permission>
,它将从这个版本开始试用,并且正在努力走向标准化。
今天我们一起来看下这个 <permission>
元素的用法。
当 Web 应用程序需要访问浏览器的高级功能时,需要向用户主动请求许可。例如,当百度地图使用 Geolocation API
获取用户的地理位置时,浏览器会提示用户申请权限,这是权限规范中定义明确的概念。
申请权限的触发方式一般分为两类,被动隐式触发,或者主动显示触发:
例如,Geolocation API
是一个强大的 API
,它的使用依赖于首次使用时隐式询问的方法。例如,当程序调用 navigator.geolocation.getCurrentPosition()
方法时,权限提示框会在第一次调用时自动弹出,还有另外一个例子是 navigator.mediaDevices.getUserMedia()
。
一些其他的 API
,如 Notification API
或 Device Orientation API
,通常有一种显式的方式通过静态方法来请求权限,如 Notification.requestPermission()
或 DeviceMotionEvent.requestPermission()
。
网站可以在加载时立即调用诸如 navigator.mediaDevices.getUserMedia()
或 Notification.requestPermission()
等方法。这会导致在用户还没与网站进行交互时就弹出权限提示。这就是明显的权限滥用行为,并且影响到两种方式,既包括首次使用时的隐含询问,也包括提前明确请求。
权限滥用导致浏览器厂商要求有像点击按钮或按下按键这样的用户操作,然后才会显示权限提示。这种方法的问题在于,浏览器很难确定某个特定的用户操作是否应该导致显示权限提示。也许用户只是因为页面加载时间太长而在页面上随意某个地方随便点击,有些网站也变得非常擅长诱骗用户点击内容来触发提示。
另一个问题是权限提示框通常显示的方式:在网站的 “死亡线” 之上(特别是在大屏幕上),也就是说,在应用程序能够绘制到的浏览器窗口区域之外。用户在刚刚点击了窗口底部的一个按钮后,可能会错过浏览器窗口顶部的提示,这种情况还是挺常见的。当浏览器有应对权限滥用的缓解措施时,这个问题往往会更加严重。
另外,用户一旦做出了拒绝某个权限的操作,之后想要改变就不太容易了。他们得找到特定的地方,比如那个网站信息下拉菜单,然后去进行重置或调整权限的操作,而且还得重新加载页面才行。网站也没办法提供很方便的途径让用户快速改变权限状态,还得详细地告诉用户怎么去找到地方改变设置。
如果某个权限是非常重要的,比如视频会议软件要用麦克风权限,那像谷歌会议这类的软件就会弹出很显眼的对话框来告诉用户怎么去把之前阻止的权限给开通。
<permission>
元素为了解决上面的这些问题,<permission>
元素诞生了。这个元素允许开发者以声明方式请求使用权限,如下例所示:
<permission type="camera" />
“type” 属性代表你正在请求的权限列表(如果有多个可以以空格分割)。目前,允许的值是 'camera'
,'microphone'
以及 'camera microphone'
。默认情况下,这个元素呈现出来的样子类似于具有最简用户代理样式的按钮。
对于某些允许附加参数的权限,type-ext
属性接受以空格分隔的键值对,例如 precise:true
地理位置权限。
当用户与 <permission>
元素交互时,他们可以循环经历各个阶段:
如果他们之前不允许某项功能,他们可以在每次访问时允许该功能,或者在当前访问时允许该功能。
如果他们之前允许该功能,他们可以继续允许,或者停止允许。
如果他们之前不允许某项功能,他们可以继续不允许它,或者这次允许它。
<permission>
元素的文本会根据状态自动更新。例如,如果已授予使用某项功能的权限,则文本会更改为表示允许使用该功能。如果需要先授予权限,则文本会更改为邀请用户使用该功能。将之前的屏幕截图与以下屏幕截图进行比较,以查看这两种状态。
<permission>
元素可以与 Permissions API
一起使用。有许多事件可供监听:
onpromptdismiss
:当元素触发的权限提示被用户关闭(例如,单击关闭按钮或单击提示之外)时,会触发此事件。onpromptaction
:当元素触发的权限提示已被用户对提示本身采取某种操作解决时,触发此事件。这并不一定意味着权限状态已经改变,用户可能已经采取了维持现状的操作(例如继续允许权限)。onvalidationstatuschange
:当元素从 "valid"
切换到 "invalid"
时触发此事件,例如当元素被其他超文本标记语言内容部分遮挡时,会认为是 "invalid"
。我们可以直接在 HTML 代码中内联注册这些事件的事件监听器(<permission type="…" onpromptdismiss="alert('The prompt was dismissed');" />
),或者在 <permission>
元素上使用 addEventListener()
:
<permission type="camera" />
<script>
const permission = document.querySelector('permission');
permission.addEventListener('promptdismiss', showCameraWarning);
function showCameraWarning() {
// Show warning that the app isn't fully usable
// unless the camera permission is granted.
}
const permissionStatus = await navigator.permissions.query({name: "camera"});
permissionStatus.addEventListener('change', () => {
// Run the check when the status changes.
if (permissionStatus.state === "granted") {
useCamera();
}
// Run the initial check.
if (permissionStatus.state === "granted") {
useCamera();
}
});
</script>
参考:https://developer.chrome.com/blog/permission-element-origin-trial