设备访问
可以被用来连接蓝牙设备。 为了在 Electron 中使用此 API , 开发者将需要在 webContent 处理 select-bluetooth-device 事件 ,从而与设备请求相关联。
此外, 方法可以被用来处理蓝牙设备配对, 这在 Windows 或 Linux 下进行额外的引脚校验时很有效.
这个示例演示了一个 Electron 应用程序,当点击了 按钮时,它会自动选择第一个可用的蓝牙设备。
- main.js
- preload.js
- index.html
- renderer.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
bluetoothPairingRequest: (callback) => ipcRenderer.on('bluetooth-pairing-request', callback),
bluetoothPairingResponse: (response) => ipcRenderer.send('bluetooth-pairing-response', response)
})
<!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)
window.electronAPI.bluetoothPairingRequest((event, details) => {
const response = {}
switch (details.pairingKind) {
case 'confirm': {
response.confirmed = confirm(`Do you want to connect to device ${details.deviceId}?`)
break
}
case 'confirmPin': {
response.confirmed = confirm(`Does the pin ${details.pin} match the pin displayed on device ${details.deviceId}?`)
break
}
case 'providePin': {
const pin = prompt(`Please provide a pin for ${details.deviceId}.`)
if (pin) {
response.pin = pin
response.confirmed = true
} else {
response.confirmed = false
}
}
}
window.electronAPI.bluetoothPairingResponse(response)
})
- 调用
navigator.hid.requestDevice
并选择高清设备,将触发会话内的 select-hid-device 事件 在处理select-hid-device
事件期间, 和 hid-device-removed 两种 Session 事件可以被用来处理设备插拔. Note: These events only fire until the callback fromselect-hid-device
is called. They are not intended to be used as a generic hid device listener. - 在第一次调用
navigator.hid.requestDevice
前, 可以通过 给予设备默认权限, Additionally, the default behavior of Electron is to store granted device permission through the lifetime of the corresponding WebContents. 如果需要更长期的存储,开发人员可以存储设备许可信息(比如: 在处理select-hid-device
事件时), 然后通过setDevicePermissionHandler
从存储的信息中读取 - ses.setPermissionCheckHandler(handler) 可以用于禁用特定来源的 HID 访问。
默认情况下,Electron 使用与 Chromium 相同的 blocklist 如果您想要覆盖此行为,您可以通过设置 disable-hid-blocklist
标志来做到这一点:
这个示例演示了,当 Test WebHID
按钮被点击后,一个Electron 应用将通过 ses.setDevicePermissionHandler(handler) 和 自动选择 HID 设备
docs/fiddles/features/web-hid (23.0.0)
- 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)
可以被用来访问串口设备比如 USB 或蓝牙。 为了在 Electron 中使用这个 API, 开发者需要先定义关联在串口请求中的 select-serial-port 会话事件.
- The and serial-port-removed events on the Session can be used to handle devices being plugged in or unplugged when handling the
select-serial-port
event. Note: These events only fire until the callback fromselect-serial-port
is called. They are not intended to be used as a generic serial port listener. - 在第一次调用
navigator.serial.requestPort
前, 可以通过 给予设备默认权限, Additionally, the default behavior of Electron is to store granted device permission through the lifetime of the corresponding WebContents. 如果需要更长期的存储,开发人员可以存储设备许可信息(比如: 在处理select-serial-port
事件时), 然后通过setDevicePermissionHandler
从存储的信息中读取 - ses.setPermissionCheckHandler(handler) 可以用于禁用特定来源的串口访问。
这个示例项目既演示了一个 Electron 应用通过 ses.setDevicePermissionHandler(handler) 自动选择串口设备,又演示了当 Test Web Serial
按钮被点击后,通过 选择第一个可用的(若已连接) Arduino Uno 串口设备的流程。
docs/fiddles/features/web-serial (23.0.0)
- main.js
- index.html
- renderer.js
<!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)
The can be used to access USB devices. Electron provides several APIs for working with the WebUSB API:
- The select-usb-device event on the Session can be used to select a USB device when a call to
navigator.usb.requestDevice
is made. Additionally the and usb-device-removed events on the Session can be used to handle devices being plugged in or unplugged when handling theselect-usb-device
event. Note: These two events only fire until the callback fromselect-usb-device
is called. They are not intended to be used as a generic usb device listener. - The can be used to respond when device.forget() is called on a USB device.
- can be used to provide default permissioning to devices without first calling for permission to devices via
navigator.usb.requestDevice
. Additionally, the default behavior of Electron is to store granted device permission through the lifetime of the corresponding WebContents. If longer term storage is needed, a developer can store granted device permissions (eg when handling theselect-usb-device
event) and then read from that storage withsetDevicePermissionHandler
. - ses.setPermissionCheckHandler(handler) can be used to disable USB access for specific origins.
This example demonstrates an Electron application that automatically selects USB devices (if they are attached) through ses.setDevicePermissionHandler(handler) and through when the Test WebUSB
button is clicked.
- index.html
- renderer.js
const e = require('express')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
width: 800,
height: 600
})
let grantedDeviceThroughPermHandler
mainWindow.webContents.session.on('select-usb-device', (event, details, callback) => {
//Add events to handle devices being added or removed before the callback on
//`select-usb-device` is called.
mainWindow.webContents.session.on('usb-device-added', (event, device) => {
console.log('usb-device-added FIRED WITH', device)
//Optionally update details.deviceList
})
mainWindow.webContents.session.on('usb-device-removed', (event, device) => {
console.log('usb-device-removed FIRED WITH', device)
//Optionally update details.deviceList
})
event.preventDefault()
if (details.deviceList && details.deviceList.length > 0) {
const deviceToReturn = details.deviceList.find((device) => {
if (!grantedDeviceThroughPermHandler || (device.deviceId != grantedDeviceThroughPermHandler.deviceId)) {
return true
}
})
if (deviceToReturn) {
callback(deviceToReturn.deviceId)
} else {
callback()
}
}
})
mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
if (permission === 'usb' && details.securityOrigin === 'file:///') {
return true
}
})
mainWindow.webContents.session.setDevicePermissionHandler((details) => {
if (details.deviceType === 'usb' && details.origin === 'file://') {
if (!grantedDeviceThroughPermHandler) {
grantedDeviceThroughPermHandler = details.device
return true
} else {
return false
}
}
})
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()
})
function getDeviceDetails(device) {
return grantedDevice.productName || `Unknown device ${grantedDevice.deviceId}`
}
async function testIt() {
const noDevicesFoundMsg = 'No devices found'
const grantedDevices = await navigator.usb.getDevices()
let grantedDeviceList = ''
if (grantedDevices.length > 0) {
grantedDevices.forEach(device => {
grantedDeviceList += `<hr>${getDeviceDetails(device)}</hr>`
})
} else {
grantedDeviceList = noDevicesFoundMsg
}
document.getElementById('granted-devices').innerHTML = grantedDeviceList
grantedDeviceList = ''
try {
const grantedDevice = await navigator.usb.requestDevice({
filters: []
})
grantedDeviceList += `<hr>${getDeviceDetails(device)}</hr>`
} catch (ex) {
if (ex.name === 'NotFoundError') {
grantedDeviceList = noDevicesFoundMsg
}
}
document.getElementById('granted-devices2').innerHTML = grantedDeviceList
}