Teil 5: Überall zu Hause

Die Desktopanwendung für alle Systeme im Praxiseinsatz
Keine Kommentare

Für die Cross-Plattform-Programmierung von Desktopapplikationen stehen verschiedene Technologien zur Verfügung. Um den besten Ansatz für das eigene Projekt auszuwählen, müssen technische Unterschiede, gegebene Voraussetzungen, vorhandener Quellcode und die Ziele der Entwicklung betrachtet werden. Auf jeden Fall sollte man vor einer Entscheidung den einen oder anderen Ansatz an einem Praxisbeispiel erproben.

Unsere Serie zur Cross-Plattform-Programmierung geht in die letzte Runde. Nach einem allgemeinen Überblick im ersten Teil ging es um die Entwicklung von Apps für die mobilen Systeme iOS und Android in Theorie und Praxis (Teil 2 und 3). In Teil 4 war der Desktop das Ziel. Das ist auch diesmal der Fall – mit Beispielen für die Praxis.


Folgende Technologien hatten wir uns in Teil 4 angesehen:

  • Java, gewissermaßen der Industriestandard mit unterschiedlichen Bibliotheken für die grafischen Benutzeroberflächen (AWT, Swing und JavaFX)
  • .NET Core als plattformübergreifender Ansatz. Derzeit befinden sich die User-Interface-Technologien WinForms, WPF und UWP in der Portierung für Windows-Systeme; für andere Betriebssysteme muss man auf Bibliotheken von Drittanbietern zurückgreifen
  • RAD Studio mit Delphi bzw. C++ Builder und dem Grafik-Framework FireMonkey für native Applikationen für Windows, macOS und Linux
  • Qt als unabhängiges Framework zur plattformübergreifenden Programmierung des User Interface
  • Electron und NW.js zur Portierung von Webapplikationen auf den Desktop

All diese Ansätze sind ausgereift und eignen sich (mit Ausnahme der UI-Technologie von .NET Core) dafür, moderne Desktopapplikationen für die Zielsysteme Windows, macOS und Linux zu erstellen. Welchen man letztlich nutzen sollte, hängt von mehreren Faktoren ab. Darunter:

  • Native Applikation: In diesem Fall muss man einen Ansatz wählen, der bereits zur Designzeit die plattformspezifischen ausführbaren Dateien mit Hilfe eines Compilers generiert. Hier bieten sich zum Beispiel Delphi oder der C++ Builder an. Sind die Ansprüche an die Performance nicht so groß, kann man auch eine Java-Applikation einsetzen, die auf jedem System die Java Runtime erfordert.
  • Abhängigkeit von Bibliotheken: In Ergänzung zum erstgenannten Punkt muss man prüfen, ob man (System-)Bibliotheken, z. B. .NET Core oder die Java Runtime, auf dem Zielsystem verwenden kann und ob man sie mit der Installation bereitstellen muss.
  • Vorhandener Quellcode: Eventuell ist der Quellcode einer bestehenden Desktopapplikation, die auf ein anderes System portiert werden soll, bereits vorhanden.
  • Programmiersprache: Neue Vorgehensweisen zu erlernen ist aufwendig und kostet Zeit und Geld. Einige Ansätze funktionieren ähnlich und unterscheiden sich im Wesentlichen in der Programmiersprache. Bringt man dagegen eine existierende Webapplikation auf den Desktop, liegt ihr ein anderes Applikationsmodell (Architektur) zu Grunde.
  • Entwicklungsumgebung: Auch wenn die Desktopanwendung auf allen Systemen ausgeführt werden soll, ist es wichtig zu klären, wie die Entwicklungs- und Systemumgebung aussieht.
  • Weitere Zielsysteme: Sollen weitere Systeme und Anwendungstypen unterstützt werden, z. B. eine mobile App für iOS und Android oder eine Webapplikation?
  • Werkzeuge: Welche Entwicklungsumgebungen kommen zum Einsatz? Wie vertraut ist man selbst bzw. das Entwicklungsteam mit dem Vorgehen?
  • Unterstützung bei der Gestaltung des User Interface: Umfassende Businessapplikationen weisen oft viele Dialoge mit zahlreichen Steuerelementen auf, sodass sich der Einsatz eines guten Designers schnell auszahlt.
  • Lizenzgebühren: Fallen für Nutzung bzw. Einsatz des Entwicklungswerkzeugs Lizenzgebühren an oder ist es Open Source?

Das sind nur einige Kriterien bei der Auswahl der passenden Technologie. Hilfreich ist es, einen infrage kommenden Ansatz – idealerweise sogar mehrere – auf seine Eignung im konkreten Projekt hin zu evaluieren.

IT Security Camp

Freiberuflicher Whitehat Hacker, Trainer und Security-Coach

Christian Schneider (Schneider IT-Security)

IoT Conference 2020

All Inclusive

Katrin Rabow

Evaluation

In neue und unbekannte Technologien arbeitet man sich am besten mit Hilfe eines einfachen Beispiels ein. Das allseits bekannte „Hello World“ taugt dabei für einen ersten Einstieg, sollte jedoch bald durch praxistaugliche Beispiele ersetzt werden. Dabei bietet es sich an, sogenannte vertikale Prototypen zu erstellen. Im Gegensatz zu horizontalen Prototypen (Kasten: „Vertikale und horizontale Prototypen“), wie Mock-ups des künftigen User Interface, ziehen sich vertikale Prototypen durch alle Ebenen des künftigen Anwendungssystems. Vertikale Prototypen sind daher eine große Hilfe, um frühzeitig Feedback über die Eignung einer geplanten Technologie zu erhalten. Es ist besser, einen zunächst vielversprechenden Kandidaten rechtzeitig auszusortieren, als zu lange den falschen Weg zu beschreiten.

Vertikale und horizontale Prototypen

Horizontale Prototypen untersuchen eine bestimmte Schicht der Softwarearchitektur, zum Beispiel die Benutzeroberfläche. Dabei werden die relevanten Bestandteile dieser Schicht implementiert. Die anderen Schichten werden nicht implementiert bzw. sind ggf. lediglich als Dummys vorhanden. In diesem Fall hat man es etwa mit einem Prototyp der Benutzeroberfläche zu tun, der jedoch keine Funktionalität beinhaltet. Dagegen wird ein vertikaler Prototyp auch Durchstichprototyp genannt, weil er eine Funktionalität bzw. ein Feature nahezu vollständig umsetzt: Alle Schichten der Softwarearchitektur werden für einen bestimmten Ausschnitt des Softwaresystems implementiert (Abb. 1).

Abb. 1: Horizontaler vs. vertikaler Prototyp

Abb. 1: Horizontaler vs. vertikaler Prototyp

Mit Blick auf die Desktopapplikation müssen wir bei der Auswahl der Technologie unter anderem die folgenden Punkte betrachten und zumindest im Rahmen der Evaluierung geklärt haben:

  • Einrichtung der Entwicklungs- und Systemumgebung
  • Architektur der Applikation
  • Programmiermodell
  • Erstellen des User Interface
  • Erstellen der lauffähigen Applikationen für die Zielsysteme
  • Finales Deployment

Als Ergebnisse von Experimenten hierzu stellen wir nachfolgend zwei Ansätze vor:

  1. Plattformübergreifende Programmierung mit Hilfe von RAD Studio (Delphi) unter Windows mit Portierung der Applikation nach macOS und Linux
  2. Verpacken einer Webapplikation zu einer plattformübergreifenden Desktopanwendung für Windows, macOS und Linux

Wir betrachten die o. g. Evaluierungsaufgaben (Kasten: „Technologien systematisch evaluieren“) in kompakter Form. Für eine projektbezogene Evaluierung sollten Sie ein breiteres Auswahlfeld berücksichtigen und dabei schrittweise vorgehen (Anforderungen, Vorauswahl, Tests, Evaluierung, Entscheidung).

Technologien systematisch evaluieren

Die Auswahl der passenden Technologie ist nicht trivial und bedarf eines schrittweisen Vorgehens und der Einbeziehung mehrerer Aspekte (Abb. 2). Bevor man mit der Evaluierung unterschiedlicher Technologien beginnt, sollte der Bedarf aus verschiedenen Perspektiven betrachtet werden. Jeder Fall muss individuell bewertet werden. Als Nächstes sollte man sich den Mehrwert jeder Option genau ansehen. Dabei ist es oft nicht einfach, die Produkte verschiedener Anbieter miteinander zu vergleichen. Entweder bieten sie eine vollständig andere Herangehensweise an eine Problemstellung, oder die Voraussetzungen zur Anwendung sind sehr unterschiedlich. Die Orientierung an den eigenen Zielen ist wichtig, und man sollte sich nicht von einem vielleicht gerade vorhandenen Innovationshype ablenken lassen. Es gilt, Hype und Realität genau abzuwägen. Neue Technologien lösen stets eine gewisse Faszination aus. Bei näherer Betrachtung zeigt sich aber oft, dass sie sich für ein bestimmtes Projekt gar nicht eignen. Daher empfiehlt es sich, neue Ansätze zunächst in kleineren Projekten zu testen. So ist ein möglicher Fehlschlag begrenzt und prognostizierbar. Zudem sollte die Auswahl der Technologie auch für die Zukunft tragfähig sein, die langfristigen Aspekte müssen also ebenfalls betrachtet werden. Technologien werden zum Lösen von Problemen verwendet, vernachlässigen Sie daher die Kundensicht und die Prozessorientierung nicht.

Abb. 2: Mögliche Aspekte bei der Evaluierung von Technologien

Abb. 2: Mögliche Aspekte bei der Evaluierung von Technologien

Native Desktopapplikation mit Delphi und FireMonkey

Im vorigen Serienteil haben wir diesen Ansatz bereits vorgestellt, sodass wir jetzt direkt starten können. Wir gehen nun die Punkte Entwicklungs- und Systemumgebung, Architektur, Programmiermodell, Erstellen des User Interface, Erstellen der Applikationen für die Zielsysteme und das finale Deployment im Einzelnen durch. Dabei entwickeln wir unter Microsoft Windows.

Installieren Sie dazu beispielsweise die Community Edition von Delphi. Damit können Sie für Windows und macOS programmieren. Für Linux-Anwendungen braucht man dagegen die Enterprise Edition. Außerdem benötigen Sie Zugriff auf macOS und eine Linux-Distribution. Es bietet sich an, mit virtuellen Maschinen zu arbeiten. Als Hostbetriebssystem setzen wir macOS ein und verwenden zwei virtuelle Maschinen. In der virtuellen Maschine für Windows installieren Sie Delphi als Entwicklungsumgebung, in der anderen virtuellen Maschine das Linux-System (Ubuntu). Unter macOS und Linux müssen Sie den PAServer installieren, um von außen (Windows) aus Delphi heraus auf die Systeme zugreifen zu können. Die Installationsdateien für den PAServer finden Sie hier für Linux und hier für macOS.

Wir entwickeln die Applikation mit Delphi. Das User Interface wird im grafischen Designer mit Hilfe der vorgefertigten Komponenten gestaltet. Legen Sie dazu ein neues Projekt an. Es muss die Vorlage Geräteübergreifende Anwendung verwendet werden. Der Hintergrund: Eine solche Anwendung basiert auf dem Grafik-Framework FireMonkey, und die erstellten Applikationen können unter den Betriebssystemen Windows, macOS und Linux ausgeführt werden. Als Beispiel dient ein Kreditrechner (Kasten: „Beispiel Kreditrechner – Annuitätendarlehen“).

Beispiel Kreditrechner – Annuitätendarlehen

Nach der Eingabe der Daten für den Kreditbetrag (in Euro), Zinssatz (in Prozent), anfängliche Tilgung (in Prozent) und Laufzeit (in Jahren) wird der Tilgungsplan berechnet und ausgegeben. Die Berechnung ist nicht weiter kompliziert. Die Daten werden aus dem Formular entgegengenommen, für das erste Jahr werden die Zinsen (= Zinssatz * Kreditbetrag / 100), die Tilgung (= Tilgungssatz * Kreditbetrag / 100), die Annuität (= Zinsen + Tilgung) und der danach noch offene Restbetrag (= Kreditbetrag – Tilgung) errechnet. Für die Jahre 2 bis zum Ende der Laufzeit sind der noch offene Betrag (= Restbetrag des Vorjahrs), die Zinsen (= offener Betrag * Zinssatz / 100), die Tilgung (= Annuität – Zinsen) und der verbleibende Restbetrag (= offener Betrag am Anfang des Jahres – Tilgung) zu errechnen. Die Gesamtbelastung (Annuität = Zins + Tilgung) bleibt also über die Laufzeit konstant, wobei die Zinsen von Jahr zu Jahr abnehmen und die Tilgung entsprechend steigt. Einen Onlinerechner finden Sie auf dieser Webseite.

Für die Gestaltung der Benutzeroberfläche brauchen wir TEdit-Steuerelemente zur Erfassung der Zahlenwerte (Kreditbetrag, Zinssatz, Tilgungssatz), ein TCombo-Element für die Festlegung der Laufzeit (z. B. fünf, zehn oder fünfzehn Jahre) und ein TStringGrid-Element, um den Tilgungsplan auszugeben. Ordnen Sie die Elemente auf dem Formular an. Die Berechnung lösen wir mit einem Klick auf einen Button (Komponente des Typs TButton) mit dem Titel Berechnen aus. Dazu wird der in Listing 1 dargestellte Quellcode hinterlegt (Delphi), d. h., dem onClick(…)-Event des Buttons zugewiesen.

procedure TForm1.Button1Click(Sender: TObject);
var
  laufzeit: integer;
  kreditbetrag: Double;
  zinssatz: Double;
  tilgungssatz: Double;
 
  betrag: Double;
  annuitaet: Double;
  zinsen: Double;
  tilgung: Double;
  restbetrag: Double;
  i: integer;
begin
  // Daten aus Formular holen
  kreditbetrag := StrToFloat(EditBetrag.Text);
  laufzeit := strtoint(ComboEdit.Text);
  zinssatz := StrToFloat(EditZinssatz.Text);
  tilgungssatz := StrToFloat(EditTilgungssatz.Text);
 
  // Anpassung der Anzahl der Zeilen im Grid
  StringGrid.RowCount := laufzeit;
  // Jahr 1
  betrag := kreditbetrag;
  zinsen := betrag * zinssatz / 100;
  tilgung := betrag * tilgungssatz / 100;
  annuitaet := zinsen + tilgung;
  restbetrag := betrag - tilgung;
  // Datenausgabe
  StringGrid.Cells[0, 0] := '1';
  StringGrid.Cells[1, 0] := FloatToStrF(betrag, ffCurrency, 8, 2);
  StringGrid.Cells[2, 0] := FloatToStrF(zinsen, ffCurrency, 8, 2);
  StringGrid.Cells[3, 0] := FloatToStrF(tilgung, ffCurrency, 8, 2);
  StringGrid.Cells[4, 0] := FloatToStrF(annuitaet, ffCurrency, 8, 2);
  StringGrid.Cells[5, 0] := FloatToStrF(restbetrag, ffCurrency, 8, 2);
  // Jahre 2-n
  for i := 2 to laufzeit do
  begin
    // Berechnung
    betrag := restbetrag;
    zinsen := betrag * zinssatz / 100;
    tilgung := annuitaet - zinsen;
    restbetrag := betrag - tilgung;
    // Datenausgabe
    StringGrid.Cells[0, i - 1] := IntToStr(i);
    StringGrid.Cells[1, i - 1] := FloatToStrF(betrag, ffCurrency, 8, 2);
    StringGrid.Cells[2, i - 1] := FloatToStrF(zinsen, ffCurrency, 8, 2);
    StringGrid.Cells[3, i - 1] := FloatToStrF(tilgung, ffCurrency, 8, 2);
    StringGrid.Cells[4, i - 1] := FloatToStrF(annuitaet, ffCurrency, 8, 2);
    StringGrid.Cells[5, i - 1] := FloatToStrF(restbetrag, ffCurrency, 8, 2);
  end;

Interessant ist nun das Kompilieren für die unterschiedlichen Zielsysteme. Wählen Sie zunächst Windows 64 Bit als Betriebssystem. Die Applikation wird gestartet und sollte erwartungsgemäß funktionieren. Wechseln Sie nun zu macOS und starten Sie den PAServer für eine externe Verbindung von Windows (virtuelle Maschine) zu macOS (Abb. 3).

Abb. 3: PAServer für die Verbindung der Entwicklungsumgebung mit macOS bzw. Linux

Abb. 3: PAServer für die Verbindung der Entwicklungsumgebung mit macOS bzw. Linux

Wählen Sie dann in Delphi macOS als neue Zielplattform. Nach einem Neustart wird unser Kreditrechner unter macOS ausgeführt. Unter Linux, mit der virtuellen Maschine von Ubuntu, verhält es sich genauso: PAServer starten, Zielplattform in Delphi wechseln und Anwendung neu erstellen. Wie die Abbildungen 4 bis 6 zeigen, sind wir nun in der Lage, die Desktopapplikation auf Windows, macOS und Linux auszuführen.

Abb. 4: Kreditrechner unter Windows

Abb. 4: Kreditrechner unter Windows

Abb. 5: Kreditrechner unter macOS

Abb. 5: Kreditrechner unter macOS

Abb. 6: Kreditrechner unter Ubuntu Linux

Abb. 6: Kreditrechner unter Ubuntu Linux

Es werden unmittelbar ausführbare Dateien generiert, die ohne Abhängigkeiten auf andere Bibliotheken auskommen. Das kann mit Blick auf die Ausführbarkeit der Applikation unter unterschiedlichsten Systemen und Versionen ein wichtiger Vorteil sein. Zudem handelt es sich um native Anwendungen; die auf den Zielplattformen ausführbaren Dateien werden also bereits zur Designzeit vom Compiler generiert.

Kommen wir zur Installation (Deployment) der Applikation auf den Zielsystemen. Unter Windows kann man ein klassisches Installationsprogramm erstellen oder für die Windows-Anwendungen das Deployment über den App Store wählen. Ursprünglich war dieser Weg für Apps der Universal Windows Platform (UWP) vorgesehen. Der Store wurde jedoch auch für klassische Windows-Applikationen geöffnet. In Delphi können Sie ein solches App-Package für den Store direkt erstellen und dann zum offiziellen Freigabeprozess bei Microsoft anmelden. Auch für macOS können Sie das Applikations-Bundle aus Delphi heraus erstellen und über den App Store bereitstellen. Dazu müssen Sie die Bedingungen des App Stores erfüllen und über einen kostenpflichtigen Developer Account verfügen. Alternativ kann unter macOS eine App auch ohne den Umweg über den Store installiert und ausgeführt werden, sofern sie von Apple „beglaubigt“ wurde. Vergleichen Sie dazu die Hinweise des Herstellers zum Thema Notarizing. Die Distribution für Linux ist weniger standardisiert und unterliegt keinen solch strengen Regeln. Benötigte Packages für Repositories der Distributionen müsste man selbst generieren.

Wie wir gesehen haben, lassen sich mit RAD Studio native Desktopapplikationen für Windows, macOS und Linux erstellen. Das User Interface wird über einen grafischen Designer gestaltet und durch das Framework FireMonkey auf die jeweilige Zielplattform transformiert.

Web-App auf dem Desktop mit Electron

Wir versuchen nun eine „Hello World“-Anwendung in Electron. Sie benötigen dazu eine aktuelle Version von Node.js. Die Installationspakete für die gängigen Betriebssysteme finden Sie auf der Webseite. Ob die Installation funktioniert hat, können Sie wie folgt überprüfen:

node --version
npm --version

Wenn wir ein Projekt mit npm erstellen, müssen wir eine package.json-Datei bereitstellen, die alle Details zu unserem Projekt enthält. npm erleichtert uns das Einrichten dieser Datei. Starten Sie Ihr Terminal, erstellen Sie einen neuen Ordner mit dem Namen hello world und öffnen Sie diesen Ordner mit dem Befehl cd. Verwenden Sie nun den Befehl npm init, um die Datei package.json mit npm zu erstellen.

Nach einigen Abfragen, zum Beispiel nach Name und Version des Projekts, wird die Datei package.json generiert und im Dateisystem erzeugt. Danach können wir bereits Electron installieren. Das geht mittels npm install -g electron-prebuilt.

Die notwendigen Packages werden aus dem Internet heruntergeladen und installiert. Das dauert einige Augenblicke. Erstellen Sie einen Ordner für die erste App, z. B. HelloWorld. Innerhalb des Ordners erstellen Sie zwei Dateien mit den Namen main.js und index.html. Die Inhalte dieser beiden Dateien sind in Listing 2 zu sehen. Um die App mit Electron zu erstellen, geben Sie auf der Kommandozeile im Projektordner den Befehl electron ein. Auch hier können Sie mit electron ––version den Erfolg der Installation überprüfen. Starten wir die erste Desktopapplikation auf der Kommandozeile: electron ./main.js

Damit sollte die App ausgeführt und das „Hello World“-Beispiel angezeigt werden. Diese App verfügt bereits über alle wesentlichen Merkmale einer Desktopanwendung, beispielsweise Fenster, Menüs usw. (Abb. 7).

Abb. 7: „Hello World“-Desktop-App mit Electron

Abb. 7: „Hello World“-Desktop-App mit Electron

main.js
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
 
let win
 
function createWindow() {
  win = new BrowserWindow({width: 800, height: 600})
  win.loadURL(url.format ({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))
}
 
app.on('ready', createWindow)
 
index.html
<!DOCTYPE html>
<html>
  <head>
     <meta charset = "UTF-8">
     <title>Hello World!</title>
  </head>
  
  <body>
     <h1>Hello World!</h1>
     We are using node <script>document.write(process.versions.node)</script>,
     Chrome <script>document.write(process.versions.chrome)</script>,
     and Electron <script>document.write(process.versions.electron)</script>.
  </body>
</html>

Wie man die App weiter aufbaut, ist in der Dokumenation sehr gut dokumentiert. Bei dieser Vorgehensweise wird die ehemalige Webapplikation quasi in ein Desktopfenster „gezwungen“. Neben der Anpassung des User Interface sind weitere Punkte zu beachten:

  • Desktopanwendungen können auch offline arbeiten, daher muss man für das Zwischenspeichern der Daten sorgen und sie später synchronisieren.
  • Die Bedienkonzepte unterscheiden sich in der Regel erheblich – welche Anpassungen müssen Sie vornehmen?
  • Wie werden dynamisch aus dem Web geladene Elemente eingebunden?

Das Ziel einer Desktopapplikation auf der Basis von Webtechnologien lässt sich deutlich einfacher erreichen, als wenn eine Webapplikation auf den Desktop migriert werden soll. Dieses Vorhaben dürfte auch eher die Ausnahme darstellen. Am Ende des Prozesses erstellt man App-Packages für die jeweilige Plattform. Das geht über den electron-packager direkt auf der Konsole.

Fazit

Es gibt mehrere Möglichkeiten, eine Desktopapplikation zu erstellen, die auf den Systemen Windows, macOS und Linux ausgeführt werden kann. Dabei können wir grundsätzlich danach unterscheiden, ob die Übersetzung zur Laufzeit stattfindet und damit eine virtuelle Umgebung auf dem Zielsystem vorhanden sein muss (Java), oder ob eine native Applikation bereits zur Designzeit durch den Compiler erstellt wird (zum Beispiel Delphi). Weitere Differenzierungsmöglichkeiten sind die Programmiersprache und das Programmiermodell.

Die Cross-Plattform-Programmierung ist gegenüber früheren Ansätzen deutlich vorangekommen. Das gilt sowohl für den Bereich der mobilen Apps als auch für Desktopapplikationen. Damit sind wir in der Lage, den Nutzer mit unseren Applikationen auf all seinen bevorzugten Geräten zu erreichen.

Weitere Informationen zu diesen und anderen Themen der IT finden Sie unter http://larinet.com.


 

Unsere Redaktion empfiehlt:

Relevante Beiträge

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu:
X
- Gib Deinen Standort ein -
- or -