L'API WebUSB rende USB più sicura e facile da usare portandola sul web.
Se ho detto in modo chiaro e semplice "USB", è molto probabile che tu pensa subito a tastiere, mouse, audio, video e dispositivi di archiviazione. Stai ma ci saranno altri tipi di dispositivi USB là.
Questi dispositivi USB non standardizzati richiedono ai fornitori di hardware di scrivere dati specifici della piattaforma per consentire a te (lo sviluppatore) di utilizzarli. Purtroppo questo codice specifico della piattaforma ha sempre impedito l'utilizzo di questi dispositivi. dal Web. Questo è uno dei motivi per cui l'API WebUSB è stata creata: offrono un modo per esporre i servizi dei dispositivi USB sul Web. Con questa API, i produttori potranno creare SDK JavaScript multipiattaforma per dispositivi mobili.
Ma soprattutto questo rende l'USB più sicura e più facile da usare poiché al web.
Vediamo il comportamento che ci si potrebbe aspettare con l'API WebUSB:
- Acquista un dispositivo USB.
- Collegalo al computer. Viene visualizzata subito una notifica, con il pulsante sito web a cui visitare il sito per questo dispositivo.
- Fai clic sulla notifica. Il sito web è lì e pronto per essere utilizzato.
- Se fai clic per connetterti, in Chrome viene visualizzato un Selettore dispositivi USB da cui puoi scegli il tuo dispositivo.
Ehilà!
Come sarebbe questa procedura senza l'API WebUSB?
- Installare un'applicazione specifica della piattaforma.
- Se è supportata anche dal mio sistema operativo, verifica di aver scaricato l'app la cosa giusta.
- Installa il dispositivo. Se hai fortuna, non riceverai popup o prompt del sistema operativo spaventosi che ti avvisa in merito all'installazione di driver/applicazioni da Internet. Se sei sfortunato, le applicazioni o i driver installati non funzionano correttamente e danneggiano del tuo computer. Ricorda che il web è progettato per contenere malfunzionamenti siti web).
- Se utilizzi la funzione una sola volta, il codice rimane sul computer finché non pensare di rimuoverlo. (Sul Web, lo spazio per i dati inutilizzati alla fine reclaimed.)
Prima di iniziare
In questo articolo si presuppone che tu abbia una conoscenza di base del funzionamento di USB. In caso contrario, consigliamo di leggere l'articolo USB in a NutShell. Per informazioni di base sull'interfaccia USB, consulta le specifiche ufficiali USB.
L'API WebUSB è disponibile in Chrome 61.
Disponibile per le prove dell'origine
Per ottenere il maggior feedback possibile dagli sviluppatori che utilizzano WebUSB l'API sul campo, in precedenza avevamo aggiunto questa funzionalità a Chrome 54 e Chrome 57 come prova dell'origine.
L'ultima prova è terminata correttamente a settembre 2017.
Privacy e sicurezza
Solo HTTPS
Grazie alla sua potenza, questa funzionalità funziona solo in contesti sicuri. Ciò significa dovrai creare tenendo presente TLS.
Gesto dell'utente richiesto
Come misura di sicurezza, navigator.usb.requestDevice()
può soltanto
essere chiamato tramite un gesto dell'utente, ad esempio un tocco o un clic del mouse.
Norme sulle autorizzazioni
I criteri relativi alle autorizzazioni sono un meccanismo che consente agli sviluppatori di attivare selettivamente e disattivare varie funzionalità e API del browser. Può essere definito tramite un protocollo HTTP un'intestazione e/o un iframe "allow" .
Puoi definire un criterio relativo alle autorizzazioni che controlli se l'attributo usb
viene
visibili sull'oggetto Navigator o, in altre parole, se consenti WebUSB.
Di seguito è riportato un esempio di criterio di intestazione in cui WebUSB non è consentito:
Feature-Policy: fullscreen "*"; usb "none"; payment "self" https://payment.example.com
Di seguito è riportato un altro esempio di criterio dei container in cui è consentito USB:
<iframe allowpaymentrequest allow="usb; fullscreen"></iframe>
Iniziamo a programmare
L'API WebUSB fa grande affidamento sulle promesse JavaScript. Se non hai familiarità
guarda questo fantastico tutorial sulle promesse. Un'ultima cosa: () => {}
sono semplicemente funzioni freccia in ECMAScript 2015.
Accedere ai dispositivi USB
Puoi chiedere all'utente di selezionare un singolo dispositivo USB connesso utilizzando
navigator.usb.requestDevice()
o chiama navigator.usb.getDevices()
per ricevere un
l'elenco di tutti i dispositivi USB connessi a cui è stato concesso l'accesso al sito web.
La funzione navigator.usb.requestDevice()
accetta un oggetto JavaScript obbligatorio
che definisce filters
. Questi filtri vengono utilizzati per associare qualsiasi dispositivo USB ai
determinati identificatori del fornitore (vendorId
) e, facoltativamente, del prodotto (productId
).
Le chiavi classCode
, protocolCode
, serialNumber
e subclassCode
possono
in questa pagina.
Ad esempio, ecco come ottenere l'accesso a un dispositivo Arduino connesso configurato per consentire l'origine.
navigator.usb.requestDevice({ filters: [{ vendorId: 0x2341 }] })
.then(device => {
console.log(device.productName); // "Arduino Micro"
console.log(device.manufacturerName); // "Arduino LLC"
})
.catch(error => { console.error(error); });
Prima che tu lo chieda, non ho magicamente inventato questo esadecimale 0x2341
numero. Ho semplicemente cercato la parola "Arduino" in questo elenco di ID USB.
L'USB device
restituita nella promessa rispettata di cui sopra ha alcune basi, ma
per informazioni importanti sul dispositivo, ad esempio la versione USB supportata,
dimensione massima del pacchetto, ID fornitore e ID prodotto, il numero
configurazioni che il dispositivo può avere. Contiene tutti i campi della
descrittore USB del dispositivo.
// Get all connected USB devices the website has been granted access to.
navigator.usb.getDevices().then(devices => {
devices.forEach(device => {
console.log(device.productName); // "Arduino Micro"
console.log(device.manufacturerName); // "Arduino LLC"
});
})
A proposito, se un dispositivo USB annuncia che supporta WebUSB, oltre a definendo un URL pagina di destinazione, Chrome mostrerà una notifica persistente quando Dispositivo USB collegato. Se fai clic su questa notifica, si aprirà la pagina di destinazione.
Parla a una scheda USB Arduino
Vediamo com'è facile comunicare da un dispositivo WebUSB compatibile Scheda Arduino tramite porta USB. Consulta le istruzioni all'indirizzo https://github.com/webusb/arduino per abilitare WebUSB per i tuoi schizzi.
Non preoccuparti, più avanti tratterò tutti i metodi per i dispositivi WebUSB menzionati di seguito questo articolo.
let device;
navigator.usb.requestDevice({ filters: [{ vendorId: 0x2341 }] })
.then(selectedDevice => {
device = selectedDevice;
return device.open(); // Begin a session.
})
.then(() => device.selectConfiguration(1)) // Select configuration #1 for the device.
.then(() => device.claimInterface(2)) // Request exclusive control over interface #2.
.then(() => device.controlTransferOut({
requestType: 'class',
recipient: 'interface',
request: 0x22,
value: 0x01,
index: 0x02})) // Ready to receive data
.then(() => device.transferIn(5, 64)) // Waiting for 64 bytes of data from endpoint #5.
.then(result => {
const decoder = new TextDecoder();
console.log('Received: ' + decoder.decode(result.data));
})
.catch(error => { console.error(error); });
Tieni presente che la libreria WebUSB che sto utilizzando sta solo implementando un protocollo di esempio (basato sul protocollo seriale USB standard) e che i produttori possono creare qualsiasi insieme e tipo di endpoint. I trasferimenti di controllo sono particolarmente utili per comandi di configurazione di piccole dimensioni, hanno la priorità sugli autobus e hanno una struttura ben definita.
Ed ecco lo schizzo che è stato caricato sulla lavagna Arduino.
// Third-party WebUSB Arduino library
#include <WebUSB.h>
WebUSB WebUSBSerial(1 /* https:// */, "webusb.github.io/arduino/demos");
#define Serial WebUSBSerial
void setup() {
Serial.begin(9600);
while (!Serial) {
; // Wait for serial port to connect.
}
Serial.write("WebUSB FTW!");
Serial.flush();
}
void loop() {
// Nothing here for now.
}
La libreria WebUSB Arduino di terze parti utilizzata nel codice campione sopra riportato due cose:
- Il dispositivo funge da dispositivo WebUSB che consente a Chrome di leggere l'URL pagina di destinazione.
- Espone un'API WebUSB Serial che puoi utilizzare per eseguire l'override di quella predefinita.
Controlla di nuovo il codice JavaScript. Quando l'utente sceglie device
,
device.open()
esegue tutti i passaggi specifici della piattaforma per avviare una sessione con l'USB
dispositivo. Quindi, devo selezionare una configurazione USB disponibile con
device.selectConfiguration()
. Ricorda che una configurazione specifica il modo in cui
è alimentato, il consumo massimo e il numero di interfacce.
A proposito di interfacce, devo richiedere anche l'accesso esclusivo con
device.claimInterface()
poiché i dati possono essere trasferiti solo a un'interfaccia o
associati agli endpoint quando viene richiesta l'interfaccia. Finalmente le chiamate
device.controlTransferOut()
è necessario per configurare il dispositivo Arduino con
i comandi appropriati per comunicare tramite l'API WebUSB Serial.
Da qui, device.transferIn()
esegue un trasferimento collettivo sulla
per informarlo che l'host è pronto a ricevere dati in blocco. Quindi,
la promessa viene soddisfatta con un oggetto result
contenente un data
DataView che
devono essere analizzati correttamente.
Se hai familiarità con USB, tutto questo dovrebbe esserti familiare.
Voglio di più
L'API WebUSB ti consente di interagire con tutti i tipi di trasferimento/endpoint USB:
- CONTROLLI trasferimenti, utilizzati per inviare o ricevere configurazione o comandi
a un dispositivo USB, vengono gestiti con
controlTransferIn(setup, length)
econtrolTransferOut(setup, data)
. - I trasferimenti INTERRUPT, utilizzati per una piccola quantità di dati sensibili al tempo, vengono
gestiti con gli stessi metodi dei trasferimenti BULK con
transferIn(endpointNumber, length)
etransferOut(endpointNumber, data)
. - I trasferimenti ISOCHRONOUS, utilizzati per flussi di dati come video e audio, sono
gestito con
isochronousTransferIn(endpointNumber, packetLengths)
eisochronousTransferOut(endpointNumber, data, packetLengths)
. - Trasferimenti BULK, utilizzati per trasferire una grande quantità di dati non sensibili al tempo in
in modo affidabile, vengono gestiti con
transferIn(endpointNumber, length)
transferOut(endpointNumber, data)
.
Puoi anche dare un'occhiata al progetto WebLight di Mike Tsao, che offre un esempio pratico della realizzazione di un dispositivo LED controllato tramite USB progettato per l'API WebUSB (in questo caso non si utilizza Arduino). Troverai hardware, software e firmware.
Revocare l'accesso a un dispositivo USB
Il sito web può eliminare le autorizzazioni per accedere a un dispositivo USB di cui non ha più bisogno
chiamando forget()
sull'istanza USBDevice
. Ad esempio, per un
un'applicazione web didattica utilizzata su un computer condiviso con molti dispositivi, un
numero di autorizzazioni generate dagli utenti accumulate crea un'esperienza utente scadente.
// Voluntarily revoke access to this USB device.
await device.forget();
Poiché forget()
è disponibile in Chrome 101 o versioni successive, controlla se questa funzionalità è
supportati con quanto segue:
if ("usb" in navigator && "forget" in USBDevice.prototype) {
// forget() is supported.
}
Limiti delle dimensioni di trasferimento
Alcuni sistemi operativi impongono dei limiti alla quantità di dati che possono transazioni USB in attesa. Suddividi i dati in transazioni più piccole e l'invio di un numero limitato di richieste alla volta consente di evitare tali limitazioni. Inoltre, riduce la quantità di memoria utilizzata e consente all'applicazione di segnalare l'avanzamento come trasferimenti completati.
Poiché più trasferimenti inviati a un endpoint vengono sempre eseguiti in ordine, è possibile migliorare la velocità effettiva inviando più blocchi in coda per evitare di latenza tra i trasferimenti USB. Ogni volta che un chunk viene trasmesso completamente, avvisa il tuo codice che deve fornire più dati, come documentato nell'helper di seguito.
const BULK_TRANSFER_SIZE = 16 * 1024; // 16KB
const MAX_NUMBER_TRANSFERS = 3;
async function sendRawPayload(device, endpointNumber, data) {
let i = 0;
let pendingTransfers = [];
let remainingBytes = data.byteLength;
while (remainingBytes > 0) {
const chunk = data.subarray(
i * BULK_TRANSFER_SIZE,
(i + 1) * BULK_TRANSFER_SIZE
);
// If we've reached max number of transfers, let's wait.
if (pendingTransfers.length == MAX_NUMBER_TRANSFERS) {
await pendingTransfers.shift();
}
// Submit transfers that will be executed in order.
pendingTransfers.push(device.transferOut(endpointNumber, chunk));
remainingBytes -= chunk.byteLength;
i++;
}
// And wait for last remaining transfers to complete.
await Promise.all(pendingTransfers);
}
Suggerimenti
Il debug USB in Chrome è più semplice con la pagina interna about://device-log
dove puoi vedere in un unico posto tutti gli eventi relativi ai dispositivi USB.
Anche la pagina interna about://usb-internals
è utile e ti consente
per simulare la connessione e la disconnessione di dispositivi WebUSB virtuali.
È utile per eseguire test dell'interfaccia utente senza hardware reale.
Sulla maggior parte dei sistemi Linux, i dispositivi USB sono mappati con autorizzazioni di sola lettura
predefinito. Per consentire a Chrome di aprire un dispositivo USB, dovrai aggiungere un nuovo udev
personalizzata. Crea un file all'indirizzo /etc/udev/rules.d/50-yourdevicename.rules
con
i seguenti contenuti:
SUBSYSTEM=="usb", ATTR{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
dove [yourdevicevendor]
è 2341
se il tuo dispositivo, ad esempio, è una Arduino.
Puoi anche aggiungere ATTR{idProduct}
per una regola più specifica. Assicurati che
user
è un membro del gruppo plugdev
. Dopodiché ricollega il dispositivo.
Risorse
- Stack Overflow: https://stackoverflow.com/questions/tagged/webusb
- Specifiche API WebUSB: http://wicg.github.io/webusb/
- Stato delle funzionalità di Chrome: https://www.chromestatus.com/feature/5651917954875392
- Problemi con le specifiche: https://github.com/WICG/webusb/issues
- Bug di implementazione: http://crbug.com?q=component:Blink>USB
- WebUSB ❤ ️Arduino: https://github.com/webusb/arduino
- IRC: #webusb su IRC di W3C
- Mailing list WICG: https://lists.w3.org/Archives/Public/public-wicg/
- Progetto WebLight: https://github.com/sowbug/weblight
Invia un tweet a @ChromiumDev utilizzando l'hashtag
#WebUSB
:
e facci sapere dove e come lo utilizzi.
Ringraziamenti
Grazie a Joe Medley per aver letto questo articolo.