在浏览器上访问USB设备
如果我说简单明了的“ USB”,您很有可能会立即想到键盘,鼠标,音频,视频和存储设备。没错,但是您会发现其他种类的通用串行总线(USB)设备。
这些非标准USB设备要求硬件供应商编写本机驱动程序和SDK,以便您(开发人员)能够利用它们。遗憾的是,此本地代码历来阻止了Web使用这些设备。这就是创建WebUSB API的原因之一:提供一种将USB设备服务公开到Web的方法。使用此API,硬件制造商将能够为其设备构建跨平台的JavaScript SDK。但是最重要的是,通过将USB引入网络,这将使USB更安全,更易于使用。
让我们看看您对WebUSB API的期望:
购买USB设备。
将其插入计算机。
随即会显示一条通知,并提供访问此设备的正确网站。
只需单击它。网站在那里,随时可以使用!
单击以连接,然后USB设备选择器将显示在Chrome中,您可以在其中选择设备。
多田!
如果没有WebUSB API,此过程将如何?
阅读框,标签或在线搜索,可能最终会在错误的网站上看到。
必须安装本机应用程序。
我的操作系统支持吗?确保下载“正确”的东西。
可怕的操作系统提示弹出窗口,并警告您有关从Internet安装驱动程序/应用程序的信息。
错误的代码会损害整个计算机。该Web 包含故障网站。
只能使用USB设备一次?在Web上,一旦关闭选项卡,该网站就会消失。在计算机上,代码始终存在。
开始之前
本文假定您具有USB工作原理的一些基本知识。如果没有,我建议您在NutShell中读取USB。有关USB的背景信息,请查看官方USB规格。
该WebUSB API在Chrome 61是可用的。
适用于原产地审判
为了从使用该领域的WebUSB API的开发人员那里获得尽可能多的反馈,我们先前已在Chrome 54和Chrome 57中将此功能添加为原始试用。
最新的审判已于2017年9月成功结束。
隐私权与安全性
仅HTTPS
由于此API是网络上新增的强大功能,因此Chrome旨在使其仅可用于安全上下文。这意味着您需要在构建时考虑TLS。
在开发过程中,您将能够http://localhost
使用Chrome Dev Editor 或handy之类的工具与WebUSB进行交互 python -m SimpleHTTPServer
,但是要在网站上部署它,则需要在服务器上设置HTTPS。我个人出于演示目的而喜欢GitHub Pages。
要将HTTPS添加到服务器,您需要获取TLS证书并进行设置。请务必查看“ 使用HTTPS 进行安全性”文章,以获取最佳实践。有关信息,您现在可以使用新的证书颁发机构Let's Encrypt获得免费的TLS证书。
需要用户手势
作为一项安全功能,navigator.usb.requestDevice
必须通过诸如触摸或鼠标单击之类的用户手势来调用已连接的USB设备 。
功能政策
功能策略是一种机制,允许开发人员有选择地启用和禁用各种浏览器功能和API。可以通过HTTP标头和/或iframe“ allow”属性进行定义。
您可以定义一个功能来控制usb属性是否显示在Navigator对象上,或者如果允许WebUSB,则换句话说。
以下是不允许使用WebUSB的标头策略的示例:
Feature-Policy: fullscreen "*"; usb "none"; payment "self" https://payment.example.com
下面是另一个允许USB的容器策略的示例:
<iframe allowpaymentrequest allow=’usb fullscreen’></iframe>
让我们开始编码
WebUSB API严重依赖JavaScript Promises。如果您不熟悉它们,请查看此出色的 Promises教程。还有一件事,() => {}
就是ECMAScript 2015 Arrow函数 -与函数表达式相比,它们的语法更短,并且用词法绑定了this
。的值。
存取USB装置
您可以使用或提示用户选择单个连接的USB设备,也可以通过 navigator.usb.requestDevice
调用navigator.usb.getDevices
获取源可以访问的所有连接的USB设备的列表。
该navigator.usb.requestDevice
函数接受一个定义为的强制性JavaScript对象filters
。这些过滤器用于将任何USB设备与给定的供应商(vendorId
)和可选的产品(productId
)标识符进行匹配。在 classCode
,protocolCode
,serialNumber
,和subclassCode
键也可以在那里定义为好。
例如,以下是访问已配置为允许起点的已连接Arduino设备的方法。
navigator.usb.requestDevice({ filters: [{ vendorId: 0x2341 }] }).then(device => {
console.log(device.productName); // "Arduino Micro"
console.log(device.manufacturerName); // "Arduino LLC"}).catch(error => { console.log(error); });
在您问之前,我没有神奇地得出这个0x2341
十六进制数。我只是在此USB ID列表中搜索了“ Arduino”一词。
device
以上已兑现承诺中返回的USB 具有有关设备的一些基本但重要的信息,例如受支持的USB版本,最大数据包大小,供应商和产品ID,设备可具有的可能配置数量-基本上, 设备USB描述符
有关信息,如果USB设备宣布支持WebUSB并定义了登录页面URL,则在插入USB设备时,Chrome会显示一个持久通知。单击此通知将打开登录页面。
从那里,您可以简单地调用navigator.usb.getDevices
并访问Arduino设备,如下所示。
navigator.usb.getDevices().then(devices => {
devices.map(device => {
console.log(device.productName); // "Arduino Micro"
console.log(device.manufacturerName); // "Arduino LLC"
});})
与Arduino USB板交谈
好的,现在让我们看看通过USB端口与WebUSB兼容的Arduino板进行通信有多么容易。请查看https://github.com/webusb/arduino上的说明, 以使WebUSB启用草图。
不用担心,我将介绍本文下文中提到的所有WebUSB设备方法。
var 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 => {
let decoder = new TextDecoder();
console.log('Received: ' + decoder.decode(result.data));}).catch(error => { console.log(error); });
请记住,我们在这里使用的WebUSB库仅实现了一个示例协议(基于标准USB串行协议),制造商可以创建他们想要的任何端点集和类型。对于小型配置命令,控制传输特别好,因为它们具有总线优先级并具有明确定义的结构。
这是已上传到Arduino板的草图。
// Third-party WebUSB Arduino library#include <WebUSB.h>WebUSB WebUSBSerial(1 /* https:// */, "webusb.github.io/arduino/demos");#define Serial WebUSBSerialvoid setup() {
Serial.begin(9600);
while (!Serial) {
; // Wait for serial port to connect.
}
Serial.write("WebUSB FTW!");
Serial.flush();}void loop() {
// Nothing here for now.}
上面的示例代码中使用的第三方WebUSB Arduino库基本上完成了两件事:
该设备充当WebUSB设备,使Chrome浏览器可以读取目标网页的网址。
它公开了一个WebUSB串行API,您可以使用它重写默认的API。
让我们再次看一下JavaScript代码。一旦我们被device
用户选择,device.open
只需运行所有特定于平台的步骤即可开始与USB设备的会话。然后,我们必须使用选择一个可用的USB配置device.selectConfiguration
。请记住,配置指定了设备的供电方式,最大功耗以及接口数量。在谈论接口时,我们还需要使用独占访问权限,device.claimInterface
因为只有在声明接口所有权时,数据才能传输到接口或关联的端点。最后device.controlTransferOut
需要调用 以使用适当的命令设置Arduino设备,以通过WebUSB串行API进行通信。
从那里device.transferIn
执行批量传输到设备上,以通知主机主机已准备好接收批量数据。然后,使用result
包含必须正确解析的DataView 的对象 来实现promise data
。
对于那些熟悉USB的人来说,所有这些看起来都应该很熟悉。
我想要更多
WebUSB API使您可以与所有USB传输/端点类型进行交互:
通过
controlTransferIn(setup, length)
和来处理用于向USB设备发送或接收配置或命令参数的CONTROL传输controlTransferOut(setup, data)
。用于少量时间敏感数据的INTERRUPT传输的处理方法与
transferIn(endpointNumber, length)
和和进行BULK传输的处理方法相同transferOut(endpointNumber, data)
。同步传输,用于类似的视频和声音数据的流与处理
isochronousTransferIn(endpointNumber, packetLengths)
和isochronousTransferOut(endpointNumber, data, packetLengths)
。批量传输(用于以可靠的方式传输大量非时间敏感数据)由
transferIn(endpointNumber, length)
和 处理transferOut(endpointNumber, data)
。
您可能还想看看Mike Tsao的WebLight项目,该项目提供了一个构建示例的示例,该示例构建了一个为WebUSB API设计的USB控制的LED设备(此处不使用Arduino)。您会找到硬件,软件和固件。
提示
通过内部页面chrome://device-log
,可以更轻松地在Chrome中调试USB ,您可以在一个位置查看所有与USB设备相关的事件。
内部页面chrome://usb-internals
也很方便,使您可以模拟虚拟WebUSB设备的连接连接和断开连接。这对于无需实际硬件即可进行UI测试非常有用。
在大多数Linux系统上,默认情况下USB设备被映射为只读权限。要允许Chrome打开USB设备,您需要添加新的udev规则。创建一个包含/etc/udev/rules.d/50-yourdevicename.rules
以下内容的文件:
SUBSYSTEM=="usb", ATTR{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
这里[yourdevicevendor]
是2341
如果你的设备是例如一个Arduino。 ATTR{idProduct}
也可以添加更具体的规则。确保您 user
是该plugdev
组的成员。然后,只需重新连接设备即可。
下一步是什么
WebUSB API的第二次迭代将关注Shared Worker 和Service Worker 支持。例如,想象一下使用WebUSB API的安全密钥网站,该网站将安装服务工作者以充当中间人来认证用户。