如果你曾经做过需要申请权限的应用 (推送通知, 访问摄像头, 音频设备等), 你可能注意到了, 它们的 API 看起来不太一样.
- // 对于定位 API , 需要调用 getCurrentPosition 来检查定位信息是否可用
- navigator.geolocation.getCurrentPosition(gotLocation, didNotGetLocation);
- // 对于消息通知, 我们可以直接检查 Notification 对象
- if (Notification.permission == 'granted')
- // 授权后的逻辑
- if (Notification.permission == 'denied')
- // 请求授权
这显然不太方便.
权限 API 让我们可以查看页面上可用的权限. 我们说的 "权限" 是指在代码里能否访问某个特性. 需要用代码通过权限访问的特性称为 "强力特性". 摄像头, 音频设备接口 (midi), 通知, 地理位置等都是强力特性.
所有强力特性的 API 都有细微的差别. 因此, 要弄清楚每个特性的权限状态可能很麻烦. 有了权限 API, 我们可以通过单个接口管理所有权限的状态.
权限 API 基本概念
权限 API 目前还处于试验阶段, 需要谨慎使用. 只有在你能跟上破坏性的特性变化时才能在关键业务上使用它. 例如, 一些浏览器曾经支持 navigator.permissions.revoke , 但现在已经弃用了.
写这篇文章的时候, query 是 permissions 接口里唯一可用的属性. query 接受一个叫做 PermissionDescriptor 的对象参数. 该对象有个字段叫 name, 就是你要访问的权限名称.
- // 该查询返回摄像头的权限信息
- navigator.permissions.query({
- name: 'camera'
- });
查询返回一个 promise,resolve 结果是一个 PermissionStatus. 它有两个字段: state 和 onchange.
- navigator.permissions.query({name: 'camera'}).then( permissionStatus => {
- console.log(permissionStatus);
- // 我的浏览器控制台输出:
- //{
- // state: "prompt",
- // onchange: null,
- // }
- })
state 有 3 个可能的值: granted,denied 和 prompt.granted 表示允许访问, denied 表示不能访问, prompt 表示浏览器在请求权限的时候弹出提示, 询问用户.
有些 PermissionDescriptor 还有其他字段, 你可以在这里查看更多. 例如, camera 的 PermissionDescriptor 还有一个额外的字段叫 deviceId, 用于指定某个摄像头. 查询可能是这样:.query({name: 'camera', deviceId: "my-device-id"}).
onchange 是个事件监听器, 当查询的权限变化时会被触发.
- navigator.permissions.query({name:'camera'}).then(res => {
- res.onchange = ((e)=>{
- if (e.type === 'change'){
- const newState = e.target.state
- if (newState === 'denied') {
- console.log('你怎么狠心拒绝我?')
- } else if (newState === 'granted') {
- console.log('在一起, 不离不弃!')
- } else {
- console.log('让我们回到当初')
- }
- }
- })
- })
所有的权限 API
强力特性权限还有很多, 并且浏览器支持情况不一. 下面列出了 W3C 编辑草案中描述的 permissionsName 变量包含的所有权限. getAllPermissions 函数返回可用的权限数组及其状态. 注意, 这个结果会根据你的浏览器, 用户设置和网站的设定而变化.
- const permissionsNames = [
- "geolocation",
- "notifications",
- "push",
- "midi",
- "camera",
- "microphone",
- "speaker",
- "device-info",
- "background-fetch",
- "background-sync",
- "bluetooth",
- "persistent-storage",
- "ambient-light-sensor",
- "accelerometer",
- "gyroscope",
- "magnetometer",
- "clipboard",
- "display-capture",
- "nfc"
- ];
- const getAllPermissions = async () => {
- const allPermissions = [];
- await Promise.all(
- permissionsNames.map(async permissionName => {
- try {
- let permission;
- switch (permissionName) {
- case 'push':
- // 目前 Chrome 只支持用通知推送消息
- permission = await navigator.permissions.query({name: permissionName, userVisibleOnly: true});
- break;
- default:
- permission = await navigator.permissions.query({name: permissionName});
- }
- console.log(permission);
- allPermissions.push({permissionName, state: permission.state});
- }
- catch(e){
- allPermissions.push({permissionName, state: 'error', errorMessage: e.toString()});
- }
- })
- )
- return allPermissions;
- }
在浏览器控制台执行:
- (async function () {
- const allPermissions = await getAllPermissions();
- console.log(allPermissions);
- })()
结果如下:
image.PNG
Worker 中的权限
到目前为止, 我们只使用了 navigator.permissions API, 因为用它写的例子更简单明了. 权限 API 在 Worker 里同样可用, WorkerNavigator.permissions 即用于检查 Worker 内部的权限.
总结
本文简单介绍了 JavaScript 权限 API, 希望能帮助你了解它的基本用法. 它不复杂, 也不是必需的, 但如果你的网站要用到权限接口, 用它来管理还是比较方便的. API 以后可能会有所变化, 我会为你持续关注.
更多前端技术干货尽在微信公众号: 1024 译站
微信公众号: 1024 译站
来源: http://www.jianshu.com/p/627619b69748