さまざまな機能(プッシュ通知、Webカメラアクセス、midiアクセスなど)を必要とするWebアプリケーションを作成したことがある場合は、APIの外観が大きく異なることに気付いたと思います。

// for the geolocation API you need to call getCurrentPosition to check if geolocation is accessible
navigator.geolocation.getCurrentPosition(gotLocation, didNotGetLocation);

// for notifications we can directly check on the Notification object

if (Notification.permission == 'granted')
  // do notification stuff
if (Notification.permission == 'denied')
  // ask for notification access ....

これはあまり便利ではありません。

パーミッションAPIを使用すると、ページで使用できるパーミッションの概要を把握できます。 「許可」とは、コードを使用して特定の機能にアクセスできるかどうかを意味します。 コードでそれらにアクセスするための許可を必要とする機能は、強力な機能と呼ばれます。 カメラ、ミディ、通知、ジオロケーションはすべて強力な機能です。

すべての強力な機能のAPIは少し異なります。 したがって、各機能の権限の状態を把握するのは面倒な場合があります。 パーミッションAPIを使用すると、1つのインターフェースですべてのパーミッションのステータスを管理できます。

パーミッションAPIの基本

パーミッションAPIはこの段階では非常に実験的なものであり、慎重に使用する必要があります。 ミッションクリティカルであり、将来の重大な変更に対応できる場合にのみ使用してください。 たとえば、以前はnavigator.permissions.revokeをサポートしていたブラウザがいくつかありましたが、現在は非推奨になっています。

執筆時点では、queryは、permissionsインターフェイスからアクセスできる唯一のプロパティです。 queryは、PermissionDescriptorと呼ばれる引数としてオブジェクトを取ります。 権限記述子には、nameという1つのフィールドがあります。これは、アクセスする権限の名前です。

// This query will give us information about the permissions attached to the camera
navigator.permissions.query({name: 'camera'})

クエリは、PermissionStatusに解決されるpromiseを返します。 PermissionStatusには、stateonchangeの2つのフィールドがあります。

navigator.permissions.query({name: 'camera'}).then( permissionStatus => {
  console.log(permissionStatus)
  // in my browser on this page it logs:
  //{
  //   status: "prompt",
  //   onchange: null,
  // }
})

stateには、「許可」、「拒否」、「プロンプト」の3つの状態があります。 「許可された」とは、その機能にアクセスできることを意味します。 「拒否」とは、その機能にアクセスできないことを意味します。 「プロンプト」とは、ユーザーエージェント(つまり、 ブラウザ)は、その機能にアクセスしようとすると、ユーザーに許可を求めます。

一部のPermissionDescriptorには追加のフィールドがあり、ここでそれらの詳細を読むことができます。 たとえば、特定のカメラをターゲットにする場合、cameraのPermissionDescriptorにはdeviceIdという追加のフィールドがあります。 クエリは次のようになります:.query({name: 'camera', deviceId: "my-device-id"})

onchangeは、照会された機能の権限が変更されるたびにアクティブになるイベントリスナーです。

navigator.permissions.query({name:'camera'}).then(res => {
  res.onchange = ((e)=>{
    // detecting if the event is a change
    if (e.type === 'change'){
      // checking what the new permissionStatus state is
      const newState = e.target.state
      if (newState === 'denied') {
        console.log('why did you decide to block us?')
      } else if (newState === 'granted') {
        console.log('We will be together forever!')
      } else {
        console.log('Thanks for reverting things back to normal')
      }
    }
  })
})

すべての権限API

さまざまな強力な権限があり、ブラウザのサポートは非常に不均一です。 次のスクリプトでは、W3Cの編集者のドラフトによって記述されたすべてのアクセス許可をpermissionsName変数で確認できます。 getAllPermissions関数は、使用可能なさまざまなアクセス許可とその状態を含む配列を返します。 結果は、ブラウザ、ユーザーの好み、そしてもちろんWebサイトの設定によって変わることに注意してください。

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 = []
  // We use Promise.all to wait until all the permission queries are resolved
  await Promise.all(
    permissionsNames.map(async permissionName => {
        try {
          let permission
          switch (permissionName) {
            case 'push':
              // Not necessary but right now Chrome only supports push messages with  notifications
              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
}

次に、Alligator.ioの開発者コンソールで次のコードを実行すると次のようになります。

(async function () {
  const allPermissions = await getAllPermissions()
  console.log(allPermissions)
})()

これが私がコンソールで得たもののスクリーンショットです:

労働者の許可

これまでは、navigator.permissions APIのみを使用していました。これは、簡潔な例を作成する方がはるかに簡単だからです。 パーミッションAPIは、ワーカー内でも使用できます。 WorkerNavigator.permissionsを使用すると、ワーカー内の権限を確認できます。

うまくいけば、PermissionsAPIの使用方法についてより良いアイデアが得られたと思います。 それほど複雑ではなく、必須でもありませんが、JavaScriptベースのアプリで権限を管理するのがはるかに簡単になります。 APIにはおそらくいくつかの新機能と変更があり、最新情報をお届けします。