Aller au contenu principal

Accès aux périphériques

Comme les navigateurs basés sur Chromium, Electron fournit un accès au matériel du périphérique via des API Web. Ces API fonctionnent pour la plupart, comme dans un navigateur, mais il y a quelques différences qui doivent être prises en compte. La principale différence entre Electron et les navigateurs est ce qui se passe lorsque l'accès à l'appareil est demandé . Dans un navigateur, les utilisateurs se voient présenter une popup où ils peuvent accorder l' accès à un appareil individuel. Dans Electron des API sont fournies pouvant être utilisées par un développeur pour choisir automatiquement un périphérique ou demander aux utilisateurs de choisir un périphérique via une interface créée par un développeur.

API Web Bluetooth

L’API Web Bluetooth peut être utilisée pour communiquer avec des périphériques Bluetooth. Afin d'utiliser cette API dans Electron, les développeurs devront gérer l'événement select-bluetooth-device sur le webContents associé à la demande de périphérique.

De plus, ses.setBluetoothPairingHandler(handler) peut être utilisé pour gérer l'appairage aux périphériques bluetooth sous Windows ou Linux lorsque une validation supplémentaire comme un code personnel est nécessaire.

Exemple

Cet exemple montre une application Electron qui sélectionne automatiquement le premier périphérique Bluetooth disponible lorsque le bouton Test Bluetooth est cliqué.

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()
})

API WebHID

L' API WebHID peut être utilisée pour accéder aux périphériques HID tels que les claviers et les manettes. Electron fournit plusieurs API pour travailler avec l'API WebHID:

  • L'événement select-hid-device de la Session peut être utilisé pour sélectionner un périphérique HID lorsqu'un appel à navigator.hid.requestDevice est effectué. De plus, les événements hid-device-added et hid-device-removed de la Session peuvent être utilisés pour gérer les appareils branchés ou débranchés lors de la gestion de l'événement select-hid-device. Note: Ces événements pourront se déclencher tant que la fonction de callback de select-hid-device n'a pas pas encore été appelée. Ils ne sont pas, d'ailleurs, destinés à être utilisés comme écouteurs génériques de port série.
  • ses.setDevicePermissionHandler(handler) peut être utilisé pour fournir des autorisations par défaut aux appareils sans devoir demander au préalable l'autorisation aux appareils via navigator.hid.requestDevice. De plus, le comportement par défaut d'Electron est de stocker les autorisations accordées à l'appareil pendant la durée de vie du WebContents. Si un stockage à plus long terme est nécessaire, le développeur peut stocker les autorisations accordées à l'appareil (par exemple lors de la gestion de l'événement select-hid-device) puis les lire à partir de ce stockage avec setDevicePermissionHandler.
  • ses.setPermissionCheckHandler(handler) peut être utilisé pour désactiver l'accès HID pour des origines spécifiques.

Blocklist

Par défaut, Electron utilise la même liste noire que celle utilisée par Chromium. Si vous souhaitez outrepasser ce comportement, vous pouvez le faire en définissant le drapeau disable-hid-blocklist:

app.commandLine.appendSwitch('disable-hid-blocklist')

Exemple

Cet exemple présente une application Electron qui sélectionne automatiquement les périphériques HID à travers ses.setDevicePermissionHandler(handler) et à travers select-hid-device événement sur la session lorsque le bouton Test WebHID est cliqué.

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()
})

API Web Serial

L' API Web Serial peut être utilisée pour accéder aux périphériques série qui sont connectés par port série, USB, ou Bluetooth. Afin d'utiliser cette API dans Electron, les développeurs devront gérer l'événement select-serial-port sur la session associée à la requête de port série.

Il existe plusieurs API supplémentaires pour travailler avec l'API Web Serial :

  • Les évènements serial-port-added et serial-port-removed de la session peuvent être utilisés pour gérer les périphériques branchés ou débranchés lors de la gestion de l'événement select-serial-port. Note: Ces événements pourront se déclencher tant que la fonction de callback de select-serial-port n'a pas pas encore étét appelée. Ils ne sont pas d'ailleurs destinés à être utilisés comme écouteurs génériques de port série.
  • ses.setDevicePermissionHandler(handler) peut être utilisé pour fournir des autorisations par défaut aux appareils sans devoir demander au préalable l'autorisation aux appareils via navigator.serial.requestPort. De plus, le comportement par défaut d'Electron est de stocker les autorisations accordées à l'appareil pendant la durée de vie du WebContents. Si un stockage à plus long terme est nécessaire, le développeur peut stocker les autorisations accordées à l'appareil (par exemple lors de la gestion de l'événement select-serial-port) puis les lire à partir de ce stockage avec setDevicePermissionHandler.
  • ses.setPermissionCheckHandler(handler) peut être utilisé pour désactiver l'accès série pour des origines spécifiques.

Exemple

Cet exemple présente une application Electron qui sélectionne automatiquement les périphériques série à travers ses.setDevicePermissionHandler(handler) et illustre la sélection du premier périphérique série Arduino Uno disponible (si connecté) via select-serial-port événement sur la session lorsque le bouton Test Web Serial est cliqué.

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()
})

API WebUSB

L' API WebUSB peut être utilisée pour accéder aux périphériques USB. Electron fournit plusieurs API pour travailler avec l'API WebUSB :

  • L’événement select-usb-device de la Session peut être utilisé pour sélectionner un périphérique USB lorsqu’un appel à navigator.usb.requestDeviceest effectué. En outre, les événements usb-device-added and usb-device-removed de la session peuvent être utilisés pour gérer les appareils branchés ou débranchés lors de la gestion de l’événement select-usb-device. Note: Ces deux événements ne se déclenchent qu'après l'appel à la callback de select-usb-device . Ils ne sont pas destinés à être utilisés comme un écouteur de périphérique Usb générique.
  • L’événement usb-device-revoked de la session peut être utilisé pour réagir lorsque device.forget() est appelé sur un périphérique USB.
  • ses.setDevicePermissionHandler(handler) peut être utilisé pour fournir une autorisation par défaut aux périphériques sans avoir à en faire la demande préalablement via navigator.usb.requestDevice. De plus, le comportement par défaut d'Electron est de stocker les autorisations accordées à l'appareil pendant la durée de vie du WebContents. Si un stockage à plus long terme est nécessaire, un développeur peut stocker les autorisations de périphérique accordées (par exemple lors de la gestion l’événement select-usb-device) afin de pouvoir ensuite relire à partir de ce stockage avec setDevicePermissionHandler.
  • ses.setPermissionCheckHandler(handler) peut être utilisé afin de désactiver l'accès à USB piour certaines origines.
  • ses.setUSBProtectedClassesHandler peut être utilisé pour autoriser l'usage de classes USB protégées qui ne sont pas disponibles par défaut.

Exemple

Cet exemple montre une application Electron qui sélectionne automatiquement les périphériques USB (s’ils sont attachés) via ses.setDevicePermissionHandler(gestionnaire) et l'événement select-usb-device de la Session lorsque l'on click sur le bouton Test WebUSB.

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()
})