Acceso del dispositivo
Al igual que los navegadores basados en Chromium, Electron proporciona acceso al dispositivo del hardware a través de las APIs web. En la mayor parte estas APIs trabajan como lo hacen en un navegador, pero hay algunas diferencias que necesitan ser tomadas en cuenta. La diferencia principal entre Electron y los navegadores es lo que ocurre cuando el acceso al dispositivo es solicitado. En un navegador, a los usuarios se le presenta una ventana emergente donde ellos puede otorgar acceso a un dispositivo individual. En Electron, se proporcionan APIs que un desarrollador puede utilizar para elegir automáticamente un dispositivo o para solicitar a los usuarios que elijan un dispositivo a través de una interfaz creada por el desarrollador.
API Web Bluetooth
La Web Bluetooth API puede ser utilizada para comunicarse con dispositivos bluetooth. Para poder utilizar esta API en Electron, los desarrolladores necesitan manejar el evento select-bluetooth-device
en el webContents asociado con la solicitud del dispositivo.
Ejemplo
Este ejemplo demuestra un aplicación Electron que automáticamente selecciona el primer dispositivo bluetooth disponible cuando el botón Test Bluetooth
es pulsado.
- 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)
API WebHID
La WebHID API puede ser usada para acceder a dispositivos HID tales como teclados y gamepads. Electron proporciona varias APIs, para trabajar con la API WebHID:
- El evento
select-hid-device
en la Session puede ser usado para seleccionar un dispositivo HID cuando se hace una llamada anavigator.hid.requestDevice
. Adicionalmente, los eventoshid-device-added
yhid-device-removed
en la Session pueden ser utilizados para manejar dispositivos que se conectan o desconectan durante el procesonavigator.hid.requestDevice
. ses.setDevicePermissionHandler(handler)
puede ser utilizado para proveer permisos predeterminados a los dispositivos sin llamar primero para obtener permiso a dispositivo a través denavigator.hid.requestDevice
. Adicionalmente el comportamiento por defecto de Electron es almacenar el permiso de dispositivo concedido a través de la vida útil del correspondiente WebContents. Si se necesita almacenamiento a más largo plazo, un desarrollado puede almacenar los permisos de dispositivos otorgados (p.ej. cuando se maneja el eventoselect-hid-device
) y luego leer desde ese almacenamiento consetDevicePermissionHandler
.ses.setPermissionCheckHandler(handler)
puede ser usado para desactivar el acceso a HID a orígenes específicos.
Lista de bloqueados
Por defecto Electron emplea la misma blocklist usada por Chromium. Si desea anular este comportamiento, puede hacerlo estableciendo la bandera disable-hid-blocklist
:
app.commandLine.appendSwitch('disable-hid-blocklist')
Ejemplo
Este ejemplo demuestra una aplicación Electron que automáticamente selecciona dispositivos HID a través de ses.setDevicePermissionHandler(handler)
y a través del evento select-hid-device
en la Session cuando el botón Test WebHID
es pulsado.
- 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) => {
event.preventDefault()
if (details.deviceList && details.deviceList.length > 0) {
callback(details.deviceList[0].deviceId)
}
})
mainWindow.webContents.session.on('hid-device-added', (event, device) => {
console.log('hid-device-added FIRED WITH', device)
})
mainWindow.webContents.session.on('hid-device-removed', (event, device) => {
console.log('hid-device-removed FIRED WITH', device)
})
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)
API Serial Web
La Web Serial API puede ser utilizada para acceder a dispositivos seriales que están conectados a través de la puerta serial, USB, or Bluetooth. Para utilizar esta API en Electron, los desarrolladores necesitan manejar el evento select-serial-port
en la Session asociado con la solicitud de puerto serial.
Hay varias APIs adicionales para trabajar con la API Web Serial:
- Los eventos
serial-port-added
yserial-port-removed
en la Session pueden ser usados para maenjar dispositivos que están conectados o desconectados durante el procesonavigator.serial.requestPort
. ses.setDevicePermissionHandler(handler)
puede ser utilizado para proveer permisos predeterminados a los dispositivos sin llamar primero para obtener permiso a dispositivo a través denavigator.serial.requestPort
. Adicionalmente el comportamiento por defecto de Electron es almacenar el permiso de dispositivo concedido a través de la vida útil del correspondiente WebContents. Si se necesita almacenamiento a más largo plazo, un desarrollado puede almacenar los permisos de dispositivos otorgados (pj cuando se maneja el eventoselect-serial-port
) y luego leer desde ese almacenamiento consetDevicePermissionHandler
.ses.setPermissionCheckHandler(handler)
puede ser usado para desactivar el acceso serial a orígenes específicos.
Ejemplo
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 select-serial-port
event on the Session when the Test Web Serial
button is clicked.
- 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) => {
event.preventDefault()
if (portList && portList.length > 0) {
callback(portList[0].portId)
} else {
callback('') //Could not find any matching devices
}
})
mainWindow.webContents.session.on('serial-port-added', (event, port) => {
console.log('serial-port-added FIRED WITH', port)
})
mainWindow.webContents.session.on('serial-port-removed', (event, port) => {
console.log('serial-port-removed FIRED WITH', port)
})
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)