1. Overview

When you develop a JavaFX Application, the result of the Java compile process is Java Bytecode.

In order to execute this Bytecode, you need a Java Runtime Environment containing the Java Class Libraries (e.g. java.lang.String) and the native libraries used by the runtime. This is shown in the picture below:

JRE

The parts in red are specific for a specific Operating System. The class libraries are common accross different Operating systems. This explains why there are different JRE distributions for e.g. Windows, MacOS and Linux.

This concept requires the installation of the JRE on top of an Operating System. In the typical appstore model, this is not possible. An application needs to be self-contained, and must be packaged in a specific way. This makes the situation more complicated:

  1. We need OS-specific implementations of the execution engine and the native libraries

  2. We need a mechanism to bundle the application AND (parts of) the JRE in a single package

The situation between the iOS implementation and the Android implementation is a bit different. For the iOS port, the JRE needs to be packaged completely inside a bundle. On Android, we leverage the Dalvik VM, which is relative similar to the Java VM.

1.1. Android

On Android, the situation is as follows:

The Android SDK, distributed by Google, contains tools for bundling applications, resources and libraries into an Android package (APK).

In order to facilitate this process, the jfxmobile Gradle plugin which is discussed in the Getting Started section creates a number of tasks that leverage the Android tools for creating or installing the APK. The jfxmobile plugin will make sure your JavaFX Application is bundled with the latest JavaFX runtime environment for Android.

This is shown below:

apk

1.2. iOS

On iOS, we are leveraging the RoboVM Compiler to translate the Java code into native iOS code, linking the required runtime libraries with the application. As RoboVM is using the same runtime classes as Android, the same APIs that work on Dalvik are also working on iOS. At this moment, this means that most of the Java 7 SE APIs are available, and a few Java 8 APIs are supported as well.

2. Getting Started

The easiest way to get started, is to use the Gradle build system for writing your applications. We provide a Gradle plugin, named jfxmobile-plugin, that does almost all the work. Including this plugin in your regular JavaFX application will automatically create a number of tasks for you, that will package your application as a native iOS or a native Android package. A great example is the JavaFX Ensemble demo, created by the Oracle JavaFX team. You can checkout this example here. The gradle build-file in this demo is very simple, and you can adapt it to your own application:

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath 'org.javafxports:jfxmobile-plugin:1.3.10'
    }
}

apply plugin: 'org.javafxports.jfxmobile'

mainClassName = 'ensemble.EnsembleApp'

repositories {
    jcenter()
}

jfxmobile {
    ios {
        forceLinkClasses = ['ensemble.**.*']
    }
    android {
        applicationPackage = 'org.javafxports.ensemble'
    }
}

Once you have applied the jfxmobile plugin, you can use the following tasks:

  • ./gradlew android will create an Android package signed with a debug keystore

  • ./gradlew androidRelease will create an Android package signed with the configured signingConfig

  • ./gradlew androidInstall installs your Android application on an Android device that is connected to your development system via a USB cable

  • ./gradlew launchIOSDevice launches your application on an iOS device that is connected to your development system

  • ./gradlew launchIPadSimulator launces your application in an iPad simulator

  • ./gradlew launchIPhoneSimulator launches your application in an iPhone simulator

  • ./gradlew createIpa creates an iOS IPA package

  • ./gradlew run will launch your application on your development system

  • ./gradlew runEmbedded will launch your application on an embedded device

2.1. Prerequisites

2.1.1. General

  1. The latest version of JDK 8, available from http://www.oracle.com/technetwork/java/javase/downloads/index.html

  2. Gradle 2.2 or higher is required to build applications with the jfxmobile plugin

2.1.2. iOS

  1. A Mac with MacOS X 10.11.5 or superior

  2. Xcode 8.x or superior, available from the Mac App Store

2.1.3. Android

  1. The Android SDK, available here.

  2. From the Android SDK Manager, install at least version 23.0.1 of the Build-tools, the SDK Platform for API 21 and from Extras the Android Support Repository. Getting started with the Android SDK Manager is explained here.

  3. Finally, you have to let the jfxmobile plugin know where to look for the Android SDK installation directory using one of the following ways:

    • an androidSdk property defined under jfxmobile.android in build.gradle

    • a gradle property with the name ANDROID_HOME: defined in ~/.gradle/gradle.properties or by passing -PANDROID_HOME to the gradle build

    • a system environment variable with the name ANDROID_HOME

The jfxmobile plugin will first try to look if an androidSdk property has been set. If not, it will look for the ANDROID_HOME gradle property and finally resort to the ANDROID_HOME system environment variable.

2.1.4. Embedded

  1. The latest version of JDK 8 installed on your embedded device, available from http://www.oracle.com/technetwork/java/javase/downloads/index.html

  2. The latest version of the JavaFX Embedded SDK port, available from http://gluonhq.com/open-source/javafxports/downloads. Unzip the downloaded JavaFX Embedded SDK and copy the following files into the JDK 8 installation directory:

armv6hf-sdk/rt/lib/ext/jfxrt.jar

jre/lib/ext/

armv6hf-sdk/rt/lib/arm/*

jre/lib/arm/

armv6hf-sdk/rt/lib/javafx.platform.properties

jre/lib/

armv6hf-sdk/rt/lib/javafx.properties

jre/lib/

armv6hf-sdk/rt/lib/jfxswt.jar

jre/lib/

2.2. How it works

The jfxmobile plugin adds a number of tasks to your Java Application that allow you to create packages that can be uploaded to the Apple AppStore and the Android Play Store. You can also execute your applications on the devices, in order to test them. The jfxmobile plugin will download and install the JavaFX SDKs for iOS and Android. The source code for those SDKs is available here. Zipped versions of the SDKs are uploaded to maven central, and downloaded by the jfxmobile plugin. In order to create an Android application, the Android SDK is needed. You download and install the Android SDK as described above. The location where you install the Android SDK has to be supplied to the plugin as explained before. The plugin will then execute a number of commands that will lead to the creation of an Android package (apk) in the directory build/javafxports/android. On iOS, the situation is internally different — but the gradle commands are similar. The plugin will download and install the RoboVM compiler, and it will use RoboVM compiler commands to create an iOS application in build/javafxports/ios.

2.3. The code

In case you’re interested in the source code for the jfxmobile plugin, you can check it out here

3. Setting Up

This page is a guide to setting up a JavaFX application with gradle. Using gradle means we can make use of its convention over configuration paradigm. This allows us to have very simple build scripts, if you follow the conventions when setting up your project.

3.1. Structure

By convention, the project directory structure should be as follows:

Table 1. PLATFORM INDEPENDENT

src/main/java

Common Java source

src/main/resources

Common resources

Java code and resources contained in these directories will be shared across all supported platforms. If you want to write code for a specific platform, you will need to add extra directories for them. The jfxmobile plugin will automatically provide the correct classpath dependencies for each different platform, when you write code in the designated platform directory. Below is a listing of the directories that are picked up by the jfxmobile plugin by default.

Table 2. ANDROID

src/android/java

Android Java source

src/android/resources

Android resources

src/android/assets

Android assets

src/android/jniLibs

Android native libraries

Table 3. IOS

src/ios/java

iOS Java source

src/ios/resources

iOS resources

src/ios/assets

iOS assets

src/ios/jniLibs

iOS native libraries

src/ios/frameworks

third-party iOS frameworks

Table 4. DESKTOP

src/desktop/java

Desktop Java source

src/desktop/resources

Desktop resources

Table 5. EMBEDDED

src/embedded/java

Embedded Java source

src/embedded/resources

Embedded resources

The difference between assets and resources is that the files that are included in src/…/resources are automatically added to the classpath of the application, while assets are added as platform specific resources. On Android, assets are the same as the regular Android assets resources. On iOS, assets are the same as iOS resource files.

3.2. build.gradle

To build a gradle project, you need a build.gradle script. The build.gradle file should be created at the root of your project structure. To apply the jfxmobile plugin to your gradle project, add the following lines at the top of the script:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'org.javafxports:jfxmobile-plugin:1.3.10'
    }
}

apply plugin: 'org.javafxports.jfxmobile'

repositories {
    jcenter()
}

The next required step is to specify your main class name. This is the class that extends the JavaFX Application object. The name of the property is mainClassName:

mainClassName = 'com.example.myproject.MyApplication'

For the Android and Desktop platforms you are now good to go. If you also want to run on iOS, there is one final required configuration to set:

jfxmobile {
    ios {
        forceLinkClasses = [ 'com.example.myproject.**.*' ]
    }
}

This is required because the iOS port of JavaFX will load the main class at runtime. Therefor it is not visible by default when calling the RoboVM compiler. The forceLinkClasses property ensures that those classes are linked in during RoboVM compilation.

3.3. JavaFX Application

As the last step we need to create the actual JavaFX application main class. Below shows the code that should be included as a bare minimum for the application to behave correctly.

package com.example.myproject;

import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Screen;
import javafx.stage.Stage;

public class MyApplication extends Application {
    @Override
    public void start(Stage stage) {
        Rectangle2D bounds = Screen.getPrimary().getVisualBounds();
        Scene scene = new Scene(new StackPane(new Label("Hello World!")),
                bounds.getWidth(), bounds.getHeight());
        stage.setScene(scene);
        stage.show();
    }
}

The width and height of the Scene should be set to the width and height of the visual bounds of the device’s screen to ensure that the application is properly sized when starting it.

3.4. Building and running

Finally we can build the application and run it on our platforms. To run a gradle build, just type gradle followed by the desired task name, e.g. gradle build. Run gradle tasks to get an overview of the gradle tasks that are available in your project. The jfxmobile plugin will add the following platform specific tasks to your project:

3.4.1. Desktop

  • run will launch the application on your desktop environment

3.4.2. Embedded

  • runEmbedded will launch the application on your embedded device, by running a remote ssh command

3.4.3. Android

  • android generates an apk that is signed with a debug keystore and put it in the directorybuild/javafxports/android

  • androidRelease generates an apk that is signed with the configured signingConfig and put it in the directorybuild/javafxports/android

  • androidInstall installs the generated debug apk onto a device that is connected to your desktop

3.4.4. iOS

  • ios generates the ipa in the directory build/javafxports/ios

  • launchIOSDevice launches the application on the device that is connected to your desktop

  • launchIPhoneSimulator launches the application on an iPhone simulator

  • launchIPadSimulator launches the application on an iPad simulator

Running on an iOS Device

If you want to distribute your app via the Apple AppStore, you’ll need to enroll in the Apple Developer Program. See the Apple documentation to find out how it works. If you only want to run on your own device you could be able to use the free provisioning.

Free Provisioning

For more information about free provisioning, see Free Provisioning in the RoboVM documentation.

After following the steps in that documentation:

  • Make sure your Bundle ID of your Xcode app, matches the value of the CFBundleIdentifier in your Info.plist (see Configuration on how to include a custom Info.plist file)

  • Make sure to specify the name of the provisioning profile Xcode created for you in the property iosProvisioningProfile in your build.gradle.

  • Run ./gradlew launchIOSDevice

You can use Xcode → Preferences → Accounts → View details to see the names of available provisioning profiles.

Development deployment

If you are enrolled into the Apple Developer Program but have never deployed an App to a device, you can follow these steps:

  • Open Xcode and go to Preferences → Accounts

  • Add your Apple ID that was used to enroll in the Developer Program

  • Then (still in Xcode) choose File → New project and create a simple app. You can choose from some templates. e.g. Single View Application

  • Connect your device and try to run your simple app

  • Xcode will suggest to create certificates and an iOS Development provisioning profile (usually with a wildcard * Bundle ID).

Once you got the sample app deployed on your device from Xcode, you can switch to your JavaFXPorts app and launch it on your device:

  • ./gradlew launchIOSDevice

If you’re still having trouble, try this:

  • Open a terminal and run: security find-identity -v -p codesigning

  • Copy/paste the name of the certificate you want to use (the value between quotes) in the property iosSignIdentity of your build.gradle. For development, the certificate usually is named "iPhone Developer: your name (some ID)".

  • Open Xcode → Preferences → Accounts → View details and look under "Provisioning Profiles". The default development profile is usually called "iOS Development". If you need to use another provisioning profile, specify it using the property iosProvisioningProfile in your build.gradle.

4. Configuration

4.1. Dependency Configurations

4.1.1. Platform Dependencies

Apart from the default dependency configurations compile and runtime, the jfxmobile plugin adds extra configurations for each supported platform. This allows developers to add dependencies that should only be applied to a specific platform. The names of the platform specific configurations are platformCompile and platformRuntime where platform can be one of the following: android, ios, desktop or embedded. The platform specific compile and runtime configurations extend from the default compile and runtime configuration respectively.

For instance, if your android code wants to do some json processing, you configure the dependencies as follows:

dependencies {
    androidCompile 'org.glassfish:javax.json:1.0.4'
}

The dependency declared above will make sure the json library is only included when targetting the Android platform, e.g. when creating an APK or when installing it on an Android device. In other words, it won’t be part of an iOS build or when running the application directly on your desktop.

4.1.2. Retrolambda Dependencies

Retrolambda is a tool that converts classes that were compiled with Java 8 as the target into bytecode that can be run on a Java 6 runtime. Retrolambda is required for any Java code that needs to run on an Android device. That is because Android platforms before API 19 only support Java 6, while Java 7 is supported by Android platforms starting from API 19. More information about retrolambda can be read here.

When creating the Android APK of your application, the jfxmobile plugin will apply retrolambda to all compiled classes and to all classes from the dependencies that are found in the androidRuntime configuration. In short this applies to all libraries that are declared in either the compile, runtime, androidCompile or androidRuntime configurations. However, in some cases, applying retrolambda to a library that for instance has already been processed with retrolambda itself, can result in the following exception when running the application on an Android device.

Caused by: java.lang.IncompatibleClassChangeError: The method 'java.lang.Object com.airhacks.afterburner.views.FXMLView.lambda$loadSynchronously$2(java.lang.Class)' *was expected to be of type direct but instead was found to be of type virtual* (declaration of 'com.airhacks.afterburner.views.FXMLView' appears in /data/app/com.gluonhq.otn-1/base.apk)

In that case, you can use the compileNoRetrolambda or runtimeNoRetrolambda configurations to exclude the library from the retrolambda process. For instance, if you don’t want to apply retrolambda to the afterburner library, you can configure it with the following code:

dependencies {
    compile 'com.gluonhq:charm:4.3.5'
    compileNoRetrolambda 'com.airhacks:afterburner.mfx:1.6.2'
    androidRuntime 'com.gluonhq:charm-down-core-android:3.5.0'
}

In this configuration, all three dependencies will be included in the android application, but retrolambda will only be applied to the two gluon libraries, not to the afterburner library. Note that the afterburner version 1.6.3 can be used now with compile, as it doesn’t apply retrolambda anymore.

4.2. General

Use the jfxmobile gradle extension to further configure JavaFXPorts:

jfxmobile {
    javafxportsVersion = '8.60.9'
}

4.2.1. Properties

property

description

default value

javafxportsVersion

Specifies which version of javafxports to use.

8.60.9

javacEncoding

The character encoding that is used when compiling java sources.

utf-8

4.2.2. Extensions

downConfig

The downConfig extension is a convenience class for configuring the dependencies to Charm Down plugins that are being used in a jfxmobile project. It will take care of adding the correct compile and runtime dependencies for each platform. The following example adds the dependency configuration for two Charm Down plugins, storage and lifecycle, using version 3.5.0:

jfxmobile {
    downConfig {
        version '3.5.0'
        plugins 'storage', 'lifecycle'
    }
}

The above code is the equivalent of adding the dependencies to the two plugins manually in the dependencies section of the build.gradle file, like shown below. Note that it’s still perfectly valid to define those dependencies manually. In case duplicate dependencies were created, the one with the highest version will be the final dependency being used.

dependencies {
    compile 'com.gluonhq:charm-down-core:3.5.0'
    compile 'com.gluonhq:charm-down-plugins-storage:3.5.0'
    compile 'com.gluonhq:charm-down-plugins-lifecycle:3.5.0'

    androidRuntime 'com.gluonhq:charm-down-core-android:3.5.0'
    androidRuntime 'com.gluonhq:charm-down-plugins-storage-android:3.5.0'
    androidRuntime 'com.gluonhq:charm-down-plugins-lifecycle-android:3.5.0'

    iosRuntime 'com.gluonhq:charm-down-core-ios:3.5.0'
    iosRuntime 'com.gluonhq:charm-down-plugins-storage-ios:3.5.0'
    iosRuntime 'com.gluonhq:charm-down-plugins-lifecycle-ios:3.5.0'

    desktopRuntime 'com.gluonhq:charm-down-plugins-storage-desktop:3.5.0'
    desktopRuntime 'com.gluonhq:charm-down-plugins-lifecycle-desktop:3.5.0'
}
Properties

property

description

default value

version

The version to use when configuring the Charm Down dependencies.

3.5.0

Methods

method

description

plugins(String…​plugins)

A list of Charm Down plugins to create the dependencies for.

4.3. Android

Android specific configuration can be done in the android gradle extension within the jfxmobile configuration:

jfxmobile {
    javafxportsVersion = '8.60.9'
    android {
        manifest = 'src/android/AndroidManifest.xml'
        dexOptions {
            javaMaxHeapSize '3g'
        }
        packagingOptions {
            exclude 'META-INF/LICENSE.txt'
            exclude 'META-INF/NOTICE.txt'
        }
    }
}

4.3.1. Properties

property

description

default value

androidSdk

The directory containing the Android SDK.

The ANDROID_HOME gradle property or the system environment variable with the same name.

dalvikSdk

The directory containing the JavaFX port for dalvik.

It will be downloaded from maven central when not specified.

buildToolsVersion

The version of the Android build-tools that should be used.

The plugin will try to look for the highest non-preview version available in the Android SDK.

applicationPackage

The name of the Android package, that uniquely identifies your application.

The package name of your main class name.

manifest

The location to a custom AndroidManifest.xml file to use for the application.

The plugin will generate a default AndroidManifest.xml file. A copy can be found in build/javafxports/tmp/android.

compileSdkVersion

The API version of the Android platform to compile against.

21

minSdkVersion

The minimum API version where the application can run on.

4

targetSdkVersion

The API version that the application targets.

compileSdkVersion

assetsDirectory

The directory that contains the Android assets.

src/android/assets

resDirectory

The directory containing the Android resources.

src/android/res

nativeDirectory

The directory containing the native Android libraries.

src/android/jniLibs

4.3.2. Extensions

dexOptions

The dexOptions extension adds options to configure Android dex processing. It is an extension of the DexOptions class found in the Android build tools.

Properties

property

description

default value

additionalParameters

List of additional parameters to be passed to dex.

[]

javaMaxHeapSize

Specifies the -Xmx value when calling dex. Example value is "2048m".

2g

jumboMode

Enable jumbo mode in dex (--force-jumbo).

false

keepRuntimeAnnotatedClasses

Keep all classes with runtime annotations in the main dex in legacy multidex. Disable this for apps that do not use reflection and need more space in their main dex.

true

packagingOptions

The packagingOptions extension adds options that decide what to do when encountering duplicate files during APK generation. It is based entirely on the PackagingOptions class found in the Android build tools.

Properties

property

description

default value

excludes

The list of excluded paths.

[]

pickFirsts

The list of paths where the first occurrence is packaged in the APK.

[]

Methods

method

description

exclude(String path)

Adds an excluded path.

pickFirst(String path)

Adds a firstPick path. First pick paths do get packaged in the APK, but only the first occurrence gets packaged.

signingConfig

The signingConfig extension is used for signing configuration for the release build. It is based entirely on the SigningConfig class found in the Android build tools.

See Signing Your Applications at the Android developer guide for more information. The only difference with the Android gradle plugin is, that you directly set the configuration instead of a reference to a signing configuration that was defined elsewhere.

The android task will use a debug certificate generated by the plugin. The debug keystore and certificate are stored in $HOME/.android/debug.keystore. The androidRelease tasks requires a signingConfig to be configured.

Properties

property

description

keyAlias

Key alias used when signing.

keyPassword

Key password used when signing.

storeFile

Store file used when signing.

storePassword

Store password used when signing.

storeType

Store type used when signing.

4.4. iOS

iOS specific configuration can be done in the ios gradle extension within the jfxmobile configuration:

jfxmobile {
    javafxportsVersion = '8.60.9'
    ios {
        forceLinkClasses = [ 'ensemble.**.*' ]
        infoPList = file('src/ios/Info.plist')
    }
}

property

description

default

iosSdk

The directory containing the JavaFX port for ios.

It will be downloaded from maven central when not specified.

robovmVersion

The version of the RoboVM compiler to use.

2.3.1

forceLinkClasses

A list of string patterns for classes and/or complete packages that should be linked when starting the RoboVM compiler.

[]

frameworks

A list of string for iOS frameworks that should be added to the list of frameworks that are already included by default (which are: UIKit, OpenGLES, QuartzCore, CoreGraphics, CoreText, ImageIO, MobileCoreServices, CoreBluetooth, CoreLocation, CoreMedia, CoreMotion, AVFoundation, AudioToolbox, MediaPlayer, UserNotifications, AVKit and StoreKit).

[]

infoPList

A File that specifies a custom Info.plist file to use for the application.

The plugin will generate a default Default-Info.plist file. A copy can be found in build/javafxports/tmp/ios.

propertiesFile

The path to a RoboVM properties file which contains info for the application.

robovm.properties and robovm.local.properties

configFile

The path to a RoboVM configuration file which configures the RoboVM compiler.

robovm.xml

os

The operating system to use when running the application. Can be any of the following values: ios, macosx, linux.

ios

arch

The architecture to use when running the application. Can be any of the following values: x86, x86_64, thumbv7, arm64.

arm64

iosSkipSigning

A boolean specifying whether signing of the application should be skipped or not.

false

iosSignIdentity

The name of the identity to sign with when building an iOS bundle for the application.

Default is to look for an identity starting with ‘iPhone Developer’ or ‘iOS Development’.

iosProvisioningProfile

The name of the provisioning profile to use when building for device.

debug

A boolean specifying whether the application should be launched in debug mode or not. The application will suspend before the main method is called and will wait for a debugger to connect.

false

debugPort

An integer specifying the port to listen for debugger connections on when launching in debug mode.

If not set a default port will be used. The port that is actually used, will be written to the console before the app is launched.

ipaArchs

A list of architectures to include in the IPA. Either thumbv7 or arm64 or both.

thumbv7, arm64

apsEnvironment

The value for the aps-environment key in the Entitlements.plist file. Valid values are development and production.

assetsDirectory

The directory that contains the iOS resource files.

src/ios/assets

nativeDirectory

The directory containing the native iOS libraries.

src/ios/jniLibs

A lot of the configuration properties for iOS can be directly overruled using gradle properties. For instance, instead of specifying the debug in the build.gradle file, you can run gradle as follows to enable debugging: gradle -Probovm.debug=true -Probovm.debugPort=9000 launchIPhoneSimulator. Below follows a list of properties that can be overruled by which gradle property:

configuration property

gradle property

os

robovm.os

arch

robovm.arch

iosSkipSigning

robovm.iosSkipSigning

iosSignIdentity

robovm.iosSignIdentity

iosProvisioingProfile

robovm.iosProvisioningProfile

debug

robovm.debug

debugPort

robovm.debugPort

ipaArchs

robovm.ipaArchs

apsEnvironment

jfxmobile.ios.apsEnvironment

Finally, two more gradle properties can be provided when launching the iOS simulator to specify which device name and sdk version the simulator should run.

gradle property

description

robovm.device.name

The name of the device to use in the iOS simulator. For instance: iPhone-6s, iPhone-7 or iPad-2.

robovm.sdk.version

The iOS sdk version to use in the iOS simulator. 8.4, 9.3 or 10.3.

To get a list of possible device names and matching sdk versions, you can open Xcode, Window→Devices, and see a list of possible simulators on the left, or click on the plus icon to add a new simulator, and see the list of available devices and simulator SDKs (already available or to be installed).

4.5. Embedded

If you want to run your application on an embedded device, you need to configure a remotePlatform in the embedded extension within the jfxmobile extension:

jfxmobile {
    javafxportsVersion = '8.60.9'
    embedded {
        remotePlatforms {
            raspberry {
                host = '192.168.1.10'
                username = 'pi'
                password = 'raspberry'
                workingDir = '/home/pi/sample'
                jreLocation = '/opt/java'
                execPrefix = 'sudo'
            }
        }
    }
}

property

description

default

host

The ip address of the embedded device. It must be reachable from your development environment.

port

The port that is being used by the ssh server on the embedded device.

22

username

The username to use when connecting to the embedded device.

password

The password of the user that is used when connecting to the embedded device.

keyfile

A keyfile that is being used for connecting to the embedded device. This property will be ignored when a password has been provided.

passphrase

The passphrase for the configured keyfile. This property will be ignored when a password has been provided.

jreLocation

The installation location of JDK 8 for the embedded device.

execPrefix

This string will be prepended to the java command, e.g. sudo

5. Examples

A few examples can be found here. We will add more examples when time permits.

You can clone the project, and all the samples will be included as subprojects. Open the build.gradle file and update the plugin to the latest version (find it here):

classpath 'org.javafxports:jfxmobile-plugin:1.3.10'

You can build the whole project using:

./gradlew clean build

5.1. HelloWorld

This is a very simple application that can be executed on Desktop, and both on iOS and on Android. We start with a very simple example containing a single class, showing a Button and a Label in a JavaFX StackPane.

The source code is in src/main/java

The JavaFX code for the class is shown below and should be placed in src/main/java/org/javafxports/helloworld/Main.java.

package org.javafxports.helloworld;

import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Screen;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
        double width = visualBounds.getWidth();
        double height = visualBounds.getHeight();

        Label label = new Label("Click the button.");
        label.setTranslateY(30);

        Button button = new Button("Hello JavaFXPorts");
        button.setOnAction(e -> label.setText("You clicked the button!"));

        Rectangle rectangle = new Rectangle(width - 20, height - 20);
        rectangle.setFill(Color.LIGHTBLUE);
        rectangle.setArcHeight(6);
        rectangle.setArcWidth(6);

        StackPane stackPane = new StackPane();
        stackPane.getChildren().addAll(rectangle, button, label);

        Scene scene = new Scene(stackPane, visualBounds.getWidth(), visualBounds.getHeight());

        stage.setScene(scene);
        stage.show();
    }
}

You can paste this in your favourite IDE, or you can use a text editor.

5.1.1. Desktop version

Running it on a desktop is easily done from command line as follows:

./gradlew HelloWorld:run

This will show a user interface with a button and a label. Clicking on the button will change the text in the label.

5.1.2. Android version

The Android version does not require any new code. Before we start, make sure you have the mentioned prerequisites for Android.

Plug your device and run:

./gradlew HelloWorld:androidInstall

If everything is in place, you will see all the tasks performed before the apk is installed successfully on your device:

:HelloWorld:compileJava UP-TO-DATE
:HelloWorld:compileRetrolambdaMain UP-TO-DATE
:HelloWorld:processResources UP-TO-DATE
:HelloWorld:classes UP-TO-DATE
:HelloWorld:compileAndroidJava UP-TO-DATE
:HelloWorld:compileRetrolambdaAndroid SKIPPED
:HelloWorld:compileTestJava UP-TO-DATE
:HelloWorld:compileRetrolambdaTest SKIPPED
:HelloWorld:compileRetrolambda UP-TO-DATE
:HelloWorld:mergeClassesIntoJar
:HelloWorld:validateManifest
:HelloWorld:collectMultiDexComponents
:HelloWorld:shrinkMultiDexComponents
:HelloWorld:createMainDexList
:HelloWorld:dex
:HelloWorld:mergeAndroidAssets
:HelloWorld:mergeAndroidResources
:HelloWorld:processAndroidResources UP-TO-DATE
:HelloWorld:processAndroidResourcesDebug
:HelloWorld:validateSigningDebug
:HelloWorld:apkDebug
:HelloWorld:zipalignDebug
:HelloWorld:androidInstall
Installed on device.

BUILD SUCCESSFUL

Total time: 51.342 secs

Now on your device you will find a new app, named HelloWorld.

Hello World app on Android

5.1.3. iOS version

If you have the mentioned prerequisites for iOS, you will be able to run the app on the simulator or deploy it to an iOS device.

Running the application in the iOS emulator is done as follows:

./gradlew HelloWorld:launchIPhoneSimulator

Again, if everything is in place, you should see something like this:

Hello World app on iOS Simulator

Note the black bordes on top and bottom. This has to do with some assets, like default launch images, that have to be provided. These should be placed in src/ios/assets/.

Check Running on iOS devices to find out about details on the Apple Developer Program. Once you have a valid provisioning profile, you will be able to deploy the application on your iPhone or iPad:

./gradlew HelloWorld:launchIOSDevice

If everything is in place, you should see something like this:

Hello World app on iPad

5.2. Other samples

The rest of the samples on the project are:

  • HelloWorldFXML. This is the most simple JavaFX Application, using FXML.

  • HelloPreloader. This is the most simple JavaFX Application, using a custom Preloader.

  • HelloPlatform. A gradle project that shows how to build and run platform specific code on Android, iOS and desktop using the java.util.ServiceLoader.

  • J3D. Simple example showing a 3D sphere in JavaFX

  • Kokos. Kokos is a sample showing how to use JavaFX code in an Android project, created with Android studio.

  • WebDemo. Simple demo using the JavaFX WebView

5.3. Questions

Questions, remarks, comments? Take a look at the support options provided by Gluon.

6. External Resources