设备访问 | Electron
https://www.electronjs.org/zh/docs/latest/tutorial/devices • 271 KB fetched
Open original page
设备访问 | Electron
跳转到主内容
Electron 文档 应用开发接口(API) 博客 工具
* Electron Forge
* Electron Fiddle
社区
* 治理
* 案例展示
* 资源
版本发布 中文
* English
* Deutsch
* Español
* Français
* 日本語
* Português
* Русский
* 中文
搜索
* 开始上手
* Electron 中的流程
* 最佳实践
* 示例
* Dark Mode
* 设备访问
* 应用程序内购
*
* 键盘快捷键
* 深度链接 (Deep Links)
* 桌面启动器快捷操作
*
* Menus
* 多线程
* 原生文件拖 & 放
* 导航历史
* 通知(Notifications)
* 离屏渲染
* 在线/离线事件探测
* 进度条
* 最近的文件
*
*
* 在 BrowserWindow 中展示文件
*
* 拼写检查器
* Web 嵌入
* 任务栏自定义
*
* 自定义窗口
* 开发
* Native Node Modules
* 分发
* 检测和调试
* 引用
* 参与贡献
*
* 示例
* 设备访问 在本页面
设备访问
类似基于 Chromium 的浏览器一样, Electron 也提供了通过 web API 访问设备硬件的方法。 大部分接口就像在浏览器调用的 API 一样,但有一些差异需要考虑到。 Electron和浏览器之间的主要区别是请求访问设备时发生的情况。 在浏览器中,用户可以在弹出窗口中允许访问单独的设备。 在 Electron API中,提供了可供开发者自动选择设备或提示用户通过开发者创建的接口选择设备。
Web Bluetooth API
Web Bluetooth API 可以被用来连接蓝牙设备。 为了在 Electron 中使用此 API ,开发者将需要处理与设备请求相关的 webContent 的 select-bluetooth-device 事件 。
此外,当需要进行例如 pin 的额外验证时, ses.setBluetoothPairingHandler(handler) 可以用于在 Windows 或 Linux 上处理配对蓝牙设备。
示例
这个示例演示了一个 Electron 应用程序,当点击了 Test Bluetooth 按钮时,它会自动选择第一个可用的蓝牙设备。
docs/fiddles/features/web-bluetooth ( 43.4.0 ) Open in Fiddle
* main.js
* preload.js
* index.html
* renderer.js const { app , BrowserWindow , ipcMain } = require ( 'electron/main' )
const path = require ( 'node:path' )
let bluetoothPinCallback
let selectBluetoothCallback
function createWindow ( ) {
const mainWindow = new BrowserWindow ( {
width : 800 ,
height : 600 ,
webPreferences : {
preload : path . join ( __dirname , 'preload.js' )
}
} )
mainWindow . webContents . on ( 'select-bluetooth-device' , ( event , deviceList , callback ) => {
event . preventDefault ( )
selectBluetoothCallback = callback
const result = deviceList . find ( ( device ) => {
return device . deviceName === 'test'
} )
if ( result ) {
callback ( result . deviceId )
} else {
// The device wasn't found so we need to either wait longer (eg until the
// device is turned on) or until the user cancels the request
}
} )
ipcMain . on ( 'cancel-bluetooth-request' , ( event ) => {
selectBluetoothCallback ( '' )
} )
// Listen for a message from the renderer to get the response for the Bluetooth pairing.
ipcMain . on ( 'bluetooth-pairing-response' , ( event , response ) => {
bluetoothPinCallback ( response )
} )
mainWindow . webContents . session . setBluetoothPairingHandler ( ( details , callback ) => {
bluetoothPinCallback = callback
// Send a message to the renderer to prompt the user to confirm the pairing.
mainWindow . webContents . send ( 'bluetooth-pairing-request' , details )
} )
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 ( )
} )
const { contextBridge , ipcRenderer } = require ( 'electron/renderer' )
contextBridge . exposeInMainWorld ( 'electronAPI' , {
cancelBluetoothRequest : ( ) => ipcRenderer . send ( 'cancel-bluetooth-request' ) ,
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 >
< button id = " cancel " > Cancel Bluetooth Request </ 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 )
function cancelRequest ( ) {
window . electronAPI . cancelBluetoothRequest ( )
}
document . getElementById ( 'cancel' ) . addEventListener ( 'click' , cancelRequest )
window . electronAPI . bluetoothPairingRequest ( ( event , details ) => {
const response = { }
switch ( details . pairingKind ) {
case 'confirm' : {
response . confirmed = window . confirm ( ` Do you want to connect to device ${ details . deviceId } ? ` )
break
}
case 'confirmPin' : {
response . confirmed = window . confirm ( ` Does the pin ${ details . pin } match the pin displayed on device ${ details . deviceId } ? ` )
break
}
case 'providePin' : {
const pin = window . prompt ( ` Please provide a pin for ${ details . deviceId } . ` )
if ( pin ) {
response . pin = pin
response . confirmed = true
} else {
response . confirmed = false
}
}
}
window . electronAPI . bluetoothPairingResponse ( response )
} )
WebHID API
WebHID API 可以用于访问HID 设备,例如 键盘和游戏机。 Electron 提供了几个使用 WebHID API的接口:
* 当 navigator.hid.requestDevice 被调用时, Session 的 select-hid-device 事件 可以用来选择一个 HID 设备。 此外,在处理 select-hid-device 事件时,Session 的 hid-device-added 和 hid-device-removed 事件可以用来处理设备拔插。 注意: 这些事件仅会在 select-hid-device 的回调之后被触发。 它们不能作为通用HID设备监听器使用。
* ses.setDevicePermissionHandler(handler) 可以给予设备默认权限而不需要先调用 navigator.hid.requestDevice 获取设备权限。 此外,Electron的默认行为是在相应的WebContents的生命周期内存储已授予的设备权限。 如果需要更长期的存储,开发人员可以存储设备许可信息(比如: 在处理 select-hid-device 事件时), 然后通过 setDevicePermissionHandler 从存储的信息中读取
* ses.setPermissionCheckHandler(handler) 可以用来禁用特定源的 HID 访问。
阻止列表
默认情况下,Electron 使用和 Chromium 相同的 阻止列表 。 如果您想要覆盖此行为,您可以通过设置 disable-hid-blocklist 标志来做到这一点:
app . commandLine . appendSwitch ( 'disable-hid-blocklist' )
示例
这个例子演示了,一个 Electron 应用在 Test WebHID 按钮被点击时,自动通过 ses.setDevicePermissionHandler(handler) 和 Session 的 select-hid-device 事件 选择 HID 设备。
docs/fiddles/features/web-hid ( 43.4.0 ) Open in Fiddle
* main.js
* index.html
* renderer.js const { app , BrowserWindow } = require ( 'electron/main' )
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 >
function formatDevices ( devices ) {
return devices . map ( device => device . productName ) . join ( '<hr>' )
}
async function testIt ( ) {
document . getElementById ( 'granted-devices' ) . innerHTML = formatDevices ( await navigator . hid . getDevices ( ) )
document . getElementById ( 'granted-devices2' ) . innerHTML = formatDevices ( await navigator . hid . requestDevice ( { filters : [ ] } ) )
}
document . getElementById ( 'clickme' ) . addEventListener ( 'click' , testIt )
Web Serial API
Web Serial API 可以被用来访问串口设备比如 USB 或蓝牙。 为了在 Eletron 中使用这个 API,开发者需要处理与串口请求相关的 Session 的 select-serial-port 事件 。
有几个额外的 API 用于与 Web Serial API 合作:
* 在处理 select-serial-port 事件时,Session 的 serial-port-added 和 serial-port-removed 事件可以用来处理设备拔插。 注意: 这些事件仅会在 select-serial-port 的回调之后被触发。 它们不能作为通用串口监听器使用。
* ses.setDevicePermissionHandler(handler) 可以给予设备默认权限而不需要先调用 navigator.serial.requestPort 获取设备权限。 此外,Electron的默认行为是在相应的WebContents的生命周期内存储已授予的设备权限。 如果需要更长期的存储,开发人员可以存储设备许可信息(比如: 在处理 select-serial-port 事件时), 然后通过 setDevicePermissionHandler 从存储的信息中读取
* ses.setPermissionCheckHandler(handler) 可以用来禁用特定源的串口访问。
阻止列表
默认情况下,Electron 使用和 Chromium 相同的 阻止列表 。 如果您想要覆盖此行为,您可以通过设置 disable-serial-blocklist 标志来做到这一点:
app . commandLine . appendSwitch ( 'disable-serial-blocklist' )
示例
这个例子演示了一个 Eletron 应用通过 ses.setDevicePermissionHandler(handler) 自动选择窗口设备,以及当 Test Web Serial 按钮被点击时通过 Session 的 select-serial-port 事件 选择第一个可用的 Arduino Uno 串口设备(如果已连接)。
docs/fiddles/features/web-serial ( 43.4.0 ) Open in Fiddle
* main.js
* index.html
* renderer.js const { app , BrowserWindow } = require ( 'electron/main' )
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 {
// eslint-disable-next-line n/no-callback-literal
callback ( '' ) // Could not find any matching devices
}
} )
mainWindow . webContents . session . setPermissionCheckHandler ( ( webContents , permission , requestingOrigin , details ) => {
if ( permission === 'serial' && details . securityOrigin === 'file:///' ) {
return true
}
return false
} )
mainWindow . webContents . session . setDevicePermissionHandler ( ( details ) => {
if ( details . deviceType === 'serial' && details . origin === 'file://' ) {
return true
}
return false
} )
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 )
WebUSB API
WebUSB API 可用于访问USB设备。 Electron提供了几个与WebUSB API配合使用的API:
* 当 navigator.usb.requestDevice 被调用时, Session 的 select-usb-device 事件 可以用来选择一个 USB 设备。 此外,在处理 select-usb-device 事件时,Session 的 usb-device-added 和 usb-device-removed 事件可以用来处理设备拔插。 **注意:**这两个事件只有在 select-usb-device 的回调被调用时才会触发。 它们不是设计来作为通用 USB 设备监听器使用的。
* 当 device.forget() 在 USB 设备上被调用时, Session 的 usb-device-revoked 事件 可以用来响应。
* ses.setDevicePermissionHandler(handler) 可以给予设备默认权限而不需要先调用 navigator.usb.requestDevice 获取设备权限。 此外,Electron的默认行为是在相应的WebContents的生命周期内存储已授予的设备权限。 如果需要长期存储,开发者可以存储授予的设备权限(如处理 select-usb-device 事件时),然后使用 setDevicePermissionHandler 从存储中读取。
* ses.setPermissionCheckHandler(handler) 可以用来禁用特定源的 USB 访问。
* ses.setUSBProtectedClassesHandler 可以用来允许使用默认不可用的 受保护的 USB 类 。
阻止列表
默认情况下,Electron 使用和 Chromium 相同的 阻止列表 。 如果您想要覆盖此行为,您可以通过设置 disable-usb-blocklist 标志来做到这一点:
app . commandLine . appendSwitch ( 'disable-usb-blocklist' )
示例
这个例子演示了,一个 Electron 应用在 Test WebUSB 按钮被点击时,自动通过 ses.setDevicePermissionHandler(handler) 和 Session 的 select-usb-device 事件 选择 USB 设备(如果它们已被连接)。
docs/fiddles/features/web-usb ( 43.4.0 ) Open in Fiddle
* main.js
* index.html
* renderer.js const { app , BrowserWindow } = require ( 'electron/main' )
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 ) => {
return ! grantedDeviceThroughPermHandler || ( device . deviceId !== grantedDeviceThroughPermHandler . deviceId )
} )
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 . webContents . session . setUSBProtectedClassesHandler ( ( details ) => {
return details . protectedClasses . filter ( ( usbClass ) => {
// Exclude classes except for audio classes
return usbClass . indexOf ( 'audio' ) === - 1
} )
} )
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 > WebUSB API </ title >
</ head >
< body >
< h1 > WebUSB API </ h1 >
< button id = " clickme " > Test WebUSB </ button >
< h3 > USB devices automatically granted access via < i > setDevicePermissionHandler </ i > </ h3 >
< div id = " granted-devices " > </ div >
< h3 > USB devices automatically granted access via < i > select-usb-device </ i > </ h3 >
< div id = " granted-devices2 " > </ div >
< script src = " ./renderer.js " > </ script >
</ body >
</ html >
function getDeviceDetails ( device ) {
return device . productName || ` Unknown device ${ device . deviceId } `
}
async function testIt ( ) {
const noDevicesFoundMsg = 'No devices found'
const grantedDevices = await navigator . usb . getDevices ( )
let grantedDeviceList = ''
if ( grantedDevices . length > 0 ) {
for ( const device of grantedDevices ) {
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 ( grantedDevice ) } </hr> `
} catch ( ex ) {
if ( ex . name === 'NotFoundError' ) {
grantedDeviceList = no
Links found on this page
- 跳转到主内容 [direct]
- Electron [direct]
- 文档 [direct]
- 应用开发接口(API) [direct]
- 博客 [direct]
- Electron Forge [direct]
- Electron Fiddle [direct]
- 治理 [direct]
- 案例展示 [direct]
- 资源 [direct]
- 版本发布 [direct]
- English [direct]
- Deutsch [direct]
- Español [direct]
- Français [direct]
- 日本語 [direct]
- Português [direct]
- Русский [direct]
- Electron 中的流程 [direct]
- 最佳实践 [direct]
- 示例 [direct]
- Dark Mode [direct]
- 应用程序内购 [direct]
- 键盘快捷键 [direct]
- 深度链接 (Deep Links) [direct]
- 桌面启动器快捷操作 [direct]
- Menus [direct]
- 多线程 [direct]
- 原生文件拖 & 放 [direct]
- 导航历史 [direct]
- 通知(Notifications) [direct]
- 离屏渲染 [direct]
- 在线/离线事件探测 [direct]
- 进度条 [direct]
- 最近的文件 [direct]
- 在 BrowserWindow 中展示文件 [direct]
- 拼写检查器 [direct]
- Web 嵌入 [direct]
- 任务栏自定义 [direct]
- 自定义窗口 [direct]
- 开发 [direct]
- Native Node Modules [direct]
- 分发 [direct]
- 检测和调试 [direct]
- 引用 [direct]
- 参与贡献 [direct]
- Web Bluetooth API [direct]
- webContent 的 select-bluetooth-device 事件 [direct]
- ses.setBluetoothPairingHandler(handler) [direct]
- docs/fiddles/features/web-bluetooth ( 43.4.0 ) [direct]
- Open in Fiddle [direct]
- WebHID API [direct]
- 阻止列表 [direct]
- docs/fiddles/features/web-hid ( 43.4.0 ) [direct]
- Open in Fiddle [direct]
- Web Serial API [direct]
- 阻止列表 [direct]
- docs/fiddles/features/web-serial ( 43.4.0 ) [direct]
- Open in Fiddle [direct]
- WebUSB API [direct]
- device.forget() [direct]
- 受保护的 USB 类 [direct]
- docs/fiddles/features/web-usb ( 43.4.0 ) [direct]
- Open in Fiddle [direct]
- 编辑此页面 [direct]
- 安全 [direct]
- Discord [direct]
- Bluesky [direct]
- X [direct]
- Mastodon [direct]
- Stack Overflow [direct]
- GitHub [direct]
- Open Collective [direct]
- 基础看板 [direct]
- OpenJS Foundation [direct]
- 商标政策 [direct]
- 商标列表 [direct]
- 使用条款 [direct]
- 隐私政策 [direct]
- 章程 [direct]