link89
link89

Reputation: 1821

navigator.usb.requestDevices is missing in chrome extension service-worker

I am working on a Chrome Extension which will save specific resource to my Oculus Quest directly via WebUsb.

The problem is, I find the navigator.usb.requestDevice is not exist in service worker.

My plan is to maintain a adb connection between extension service worker and my Android device, so that when I click to download specific url, the extension will send an event to the service-worker, which will download the content and send it to my Android device.

My question is, how to make requestDevice work in service-worker, or do I have to create adb connection in contentScript instead of running in background?

enter image description here

Update:

I have try chrome.windows.create and it doesn't work. It is supposed to have a choose device show up in the address bar but the window created by service worker doesn't have one, so it is always report No device selected

enter image description here

Upvotes: 0

Views: 63

Answers (2)

link89
link89

Reputation: 1821

Thanks to Reilly's answer I have figured out a solution.

The key point is to create a normal window and handle the WebUSB in it, either offscreen, popup or panel window won't work as device selected menu won't be displayed and end up with No device selected.

And here is the key snippet of this solution

function createPopupAndSend(message: DownloadEvent) {
  chrome.windows.create({
    url: chrome.runtime.getURL(new URL("popup.html", import.meta.url).pathname),
    type: "normal",
    width: 600,
    height: 500,
  }, (newWindow) => {
    if (newWindow && newWindow.id !== undefined) {
      popupWindowId = newWindow.id;
      // Delay sending the message to give the popup time to load.
      setTimeout(() => {
        chrome.runtime.sendMessage(message);
      }, 500);
    }
  });
}

Upvotes: 1

Reilly Grant
Reilly Grant

Reputation: 6093

requestDevice() cannot be called from a Service Worker because it has to show the permissions prompt UI (there are probably solutions to this, but they introduce additional challenges so it's the reason why it's currently disallowed).

For your use case, I think you have two options:

  1. In the Service Worker you can call navigator.usb.getDevices() to get a list of all the USB devices your extension has permission to access. If the device is already there you can perform the transfer in the background using the Service Worker. If not you need to call chrome.windows.create() to open a pop-up and request permission before the Service Worker can continue.

  2. Always call chrome.windows.create() to open a pop-up as part of transferring the file to the device, and use the pop-up to display progress in addition to needing it for the occasional permission prompt.

While an offscreen document, as suggested by one of the comments, can call requestDevice(), it will always throw an exception because the document is not visible.

Upvotes: 1

Related Questions