首页 > 解决方案 > WebUSB:如果 navigator.usb.getDevices() 失败,如何调用 navigator.usb.requestDevice()

问题描述

我正在为 Scratch3 编写一个基于 WebUSB 的扩展。在扩展构造函数中,我需要建立 WebUSB 连接。理想情况下,我想使用 navigator.usb.getDevices() 检查可用/配对的设备,如果失败,我想要求用户使用 navigator.usb.requestDevice() 选择设备。

问题是 navigator.usb.requestDevice() 需要从用户手势中调用。在大多数情况下,scratch3 扩展构造函数是从用户操作中调用的,因此我可以很好地使用 navigator.usb.requestDevice()。

但是 navigator.usb.getDevices() 返回一个 Promise 并从那里调用 navigator.usb.requestDevice() 失败,并显示“必须处理用户手势以显示权限请求”。

所以以下工作(但每次都会打开一个请求对话框):

navigator.usb.requestDevice({ filters: [{ vendorId: 0x2341 }] })
        .then(selectedDevice => {
            // ...
        })

但是由于缺少“用户手势”而导致以下失败:

navigator.usb.getDevices().then(devices => {
    if(devices.length == 0) {
        navigator.usb.requestDevice({ filters: [{ vendorId: 0x2341 }] })
            .then(selectedDevice => {
                // ...
        })
    }
})

我想避免弄乱 Scratch 3 核心,因此不想添加另一个 UI 元素。

在第一个片段中仅使用 navigator.usb.requestDevice() 有两个主要缺点:

  1. 它一直打开请求对话框,尽管它只需要一次
  2. 有时稍后可能会从非交互式情况调用构造函数,并且 navigator.usb.requestDevice() 会完全失败,而 navigator.usb.getDevices() 会成功

有没有办法使第二个代码片段的方法起作用?

标签: javascriptpromiseusbwebusb

解决方案


从 Chrome 72 开始,此问题已通过用户激活 v2功能修复。


推荐阅读