Appearance
Kapitel 15: Fortgeschrittene Techniken
In diesem Kapitel lernen Sie fortgeschrittene Techniken zur Steigerung der Entwicklungseffizienz.
15.1 Automatische Anwendungsaktualisierung
autoUpdater-Modul verwenden
Das autoUpdater-Modul ermöglicht die automatische Aktualisierung von Electron-Anwendungen.
Grundlegende Konfiguration
javascript
// main.js
const { app, autoUpdater, dialog } = require('electron');
const log = require('electron-log');
// Logging einrichten
autoUpdater.logger = log;
autoUpdater.logger.transports.file.level = 'info';
// Update-Server URL
const server = 'https://update.example.com';
const url = `${server}/update/${process.platform}/${app.getVersion()}`;
autoUpdater.setFeedURL({ url });
// Update-Ereignisse
autoUpdater.on('checking-for-update', () => {
log.info('Suche nach Updates...');
});
autoUpdater.on('update-available', (info) => {
log.info('Update verfügbar:', info.version);
});
autoUpdater.on('update-not-available', (info) => {
log.info('Kein Update verfügbar:', info.version);
});
autoUpdater.on('error', (err) => {
log.error('Fehler beim Update:', err);
});
autoUpdater.on('download-progress', (progressObj) => {
let log_message = 'Download-Geschwindigkeit: ' + progressObj.bytesPerSecond;
log_message = log_message + ' - Aktuell ' + progressObj.percent + '%';
log_message = log_message + ' (' + progressObj.transferred + '/' + progressObj.total + ')';
log.info(log_message);
});
autoUpdater.on('update-downloaded', (info) => {
log.info('Update heruntergeladen:', info.version);
// Benutzer fragen, ob neu starten
dialog.showMessageBox({
type: 'info',
title: 'Update verfügbar',
message: `Version ${info.version} wurde heruntergeladen. Möchten Sie die Anwendung jetzt neu starten, um das Update zu installieren?`,
buttons: ['Ja', 'Später']
}).then((returnValue) => {
if (returnValue.response === 0) {
autoUpdater.quitAndInstall();
}
});
});
// Alle 10 Minuten nach Updates suchen
setInterval(() => {
autoUpdater.checkForUpdates();
}, 10 * 60 * 1000);
// Beim Starten nach Updates suchen
app.whenReady().then(() => {
autoUpdater.checkForUpdates();
});Update-Server einrichten (vereinfacht)
javascript
// update-server.js (einfacher Express-Server)
const express = require('express');
const path = require('path');
const app = express();
const PORT = 3000;
// Update-Dateien servieren
app.get('/update/:platform/:version', (req, res) => {
const { platform, version } = req.params;
let fileName;
if (platform === 'win32') {
fileName = 'my-app-setup.exe';
} else if (platform === 'darwin') {
fileName = 'my-app.dmg';
} else {
fileName = 'my-app.AppImage';
}
const filePath = path.join(__dirname, 'releases', fileName);
res.download(filePath, (err) => {
if (err) {
res.status(404).json({ message: 'Kein Update verfügbar' });
}
});
});
app.listen(PORT, () => {
console.log(`Update-Server läuft auf Port ${PORT}`);
});electron-builder mit Auto-Update
json
{
"build": {
"publish": [
{
"provider": "generic",
"url": "https://update.example.com"
}
]
}
}15.2 Benutzerdefinierte Anwendungsicons und Startseite
Animierter Startbildschirm (Splash Screen)
javascript
// main.js
const { BrowserWindow, app } = require('electron');
const path = require('path');
function createWindow() {
// Splash Screen erstellen
const splash = new BrowserWindow({
width: 400,
height: 300,
transparent: false,
frame: false,
alwaysOnTop: true,
center: true,
skipTaskbar: true
});
splash.loadFile('splash.html');
// Hauptfenster erstellen
const mainWin = new BrowserWindow({
width: 1200,
height: 800,
show: false, // Erst anzeigen, wenn bereit
icon: path.join(__dirname, 'assets', 'icon.png')
});
// Wenn Hauptfenster bereit
mainWin.once('ready-to-show', () => {
setTimeout(() => {
splash.destroy();
mainWin.show();
}, 2000); // 2 Sekunden warten
});
mainWin.loadFile('index.html');
}
app.whenReady().then(createWindow);splash.html
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lädt...</title>
<style>
body {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
font-family: Arial, sans-serif;
}
.logo {
font-size: 48px;
margin-bottom: 20px;
}
.progress {
width: 80%;
height: 4px;
background: rgba(255, 255, 255, 0.3);
border-radius: 2px;
overflow: hidden;
}
.progress-bar {
width: 0%;
height: 100%;
background: white;
animation: progress 2s ease-in-out forwards;
}
@keyframes progress {
0% { width: 0%; }
100% { width: 100%; }
}
.status {
margin-top: 20px;
font-size: 14px;
opacity: 0.8;
}
</style>
</head>
<body>
<div class="logo">🚀</div>
<h1>Meine App</h1>
<div class="progress">
<div class="progress-bar"></div>
</div>
<div class="status">Anwendung wird geladen...</div>
</body>
</html>Tray-Icon mit Kontextmenü
javascript
// main.js
const { Tray, Menu, BrowserWindow } = require('electron');
const path = require('path');
let tray = null;
let mainWin;
function createTray() {
// Tray-Icon erstellen
tray = new Tray(path.join(__dirname, 'assets', 'tray-icon.png'));
// Kontextmenü erstellen
const contextMenu = Menu.buildFromTemplate([
{
label: 'Fenster anzeigen',
click: () => {
if (mainWin) {
mainWin.show();
mainWin.focus();
}
}
},
{
label: 'Neue Nachricht',
click: () => {
// Benachrichtigung senden
if (mainWin) {
mainWin.webContents.send('new-message', {
title: 'Neue Nachricht',
body: 'Sie haben eine neue Nachricht erhalten.'
});
}
}
},
{ type: 'separator' },
{
label: 'Einstellungen',
click: () => {
if (mainWin) {
mainWin.webContents.send('open-settings');
}
}
},
{ type: 'separator' },
{
label: 'Beenden',
click: () => {
app.quit();
}
}
]);
tray.setToolTip('Meine Electron-App');
tray.setContextMenu(contextMenu);
// Tray-Klick-Event
tray.on('click', () => {
if (mainWin.isVisible()) {
mainWin.hide();
} else {
mainWin.show();
mainWin.focus();
}
});
}
function createWindow() {
mainWin = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
});
mainWin.loadFile('index.html');
createTray();
}
app.whenReady().then(createWindow);15.3 Haupt- und Renderer-Prozess-Berechtigungssteuerung
Sicherheitsbeste Practices
1. Context Isolation aktivieren
javascript
// main.js - RICHTIG
const mainWin = new BrowserWindow({
webPreferences: {
contextIsolation: true, // WICHTIG: Einschalten!
nodeIntegration: false, // WICHTIG: Ausschalten!
preload: path.join(__dirname, 'preload.js')
}
});2. Preload-Skript als sichere Brücke
javascript
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
// Nur spezifische APIs freigeben
contextBridge.exposeInMainWorld('api', {
// Nur notwendige Funktionen freigeben
saveData: (data) => ipcRenderer.invoke('save-data', data),
loadData: () => ipcRenderer.invoke('load-data'),
// Event-Listener
onUpdateAvailable: (callback) => {
ipcRenderer.on('update-available', (event, info) => callback(info));
}
});
// NICHT alles freigeben!
// FALSCH:
// contextBridge.exposeInMainWorld('electron', require('electron'));3. Content Security Policy (CSP)
html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy"
content="
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
connect-src 'self' https://api.example.com;
">
<title>Meine App</title>
</head>
<body>
<!-- Inhalt -->
</body>
</html>4. Remote-Content isolieren
javascript
// main.js
const mainWin = new BrowserWindow({
webPreferences: {
// Sandbox für zusätzliche Sicherheit
sandbox: true,
// WebSecurity aktivieren
webSecurity: true,
// Keine Node.js-Integration
nodeIntegration: false,
nodeIntegrationInWorker: false,
nodeIntegrationInSubFrames: false,
// Context Isolation
contextIsolation: true,
// Preload-Skript
preload: path.join(__dirname, 'preload.js')
}
});15.4 Verwendung von Drittanbieter-Plugins
Häufig verwendete Plugins
electron-store (Datenspeicherung)
bash
npm install electron-storejavascript
// main.js
const Store = require('electron-store');
const store = new Store();
// Daten speichern
store.set('user.name', 'Max Mustermann');
store.set('settings.theme', 'dark');
// Daten abrufen
const userName = store.get('user.name');
const theme = store.get('settings.theme', 'light'); // Standard: 'light'
// Alle Daten abrufen
const allData = store.store;
// Daten löschen
store.delete('user.name');
// Store zurücksetzen
store.clear();electron-log (Protokollierung)
bash
npm install electron-logjavascript
// main.js
const log = require('electron-log');
// Log-Ausgabe
log.info('Anwendung gestartet');
log.warn('Warnung: ...');
log.error('Fehler: ', new Error('Ein Fehler'));
// Log-Datei finden
console.log('Log-Datei:', log.transports.file.getFile());
// Log-Level festlegen
log.transports.file.level = 'info';
// Log-Datei-Größe begrenzen
log.transports.file.maxSize = 5 * 1024 * 1024; // 5 MBaxios (HTTP-Anfragen)
bash
npm install axiosjavascript
// main.js oder preload.js
const axios = require('axios');
async function fetchData() {
try {
const response = await axios.get('https://api.example.com/data', {
headers: {
'Authorization': 'Bearer token123'
}
});
console.log('Daten abgerufen:', response.data);
return response.data;
} catch (error) {
console.error('Fehler beim Abrufen:', error.message);
throw error;
}
}15.5 Electron-Versionsaktualisierung und Kompatibilität
Electron-Version aktualisieren
bash
# Electron auf neueste Version aktualisieren
npm install electron@latest --save-dev
# Auf spezifische Version aktualisieren
npm install electron@31.0.0 --save-devKompatibilitätstabelle
| Electron-Version | Chromium-Version | Node.js-Version |
|---|---|---|
| 31.0.0 | 126 | 20.x |
| 30.0.0 | 124 | 20.x |
| 29.0.0 | 122 | 18.x |
| 28.0.0 | 120 | 18.x |
Migrationsleitfaden
Von Electron 28 auf 29
javascript
// Änderungen in der neuen Version beachten
// Zum Beispiel: Veraltete APIs entfernen
// Veraltet (Electron 28):
ipcRenderer.sendSync('channel', data);
// Neu (Electron 29+):
// Verwenden Sie invoke/handle mit Promises
ipcRenderer.invoke('channel', data).then(result => {
console.log(result);
});Zusammenfassung
In diesem Kapitel haben Sie gelernt:
- Automatische Anwendungsaktualisierung mit
autoUpdaterzu implementieren - Benutzerdefinierte Icons und Startseiten zu erstellen
- Berechtigungen für Haupt- und Renderer-Prozesse sicher zu steuern
- Drittanbieter-Plugins effektiv zu nutzen
- Electron-Versionen zu aktualisieren und Kompatibilität zu wahren
Im nächsten Kapitel werden wir sich auf häufige Interviewfragen vorbereiten.
