メインコンテンツにスキップ

デバイスアクセス

Chromiumベースのブラウザと同様に、ElectronはWeb APIを介してデバイスハードウェアへのアクセスを提供します。ほとんどの場合、これらのAPIはブラウザと同じように機能しますが、考慮する必要があるいくつかの違いがあります。Electronとブラウザの主な違いは、デバイスアクセスが要求されたときに何が起こるかです。ブラウザでは、ユーザーは個々のデバイスへのアクセスを許可できるポップアップが表示されます。Electronでは、開発者がデバイスを自動的に選択したり、開発者が作成したインターフェースを介してデバイスを選択するようユーザーに促したりできるAPIが提供されます。

Web Bluetooth API

Web Bluetooth APIを使用して、Bluetoothデバイスと通信できます。ElectronでこのAPIを使用するには、開発者はデバイスリクエストに関連付けられたwebContentsselect-bluetooth-deviceイベントを処理する必要があります。

さらに、ピンなどの追加の検証が必要な場合に、WindowsまたはLinuxでBluetoothデバイスへのペアリングを処理するために、ses.setBluetoothPairingHandler(handler)を使用できます。

この例では、「Test Bluetooth」ボタンがクリックされたときに、最初に使用可能なBluetoothデバイスを自動的に選択するElectronアプリケーションを示します。

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

WebHID API

WebHID APIを使用して、キーボードやゲームパッドなどのHIDデバイスにアクセスできます。Electronは、WebHID APIを操作するためのいくつかのAPIを提供しています。

  • navigator.hid.requestDeviceが呼び出されたときにHIDデバイスを選択するために、セッションのselect-hid-deviceイベントを使用できます。さらに、セッションのhid-device-addedイベントとhid-device-removedイベントを使用して、select-hid-deviceイベントを処理する際にデバイスのプラグインまたはプラグアウトを処理できます。注: これらのイベントは、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')

この例では、「Test WebHID」ボタンがクリックされたときに、ses.setDevicePermissionHandler(handler)セッションのselect-hid-deviceイベントを通じてHIDデバイスを自動的に選択するElectronアプリケーションを示します。

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

Web Serial API

Web Serial APIを使用して、シリアルポート、USB、またはBluetooth経由で接続されたシリアルデバイスにアクセスできます。ElectronでこのAPIを使用するには、開発者はシリアルポートリクエストに関連付けられたセッションのselect-serial-portイベントを処理する必要があります。

Web Serial APIを操作するための追加のAPIがいくつかあります。

  • セッションのserial-port-addedイベントとserial-port-removedイベントを使用して、select-serial-portイベントを処理する際にデバイスのプラグインまたはプラグアウトを処理できます。注: これらのイベントは、select-serial-portからのコールバックが呼び出されるまでのみ発生します。これらは、一般的なシリアルポートリスナーとして使用することを意図していません。
  • ses.setDevicePermissionHandler(handler)を使用して、navigator.serial.requestPortを介して最初にデバイスへのアクセス許可を求めることなく、デバイスへのデフォルトのアクセス許可を提供できます。さらに、Electronのデフォルトの動作は、対応するWebContentsの有効期間中に許可されたデバイスのアクセス許可を保存することです。長期的な保存が必要な場合、開発者は許可されたデバイスのアクセス許可を保存し(たとえば、select-serial-portイベントを処理するとき)、setDevicePermissionHandlerを使用してそのストレージから読み取ることができます。
  • ses.setPermissionCheckHandler(handler)を使用して、特定のオリジンに対するシリアルアクセスを無効にできます。

この例では、「Test Web Serial」ボタンがクリックされたときに、ses.setDevicePermissionHandler(handler)を通じてシリアルデバイスを自動的に選択し、セッションのselect-serial-portイベントを通じて、最初に使用可能なArduino Unoシリアルデバイス(接続されている場合)を選択するElectronアプリケーションを示します。

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

WebUSB API

WebUSB APIを使用して、USBデバイスにアクセスできます。Electronは、WebUSB APIを操作するためのいくつかのAPIを提供しています。

  • navigator.usb.requestDeviceが呼び出されたときにUSBデバイスを選択するために、セッションのselect-usb-deviceイベントを使用できます。さらに、セッションのusb-device-addedイベントとusb-device-removedイベントを使用して、select-usb-deviceイベントを処理する際にデバイスのプラグインまたはプラグアウトを処理できます。注: これらの2つのイベントは、select-usb-deviceからのコールバックが呼び出されるまでのみ発生します。これらは、一般的なUSBデバイスリスナーとして使用することを意図していません。
  • セッションのusb-device-revokedイベントを使用して、USBデバイスでdevice.forget()が呼び出されたときに応答できます。
  • ses.setDevicePermissionHandler(handler)を使用して、navigator.usb.requestDeviceを介して最初にデバイスへのアクセス許可を求めることなく、デバイスへのデフォルトのアクセス許可を提供できます。さらに、Electronのデフォルトの動作は、対応するWebContentsの有効期間中に許可されたデバイスのアクセス許可を保存することです。長期的な保存が必要な場合、開発者は許可されたデバイスのアクセス許可を保存し(たとえば、select-usb-deviceイベントを処理するとき)、setDevicePermissionHandlerを使用してそのストレージから読み取ることができます。
  • ses.setPermissionCheckHandler(handler)を使用して、特定のオリジンに対するUSBアクセスを無効にできます。
  • ses.setUSBProtectedClassesHandlerを使用して、デフォルトでは利用できない保護されたUSBクラスの使用を許可できます。

この例では、「Test WebUSB」ボタンがクリックされたときに、ses.setDevicePermissionHandler(handler)セッションのselect-usb-deviceイベントを通じて、USBデバイス(接続されている場合)を自動的に選択するElectronアプリケーションを示します。

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