Device Access设备访问
Like Chromium based browsers, Electron provides access to device hardware through web APIs. 与基于Chromium的浏览器一样,Electron通过web API提供对设备硬件的访问。For the most part these APIs work like they do in a browser, but there are some differences that need to be taken into account. 在大多数情况下,这些API的工作方式与浏览器类似,但需要考虑一些差异。The primary difference between Electron and browsers is what happens when device access is requested. Electron浏览器和浏览器之间的主要区别是当请求设备访问时会发生什么。In a browser, users are presented with a popup where they can grant access to an individual device. 在浏览器中,用户会看到一个弹出窗口,可以在其中授予对单个设备的访问权限。In Electron APIs are provided which can be used by a developer to either automatically pick a device or prompt users to pick a device via a developer created interface.提供了In-Electron API,开发者可以使用该API自动选择设备或通过开发者创建的界面提示用户选择设备。
Web Bluetooth APIWeb蓝牙API
The Web Bluetooth API can be used to communicate with bluetooth devices. Web蓝牙API可用于与蓝牙设备通信。In order to use this API in Electron, developers will need to handle the 为了在Electron中使用此API,开发人员需要处理与设备请求相关联的WebContents上的select-bluetooth-device
event on the webContents associated with the device request.select-bluetooth-device
事件。
Example示例
This example demonstrates an Electron application that automatically selects the first available bluetooth device when the 此示例演示了一个Electron应用程序,当单击Test Bluetooth
button is clicked.Test Bluetooth
按钮时,它会自动选择第一个可用的蓝牙设备。
- main.js
- index.html
- renderer.js
const {app, BrowserWindow} = require('electron')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
width: 800,
height: 600
})
mainWindow.webContents.on('select-bluetooth-device', (event, deviceList, callback) => {
event.preventDefault()
if (deviceList && deviceList.length > 0) {
callback(deviceList[0].deviceId)
}
})
mainWindow.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Web Bluetooth API</title>
</head>
<body>
<h1>Web Bluetooth API</h1>
<button id="clickme">Test Bluetooth</button>
<p>Currently selected bluetooth device: <strong id="device-name""></strong></p>
<script src="./renderer.js"></script>
</body>
</html>
async function testIt() {
const device = await navigator.bluetooth.requestDevice({
acceptAllDevices: true
})
document.getElementById('device-name').innerHTML = device.name || `ID: ${device.id}`
}
document.getElementById('clickme').addEventListener('click',testIt)
WebHID API
The WebHID API can be used to access HID devices such as keyboards and gamepads. WebHID API可用于访问HID设备,如键盘和游戏机。Electron provides several APIs for working with the WebHID API:Electron为使用WebHID API提供了几个API:
The会话上的select-hid-device
event on the Session can be used to select a HID device when a call tonavigator.hid.requestDevice
is made.select-hid-device
事件可用于在调用navigator.hid.requestDevice
时选择HID设备。Additionally the此外,会话上的hid-device-added
and hid-device-removed events on the Session can be used to handle devices being plugged in or unplugged when handling theselect-hid-device
event.hid-device-added
和hid-device-removed事件可用于处理在处理select-hid-device
事件时插入或拔出的设备。Note: These events only fire until the callback from注意:这些事件仅在调用select-hid-device
is called.select-hid-device
的回调之前触发。They are not intended to be used as a generic hid device listener.它们不打算用作通用hid设备监听器。- ses.setDevicePermissionHandler(handler)
can be used to provide default permissioning to devices without first calling for permission to devices via可用于为设备提供默认许可,而无需首先通过navigator.hid.requestDevice
.navigator.hid.requestDevice
调用设备许可。Additionally, the default behavior of Electron is to store granted device permision through the lifetime of the corresponding WebContents.此外,Electron的默认行为是在相应网络内容的生命周期内存储授予的设备许可。If longer term storage is needed, a developer can store granted device permissions (eg when handling the如果需要长期存储,开发人员可以存储授予的设备权限(例如在处理select-hid-device
event) and then read from that storage withsetDevicePermissionHandler
.select-hid-device
事件时),然后使用setDevicePermissionHandler
从该存储中读取。 - ses.setPermissionCheckHandler(handler)
can be used to disable HID access for specific origins.可用于禁用特定来源的HID访问。
Blocklist黑名单
By default Electron employs the same blocklist used by Chromium. 默认情况下,Electron使用与Chromium相同的黑名单。If you wish to override this behavior, you can do so by setting the 如果希望覆盖此行为,可以通过设置disable-hid-blocklist
flag:disable-hid-blocklist
标志:
app.commandLine.appendSwitch('disable-hid-blocklist')
Example示例
This example demonstrates an Electron application that automatically selects HID devices through ses.setDevicePermissionHandler(handler) and through 本示例演示了一个Electron应用程序,该应用程序通过ses.setDevicePermissionHandler(handler)和单击测试WebHID按钮时会话上的select-hid-device
event on the Session when the Test WebHID
button is clicked.select-hid-device
事件自动选择HID设备。
- main.js
- index.html
- renderer.js
const {app, BrowserWindow} = require('electron')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
width: 800,
height: 600
})
mainWindow.webContents.session.on('select-hid-device', (event, details, callback) => {
//Add events to handle devices being added or removed before the callback on
//`select-hid-device` is called.
mainWindow.webContents.session.on('hid-device-added', (event, device) => {
console.log('hid-device-added FIRED WITH', device)
//Optionally update details.deviceList
})
mainWindow.webContents.session.on('hid-device-removed', (event, device) => {
console.log('hid-device-removed FIRED WITH', device)
//Optionally update details.deviceList
})
event.preventDefault()
if (details.deviceList && details.deviceList.length > 0) {
callback(details.deviceList[0].deviceId)
}
})
mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
if (permission === 'hid' && details.securityOrigin === 'file:///') {
return true
}
})
mainWindow.webContents.session.setDevicePermissionHandler((details) => {
if (details.deviceType === 'hid' && details.origin === 'file://') {
return true
}
})
mainWindow.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>WebHID API</title>
</head>
<body>
<h1>WebHID API</h1>
<button id="clickme">Test WebHID</button>
<h3>HID devices automatically granted access via <i>setDevicePermissionHandler</i></h3>
<div id="granted-devices"></div>
<h3>HID devices automatically granted access via <i>select-hid-device</i></h3>
<div id="granted-devices2"></div>
<script src="./renderer.js"></script>
</body>
</html>
async function testIt() {
const grantedDevices = await navigator.hid.getDevices()
let grantedDeviceList = ''
grantedDevices.forEach(device => {
grantedDeviceList += `<hr>${device.productName}</hr>`
})
document.getElementById('granted-devices').innerHTML = grantedDeviceList
const grantedDevices2 = await navigator.hid.requestDevice({
filters: []
})
grantedDeviceList = ''
grantedDevices2.forEach(device => {
grantedDeviceList += `<hr>${device.productName}</hr>`
})
document.getElementById('granted-devices2').innerHTML = grantedDeviceList
}
document.getElementById('clickme').addEventListener('click',testIt)
Web Serial 串行API
The Web Serial API can be used to access serial devices that are connected via serial port, USB, or Bluetooth. Web串行API可用于访问通过串行端口、USB或蓝牙连接的串行设备。 In order to use this API in Electron, developers will need to handle the 为了在Electron中使用此API,开发人员需要在与串行端口请求相关联的会话上处理select-serial-port
event on the Session associated with the serial port request.select-serial-port
事件。
There are several additional APIs for working with the Web Serial API:有几个额外的API用于使用Web串行API:
The serial-port-added and serial-port-removed events on the Session can be used to handle devices being plugged in or unplugged when handling the会话上的serial-port-added和serial-port-removed事件可用于在处理选择串行端口事件时处理插入或拔出的设备。select-serial-port
event.Note:注意:These events only fire until the callback from这些事件仅在调用select-serial-port
is called.select-serial-port
的回调之前触发。They are not intended to be used as a generic serial port listener.它们不打算用作通用串行端口侦听器。- ses.setDevicePermissionHandler(handler)
can be used to provide default permissioning to devices without first calling for permission to devices via可用于为设备提供默认许可,而无需首先通过navigator.serial.requestPort
.navigator.serial.requestPort
调用设备许可。Additionally, the default behavior of Electron is to store granted device permision through the lifetime of the corresponding WebContents.此外,Electron的默认行为是在相应网络内容的生命周期内存储授予的设备许可。If longer term storage is needed, a developer can store granted device permissions (eg when handling the如果需要长期存储,开发人员可以存储授予的设备权限(例如在处理select-serial-port
event) and then read from that storage withsetDevicePermissionHandler
.select-serial-port
事件时),然后使用setDevicePermissionHandler
从该存储中读取。 - ses.setPermissionCheckHandler(handler)
can be used to disable serial access for specific origins.可用于禁用特定来源的串行访问。
Example示例
This example demonstrates an Electron application that automatically selects serial devices through ses.setDevicePermissionHandler(handler) as well as demonstrating selecting the first available Arduino Uno serial device (if connected) through 本示例演示了一个Electron应用程序,它通过ses.setDevicePermissionHandler(handler)自动选择串行设备,并演示了在单击select-serial-port
event on the Session when the Test Web Serial
button is clicked.Test Web Serial
按钮时,通过会话上的select-serial-port
事件选择第一个可用的Arduino Uno串行设备(如果已连接)。
- main.js
- index.html
- renderer.js
const {app, BrowserWindow} = require('electron')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
width: 800,
height: 600
})
mainWindow.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => {
//Add listeners to handle ports being added or removed before the callback for `select-serial-port`
//is called.
mainWindow.webContents.session.on('serial-port-added', (event, port) => {
console.log('serial-port-added FIRED WITH', port)
//Optionally update portList to add the new port
})
mainWindow.webContents.session.on('serial-port-removed', (event, port) => {
console.log('serial-port-removed FIRED WITH', port)
//Optionally update portList to remove the port
})
event.preventDefault()
if (portList && portList.length > 0) {
callback(portList[0].portId)
} else {
callback('') //Could not find any matching devices
}
})
mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
if (permission === 'serial' && details.securityOrigin === 'file:///') {
return true
}
})
mainWindow.webContents.session.setDevicePermissionHandler((details) => {
if (details.deviceType === 'serial' && details.origin === 'file://') {
return true
}
})
mainWindow.loadFile('index.html')
mainWindow.webContents.openDevTools()
}
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Web Serial API</title>
<body>
<h1>Web Serial API</h1>
<button id="clickme">Test Web Serial API</button>
<p>Matching Arduino Uno device: <strong id="device-name""></strong></p>
<script src="./renderer.js"></script>
</body>
</html>
async function testIt() {
const filters = [
{ usbVendorId: 0x2341, usbProductId: 0x0043 },
{ usbVendorId: 0x2341, usbProductId: 0x0001 }
];
try {
const port = await navigator.serial.requestPort({filters});
const portInfo = port.getInfo();
document.getElementById('device-name').innerHTML = `vendorId: ${portInfo.usbVendorId} | productId: ${portInfo.usbProductId} `
} catch (ex) {
if (ex.name === 'NotFoundError') {
document.getElementById('device-name').innerHTML = 'Device NOT found'
} else {
document.getElementById('device-name').innerHTML = ex
}
}
}
document.getElementById('clickme').addEventListener('click',testIt)