//

JavaFX: One codebase to rule them all!

19.5.2015 | 4 Minuten Lesezeit

Plattformübergreifende mobile Applikationen mit JavaFX

Mit Veröffentlichung der ersten Version von JavaFX (2+) führte sogleich „going mobile“ die Hitlisten der am meisten gewünschten Features an. Die Vorstellung, auf einer Codebasis Applikationen für diverse Plattformen bereitstellen zu können (das berühmte WORA Paradigma – Write Once Run Anywhere) erscheint schon sehr verlockend.

Auf der JavaOne 2013 hat Oracle prototypisch gezeigt, dass es möglich ist, JavaFX-basierte Applikationen auf mobile Geräte, auf denen Android und iOS läuft, zu portieren. Danach zog sich Oracle aus dem Thema offiziell zurück und übergab den Code der Community.

Das daraufhin Ende 2013 von Johan Vos gestartete Projekt JavaFXPorts hatte es sich zunächst zur Aufgabe gemacht, JavaFX basierend auf OpenJFX nach Android zu portieren und gewann auf der JavaOne 2014 den Duke’s Choice Award.

Im Februar 2015 nun taten sich Johan’s Firma LodgOn (JavaFXPorts, JavaFX -> Android) und Trillian Mobile (das Unternehmen ehemals hinter RoboVM, JavaFX -> iOS) zusammen, um gemeinsam das Gradle JavaFX Plugin „javafxmobile-plugin“ zu veröffentlichen.

Dieses Plugin adressiert die drei Plattformen Desktop, Android und iOS soweit möglich auf einer gemeinsamen Codebasis. Wenn nötig, werden Plattformspezifika durch native Services ergänzt. Mit javafxmobile-plugin kann somit ein gemeisamens Projekt für alle Zielplattformen erstellt werden, aus dem haraus auf die jeweilige Plattform „deployed“ wird.

„javafxmobile-plugin“

Bietet Oracle bereits Java für Windows, Linux, Mac OS und ARM, so bietet JavaFXPorts einen Rahmen für JavaFX-Community-SDKs mit Fokus auf iOS und Android. Dabei spielt ein entscheidender Unterschied eine Rolle: iOS- und Android-Programme werden zu nativen Applikationen konvertiert, so dass diese auf gleicher Low-Level-Ebene agieren wie „normale“ mobile Anwendungen.

Es wird also keine Laufzeitumgebung mitgeliefert, in der Java-Bytecode interpretiert wird, sondern es werden Apple-AppStore- und Google-Play-Store-fähige Pakete erstellt. Dabei kommt für eine iOS-Applikation RoboVM und Xcode in Verbindung mit einem iOS-Developer-Account zum Tragen, für Android wird das Android SDK benötigt (Getting Started with JavaFXPorts).

Projektstruktur

Die Projektstruktur sieht per Konvention folgendermaßen aus:

Plattformunabhängig (main)

src/main/java Allgemeiner Java-Code

src/main/resources Allgemeine Ressourcen

Android (android)

src/android/java Android-Java-Code

src/android/res Android-Assets

src/android/resources Android-Ressourcen

iOS (ios)

src/ios/java iOS-Java-Code

src/ios/resources iOS-Ressourcen

src/ios/assets iOS-Assets

Desktop (desktop)

src/desktop/java Desktop-Java-Code

src/desktop/resources Desktop-Ressourcen

Ressourcen und Assets?
src/…/resources werden automatisch zum Classpath hinzugefügt.
src/…/res/ src/…/assets werden wie plattformspezifische Ressourcen behandelt.

Gradle Tasks

Als Build-Tool kommt bei JavaFXPorts Gradle zum Einsatz, und es wird eine Anzahl an plattformspezifischen Build-Tasks bereitgestellt:

Desktop

run startet die Applikation in der Desktop-Umgebung

Android

android generiert ein Android „apk“ im Verzeichnis build/javafxports/android

androidInstall installiert das generierte „apk“ auf ein angeschlossenes Android-Gerät

iOS

ios generiert ein iOS „ipa“ im Verzeichnis build/javafxports/ios

launchIOSDevice startet (und installiert) die Applikation auf einem angeschlossenen iOS-Gerät

launchIPhoneSimulator startet die Applikation in einem iPhone-Simulator

launchIPadSimulator startet die Applikation in einem iPad-Simulator

Gluon

Vor einiger Zeit startete ein neues Projekt: Gluon mit dem Ziel, die Welten Desktop, Android und iOS in einer Projektstruktur zu vereinen und rund um das Thema „Entwicklung plattformübergreifender Applikationen“ Frameworks und Services anzubieten. Dabei sollen nach und nach Plugins für die gängigsten IDEs bereitgestellt werden. Derzeit ist ein Gluon-Plugin für NetBeans verfügbar, das über das NetBeans-Plugins-Portal sehr einfach installiert werden kann.

Nach der Installation des Plugins steht für neue JavaFX-Projekte das Template „Basic Gluon Application“ zur Verfügung, das eine Gluon-, bzw. JavaFXPorts- Projektstruktur erstellt:

Mit dem Laden des Videos akzeptieren Sie die Datenschutzerklärung von YouTube.
Mehr erfahren

Video laden

YouTube immer entsperren

Benötigt die neue Applikation keinerlei gerätespezifische Zugriffe, kann der gesamte Code im gemeinsamen Bereich abgelegt und eine reguläre JavaFX-Anwendung erstellt werden.

In der allermeisten Fällen wird dies jedoch nicht ausreichen. Bereits beim Zugriff auf das Dateisystem wird es spezifisch (aus Gluon Charm Down):

Desktop

1public File getPrivateStorage() {
2  String home = System.getProperty("user.home");
3  File f = new File(home, ".gluon");
4  if (!f.isDirectory()) {
5    f.mkdirs();
6  }
7  return f;
8}
9

Android

1public File getPrivateStorage() {
2  return FXActivity.getInstance().getFilesDir();
3}
4

iOS

1public File getPrivateStorage() {
2  NSFileManager fm = NSFileManager.getDefaultManager();
3  NSURL libdir = fm.getURLForDirectory(
4   NSSearchPathDirectory.LibraryDirectory,
5   NSSearchPathDomainMask.UserDomainMask, null, false);
6  File appPrivateDir = new File(libdir.getPath() + "/Caches/gluon");
7  if (!appPrivateDir.exists()) {
8    appPrivateDir.mkdirs();
9  }
10  return appPrivateDir;
11}
12

Auch für den Zugriff auf weitere Ressourcen und Dienste des Gerätes oder der Plattform wie Netzwerk/Internet, Adressbuch, Kalender, Audio/Video, GPS, Kamera etc. wird man auf native Implementierungen zugreifen.

Dabei ist es aus Entwicklersicht sicher wünschenswert, wenn sich der Zugriff auf gerätespezifische Ressourcen möglichst transparent und einheitlich gestaltet.

Gluon Charm Down

Dieses Ziel hat sich die vor Kurzem in der Version 0.0.1 freigegebene OSS-Zusatzbibliothek Gluon Charm Down gesetzt.

Damit kann dann via

1PlatformFactory.getPlatform()
2

die für die jeweilige Platform die passende Implementierung einer „Platform“ angefordert werden.
Somit bekommt man durch

1  File path = PlatformFactory.getPlatform().getPrivateStorage();
2

den jeweils gültigen Dateipfad für applikationspezifische Dateien.
Ähnliches gilt zum Beispiel auch für den Anwendungsstatus. Charm Down sieht hier eine CallBack-Schnittstelle vor, die es ermöglicht, auf die LifecycleEvents START, PAUSE, RESUME, STOP zu reagieren, zum Beispiel:

1public class IosPlatformProvider implements PlatformProvider {
2 
3    private final BooleanProperty stop = new SimpleBooleanProperty();
4    private final BooleanProperty pause = new SimpleBooleanProperty();
5 
6    {
7        PlatformFactory.getPlatform().setOnLifecycleEvent((LifecycleEvent param) -> {
8            switch (param) {
9                case START:
10                    pause.set(false);
11                    stop.set(false);
12                    break;
13                case PAUSE:
14                    pause.set(true);
15                    break;
16                case RESUME:
17                    pause.set(false);
18                    stop.set(false);
19                    break;
20                case STOP:
21                    stop.set(true);
22                    break;
23            }
24            return null;
25        });
26    }
27 
28    @Override
29    public BooleanProperty stopProperty() {
30        return stop;
31    }
32 
33    @Override
34    public BooleanProperty pauseProperty() {
35        return pause;
36    }
37}
38

Und das funktioniert wirklich?

Ja.

Es ist sicherlich noch einiges zu tun, aber zumindest hat der derzeitige Stand der Tools für José Perada und mich gereicht, um das JavaFX-Spiel 2048FX von Bruno Borges fit zu machen für Google Play (Android) und den Apple Store (iOS).

Die in den App Stores veröffentlichte Version liegt quelloffen bei Github .

    

Beitrag teilen

Gefällt mir

0

//

Weitere Artikel in diesem Themenbereich

Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.

//

Gemeinsam bessere Projekte umsetzen

Wir helfen Deinem Unternehmen

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.