Um eine Desktop-Anwendung aus einer Capacitor-Anwendung zu erstellen, umhüllen Sie die gleiche Web-Build.webDir) in einer Electron-Hülle: einen Hauptprozess, der eine BrowserWindow, einen Vorkommando, der einen kleinen Desktop-API offenlegt, und electron-builder, um Installationsprogramme für macOS, Windows und Linux zu erstellen. Ihre Benutzeroberfläche und Geschäftslogik bleiben mit iOS und Android geteilt, und Desktop-spezifische Funktionen leben im Electron-Hauptprozess.
Diese Anleitung behandelt den aktuellen Stand von Capacitor auf Electron im Jahr 2026, eine sichere Konfiguration, die mit Capacitor 8 funktioniert, wie Plugins verhalten sich, Verpacken und Signieren, und wie Web-Updates ohne neue Installationsprogramme verschickt werden können.
Der Stand von Capacitor auf Electron im Jahr 2026
Für Jahre war die Standardantwort @capacitor-community/electron, die Electron in das Capacitor CLI als Plattform einband. Das Projekt ist jetzt als nicht mehr unterstützt in seinem eigenen README markiert. Sein letzter npm-Release, 5.0.1, wurde im September 2023 veröffentlicht, erfordert Capacitor 5.4 oder später und wurde gegen Electron 26 aufgebaut. Electron hat seitdem viele wichtige Versionen veröffentlicht, und nur die letzten drei Majors erhalten Sicherheitsfixes.
Sie können es immer noch auf alten Projekten verwenden, aber für eine Capacitor 8-Anwendung sieht die Vergleichsliste so aus:
| Ansatz | Vorteile | Nachteile |
|---|---|---|
| Ihr eigener Electron-Shell (diese Anleitung) | Aktuelles Electron, volle Kontrolle, keine zusätzliche Abstraktion | Sie schreiben etwa 60 Zeilen von Haupt- und Vorladungscode code |
@capacitor-community/electron |
Vertraut cap Befehle |
Nicht mehr unterstützt, auf altes Capacitor und Electron festgelegt |
Die Shell-Methode ist weniger Arbeit als es klingt, weil Capacitor bereits eine statische Web-Anwendung erstellt. Electron muss sie nur laden.
Wie Plugins in Electron verhalten
Electrons Renderer ist Chromium, daher läuft Ihre Capacitor-Anwendung dort wie in einem Browser. Capacitor's Kern erkennt keine native Brücke und fällt auf die Web-Implementierung jeder Plugin zurück.
| Plugin-Typ | Funktioniert in Electron? | Was tun |
|---|---|---|
| Plugin mit Web-Implementierung (Einstellungen, Teilen, Auskopieren, viele Capgo-Plugins) | Ja, mit der Web-Version | Testen Sie das Web-Verhalten |
| Nur-native-Plugin (keine Web-Implementierung) | No, wird als nicht implementiert abgelehnt | Schreiben Sie ein Electron-Äquivalent hinter einem API-Vorladepreload |
| Reine JS-Bibliotheken | Ja | Nein |
Capacitor.getPlatform() keine Rückkehr 'web' erfolgt in dieser Konfiguration und Capacitor.isNativePlatform() keine Rückkehr false. Wir werden einen expliziten Desktop-Flag aus dem Vorladepreload-Script ausgeben, so dass Ihr code sauber abzweigen kann
Voraussetzungen
- Eine Capacitor-Anwendung, deren
bun run buildeine statische Ordner (denwebDiraufcapacitor.config.ts, oftdistoderwww). - Bun und ein aktuelles LTS Node.js, da Electron-Tooling noch auf Node läuft.
- Für die macOS-Distribution ist ein Apple-Entwickler-ID-Zertifikat erforderlich. Für Windows ein code-Zertifikat zur Signierung.
Schritt 1: Installieren Sie Electron und den Packager
bun add -d electron electron-builder
Hinzufügen electron/ Ordner im Projektroot:
my-app/
capacitor.config.ts
dist/ # web build, shared with iOS and Android
electron/
main.ts
preload.ts
electron-builder.yml
Schritt 2: Laden Sie die Web-Ausgabe von der Festplatte
Protokoll in der Produktion. Zwei Einstellungen sind wichtig: file:// Relative Pfadangaben zu Assets.
- __CAPGO_KEEP_0__ Mit Vite, setze
base: './'so die gebautenindex.htmlReferenzen./assets/...anstatt/assets/.... - Routing. Tiefe Links wie
/settingsexistieren nicht als Dateien. Verwenden Sie Hash-Routing für die Desktop-Build, oder stellen Sie sicher, dass Ihr Router nur kundenseitig navigiert, nachdem er geladen wurdeindex.html.
// vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
base: './',
});
Relative Pfade funktionieren auch auf iOS und Android, daher benötigen Sie keine separate Build.
Schritt 3: Schreiben Sie den Hauptprozess
// electron/main.ts
import { app, BrowserWindow, ipcMain, shell } from 'electron';
import path from 'node:path';
const isDev = !app.isPackaged;
async function createWindow() {
const win = new BrowserWindow({
width: 1280,
height: 800,
minWidth: 800,
minHeight: 600,
show: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
},
});
win.once('ready-to-show', () => win.show());
// Open external links in the default browser, never inside the app.
// Only allow https: so a script cannot launch file: or other protocol handlers.
win.webContents.setWindowOpenHandler(({ url }) => {
try {
if (new URL(url).protocol === 'https:') void shell.openExternal(url).catch(() => {});
} catch {
// invalid URL: ignore
}
return { action: 'deny' };
});
if (isDev) {
await win.loadURL('http://localhost:5173');
win.webContents.openDevTools({ mode: 'detach' });
} else {
await win.loadFile(path.join(__dirname, '..', '..', 'dist', 'index.html'));
}
}
ipcMain.handle('desktop:get-version', () => app.getVersion());
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
Behalten Sie contextIsolation: true, nodeIntegration: false, und sandbox: true. Ihr Web-App kann Drittanbieter-Scripts laden, und keines davon sollte Zugriff auf Node.js haben.
Schritt 4: Expose eine kleine Desktop-API aus der Vorkomprimierung
// electron/preload.ts
import { contextBridge, ipcRenderer } from 'electron';
contextBridge.exposeInMainWorld('desktop', {
isElectron: true,
platform: process.platform,
getVersion: () => ipcRenderer.invoke('desktop:get-version') as Promise<string>,
});
Tippen Sie es in Ihrem Web-code ein und verwenden Sie es auf die gleiche Weise wie ein Plugin:
// src/desktop.ts
declare global {
interface Window {
desktop?: {
isElectron: boolean;
platform: string;
getVersion: () => Promise<string>;
};
}
}
export const isDesktop = () => Boolean(window.desktop?.isElectron);
Jedes native-only-Funktion, das Sie auf dem Desktop benötigen, wird zu einem ipcMain.handle einen in der Hauptprozess und eine Funktion in der Vorkomprimierung. Überprüfen Sie die Argumente im Hauptprozess, da der Renderer unvertrauenswürdig ist.
Schritt 5: Erstellen und ausführen
Kompilieren Sie die Electron-Dateien mit Bun. Die Vorkomprimierung läuft sandboxed, also bündeln Sie sie als ein einzelnes CommonJS-File ein:
{
"main": "electron/dist/main.js",
"scripts": {
"build": "vite build",
"electron:compile": "bun build electron/main.ts --outdir electron/dist --target node --format cjs --external electron && bun build electron/preload.ts --outdir electron/dist --target node --format cjs --external electron",
"electron:dev": "bun run electron:compile && electron .",
"electron:pack": "bun run build && bun run electron:compile && electron-builder"
}
}
Zu Entwicklungszwecken starten Sie Ihren Dev-Server in einem Terminal (bun run dev) und bun run electron:dev in einem anderen. Sie erhalten eine Hot-Reload im Desktop-Fenster.
Schritt 6: Paketieren von Installern mit electron-builder
# electron-builder.yml
appId: com.example.myapp
productName: My App
directories:
output: release
files:
- dist/**/*
- electron/dist/**/*
- package.json
mac:
target: [dmg, zip]
category: public.app-category.productivity
hardenedRuntime: true
win:
target: [nsis]
linux:
target: [AppImage, deb]
category: Utility
Laufen bun run electron:pack.electron-builder baut für das Betriebssystem, auf dem es ausgeführt wird. Verwenden Sie eine Matrix aus macOS, Windows- und Linux-Runnern in CI, um alle drei zu produzieren.
| OS | Gemeinsame Ziele | Signierung |
|---|---|---|
| macOS | .dmg, .zip |
Entwickler-ID-Zertifikat plus Notarisation, oder Gatekeeper blockiert die Anwendung |
| Windows | NSIS .exe, MSI |
Code Signierungszertifikat, um SmartScreen-Warnungen zu vermeiden |
| Linux | AppImage, .deb, .rpm |
Optional |
Elektron-Apps sind größer als mobile Builds, da sie Chromium und Node.js enthalten. Installationsdateien liegen je nach Zielgruppe zwischen 80 und 150 MB.
Schritt 7: Schicken Sie Web-Updates ohne neue Installationsdateien
Die meisten Änderungen in einer Capacitor-Anwendung sind Web-Änderungen. Auf dem Mobilgerät können Sie diese mit Capgo Live-Updates__CAPGO_KEEP_0__-Live-Updates @capgo/electron-updater macht dasselbe mit demselben Modell: Kanäle, ein eingebauter Bundle, heruntergeladene Bundle und automatische Rollover, wenn das neue Bundle nicht funktioniert notifyAppReady().
bun add @capgo/electron-updater
Aktualisieren Sie den Hauptprozess, damit der Updater die zu ladende Bundle auswählen kann:
// electron/main.ts (production branch)
import { ElectronUpdater, setupIPCHandlers, setupEventForwarding } from '@capgo/electron-updater';
const updater = new ElectronUpdater({
appId: 'com.example.myapp',
autoUpdate: true,
});
// inside createWindow(), instead of loading dist/index.html directly
const builtinPath = path.join(__dirname, '..', '..', 'dist', 'index.html');
await updater.initialize(win, builtinPath);
setupIPCHandlers(updater);
setupEventForwarding(updater, win);
await win.loadFile(updater.getCurrentBundlePath());
Fügen Sie die Updater-Brücke in das gleiche Präloader-File ein:
// electron/preload.ts (next to the desktop API)
import { exposeUpdaterAPI } from '@capgo/electron-updater/preload';
exposeUpdaterAPI();
Und bestätige eine gesunde Startphase aus der Web-Anwendung, nur auf dem Desktop:
import { isDesktop } from './desktop';
if (isDesktop()) {
const { requireUpdater } = await import('@capgo/electron-updater/renderer');
await requireUpdater().notifyAppReady();
}
Upload a new bundle with the same CLI you use for mobile:
bun run build
bunx @capgo/cli@latest bundle upload --channel=production
Web updates cannot change Electron itself, the main process, or the preload. For those, ship a new installer with a binary auto-updater. Our guide on Elektron-aktualisierungen covers diese Pfade ab, und die electron-updater-Plugin-Seite und docs deckt alle Optionen ab.
Schwierigkeiten
Ein leerer Fenster im verpackten App. Assets verwenden absolute Pfade. Setze base: './' und neu erstellen. Öffnen Sie die DevTools im verpackten App, um 404s zu bestätigen. file:///assets/....
Routen zeigen eine leere Seite nach dem Neuladen. Der Router versuchte, zu laden /route Die Routen zeigten ein leeres Fenster nach dem Neuladen.
require is not defined oder Fehler vor dem Laden. Der sandboxierte Vorkomprimierung kann keine beliebigen Pakete zur Laufzeit laden. Komprimieren Sie es in eine Datei, wie im obigen Kompilierungsskript.
Ein Pluginaufruf wird mit „nicht implementiert auf Web“ abgelehnt. Das Plugin hat keine Web-Implementierung. Fügen Sie einen IPC-Handler in der Hauptprozess und rufen Sie ihn über window.desktop.
macOS sagt, dass die Anwendung beschädigt oder von einem unbekannten Entwickler stammt. Die Anwendung ist nicht signiert und nicht notarisiert. Konfigurieren Sie ein Entwickler-ID-Zertifikat und eine Notarisation in electron-builder.
Updates rollen sich sofort nach der Installation zurück. notifyAppReady() war nicht innerhalb der Zeitüberschreitung (10 Sekunden standardmäßig) aufgerufen. Rufen Sie es frühzeitig in Ihrem Anwendungsstart auf.
Abschluss
Sie benötigen kein spezielles Capacitor Plattformpaket, um auf den Desktop zu gelangen. Ein kurzer Electron-Hauptprozess, eine Vorkomprimierung, die einen API-Typ ausgibt, relative Asset-Pfade und electron-builder geben Ihnen Installationsprogramme für alle drei Betriebssysteme aus einer einzigen Web-Build. Fügen Sie @capgo/electron-updater und die Desktop-Anwendung erhält das gleiche live update-Workflow wie Ihre iOS- und Android-Builds. Wenn Sie noch immer eine Desktop-Laufzeitumgebung wählen, lesen Sie unseren Vergleich zwischen Electron und Tauri.