Request device permission
This page only applies to browsers. For Node.js, you can skip to the next step.
Request permission in WebUSB
In Web browsers, each website needs to request the permission to access each device separately using WebUSB's USB#requestDevice
method.
User activation
USB#requestDevice
method requires user activation, it must be called in response to a mouse click or keyboard press event.
Device picker
After calling USB#requestDevice
, the browser shows a list of connected devices to the user. The user can select one (and only one) device from the list, or cancel the picker without selecting any device.
You can filter the devices shown in the picker, but otherwise you can't control the picker's appearance or behavior.
Return value
It will return an USBDevice
instance representing the selected device, or throws an DOMException
with name
set to NotFoundError
if the user cancelled the picker.
This code is for demonstration purposes only. You should use AdbDaemonWebUsbDeviceManager#requestDevice
described below in Tango.
- JavaScript
- TypeScript
document.getElementById("button").addEventListener("click", () => {
try {
const device = await navigator.usb.requestDevice({
filters: [
{
classCode: 0xff,
subclassCode: 0x42,
protocolCode: 1,
},
],
});
alert(`Selected device: ${device.serialNumber}`);
} catch (e) {
if (e instanceof DOMException && e.name === "NotFoundError") {
alert("No device selected");
return;
}
throw e;
}
});
document.getElementById("button").addEventListener("click", () => {
try {
const device: USBDevice = await navigator.usb.requestDevice({
filters: [
{
classCode: 0xff,
subclassCode: 0x42,
protocolCode: 1,
},
],
});
alert(`Selected device: ${device.serialNumber}`);
} catch (e) {
if (e instanceof DOMException && e.name === "NotFoundError") {
alert("No device selected");
return;
}
throw e;
}
});
Permission persistence
The permission will be persisted by the browser, so from next time, the website can access that device without calling requestDevice
again. The user can revoke the permission in "Settings -> Site Permissions -> USB devices" at any time.
USB mode affects permissions
When Android devices works in USB peripheral mode, they can have multiple USB interfaces, like MTP (file transfer), ADB, RNDIS (reverse tethering), MIDI, etc.
When any interface is turned on or off from system UI, the device will disconnect and reconnect to the USB host and report a different set of interfaces.
As a result, in Web browsers, the same Android device with different sets of interfaces will be treated as different devices, and have different permissions. The website might need to request permission again when Android device switches to another mode.
Request permission in Tango
AdbDaemonWebUsbDeviceManager#requestDevice
method provides a more convenient way to request permission for Android devices with ADB interface enabled.
declare class AdbDaemonWebUsbDeviceManager {
requestDevice(): Promise<AdbDaemonWebUsbDevice | undefined>;
}
It calls USB#requestDevice
internally, thus the user activation, device picker, and permission persistence behaviors are the same as USB#requestDevice
.
The only difference is the return value:
- When the user selects a device, it returns an
AdbDaemonWebUsbDevice
instance, which includes the rawUSBDevice
handle and additional information required by later steps. - If the user cancels the picker, it returns
undefined
, instead of throwing an error.
- JavaScript
- TypeScript
document.getElementById("button").addEventListener("click", () => {
const device = await Manager.requestDevice();
if (!device) {
alert("No device selected");
return;
}
});
import { AdbDaemonWebUsbDevice } from "@yume-chan/adb-daemon-webusb";
document.getElementById("button").addEventListener("click", () => {
const device: AdbDaemonWebUsbDevice | undefined = await Manager.requestDevice();
if (!device) {
alert("No device selected");
return;
}
});
Filter devices in the picker
interface AdbDeviceFilter {
classCode: number;
subclassCode: number;
protocolCode: number;
vendorId?: number | undefined;
productId?: number | undefined;
serialNumber?: string | undefined;
}
namespace AdbDaemonWebUsbDeviceManager {
interface RequestDeviceOptions {
filters?: AdbDeviceFilter[] | undefined;
exclusionFilters?: USBDeviceFilter[] | undefined;
}
}
declare class AdbDaemonWebUsbDeviceManager {
requestDevice(
options?: AdbDaemonWebUsbDeviceManager.RequestDeviceOptions
): Promise<AdbDaemonWebUsbDevice | undefined>;
}
See Device filter for more information about how does the filter work and how to define a filter.
filters
The filters
option defaults to [ADB_DEFAULT_DEVICE_FILTER]
, which matches the ADB interface. If you want to filter devices by vendor ID, product ID, or serial number, you can specify a custom filter array.
filters
can be undefined
, but it can't be an empty array. If you want to allow all devices, use undefined
or [ADB_DEFAULT_DEVICE_FILTER]
.
exclusionFilters
It's also possible to exclude specific devices from the picker using the exclusionFilters
option. It works in reverse: if a device matches any filter in exclusionFilters
, it will be excluded from the picker.
It can be used to exclude devices that are already paired, or exclude certain devices that are incompatible.
Support for exclusive filters was added in Chrome 105. It will be ignored in older versions.
Examples
To select a specific manufacturer and model:
- JavaScript
- TypeScript
import { ADB_DEFAULT_DEVICE_FILTER } from "@yume-chan/adb-daemon-webusb";
const device = await Manager.requestDevice({
filters: [
{
...ADB_DEFAULT_DEVICE_FILTER,
vendorId: 0x18d1,
productId: 0x4ee2,
},
],
});
import { AdbDaemonWebUsbDevice, ADB_DEFAULT_DEVICE_FILTER } from "@yume-chan/adb-daemon-webusb";
const device: AdbDaemonWebUsbDevice | undefined = await Manager.requestDevice({
filters: [
{
...ADB_DEFAULT_DEVICE_FILTER,
vendorId: 0x18d1,
productId: 0x4ee2,
},
],
});
To allow multiple manufacturers/models:
- JavaScript
- TypeScript
import { ADB_DEFAULT_DEVICE_FILTER } from "@yume-chan/adb-daemon-webusb";
const device = await Manager.requestDevice({
filters: [
{
...ADB_DEFAULT_DEVICE_FILTER,
vendorId: 0x18d1,
productId: 0x4ee2,
},
{
...ADB_DEFAULT_DEVICE_FILTER,
vendorId: 0x04e8,
productId: 0x6860,
},
],
});
import { AdbDaemonWebUsbDevice, ADB_DEFAULT_DEVICE_FILTER } from "@yume-chan/adb-daemon-webusb";
const device: AdbDaemonWebUsbDevice | undefined = await Manager.requestDevice({
filters: [
{
...ADB_DEFAULT_DEVICE_FILTER,
vendorId: 0x18d1,
productId: 0x4ee2,
},
{
...ADB_DEFAULT_DEVICE_FILTER,
vendorId: 0x04e8,
productId: 0x6860,
},
],
});
Drop permission
If a device is connected and the permission to access it was granted, but you don't want to access it anymore, you can drop the permission.
device.raw.forget();
Because there is no way to retrieve permission-granted but disconnected devices (unless you got the device
before it was disconnected), it's also not possible to drop permissions for them. (See https://github.com/WICG/webusb/issues/166)