Есть ли способ заставить Chrome “забыть” устройство для тестирования navigator.usb.requestDevice, navigator.serial.requestPort?

#javascript #webusb #serialapi

#javascript #webusb #serialapi

Вопрос:

Я надеюсь перейти с использования WebUSB на SerialAPI (что здесь хорошо объясняется).

Текущий код:

 try {
    let device = await navigator.usb.requestDevice({
    filters: [{
            usbVendorId: RECEIVER_VENDOR_ID
        }]
    })
    this.connect(device)
} catch (error) {
    console.log(DEVICE_NAME   ': Permission Denied')
}
 

Новый код:

 try {
    let device = await navigator.serial.requestPort({
    filters: [{
            usbVendorId: RECEIVER_VENDOR_ID
        }]
    })
    this.connect(device)
} catch (error) {
    console.log(DEVICE_NAME   ': Permission Denied')
}
 

Новый код, похоже, работает, но я думаю, это потому, что браузер уже запросил устройство через старый код.

Я попытался перезапустить Chrome, а также очистить всю историю просмотров. Даже закрыл страницу с заявкой на USB и потребовал устройство с помощью другого приложения (во время которого оно возвращает DOMException: Unable to claim interface ошибку), но Chrome, похоже, не хочет переспрашивать. Он просто с радостью передает данные при предыдущем подключении.

Я надеялся, что использование SerialAPI позволит избежать борьбы за USB с другими процессами или, по крайней мере, проиграть им.

Обновить

Я забыл о:

 Failed to execute 'requestPort' on 'Serial': "Must be handling a user gesture to show a permission request"
 

Означает ли это, что пользователю нужно будет использовать кнопку для подключения к устройству через SerialUSB? Я думаю, что с помощью WebUSB мне удалось автоматически открыть окно подключения.

Комментарии:

1. Полученное вами сообщение точно означает, что вы должны сделать запрос из события, созданного жестом пользователя (щелчок будет сделан).

2. Спасибо, @Kaiido. В обновлении мне было интересно, нужно ли создавать экземпляр запроса жестом пользователя, что, я считаю, не относится к WebUSB.

3. По вашей собственной ссылке: web.dev/usb/#требуется пользовательский жест

4. Упс. Я думаю, SerialAPI — это своего рода другое животное (от WebUSB). Я также думаю, что требование жеста делает вывод о том, как «забыть» устройство как бы отключенным. Я могу пойти дальше и удалить этот вопрос.

Ответ №1:

Для обоих API, как отмечается в обновлении, для вызова метода or требуется жест пользователя requestDevice() requestPort() . Невозможно автоматически отобразить это приглашение. (Если есть ошибка, сообщите об этом команде Chrome, чтобы мы могли ее исправить.)

Разрешения, предоставленные сайту через WebUSB API и Web Serial API, в настоящее время отслеживаются отдельно, поэтому разрешение на доступ к устройству через одно не будет автоматически переводиться на другое.

В настоящее время нет способа программно забыть разрешение устройства. Для этого потребуется метод navigator.permissions.revoke(), который был отменен. Однако вы можете вручную отозвать разрешение на доступ к устройству, нажав на значок «блокировка» в адресной строке при посещении сайта или перейдя в chrome:// settings/content/ usbDevices (для USB-устройств) и chrome:// settings/content/ SerialPorts (для последовательных портов).

Ответ №2:

Чтобы заставить Chrome «забыть» устройство WebUSB, ранее сопряженное через API navigator.usb.requestDevice:

  1. Откройте страницу, сопряженную с устройством, которое вы хотите забыть
  2. Нажмите на значок в адресной строке
  3. Нажмите x рядом с device . Если ничего не указано, значит, для этой веб-страницы нет сопряженных устройств. введите описание изображения здесь

Ответ №3:

Новый код НЕ работал. Это просто потому, что Chrome уже был сопряжен с портом через старый код. «Новый код» не мог бы сработать, потому что, как отмечено в комментарии Калидо, SerialAPI (из-за его мощности) требует пользовательского жеста для подключения.

Код, который я использую для фактического подключения и получения данных, в основном состоит из нескольких фрагментов из приведенных выше ссылок в OP:

 navigator.serial.addEventListener('connect', e => {
  // Add |e.target| to the UI or automatically connect.
  console.log("connected");
});

navigator.serial.addEventListener('disconnect', e => {
  // Remove |e.target| from the UI. If the device was open the disconnection can
  // also be observed as a stream error.
  console.log("disconnected");
});

console.log(navigator.serial);

document.addEventListener('DOMContentLoaded', async () => {

    const connectButton = document.querySelector('#connect') as HTMLInputElement;

    if (connectButton) {
        connectButton.addEventListener('click', async () => {
            try {
        
                // Request Keiser Receiver from the user.
                const port = await navigator.serial.requestPort({
                    filters: [{ usbVendorId: 0x2341, usbProductId: not_required }]
                });
            
                try {
                    // Open and begin reading.
                    await port.open({ baudRate: 115200 });
                
                } catch (e) {
                    console.log(e);
                }
                while (port.readable) {
                  const reader = port.readable.getReader();

                  try {
                    while (true) {
                      const { value, done } = await reader.read();
                      if (done) {
                        // Allow the serial port to be closed later.
                        reader.releaseLock();
                        break;
                      }
                      if (value) {
                        console.log(value);
                      }
                    }
                  } catch (error) {
                    // TODO: Handle non-fatal read error.
                    console.log(error);
                  }
                }
            } catch (e) {
              console.log("Permission to access a device was denied implicitly or explicitly by the user.");
              console.log(e);
              console.log(port);
            }
        }
}
 

Идентификаторы поставщика и продукта, зависящие от устройства, очевидно, будут меняться от устройства к устройству. В приведенном выше примере я вставил идентификатор поставщика Arduino.

Это не отвечает на вопрос о том, как заставить Chrome «забыть», но я не уверен, актуально ли это при использовании SerialAPI из-за требуемого жеста.

Надеюсь, кто-то с большим опытом сможет опубликовать более информативный ответ.