Windows, macOS und Linux sind die Systeme für den Desktop. Java ist seit langem Standard, wenn es um Anwendungen geht, welche auf allen Systemen laufen. Es gibt aber Alternativen. Von nativen Ansätzen bis zur Web-Technologie ist alles dabei.

In diesem Artikel beschäftigen wir uns mit unterschiedlichen Ansätzen, um Applikationen für den Desktop zu erstellen, welche auf den relevanten Systemen Windows, Linux und macOS gleichermaßen laufen und aus einer gemeinsamen Quellcodebasis erstellt werden. Desktop Applikationen werden primär zum produktiven Arbeiten auf PCs und Notebooks eingesetzt. In vielen Bereichen wurden diese zwar in der Vergangenheit durch die deutlich flexibleren Web Anwendungen abgelöst, aber es gibt nach wie vor ausschlaggebende Gründe, warum man sich für eine Desktop Applikation entscheiden sollte. Das sind primär:

  • Offline-Fähigkeit: Desktop-Anwendungen bieten Offline-Funktionen. Wenn Sie die Textverarbeitung auf Ihren Computer heruntergeladen haben, können Sie jederzeit auf diese App zugreifen. Ihr Desktop ermöglicht es Ihnen, ohne Datenverbindung funktionsfähig zu bleiben.
  • Erhöhte Sicherheit: Desktop Anwendungen bieten durch die Offline-Fähigkeit eine erhöhte Sicherheit bei der Arbeit mit sensiblen Daten. Sie können Ihre LAN- oder WLAN-Verbindung trennen, wenn es notwendig ist. Mit einer Web App sind Sie immer einem bestimmten Potenzial einer Internetbedrohung (Datendiebstahl) ausgesetzt.
  • Arbeitsgeschwindigkeit: Die Ausführungsgeschwindigkeit hängt von der Geschwindigkeit Ihres Computers ab. Wenn Sie einen sehr schnellen Computer und eine sehr langsame Internet- oder Datenverbindung haben, hat eine Desktop Anwendung einen erheblichen Vorteil. Es nutzt den Arbeitsspeicher und die Verarbeitungsleistung Ihrer lokalen Ressourcen, um eine positive Benutzererfahrung zu erzielen.
  • Langfristig meist günstiger: Wenn Sie eine Desktop Anwendung kaufen (Lizenz), haben Sie normalerweise höhere Kapitalkosten als beim Kauf einer Web App oder eines Abonnements. Wenn Sie die Kosten über die Laufzeit des Programms vergleichen, sind die einmaligen Kosten in der Regel günstiger als die laufenden Zahlungen, um weiterhin auf Ihre Web App zugreifen zu können.
  • Unabhängigkeit von Dritten: Desktop Anwendungen erfordern keine Unterstützung von Dritten für die Verfügbarkeit. Solange das Gerät ordnungsgemäß funktioniert, können Sie bei Bedarf jederzeit auf Ihre Daten zugreifen.
  • Kein Upgrade-Zwang: Desktop Anwendungen zwingen Sie nicht zu einem Upgrade. Web Anwendungen können Sie dagegen ohne Zustimmung zu Upgrades zwingen, da dies Teil des automatischen Aktualisierungsprozesses ist. Wenn das Programm nach dem Update nicht wie gewünscht funktioniert, haben Sie ein Problem.
  • Uneingeschränkter Hardwarezugriff: Keine Einschränkungen beim Zugriff auf die Hardware des Systems und der Ansteuerung von spezifischen Ein- und Ausgabegeräten. Es ist i.d.R. eine vollständige und direkte Nutzung der Systemressourcen möglich.

Warum tut man sich schon immer relativ schwer mit der Cross-Plattform-Programmierung im Bereich der Desktop Applikationen? Die Antwort ist einfach: Insbesondere die doch recht großen Unterschiede der Systeme bei der Ansprache der grafischen Benutzeroberflächen führen gewissermaßen zu einem Engpass. Neben unterschiedlichen technischen Herangehensweisen gibt es unterschiedliche Controls, verschiedene Design-Richtlinien usw. Eine Applikation, welche auf allen Systemen läuft, muss diese Unterschiede berücksichtigen bzw. sich auf den kleinsten gemeinsamen Nenner der Übereinstimmungen beschränken. Möchte man native Applikationen erstellen, muss das Werkzeug in der Lage sein, aus einer allgemeinen Beschreibung der Benutzeroberfläche die passende Transformation in das Zielsystem automatisch abzuleiten.
Aktuell können wir das zum Beispiel an der Entwicklung von .NET verfolgen. .NET Core (künftig .NET 5.0) ist plattformübergreifend verfügbar [2]. Man kann es auf allen gängigen Systemen einsetzen. Möchte man jedoch grafische Desktop-Applikationen erstellen, dann ist man schon deutlich eingeschränkter. Der folgende Absatz beleuchtet den aktuellen Stand, um Desktop Applikationen mit Microsoft-Technologien zu erstellen, welche über das Windows System hinaus reichen.

.NET-Core als Basis

.NET-Core steht also für alle wichtigen Plattformen bereit [3]. Für die grafische Oberfläche stehen dabei bekanntermaßen die Systeme Windows Forms (WinForms), Windows Präsentation Foundation (WPF) und die Universelle Windows Plattform (UWP) zur Verfügung. Bekanntermaßen migriert Microsoft Windows Forms und WPF gerade vom „großen“ .NET-Framework über den Zwischenschritt .NET-Core zur neuen Plattform .NET. Zusammen mit der UWP soll es in der WinUI 3.0 – Plattform münden. Damit sind wir jedoch auf Windows-Systeme beschränkt, was das User Interface betrifft. Möchten Sie andere Systeme nutzen, dann können Sie Xamarin verwenden. Damit kann man nicht nur Apps für iOS und Android erstellen, sondern auch Applikationen für macOS, also für den Desktop (diese werden von Apple auch als Apps bezeichnet). Für Linux kann man auf diese Weise keine Anwendungen erstellen. Dazu müsste man auf Avalonia [4] ausweichen. Mit dieser Bibliothek kann man grafische Benutzeroberflächen für Windows, Linux und macOS erstellen. Der Ansatz ist deklarativ und verwendet einen XAML-Dialekt.
In diesem Artikel haben wir uns unterschiedliche Wege angesehen, Desktop Applikationen für Windows, macOS und Linux in einem Rutsch (aus einer Quellcodebasis) zu erstellen. Die Auswahl ist mit Sicherheit nicht vollständig, enthält aber wichtige Ansätze.

Java

Java gilt gewissermaßen als Standard, wenn es darum geht plattformübergreifende Anwendungen zu programmieren.

Java-Quellcode kann mit einem beliebigen Texteditor, oder wie in der Praxis üblich, mit einer umfassenden und komfortablen IDE erstellt werden. Der Compiler erzeugt den so genannten Zwischencode (Java-Bytecode), welcher später in der jeweiligen virtuellen Maschine auf dem Zielbetriebssystem ausgeführt wird. Java-Programme laufen nicht nativ auf dem Rechner, sondern sie werden stets in einer Art „Sandbox“ ausgeführt. Diese Sandbox oder auch Java-Virtuelle Maschine genannt, kümmert sich um die plattformspezifische Umsetzung. Die konkrete Umsetzung auf die Zielplattform, z.B. die grafische Benutzeroberfläche (UI), erledigt die Java-VM. Diese Aussage muss man etwas einschränken, denn komplexe Programme, welche systemspezifische Funktionen nutzen, bedürfen dennoch an der einen oder anderen Stelle die explizite Anpassung an das Zielbetriebssystem. Das gilt jedoch für jeden Ansatz der Cross-Plattform-Programmierung. Bei der Wahl der Entwicklungsumgebung ist man nicht eingeschränkt. Bekannte unter allen üblichen Betriebssystemen lauffähige Werkzeuge sind zum Beispiel: Eclipse, InteliJ und NetBeans.

Die Java-Plattform bietet eine große Zahl von Bausteinen, welche man zu dem gewünschten User Interface zusammenfügen kann. Dabei folgt der Aufbau nach dem Baukastenprinzip. Vorgefertigte Komponenten werden miteinander verschachtelt und kombiniert. Die Komponenten sind dabei einzelne Klassen, welche Bestandteil einer umfassenden Klassenbibliothek sind. Die Klassen für die Komponenten des User Interface gehören zu den Paketen java.awt und javax.swing. Das Abstract Window Toolkit (AWT) ist so ausgelegt, dass alle Elemente der Oberfläche durch das Betriebssystem zur Verfügung gestellt werden. Damit ist AWT durch den kleinsten gemeinsamen Nenner aller Betriebssysteme beschränkt. Man bezeichnet diese Vorgehensweise als Peer-Ansatz, weil die AWT-Komponenten alle Aktionen an plattformspezifische GUI-Objekte (Peers) weiterreichen. Auf unterschiedlichen Betriebssystemen sehen daher Java-Anwendungen, welche auf der Basis von AWT erstellt werden, unterschiedlich aus. AWT-Komponenten werden als schwergewichtig (heavyweight) bezeichnet. Die Swing-Klassen basieren auf einen anderen Ansatz. Sie sind fast alle selbst in Java programmiert, damit leichtgewichtig (lightweigh) und benutzen nur da wo es notwendig ist (Top-Level-Container) plattformspezifische Funktionen. Das Design kann unabhängig vom Betriebssystem gestaltet werden und es ist sogar eine Anpassung zur Laufzeit möglich. Programme auf der Basis von Swing sehen daher auf allen Betriebssystemen gleich aus.

Deutlich mehr visuellen Glanz verspricht die Bibliothek JavaFX. Diese Bibliothek ist seit einigen Versionen Bestandteil des JDK und muss nicht erst extra installiert werden. Abbildung 1 zeigt wie sich JavaFX in die Architektur einer Java-Anwendung integriert.

Architektur von JavaFX
Abbildung 1: Architektur von JavaFX [6].

Auf unterster Ebene befindet sich erwartungsgemäß die Java Virtual Machine (JVM). Bei Prism handelt es sich um eine Rendering Engine für Grafiken. Diese greift auf die Grafikhardware des Rechners zurück. Unter den Betriebssystemen macOS und Linux wird mit Hilfe von OpenGL gerendert. Unter Windows wird Direct3D verwendet. Gibt es keine Unterstützung durch die Hardware beim Rendering, so wird auf Java2D zurückgegriffen. Das Glass Windowing Toolkit stellt Low-Level-Betriebssystemroutinen zur Verfügung. Dazu gehören die Fenster- und Ereignisverwaltung. Die Media Engine bietet Unterstützung für Audio und Video. Die Web Engine ermöglicht das Einbetten von Web-Inhalten. Alle genannten Elemente von JavaFX werden über das Quantum Toolkit miteinander verknüpft. Dem Programmierer wird eine JavaFX-API zur Verfügung gestellt. Darüber erfolgt die gesamte Kommunikation

RAD Studio, Delphi, C++-Builder mit FireMonkey

RAD Studio [7] hatten wir bereits im zweiten Teil der Serie erwähnt, wo es um das Erstellen von nativen Apps für iOS und Android ging. Traditionell ist die integrierte Entwicklungsumgebung jedoch dafür prädestiniert, Desktop Applikationen für Microsoft Windows Betriebssysteme zu erstellen. Durch den Einsatz des Frameworks FireMonkey ist es jedoch möglich auch Applikationen zu erstellen, welche unmittelbar auf Windows, macOS und Linux-Distributionen ausgeführt werden können. Zu RAD Studio gehören Delphi und C++-Builder. In Delphi arbeitet man mit einer modernen und weiterentwickelten Version von Objekt Pascal. Mit C++-Builder arbeitet der Programmierer mit den aktuellen Sprachfeatures von C++. RAD Studio erzeugt native Applikationen, welche auf den Zielsystemen ohne die Abhängigkeiten zu weiteren Systembibliotheken laufen. Während der Entwicklung wird das User Interface mit Hilfe eines grafischen Designers aus Komponenten erstellt. Verschiedene Layout Container ermöglichen es, dass man die Elemente des User Interface relativ zueinander positioniert und damit die Anforderungen der unterschiedlichsten Geräteklassen bezüglich Bildschirmauflösung und -größe gemeinsam erfüllen kann. FireMonkey ermöglicht eine moderne Gestaltung des User Interface, auch 3D-Darstellungen werden unterstützt. Zur Entkopplung der Präsentations- von der Datenhaltungsschicht dienen so genannte Live Bindings. Auf diese Weise können Elemente des User Interface an die Daten- oder Modellschicht gekoppelt werden, ohne dazu Quellcode schreiben zu müssen. Der Designer erlaubt eine direkte Vorschau der definierten Screens. Soll für mehrere Gerätetypen entwickelt werden, so gibt es die Möglichkeit der geräteübergreifenden Vorschau. Damit kann der Vorgang der Gestaltung der Benutzerschnittstelle erheblich beschleunigt werden. Welche Plattformen man unterstützen möchte, dass legt man bei der Installation fest.
Die Entwicklung der Applikation erfolgt dann unter Microsoft Windows. Die Zielplattform kann direkt in der Entwicklungsumgebung erstellt werden. Um Apps für macOS zu erstellen, benötigt man den Zugriff auf Xcode und einen Mac-PC. Linux und macOS können direkt aus der Entwicklungsumgebung angesprochen werden. Auf beiden Zielsystemen wird dazu der so genannte PAServer (Platform Assistent Server) installiert, welche die Fernsteuerung von Linux bzw. macOS erlaubt (Abbildung 2).

 Systemumgebung, um Cross-Plattform Anwendungen mit RAD Studio zu erstellen.
Abbildung 2: Systemumgebung, um Cross-Plattform Anwendungen mit RAD Studio zu erstellen.

Bereits während der Designzeit der Programmoberfläche bekommt der Entwickler interaktiv bei der Auswahl der betreffenden Steuerelemente angezeigt, ob diese für die Zielplattform zur Verfügung stehen. Der komponentenbasierte Ansatz beschränkt sich nicht nur auf die Umsetzung des User Interface, sondern umfasst auch weitere Elemente der Applikation, so genannte nicht visuelle Controls. Auf diese Weise ist es möglich typische Aufgaben einer Desktop Anwendung mit wenigen Mausklicks zu integrieren. Dazu gehört zum Beispiel die komponentenbasierte Anbindung von Datenbanken oder die Steuerung von Hardwareschnittstellen usw.

Qt

Das Framework Qt [8] darf bei einer Betrachtung der Ansätze für die plattformübergreifende Entwicklung von Desktop Applikationen nicht fehlen. Es bietet ein umfassendes Framework und Werkzeuge, um plattformübergreifend Benutzeroberflächen zu erstellen. Qt beinhaltet mit QML eine eigene Auszeichnungssprache, welche das Erstellen der Oberflächen vereinfacht. Das Framework kann sehr gut durch andere Programmiersprachen, zum Beispiel Python oder Java verwendet werden. Qt ist zwischenzeitlich stark modular aufgebaut, welches das System flexibel einsatzbar macht. Wichtige Module sind zum Beispiel: Qt Core (Kernklassen), Qt GUI (Basisklassen für das UI), Qt QML (Framework und Typen für die Auszeichnungssprache QML), Qt Quick Dialogs (Systemdialoge) usw. Qt bietet eine eigene integrierte Entwicklungsumgebung den Qt Creator. Dieser enthält u.a. den Qt Designer, um die grafischen Oberflächen mit Hilfe der Qt Widgets zu erstellen.

Bei der Gestaltung der Benutzeroberfläche bietet Qt zwei unterschiedliche Möglichkeiten. Einerseits steht mit dem Qt Designer ein WYSIWYG-Editor zur Verfügung, der eng an die Qt Widgets geknüpft ist. Andererseits ist mit Qt Quick eine Alternative auswählbar, die die Entwicklung mit der QML-Sprache ermöglicht. Prägend für den Ansatz von Qt ist das Signal-Slot-Konzept. Bei einem Signal handelt es sich um eine Nachricht, die ein Objekt sendet, sobald ein bestimmtes Ereignis eintritt. Ein Slot wiederum ist eine Funktion, die mit einem Signal verknüpft wird. Diese Funktion wird dann ausgeführt, wenn sie das Signal erhält. Es ist einerseits möglich, ein Signal mit mehreren Slots zu verknüpfen, sodass mehrere Funktionen als Folge eines Ereignisses gestartet werden. Andererseits ist es auch möglich, dass ein Slot durch mehrere Signale ausgelöst wird, d.h. dieselbe Funktion wird durch unterschiedliche Ereignisse aufgerufen. Das System KDE-Plasma (Desktop-Umgebung für Linux) ist wohl eines der bekanntesten Softwareprojekte, welche mit Hilfe von Qt realisiert werden.

Electron und Co.

Im Folgenden sehen wir uns Technologien und Vorgehensweisen an, um eine Web Applikation für den Desktop zum Laufen zu bringen. Bei NW.js [10] handelt es sich um ein Framework zur Erstellung von Desktop Anwendungen in HTML, CSS und JavaScript. Der Hintergrund: Die Web Applikationen werden mit der Browser-Engine WebKit kombiniert. Dadurch können Anwendungsfenster erstellt werden, welche die Web Applikation auf den Zielsystem darstellen können. Ebenso kann man über das Web Kit auf native Betriebssystemfunktionen zugreifen. Mit Hilfe von NW.js kann man die Web Applikation dann zu einer Desktop Anwendung verpacken (Packaging). Dabei gibt man das Zielsystem, zum Beispiel Windows oder macOS, vor.
Sehr oft erwähnt wird im Moment das Framework Electron [11]. Auch Electron erlaubt es aus Web Applikationen entsprechende Desktop Anwendungen zu erstellen. Bekannte, mit Electron erstellte Applikationen sind zum Beispiel die Code Editoren Atom und Visual Studio Code. Auf der Webseite findet sich eine umfassende Liste von Applikationen, welche mit Electron programmiert wurden. Der technische Ansatz ist ähnlich dem von NW.js, auch hier wird mit Web Kit gearbeitet. Es gibt einen wichtigen Unterschied zwischen NW.js und Electron. In NW.js teilen sich Node.js und WebKit einen einzelnen JavaScript-Kontext. Dagegen werden in Electron mehrere Kontexte verwendet, einer für den Hintergrundprozess, welcher die Anwendung steuert und jeweils ein Kontext für das Anwendungsfenster. Es gibt also i.d.R. mehrere Renderer-Prozesse. In NW.js ist der Einstiegspunkt eine HTML-Datei, in Electron ist es eine JavaScript-Datei. Abbildung 7 illustriert, wie aus den einzelnen Dateien des Web-Projektes (HTML, CSS, JavaScript) und einer Konfigurationsdatei (package.json) mit Hilfe von NW.js durch Packaging eine Desktop Anwendung für das gewünschte System generiert wird.

Weitere Ansätze und Fazit

Weitere Ansätze bestehen zum Beispiel darin, dass man hoch integrierte Tools bereitstellt, mit welchen man in der Lage ist, Applikationen für die unterschiedlichsten Systeme auf primär grafischen Weg bzw. durch umfassende Tool-Unterstützung zu erstellen. Dazu gehören zum Beispiel: 8th [14]; B4J [15], ähnlich Visual Basic; Kivy [16], ein Open-source Python GUI Framework, Haxe [17] und Xojo [18]. Diese Tools sind i.d.R. auf eine bestimmte Art von Applikationstypen, zum Beispiel Business Anwendungen ausgerichtet und man versucht den Prozess zum Erstellen durch umfassende Werkzeugunterstützung weiter zu vereinfachen.Welcher Ansatz ist in einem konkreten Fall geeignet? Wie immer kommt es auf die Ziele und Voraussetzungen an. Java Applikationen sind Standard und im Business-Umfeld gut etabliert. Ein riesiger Fundus an Bibliotheken, Werkzeugen und Lösungsansätzen steht zur Verfügung. Es entstehen jedoch keine nativen Applikationen. Dieses wiederum ist bei RAD Studio der Fall. Ebenso haben wir es dort mit einer stark komponentenbasierten Entwicklungsumgebung zu tun, welche den Entwicklungsprozess erheblich beschleunigt. Ein anderer Aspekt ist die Frage danach, welches Betriebssystem primär zu unterstützen ist und/ oder für welche weiteren Systeme, zum Beispiel Android oder iOS ebenfalls Applikationen bereitzustellen sind. Mit Qt und RAD Studio kann man sehr gut den Desktop, als auch die mobile Welt bedienen. Geht die Entwicklung in Richtung Web Applikationen bzw. sollen Ansätze aus der Web-Programmierung zum Einsatz kommen, dann kann man zum Beispiel Frameworks wie Electron auf ihre Eignung prüfen.

Literatur und Links

[1] https://netmarketshare.com/
[2] https://dotnet.microsoft.com/
[3] https://dotnet.microsoft.com/download/dotnet-core/3.1
[4] https://avaloniaui.net/
[5] Ratz, D. u.a.: Grundkurs Programmieren in Java, C. Hanser Verlag München, 2011
[6] https://docs.oracle.com/javafx/2/architecture/jfxpub-architecture.htm
[7] https://www.embarcadero.com/de/products/rad-studio
[8] https://www.qt.io/
[9] Xibao Wanga; Ge Li; Peng Wang: Qt-Based Cross-platform Design of Management System for Distributed Real-time Simulation Platform, 5th International Conference on Computer Sciences and Automation Engineering (ICCSAE 2015), https://www.researchgate.net/publication/314641157_Qt-Based_Cross-platform_Design_of_Management_System_for_Distributed_Real-time_Simulation_Platform
[10] https://nwjs.io/
[11] https://www.electronjs.org/
[12] https://dzone.com/articles/what-is-nwjs
[13] https://medium.com/@vishaldwivedi13/electron-things-to-watch-out-for-before-you-dive-in-e1c23f77f38f
[14] https://8th-dev.com/
[15] https://www.b4x.com
[16] https://kivy.org/#home
[17] https://haxe.org/
[18] https://www.xojo.com/