Immer mehr plattformunabhängige Frameworks finden ihren Weg in die Entwicklerwelt: Mit Electron wird Ihre Anwendung desktoptauglich gemacht und für nahezu alle denkbaren Desktopplattformen bereitgestellt.
Seit einigen Jahren ist sie quasi Standard: eine HTML5/JavaScript-Anwendung, die dennoch auf Gerätehardware zugreifen und als eine native App laufen kann. Möglich wurde dies zum einem durch die Entwicklung des Apache-Cordova-Frameworks, aber auch aufgrund der breiteren Verwendung und Entwicklung von Single Page Applications (SPAs) sowie Progressive Web Applications (PWAs). Die Unterschiede zwischen einer App und einer Website verschwinden immer mehr. Nun ist es an der Zeit, eine Brücke zu den nativen Desktopanwendungen zu schlagen. Hierbei unterstützt das offene Framework Electron den Entwickler und erstellt aus einfachen Webanwendungen entsprechende Desktopanwendungen für Windows, Linux und macOS.
Im Normalfall reicht es für eine Desktopanwendung, die für den Endanwender gedacht ist, vollkommen aus, mit einer interpretierten Sprache entwickelt worden zu sein. Eine reine native Desktopanwendung – zum Beispiel auf Basis von C# oder Java – bietet vor allem im Zeitalter der Microservices und relativ üppiger Rechenleistung immer häufiger keine nennenswerten Vorteile mehr für den Anwender. Spezialisierte und hardwarenahe Anwendungen sind hier logischerweise ausgeschlossen.
Aufgrund dessen boomen sogenannte Progressive Web-Apps (PWAs); sie bieten zum einen den enormen Vorteil, plattformübergreifend lauffähig zu sein, gleichzeitig aber auch schnell und einfach verteilt werden zu können. Diesem Vorteil steht aber auch ein Nachteil entgegen: Die Verteilung via Webserver. Standardmäßig werden PWAs wie normale Websites gehostet, was bedeutet, dass dafür ein Server konfiguriert und gewartet werden muss. Auch wenn PWAs enorme Vorteile bieten und mit den entsprechenden Frameworks sogar direkt als Apps für Smartphones und Tablets verwendet werden können, gibt es dennoch Fälle, in denen der Entwickler eine installierbare Desktopanwendung vorzieht. Zu diesen Fällen können zum Beispiel desktoptypische Bedienelemente, die Nutzung von direktem Dateizugriff, das Drucken von Dokumenten, die Einbindung von Kontextmenüs, gezieltere Softwareverteilung oder die Verwendung von Menüleisten (insbesondere unter macOS) zählen. Genau diese Punkte machen es einer Webanwendung oder PWA schwer, da sie immer noch im Browser und dessen Sandbox ausgeführt wird. Mit dem Framework Electron kann eine SPA oder PWA genau mit diesen Features ausgerüstet werden und bietet entsprechend native Funktionalitäten.
Bevor eine solche Cross-Plattform-Anwendung entwickelt wird, muss natürlich das zu verwendende Framework festgelegt werden. Hierbei ist – vor allem für Entwickler, die im objektorientierten .NET-Umfeld entwickeln – ein Framework auf Basis von Angular und TypeScript zu empfehlen, da enorm viele Werkzeuge existieren und die Entwicklercommunity entsprechend breit aufgestellt ist. Wer sich jedoch intensiv mit der Entwicklung von Single-Page-Anwendungen (SPAs) und PWAs beschäftigt, wird ebenfalls erkennen, dass das Framework React und darauf basierende GUI-Frameworks bei vielen Entwicklern sehr beliebt sind. Beide Frameworks haben ihre Vor- und Nachteile und sollten wie immer je nach Einsatz und Entwicklerpräferenz ausgewählt werden.
Die Auswahl des Frameworks ist direkt mit der Frage verbunden, ob die neu zu entwickelnde Anwendung in gleicher Weise als PWA oder gar als mobile App verwendet werden soll. Möchte man also nur eine reine Desktopanwendung entwickeln, kann man GUI-Frameworks verwenden, die einem das native Look and Feel einer Desktopanwendung geben. Hierzu zählt zum Beispiel Photon, das jedoch noch keine Angular-Komponenten zur Verfügung stellt und rein auf JavaScript und CSS basiert. Möchte man die Anwendung gerne auch als PWA nutzen oder von Angular-Komponenten Gebrauch machen, ist Angular Material zu empfehlen. Soll die Anwendung dann auch noch als mobile App zum Einsatz kommen, führt kaum ein Weg an Ionic vorbei. Ionic ist hierbei zwar der Gigant unter den Mobile-App-Frameworks, unterstützt jedoch auch offiziell den Einsatz in PWAs. Ein weiteres nennenswertes Framework – vor allem in Hinblick auf die Unterstützung von React – wäre noch Onsen UI.
Wer jedoch für die einzelnen Anwendungsszenarien ein gesondertes App-Framework verwenden möchte, kann dies durch die Trennung von Businesslogik und Oberflächenlogik gerne tun. Entsprechend muss hierzu die Geschäftslogik mit beispielsweise Angular in einzelne Provider untergebracht werden, die übergreifend verwendet werden können. Dadurch schafft man nicht nur eine strikte Trennung der Logik, sondern minimiert den Entwicklungsaufwand für jede Verwendungsform der Anwendung. Mit diesem Ansatz können verschiedenste Oberflächenframeworks verwendet werden, die jedoch immer auf die gleiche Businesslogik zurückgreifen.
Wer bereits mobile Apps mit Ionic bzw. Cordova entwickelt hat, kennt den grundlegenden Aufbau von Cordova. Electron funktioniert sehr ähnlich und bietet pro Plattform entsprechende Anwendungstemplates, die mithilfe von Node.js und C++ geschrieben wurden. Diese Grundanwendungen basieren auf einem einfachen Chromium Control mit der bekannten V8 JavaScript Engine. In diesem Control wird unsere HTML5-Anwendung dargestellt und unser Anwendungscode entsprechend ausgeführt. Sobald native Schnittstellen wie zum Beispiel Datei öffnen-Dialoge oder die Verwendung von nativen Menüleisten in der Anwendung gefordert werden, kommen entsprechende Electron-Schnittstellen zum Einsatz, die der aktuellen PWA die notwendigen Informationen via JavaScript bereitstellen.
Aufgrund dieser Kombination ist es ziemlich einfach, eine Desktopanwendung aus reinen Webframeworks zu entwickeln und schnellstmöglich auf verschiedene Plattformen zu verteilen. Durch diverse Plug-ins und Erweiterungen wurde hier nicht nur ein reines Desktopframework geschaffen, sondern ein vollumfängliches Ökosystem. Diverse Erweiterungen und Debugger für verschiedenste IDEs bis hin zu Tools, die die Anwendung für die Einreichung in die App Stores von Microsoft und Apple vorbereiten, sind hierbei vertreten. Dem Entwickler ist ähnlich wie bei einer nativ entwickelten Desktopanwendung die Möglichkeit gegeben, zu entscheiden, für welche Plattformen und Architekturen und auf welche Art und Weise seine Software genutzt und ausgeliefert werden kann.
Ein weiterer Vorteil der Entwicklung einer Desktopanwendung mit Electron ist die direkte Integration von Installationstools und Auto-Update-Funktionalitäten. Über die direkt im Electron-Framework vorhandene Auto-Update-Funktionalität kann per eigens gehostetem Updateserver (Hazel) die aktuelle Version der Anwendung dem Kunden praktisch in Echtzeit zur Verfügung gestellt werden. Das macht die Entwicklung eines eigenen Updatemechanismus überflüssig und hält die Software beim Endkunden immer auf dem neuesten Stand. Komplexe Distributionen fallen somit weg.
Zusätzlich gibt es diverse Erweiterungen, die sich zum Beispiel um eine nahezu automatisierte Erstellung eines Installers kümmern. Zwar sind Installer bei einer Electron-Anwendung, die alle Komponenten bei sich führt, nicht zwingend notwendig, für Windows und Linux aber oft gewünscht – nicht nur aufgrund der Gewohnheit der Endanwender, sondern auch wegen der Registrierung im Startmenü oder der automatischen Softwareverteilung in größeren Unternehmen. Ein Beispiel hierfür ist das windows-installer-Projekt von Electron auf GitHub; hier wird über ein kleines Node.js-Skript nach Belieben ein Windows-Set-up für eine Electron-Anwendung generiert. Dabei kann über diverse Parameter konfiguriert werden, wie das Set-up grafisch aussehen soll und ob neben einer Executable auch ein MSI-Paket erstellt wird. Gerade Letzteres ist für eine Softwareverteilung meist zwingend erforderlich.
Sobald man sich auf ein Framework bzw. eine Vorgehensweise verständigt hat, kann mit der Entwicklung der Anwendung begonnen werden. Für das hier gezeigte Beispiel wird eine PWA als reine Desktopanwendung entwickelt. Dabei werden Angular und Angular Material für die Umsetzung verwendet.
Für diejenigen, die eine bestehende Angular-Anwendung zu einer Electron-App umwandeln möchten, gibt es einiges zu beachten. Dafür muss zunächst einmal Electron über den Node.js-Package-Manager (NPM) installiert werden. Das funktioniert wie gewohnt über den folgenden Aufruf: npm install electron –save-dev –save-exact. Weiterhin muss die Anwendung insoweit umgebaut werden, dass sie auch ein Electron-Fenster öffnet und unsere Anwendung darstellt. Wie das genau funktioniert, werden wir im Folgenden betrachten.
Beginnen wir nun mit einer leeren Anwendung auf der grünen Wiese. Hierbei gibt es entweder die Variante, Angular und Electron manuell miteinander zu „verheiraten“ und alles Schritt für Schritt zu machen, oder bereits bestehende Beispielprojekte zu verwenden, in denen das bereits erledigt wurde. Ein bekanntes Bootstrapping-Projekt wäre maximegris/angular-electron. Für dieses Beispiel und vor allem für ein besseren Verständnis des Frameworks soll hier das manuelle Schritt-für-Schritt-Vorgehen durchgespielt werden.
Um ein Angular-Projekt erstellen zu können, muss das Angular-CLI installiert werden. Das geschieht über den Kommandozeilenaufruf npm install –g @angular/cli. Nachdem dieses Paket installiert wurde, kann mit ng new ElectronApp ein neues Projekt erstellt werden. Das neu erstellte Verzeichnis bietet uns den Grundaufbau einer Angular-Anwendung und kann in unserer IDE (in diesem Beispiel Visual Studio Code) geöffnet werden. Nun folgt die Installation des gewünschten UI-Frameworks. Wie bereits erwähnt, wird in diesem Fall Angular Material verwendet, das über den Befehl npm install –save @angular/material @angular/cdk @angular/animations installiert wird.
Nun sind alle Komponenten für eine PWA installiert. Da hier eine Electron-Anwendung erstellt werden soll, fehlt logischerweise noch die dazugehörige Komponente, die ebenfalls komfortabel über NPM installiert werden kann: npm install electron –save-dev. Nachdem nun sämtliche Pakete installiert wurden, existiert in unserem Projektordner die übliche NodeJS- und Angular-Projektstruktur: Eine typische package.json-Datei, in der sämtliche NodeJS-Paketinformationen liegen, der dazugehörige node_modules-Ordner und natürlich der von Angular und dem TypeScript-Compiler verwendete src–Ordner, in dem sich unsere PWA bzw. SPA befinden wird. Für entsprechende End-to-End-(E2E-)Tests existiert ebenfalls ein entsprechendes Verzeichnis, das jedoch für unser Beispiel außen vorgelassen wird.
Um Angular Material verwenden zu können, müssen die notwendigen Module in die Datei /src/app/app.module.ts importiert werden, zum Beispiel in eine angepasste app.module.ts (Listing 1).
Listing 1: Beispiel „app.module.ts“
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import {
MatButtonModule,
MatCardModule,
MatIconModule,
MatListModule,
MatMenuModule,
MatSidenavModule,
MatSliderModule,
MatSlideToggleModule,
MatTabsModule,
MatToolbarModule
} from '@angular/material';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
MatButtonModule,
MatCardModule,
MatIconModule,
MatListModule,
MatMenuModule,
MatSidenavModule,
MatSliderModule,
MatSlideToggleModule,
MatTabsModule,
MatToolbarModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Für dieses Beispiel wurde anhand des oben beschriebenen Moduls die in Abbildung 1 dargestellte Testoberfläche gebaut, die über die Kommandozeile per ng serve transpilliert und dargestellt werden kann.
Nun kann mit dem spannenden Teil – dem Hosten der Seite in der Electron-App – begonnen werden. Hierzu müssen wir in unserem Projektverzeichnis eine Datei mit dem Namen electronApp.js erstellen. Diese Datei soll von Node.js standardmäßig als Einstiegspunkt verwendet werden und muss entsprechend in der package.json als solche hinterlegt werden. Hierzu muss die Eigenschaft main eingefügt werden: “main” : “electronApp.js”.
Wie bereits erwähnt basiert Electron auf Node.js. Dementsprechend wird die genannte JavaScript-Datei zum Start ausgeführt, die sich um das Instanziieren und Zerstören des Electron-Fensters bemühen muss. Die Logik, mit der die main.js befüllt werden muss, kann Listing 2 entnommen werden.
Listing 2: „main.js“
const { app, BrowserWindow } = require('electron')
let electronWindow;
//Funktion zum Erstellen des Electron-Fensters
function create () {
// Instanziieren des Electron-Fensters
electronWindow = new BrowserWindow({
width: 640,
height: 500,
backgroundColor: '#ffffff'
});
// Festlegen der index.html, die dargestellt werden soll
electronWindow.loadURL(`file://${__dirname}/dist/index.html`)
electronWindow.on('closed', function () {
//Referenz zum Fenster zerstören, sobald es geschlossen wurde
electronWindow = null
})
}
// Fenster erstellen, sobald die NodeJS-App bereit ist
app.on('ready', create);
In der Funktion create() wird ein neues Electron-Fenster instanziiert und mit entsprechenden Startgrößen und einer Hintergrundfarbe hinterlegt. Das BrowserWindow hat hier einige weitere Parameter, die das Aussehen des Fensters beeinflussen; das kann zum Beispiel ein Fenster-Icon oder Ähnliches sein. Mit dem Methodenaufruf loadURL(string) wird dem Fenster der URL zugewiesen, der unserer App entspricht. Im Fall einer Angular-App wird beim Transpilieren der App über ng build in der Kommandozeile der Ordner dist erstellt, in dem die Anwendung als reines HTML, JavaScript und CSS liegt. Durch Anhängen an das closed-Event des Fensters werden die Referenzen auf dieses Fenster gelöst. Über das Anwendungs-Event ready wird das Fenster erstellt und geöffnet, sobald Node.js diese Anwendung vollständig geladen hat. Theoretisch könnte unsere Anwendung nun über folgende Kommandozeilenaufrufe gestartet werden:
ng build
npm run electron .
Um dies jedoch nicht immer wieder machen zu müssen, wenn man Änderungen an der Anwendung vorgenommen hat, ist es empfehlenswert, im scripts-Block der package.json die folgenden beiden Zeilen hinzuzufügen:
"electron": "electron .",
"electron-build": "ng build --prod && electron ."
Nun kann über den Aufruf npm run electron-build die Anwendung erstellt und direkt geöffnet werden. Nachfolgend wird unser Electron-Fenster mit unserer Angular-Anwendung gestartet. Nun können alle notwendigen nativen Schnittstellen, die Electron zur Verfügung stellt, verwendet und getestet werden (Abb. 2).
Nachdem die Anwendung nun lauffähig ist, soll sie für Windows, Linux oder Mac gepackt werden. Das kann über das Open-Source-Projekt electron-userland/electron-packager geschehen. Dafür wird zunächst der Electron Packager mit npm install –g electron-packager installiert. Nach der Installation kann das Tool mittels folgendem Befehlskonstrukt gestartet werden:
electron-packager <sourcedir> <appname> --platform=<platform> --arch=<arch>
Im Fall dieses Referenzprojekts wäre zum Beispiel für das Erstellen einer 64-Bit-Anwendung für Windows folgender Aufruf notwendig:
electron-packager . ElectronApp --platform=win32 --arch=x64
Nach dem Download des Templates wird die lauffähige Anwendung im Verzeichnis ElectronApp-win32-x64 hinterlegt (Abb. 2).
Ähnlich wie der Electron-Packager existieren zahlreiche Tools als Open-Source-Projekte im Netz, die sich zum Beispiel um das Generieren von Installationsprogrammen kümmern oder sonstige hilfreiche Werkzeuge bieten.
Eine Electron-App zu entwickeln, ist sinnvoll, wenn Sie die aktuell modernen Werkzeuge verwenden möchten und keine hardwarenahe Entwicklung benötigt wird. Nicht nur, dass Sie Ihre Anwendung bei entsprechender Architektur flexibel auf sämtliche Plattformen verteilen können; Sie sind auch in der Lage, bestimmte Komponenten der Anwendung für beispielsweise mobile Apps weiterzuverwenden. Durch immer mehr prominente Tools, die mit Electron realisiert wurden (darunter auch Visual Studio Code), entstehen wiederum neue, die z. B. das Generieren von Installern sehr komfortabel gestalten. Sollten Sie also in der nächsten Zeit eine Desktopanwendung planen und sich bereits im TypeScript-, Angular- und Node.js-Umfeld wohl fühlen – geben Sie Electron eine Chance. Für einen Großteil der heutigen Endbenutzeranwendungen mit entsprechenden serviceseitigen Backends sollten die zur Verfügung stehenden Werkzeuge vollkommen ausreichend sein.