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 BluetoothLa 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.
#
EjemploEste ejemplo demuestra un aplicación Electron que automáticamente selecciona el primer dispositivo bluetooth disponible cuando el botón Test Bluetooth
es pulsado.
- index.html
- main.js
- 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 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>
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()})
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 WebHIDLa 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 (pj 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 bloqueadosPor 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')
#
EjemploEste 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.
- index.html
- main.js
- renderer.js
<!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>
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()})
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 WebLa 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.setPermissionCheckHandler(handler)
puede ser usado para desactivar el acceso serial a orígenes específicos.
#
EjemploEste ejemplo demuestra una aplicación Electron que automáticamente selecciona el primer dispositivo serial Arduino Uno (si está conectado) a través del evento select-serial-port
en la Session cuando el botón Test Web Serial
es pulsado.
- index.html
- main.js
- 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>
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()})
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)