Gluon Documentation JavaFX
Gluon Documentation JavaFX
Gluon Documentation
Last Updated: 2023-09-20 17:58:36 UTC
https://docs.gluonhq.com/#_introduction 1/191
30/09/2023, 18:48 Gluon Documentation
Table of Contents
1. Introduction
2. Getting Started
3. IDE Support
4. GluonFX plugin for Maven
5. Platforms
6. User Interface (UI)
7. Device Interface
8. Data Binding
9. CloudLink
10. Samples
11. Scene Builder
12. Conclusion
https://docs.gluonhq.com/#_introduction 2/191
30/09/2023, 18:48 Gluon Documentation
1. Introduction
Gluon provides an easy and modern approach for developing Java Client applications. These applications can run on the JVM or
can be converted to a platform specific native-images which have lighting fast startup and takes a fraction of space. Moreover,
applications can also be targeted to Android, iOS, and embedded apart from all the desktop environments.
Gluon provides all the tools necessary to build these applications including, but not limited to, build tools, IDE plugins, UI library,
cloud connectivity, data-binding etc.
https://docs.gluonhq.com/#_introduction 3/191
30/09/2023, 18:48 Gluon Documentation
2. Getting Started
Java application as native application
Any Java application can be converted to a native application for a specific platform using Gluon technology. This platform
specific application has much faster startup time, since the JVM no longer needs to be started. The resulting application will be
entirely integrated into the native operating system.
An easy way to get started is just by adding the GluonFX plugin to your Java application. GluonFX plugin leverages GraalVM
(https://www.graalvm.org) and OpenJDK (https://openjdk.java.net) by compiling the Java client application and all its required
dependencies into native code, so that it can be directly executed as a native application on the target platform.
At this moment, Gluon has support for the following target platforms and architectures:
In a similar way, Java libraries can be converted to native shared libraries, providing these are pure Java projects (no UI/JavaFX
involved), that can be used by third party projects. Currently, Gluon has support for the following target platforms and
architectures:
2.1. Requirements
Gluon applications can be developed, run, and tested on any desktop and embedded platform using JDK 11 or greater.
The platform specific requirements for the creation and deployment of native images are discussed in depth in the platforms
section.
Name, groupId and artifactId to use for the generated Maven project
JavaFX version and modules required by the project
Gluon Mobile stack to include in the project. For example, Glisten (for the UI toolkit) and Gluon Maps can be selected to be
used in the same project
Gluon Attach services required in the project
If the application needs a flexible and secure way to connect to an existing or new backend or cloud service, Gluon CloudLink
can be selected as well
All options are easily selectable and Gluon Start will generate the project with correct dependencies for you.
Unzip the project and run it via the terminal. Or, import it directly into your favorite IDE.
You can read more about the IDE plugins in the IDE Support section of the documentation.
https://docs.gluonhq.com/#_introduction 4/191
30/09/2023, 18:48 Gluon Documentation
You can still use other IDEs to develop your Gluon application, projects can be created from Gluon Start and
directly opened in your favorite IDE.
For example:
SHELL SCRIPT
mvn archetype:generate \
-DarchetypeGroupId=com.gluonhq \
-DarchetypeArtifactId=gluonfx-archetype-mobile \
-DarchetypeVersion=0.0.3 \
-DgroupId=com.gluonhq \
-DartifactId=gluon-mobile-sample \
-Dversion=1.0.0-SNAPSHOT \
-Djavafx-version=15
After you have created the project or downloaded an existing one, in order to include your license, you need to add a file called
gluonmobile.license to your resources and paste your valid license key as the content:
src/main/resources/gluonmobile.license
TEXT
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
This method allows you to keep your license private as long as you exclude it from your source version control system.
If for some reason the license service can’t be contacted, your end-users won’t be annoyed by the popup, but the license check will
be retried each time the application starts until successful.
The template can be downloaded from here (https://gluonhq.com/download/intellij-idea-live-templates/). Once the file has been
downloaded, simply do the following steps to import them into your IntelliJ IDEA:
Once the IDE has been restarted, from within your editor, you may simply type ‘fxprop‘, and a popup lets you choose the type of
property you want. Once you press tab (or enter), the code for property is generated inside the editor. You can then immediately
start typing the property name, and this will automatically update all the method names. Once you’ve done this, all you need to
do is import the relevant classes.
For a complete list of changes, please check Substrate releases (https://github.com/gluonhq/substrate/releases), GluonFX Maven plugin
releases (https://github.com/gluonhq/gluonfx-maven-plugin/releases/) and GluonFX Gradle plugin releases
(https://github.com/gluonhq/gluonfx-gradle-plugin/releases/).
Release: 1.0.21
https://docs.gluonhq.com/#_introduction 5/191
30/09/2023, 18:48 Gluon Documentation
Major changes
Release: 1.0.19
Major changes
Release: 1.0.18
Major changes
JavaFX 20 is released. Note that starting with JavaFX 20, JDK 17+ is required
Bump JavaFX static version to 21-ea+9.1
Android SDK/NDK are installed from latest Android SDK manager
Release: 1.0.17
Major changes
Bump JavaFX version to 21-ea+5. Note that starting with JavaFX 20, JDK 17+ is required
Maven plugin: Maven runtime 3.9.0 is not supported yet (an error will be thrown asking to downgrade to 3.8.8 or lower, in that
case)
Maven plugin: new goal allows building static libraries for iOS, via gluonfx:staticlib
Release: 1.0.16
Major changes
Bump JavaFX version to 20-ea+7. Note that starting with JavaFX 20, JDK 17+ is required
iOS simulator: default to iPhone 14
Android: Use of Android API level 31, added support for long press gestures
Release Attach 4.0.16
Bug fixes
Release: 1.0.15
Major changes
https://docs.gluonhq.com/#_introduction 6/191
30/09/2023, 18:48 Gluon Documentation
Added support for shared libraries, via the new gluonfx:sharedlib goal
Android: Added support of Android NDK 23+
Release Attach 4.0.15
Bug fixes
Release: 1.0.14
Major changes
Released Gluon’s GraalVM builds 22.1.0.1 for JDK 11 and JDK 17, with support for Apple Silicon chip
Android fixes: the temp dir folder issue with JDK 17, and the black screen after resuming the app and changing orientation
have been fixed
Bump JavaFX version to 19-ea+8
Add support for Attach' StoreReview service.
Bug fixes
Release: 1.0.13
Major changes
Add support for Apple Silicon (MACOS_AARCH64 profile). In order to run GraalVM for macOS AArch64, a recent GraalVM dev
build (https://github.com/graalvm/graalvm-ce-dev-builds/releases/) is needed.
Add linkerArgs option to configuration, allowing custom linker arguments
Android: Allow predictive text and swipe text
Bump JavaFX version to 19-ea+4
Bump clibs version to 27
Bug fixes
Release: 1.0.12
Major changes
Release: 1.0.11
Major changes
Add Windows package support: .exe and .msi bundles can be created
Improve MacOS package support: .dmg bundles can be created
Update ReleaseConfiguration (Maven only)
Improved support for JDK17
Allow building for iOS without LLVM backend
Fix the filter for the native agent on Windows
https://docs.gluonhq.com/#_introduction 7/191
30/09/2023, 18:48 Gluon Documentation
Release: 1.0.10
Major changes
Release: 1.0.9
Major changes
Release: 1.0.8
Major changes
https://docs.gluonhq.com/#_introduction 8/191
30/09/2023, 18:48 Gluon Documentation
3. IDE Support
The ideal way to create a Gluon application is via Gluon Start and importing it directly into your favorite IDE.
Gluon also provides basic IDE support via plugins for IntelliJ IDEA and Netbeans. These plugins can be used to create a basic
Gluon project, with all the required dependencies to natively build the project, and ultimately run the native image.
We will briefly discuss on how to install these plugins, create a new project and build a native image using GluonFX plugin in the
following section.
Now click Marketplace , type Gluon , select the result and click Install .
The Gluon Plugin will be downloaded and installed. Then press Restart IDE or simply press OK to close the plugins dialog, and
restart the IDE when asked.
In IntelliJ IDEA, click File → New → Project…and select Gluon on the left, and one of the available projects on the right. For
instance, Gluon Mobile - Single View Project . Press Next .
https://docs.gluonhq.com/#_introduction 9/191
30/09/2023, 18:48 Gluon Documentation
The first time you use the plugin, you will be asked to enter your email address.
If you already have a Gluon Mobile key for your projects, you can insert it here as well, so it will be added by default to your new
projects. If you don’t, you will be using the free (trial) version. Please find more about Gluon Mobile licenses
(http://gluonhq.com/products/mobile/buy/).
https://docs.gluonhq.com/#_introduction 10/191
30/09/2023, 18:48 Gluon Documentation
You can access these settings later on from File→Settings→Gluon (or →Gluon ):
IntelliJ IDEA→Preferences…
Type the package name and the main class name. Select the platforms to deploy the application, and the build tool of your choice.
For this tutorial, we will use the Maven build tool. Press Next .
https://docs.gluonhq.com/#_introduction 11/191
30/09/2023, 18:48 Gluon Documentation
From the list, select a valid Java JDK (11+) and press Next .
Now add a name and a location for the project and press Finish .
https://docs.gluonhq.com/#_introduction 12/191
30/09/2023, 18:48 Gluon Documentation
The Maven project has a dependency on the OpenJFX Maven Plugin and the GluonFX Maven plugin to the project.
These plugins add a series of goals and to access them we just need to open Maven tool window in IntelliJ IDEA. The Maven tool
window shows all the available Maven plugins along with their respective goals.
https://docs.gluonhq.com/#_introduction 13/191
30/09/2023, 18:48 Gluon Documentation
Before creating a native image, it’s easier to run the application first and verify that there are no errors.
Select Plugins → javafx → javafx:run from the Maven tool window. Verify that all the tasks are executed without errors, and
the project runs fine on your desktop. Alternatively you can open the terminal ( View→Tool Windows→Terminal ) and run mvn
javafx:run .
Now let’s make a slight change to the code. In the BasicView class, update the text of the label on line 20 to the following:
JAVA
button.setOnAction(e -> label.setText("Hello from IntelliJ IDEA!"));
Run it again to see that the new message shows up on your desktop when you click the button.
Make sure you set the environment variable GRAALVM_HOME . Alternatively, you can add path to GraalVM
installation directory by adding graalvmHome to the gluonfx-maven-plugin configuration.
If you are running on Windows, you need to run all the gluonfx goals from an x64 terminal.
If you are running from IDE, make sure that the mvn executable under
path/to/IntelliJ/plugins/maven/lib/maven3/bin/ has exec permissions, or select a custom Maven
installation by setting the Maven home directory from the Maven tool window, Maven Settings→Maven .
GluonFX plugin provides us various goals which are explained in detail earlier in the documentation. For this tutorial, we will be
using the gluonfx:build goal to create a native image of the application.
https://docs.gluonhq.com/#_introduction 14/191
30/09/2023, 18:48 Gluon Documentation
Execute mvn gluonfx:build from the terminal, or, select Plugins → gluonfx → gluonfx:build goal from the Maven tool
window.
This goal typically takes a couple of minutes to complete and may vary depending on the system. Once the goal is executed
successfully, the native image can be run by executing gluonfx:nativerun goal.
Go to Maven tool window, expand Profiles and check android . Make sure that all other profiles are unchecked. This will
activate the pre-existing android profile.
Run mvn -Pandroid gluonfx:build from the terminal, or alternatively, execute the gluonfx:build goal from the Maven
plugins section.
Once the native image is created, we need to package it into an apk before we can install it on a physical Android device.
Execute mvn -Pandroid gluonfx:package to create an apk. Once the goal is executed successfully, connect a physical device and
install the native image by executing the mvn -Pandroid gluonfx:install goal.
When the installation ends successfully, run mvn -Pandroid gluonfx:nativerun or find the application on your device and
open it up:
Now we are ready for deploying the same application on an iOS device.
Go to Maven tool window, expand Profiles and check ios . Make sure that all other profiles are unchecked. This will activate
the pre-existing ios profile. All gluonfx goals will now target iOS platform.
https://docs.gluonhq.com/#_introduction 15/191
30/09/2023, 18:48 Gluon Documentation
Run mvn -Pios gluonfx:build from the terminal, or alternatively, execute the gluonfx:build goal from the Maven plugins
section.
Once the goal is executed successfully, connect a physical device and run the native image on it by executing mvn -Pios
gluonfx:nativerun .
3.2. NetBeans
In this section, we’ll explain briefly how to install the Gluon plugin on Apache NetBeans and how to use it to create a sample
application that can be deployed on desktop, Android and iOS devices. Before we start, make sure to check the Platforms section
for a list of prerequisites for each platform.
https://docs.gluonhq.com/#_introduction 16/191
30/09/2023, 18:48 Gluon Documentation
Accept the license and click Install . Click Continue when prompted:
https://docs.gluonhq.com/#_introduction 17/191
30/09/2023, 18:48 Gluon Documentation
You will find the plugin under the Installed tab in the Plugins window.
https://docs.gluonhq.com/#_introduction 18/191
30/09/2023, 18:48 Gluon Documentation
In NetBeans, click File → New → Project…and select Gluon on the left, and one of the available projects on the right. For
instance, Gluon Mobile - Single View Project . Press Next .
The first time you use the plugin, you will be asked to enter your email address.
If you already have a Gluon Mobile license key for your projects, you can insert them here as well, so they will be added by
default to your new projects. If you don’t, you will be using the free (trial) version. Please find more about Gluon Mobile licenses
(http://gluonhq.com/products/mobile/buy/).
https://docs.gluonhq.com/#_introduction 19/191
30/09/2023, 18:48 Gluon Documentation
You can access these settings later on from Tools→Options→Miscellaneous→Gluon (or NetBeans→Preferences…
→Miscellaneous→Gluon ):
Type the name of the project, find a proper location, add the package name and change the main class name if required. Select
the platforms to deploy the application, and the build tool of your choice. For this tutorial, we will use the Maven build tool.
https://docs.gluonhq.com/#_introduction 20/191
30/09/2023, 18:48 Gluon Documentation
You will notice that a Maven project has been created with the pom containing profiles for the platforms you selected. These
profiles make it easier to create native images targeted to each of these platforms.
The Maven project has a dependency on the OpenJFX Maven Plugin and the GluonFX Maven plugin to the project.
These plugins add a series of goals and to access them we just need to switch to the Navigator panel in NetBeans. The Navigator
panel shows all the available Maven goals.
https://docs.gluonhq.com/#_introduction 21/191
30/09/2023, 18:48 Gluon Documentation
Make sure the Maven default JDK is properly set to 11+. Tools→Options→Java→Maven (or
NetBeans→Preferences… →Java→Maven ), set Default JDK to JDK 11+ (or click Manage Java Platfoms to add a
new Platform if it doesn’t exist).
Before creating a native image, it’s easier to run the application first and verify that there are no errors.
Select Run project (F6) or select javafx:run from the Navigator. Verify that all the tasks are executed without errors, and the
project runs fine on your desktop. Alternatively you can open the terminal ( Tools→Open in Terminal ) and run mvn
javafx:run .
Let’s make a slight change to the code. In the BasicView class, update the text of the label on line 21 to the following:
JAVA
button.setOnAction(e -> label.setText("Hello from NetBeans!"));
Run it again to see that the new message shows up on your desktop when you click the button.
https://docs.gluonhq.com/#_introduction 22/191
30/09/2023, 18:48 Gluon Documentation
Make sure you set the environment variable GRAALVM_HOME . Alternatively, you can add path to GraalVM
installation directory by adding graalvmHome to the gluonfx-maven-plugin configuration.
If you are running on Windows, you need to run all the gluonfx goals from a x64 terminal.
GluonFX plugin provides us various goals which are explained in details, earlier in the documentation. For this tutorial, we will
be using the gluonfx:build goal to create a native image of the application.
Execute mvn gluonfx:build from the terminal, or, run the gluonfx:build goal from the Navigator with modifiers, and add
Env.GRAALVM_HOME=/path/to/GraalVM .
This goal typically takes a couple of minutes to complete and may vary depending on the system. Once the goal is executed
successfully, the native image can be run by executing gluonfx:nativerun goal.
Now we are ready for deploying the same application on an Android device.
Right-click on the project and select Set Configuration and select android . This will activate the pre-existing android profile.
Run mvn -Pandroid gluonfx:build from the terminal, or, execute the gluonfx:build goal from the Navigator with modifiers,
adding profile android , and Env.GRAALVM_HOME=/path/to/GraalVM .
https://docs.gluonhq.com/#_introduction 23/191
30/09/2023, 18:48 Gluon Documentation
Once the native image is created, we need to package it into an apk before we can install it on a physical Android device.
Execute mvn -Pandroid gluonfx:package to create an apk. Once the goal is executed successfully, connect a physical device and
install the native image by executing the mvn -Pandroid gluonfx:install goal.
When the installation ends successfully, run mvn -Pandroid gluonfx:nativerun or find the application on your device and
open it up:
Now we are ready for deploying the same application on an iOS device.
Right-click on the project and select Set Configuration and select ios . This will activate the pre-existing ios profile.
Run mvn -Pios gluonfx:build from the terminal, or, execute the gluonfx:build goal from the Navigator with modifiers,
adding profile ios , and Env.GRAALVM_HOME=/path/to/GraalVM .
Once the goal is executed successfully, connect a physical device and run the native image on it by executing mvn -Pios
gluonfx:nativerun .
https://docs.gluonhq.com/#_introduction 24/191
30/09/2023, 18:48 Gluon Documentation
3.3. Eclipse
In this section, we’ll explain briefly how to create and download a project from Gluon Start, open it in the Eclipse IDE and
deployed on desktop, Android and iOS devices. Before we start, make sure to check the Platforms section for a list of prerequisites
for each platform.
https://docs.gluonhq.com/#_introduction 25/191
30/09/2023, 18:48 Gluon Documentation
The Maven project has a dependency on the OpenJFX Maven Plugin and the GluonFX Maven plugin to the project. These plugins
add a series of goals which will be used to run and create native images of the application.
Right-click on the project, select Run As → Maven Build…. An "Edit Configuration" window opens. In the Goals textfield, type
javafx:run and click Run . Verify that all the tasks are executed without errors, and the project runs fine on your desktop.
Let’s make a slight change to the code. In the BasicView class, update the text of the label on line 20 to the following:
JAVA
button.setOnAction(e -> label.setText("Hello from Eclipse!"));
Run the application again to verify that the text inside the label has changed.
https://docs.gluonhq.com/#_introduction 26/191
30/09/2023, 18:48 Gluon Documentation
Make sure you set the environment variable GRAALVM_HOME . Alternatively, you can add path to GraalVM
installation directory by adding graalvmHome to the gluonfx-maven-plugin configuration.
If you are running on Windows, you need to run all the GluonFX goals from a x64 terminal.
GluonFX plugin has various goals which are explained in details earlier in the documentation. For this tutorial, we will be using
the gluonfx:build goal to create a native image of the application.
Execute mvn gluonfx:build from the terminal, or, open the Run Configurations…window and update the Goal to
gluonfx:build and click Run .
This goal typically takes a couple of minutes to complete and may vary depending on the system. Once the goal is executed
successfully, the native image can be run by executing gluonfx:nativerun goal.
Now we are ready for deploying the same application on an Android device.
Right-click on the project and open Maven → Select Maven Profiles…window. Check android checkbox and uncheck all
others. This will activate the pre-existing android profile. All goals will now target android platform instead of desktop .
Run mvn -Pandroid gluonfx:build from the terminal, or alternatively, execute the gluonfx:build goal again, this time the
android profile should be selected by default, else add it to the profiles field.
https://docs.gluonhq.com/#_introduction 27/191
30/09/2023, 18:48 Gluon Documentation
Once the native image is created, we need to package it into an apk before we can install it on a physical Android device.
Execute mvn -Pandroid gluonfx:package goal to create an apk. Once the goal is executed successfully, connect a physical
device and install the native image by executing gluonfx:install goal.
Once the goal is executed successfully, connect a physical device and install the native image by executing the mvn -Pandroid
gluonfx:install goal.
When the installation ends successfully, run mvn -Pandroid gluonfx:nativerun or find the application on your device and
open it up:
Now we are ready for deploying the same application on an iOS device.
Right-click on the project and open Maven → Select Maven Profiles…window. Check ios checkbox and uncheck all others.
This will activate the pre-existing ios profile. All gluonfx goals will now target iOS platform.
Run mvn -Pios gluonfx:build from the terminal, or alternatively, execute the gluonfx:build goal again, this time the ios
profile should be selected by default, else add it to the profiles field.
Once the goal is executed successfully, connect a physical device and run the native image on it by executing mvn -Pios
gluonfx:nativerun .
https://docs.gluonhq.com/#_introduction 28/191
30/09/2023, 18:48 Gluon Documentation
https://docs.gluonhq.com/#_introduction 29/191
30/09/2023, 18:48 Gluon Documentation
Open Source
GluonFX Maven plugin is open sourced, and licensed under the BSD-3 license. Its source code is hosted under Gluon
organization in Github (https://github.com/gluonhq/gluonfx-maven-plugin/).
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.21</version>
<configuration>
<mainClass>your.mainClass</mainClass>
</configuration>
</plugin>
The plugin allows some options that can be set in <configuration> to override the default settings.
At the moment, the plugin doesn’t support Maven 3.9.0+. Therefore, Maven runtime must be 3.8.8 or lower.
4.2. Goals
4.2.1. Native applications
To create a native application, GluonFX plugin introduces the following goals:
gluonfx:run
gluonfx:runagent
gluonfx:compile
gluonfx:link
gluonfx:build
gluonfx:package
gluonfx:install
gluonfx:nativerun
The following image shows a flow diagram of what the goals produce and the expected order.
https://docs.gluonhq.com/#_introduction 30/191
30/09/2023, 18:48 Gluon Documentation
gluonfx:run
Since: 1.0.0
Run the application on the JVM by resolving the appropriate Attach libraries required.
gluonfx:runagent
Since: 0.1.37
Runs the project on desktop, in combination with the javafx-maven-plugin , with GraalVM’s JVM (HotSpot) and with the native-
image-agent to record the behavior of the Java application. It generates the configuration files for reflection, JNI, resource, proxy
and serialization, that will be used by the native image generation with the above goals.
If needed, this goal should be executed before the others, and requires the user intervention to discover all reachable classes, by
going through all possible scenes, views, dialogs, menus…
This goal is not strictly needed, as the GluonFX plugin already provides a basic set of configuration files that can be modified
manually. In any case, the configuration files generated by the tracing agent will be picked and merged with those generated by
the plugin (as in most cases the content of both will be duplicated).
Using the agent might have some impact in the native compilation time and the binary size.
gluonfx:compile
This goal performs AOT compilation by executing the native-image command and builds the shared object file. It is a very
intensive and lengthy task (several minutes, depending on your project and CPU), so it should be called only when the project is
ready and runs fine on a VM.
gluonfx:link
Links the object file to create a native executable file or shared library.
gluonfx:build
This goal simply combines gluonfx:compile and gluonfx:link .
https://docs.gluonhq.com/#_introduction 31/191
30/09/2023, 18:48 Gluon Documentation
gluonfx:package
Packages the executable or shared library into a target specific package that includes all the necessary dependencies.
gluonfx:install
Installs the package on the host system or attached device.
At the moment, this goal is only intended for iOS, iOS-sim, Android and Linux-AArch64.
gluonfx:nativerun
Since: 1.0.0
Runs either the executable generated by gluonfx:link on the host system or runs the application that was installed on the
connected device (iOS, Android or Linux-AARch64).
gluonfx:sharedlib
The following image shows a flow diagram of what the goal produce.
gluonfx:sharedlib
Since: 1.0.15
This goal runs internally gluonfx:compile gluonfx:link , but this time, the outcome is a native shared library and not an
executable.
Intended to be added to third party projects, this goal should be applied only to pure Java libraries, that doesn’t have any
UI/JavaFX code.
The created shared library will have the main method of the main Java class as its entrypoint method, if any.
At least, one static entry point method is required. You can use the @CEntryPoint annotation
(https://www.graalvm.org/sdk/javadoc/org/graalvm/nativeimage/c/function/CEntryPoint.html) to specify entry point methods that should be
exported and callable from C. No object types are permitted for parameters or return types; only primitive Java values, word
https://docs.gluonhq.com/#_introduction 32/191
30/09/2023, 18:48 Gluon Documentation
values (https://www.graalvm.org/sdk/javadoc/org/graalvm/word/WordBase.html), and enum values are allowed. To provide the current
thread’s execution context for the call, one of the parameters of the entry point method has to be of type IsolateThread
(https://www.graalvm.org/sdk/javadoc/org/graalvm/nativeimage/IsolateThread.html) or Isolate
(https://www.graalvm.org/sdk/javadoc/org/graalvm/nativeimage/Isolate.html).
The results will be available at target/gluonfx/$arch-$os/$AppName.$ext .
Linux - so
macOS - dylib
iOS - so
Android - dylib
gluonfx:staticlib
The following image shows a flow diagram of what the goal produce.
gluonfx:staticlib
Since: 1.0.17
This goal runs internally gluonfx:compile gluonfx:link , but this time, the outcome is a native static library and not an
executable.
The created static library will have the main method of the main Java class as its entrypoint method, if any.
At least, one static entry point method is required. You can use the @CEntryPoint annotation
(https://www.graalvm.org/sdk/javadoc/org/graalvm/nativeimage/c/function/CEntryPoint.html) to specify entry point methods that should be
exported and callable from C. No object types are permitted for parameters or return types; only primitive Java values, word
values (https://www.graalvm.org/sdk/javadoc/org/graalvm/word/WordBase.html), and enum values are allowed. To provide the current
thread’s execution context for the call, one of the parameters of the entry point method has to be of type IsolateThread
(https://www.graalvm.org/sdk/javadoc/org/graalvm/nativeimage/IsolateThread.html) or Isolate
(https://www.graalvm.org/sdk/javadoc/org/graalvm/nativeimage/Isolate.html).
iOS: .a
https://docs.gluonhq.com/#_introduction 33/191
30/09/2023, 18:48 Gluon Documentation
4.3. Configuration
The plugin allows some customization to modify the default settings, which are:
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.21</version>
<configuration>
<target>host</target>
<mainClass>your.mainClass</mainClass>
<bundlesList></bundlesList>
<resourcesList></resourcesList>
<reflectionList></reflectionList>
<jniList></jniList>
<attachList></attachList>
<nativeImageArgs></nativeImageArgs>
<linkerArgs></linkerArgs>
<runtimeArgs></runtimeArgs>
<verbose>false</verbose>
<graalvmHome></graalvmHome>
<javaStaticSdkVersion>11-ea+10</javaStaticSdkVersion>
<javafxStaticSdkVersion>21-ea+9.1</javafxStaticSdkVersion>
<enableSWRendering>false</enableSWRendering>
<remoteHostName></remoteHostName>
<remoteDir></remoteDir>
<appIdentifier></appIdentifier>
<releaseConfiguration>
<!-- all targets -->
<packageType></packageType>
<description></description>
<vendor></vendor>
<!-- macOS -->
<macAppStore></macAppStore>
<macSigningUserName></macSigningUserName>
<macAppCategory></macAppCategory>
<!-- macOS/iOS -->
<bundleName></bundleName>
<bundleVersion>1.0</bundleVersion>
<bundleShortVersion>1.0</bundleShortVersion>
<providedSigningIdentity></providedSigningIdentity>
<providedProvisioningProfile></providedProvisioningProfile>
<skipSigning>false</skipSigning>
<!-- iOS Simulator -->
<simulatorDevice></simulatorDevice>
<!-- Android -->
<appLabel></appLabel>
<versionCode>1</versionCode>
<versionName>1.0</versionName>
<providedKeyStorePath>${android-keystore-path}</providedKeyStorePath>
<providedKeyStorePassword>${android-keystore-password}</providedKeyStorePassword>
<providedKeyAlias>${android-key-alias}</providedKeyAlias>
<providedKeyAliasPassword>${android-key-password}</providedKeyAliasPassword>
</releaseConfiguration>
</configuration>
</plugin>
4.3.1. target
A string that defines the target platform. The default is host , which refers to the platform that currently hosts the process. It can
be set also to ios to create native images for iOS devices (Aarch64), or android to create native images for Android devices
(Aarch64).
Default: host
4.3.2. bundlesList
List of fully qualified resource bundles that will be added to the default list of resource bundles. By default, the list already
includes the JavaFX bundles:
com.sun.javafx.tk.quantum.QuantumMessagesBundle
com/sun/javafx/scene/control/skin/resources/controls
com/sun/javafx/scene/control/skin/resources/controls-nt
com.sun.media.jfxmedia.MediaErrors
com.sun.webkit.graphics.Images
com.sun.webkit.LocalizedStrings
https://docs.gluonhq.com/#_introduction 34/191
30/09/2023, 18:48 Gluon Documentation
javafx.scene.web.HTMLEditorSkin
com.sun.org.apache.xerces.internal.impl.msg.XMLMessages
And on Windows only:
com/sun/glass/ui/win/themes
4.3.3. resourcesList
List of additional resource patterns or extensions that will be added to the default resource list that already includes:
We keep adding extensions to this list. Please check the source code
(https://github.com/gluonhq/substrate/blob/master/src/main/java/com/gluonhq/substrate/target/AbstractTargetConfiguration.java#L70-L73) for the
latest list.
4.3.4. reflectionList
List of additional full qualified classes that will be added to the default reflection list, that already includes most of the JavaFX
classes.
Note: The current list is added to a file that can be found under
target/gluonfx/$arch-$os/gvm/reflectionconfig-$arch-$os.json .
For more advanced usage, read the JNI and Reflection section.
4.3.5. jniList
List of additional full qualified classes that will be added to the default jni list, that already includes most of the JavaFX classes.
Note: The current list is added to a file that can be found under target/gluonfx/$arch-$os/gvm/jniconfig-$arch-$os.json .
For more advanced usage, read the JNI and Reflection section.
4.3.6. attachList
If you want to include Gluon Attach (https://github.com/gluonhq/attach) services to your project, you can use attachList to including
the name of the services, like:
XML
<!-- dependencies -->
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>display</artifactId>
<version>4.0.18</version>
</dependency>
After saving the changes, the dependencies for the defined services will be resolved to include those for defined target , and
when the native compile goal is executed, the native services implementations will be added to the reflection and JNI lists.
Note: Attach platform implementations will be added only to the goals of the GluonFX plugin, but not to the JavaFX plugin. It is
convenient to use Maven profiles to overcome this issue.
4.3.7. nativeImageArgs
List of additional arguments that will be added to the native image creation.
4.3.8. linkerArgs
List of additional arguments that will be added to the linker command to provide additional linker flags.
https://docs.gluonhq.com/#_introduction 35/191
30/09/2023, 18:48 Gluon Documentation
Since: 1.0.13
4.3.9. runtimeArgs
List of additional arguments that will be added as runtime arguments to the native image executable.
Note: These arguments are usually added to the command line when executing the image, the arguments in this list can be
complementary.
4.3.10. verbose
Set to true will generate a more verbose output to the console, useful when having errors, to identify possible issues.
Also, you can get a more verbose output for these goals running with -X :
mvn -X gluonfx:compile
Default: false
Note: Regardless the verbose value, the full logs can be found under target/gluonfx/$arch-$os/gmv/log .
4.3.11. graalvmHome
Path to GraalVM installation directory. This is only required when GRAALVM_HOME is not set.
Since: 0.1.3
4.3.12. javaStaticSdkVersion
The version of the Java static libraries. These will be located under:
~/.gluon/substrate/javaStaticSdk/$javaStaticSdkVersion/$target-$arch/labs-staticjdk/lib .
Default: 11-ea+10
4.3.13. javafxStaticSdkVersion
The version of the JavaFX SDK and its static libraries. These will be located under:
~/.gluon/substrate/javafxStaticSdk/$javaStaticSdkVersion/$target-$arch/sdk/lib .
Default: 21-ea+9.1
Note: Enabling software rendering will result in a longer compile time and larger native image.
Default: false
Since: 0.1.14
4.3.15. remoteHostName
Set the host name for remote deployment, typically to an embedded system, providing it is reachable and SSH is enabled.
4.3.16. remoteDir
Sets the directory where the native image will be deployed on the remote system, providing the remote host is reachable and SSH
is enabled.
4.3.17. appIdentifier
By default, the application unique identifier is defined from the groupId and artifactId coordinates, but it can be set to something
different if needed.
Note: Useful to set the package name on an Android app or the bundleId of an iOS app.
Since: 1.0.7
https://docs.gluonhq.com/#_introduction 36/191
30/09/2023, 18:48 Gluon Documentation
jni-config.json
proxy-config.json
reflect-config.json
resource-config.json
serialization-config.json
predefined-classes-config.json
The files can be edited and modified to include or exclude content if needed.
The agent runs only on desktop, therefore only the classes for that host are discovered and added to the above
config files. However, running on other platforms these might not be available. For that reason, the agent
already filters out some of them (which are provided with the Substrate configuration files mentioned below).
If needed, these files can be edited and modified manually before running the GluonFX goals.
When building the application, the plugin will also inspect every jar dependency for the existence of these configuration files. The
files in the jar should be placed in the same folder: META-INF/substrate/config .
JSON
[
{
"name" : "package.name.ClassName",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredFields" : true,
"allPublicFields" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
}
]
This has an impact on both compilation time and memory footprint, because all methods and fields are opened. Ideally, it is better
to open only the minimal list of fields and methods that are required for your application to run.
jniconfig-$arch-$os.json and/or reflectionconfig-$arch-$os.json : these are only applied to targets that match both
the architecture and operating system. For example, specifying reflection configuration for linux 64bit can be achieved by
creating a file called reflectionconfig-x86_64-linux.json .
The files must contain the fully qualified name of classes, together with some attributes (like allDeclaredFields ), methods
and/or fields that will be invoked via reflection and that are not already part of the list.
For instance, the configuration below only adds the method named valueOf of the MaterialDesignIcon class to the final
reflection configuration:
src/main/resources/META-INF/substrate/config/reflectionconfig.json
https://docs.gluonhq.com/#_introduction 37/191
30/09/2023, 18:48 Gluon Documentation
JSON
[
{
"name":"com.gluonhq.charm.glisten.visual.MaterialDesignIcon",
"methods":[
{"name":"valueOf","parameterTypes":["java.lang.String"] }
]
}
]
Resources
The resourcesList configuration option can also be defined in a configuration file:
resourceconfig-$arch-$os.json : only applied to targets that match the given architecture and operating system
For instance, the configuration below includes a pattern to load all *.txt files found:
src/main/resources/META-INF/substrate/config/resourceconfig.json
JSON
[
{
"resources": [
{"pattern": ".*\\.txt$"}
]
}
]
Resource bundles
The bundlesList configuration option can also be defined in a configuration file:
resourcebundles-$arch-$os : only applied to targets that match the given architecture and operating system
For instance, below are the fully qualified name of two given resource bundles that will be included:
src/main/resources/META-INF/substrate/config/resourcebundles
TXT
com.mycompany.myproject.mybundle1
com.mycompany.myproject.mybundle2
initbuildtime-$arch-$os : only applied to targets that match the given architecture and operating system
This can be especially convenient for enums that have a large list of values.
4.5.1. Common
These properties are common across various platforms:
packageType
Type of package bundle that can be generated.
On macOS, 'pkg' or 'dmg' can be selected. Note that 'app' is generated by default. On Windows, exe and msi are generated by
default. On iOS 'app' and 'ipa' are generated by default. On Android 'apk' and 'aab' are generated by default.
https://docs.gluonhq.com/#_introduction 38/191
30/09/2023, 18:48 Gluon Documentation
description
A short description about the application.
Since: 1.0.12
vendor
Vendor of the application. Ideally, name of the company or individual developing the application.
Since: 1.0.11
version
Version of the application.
Since: 1.0.12
4.5.2. macOS
Only for macOS:
macAppStore
Boolean that indicates if the macOS bundle is intended for the Mac App Store.
macSigningUserName
Team or user name portion in Apple signing identities
macAppCategory
The category that best describes the app for the Mac App Store. By default it is set to public.app-category.utilities .
See LSApplicationCategoryType
(https://developer.apple.com/documentation/bundleresources/information_property_list/lsapplicationcategorytype) for the full list of categories.
4.5.3. macOS/iOS
For both macOS and iOS:
bundleName
A user-visible short name for the bundle. If not set, the Maven project’s name will be used.
bundleVersion
The version of the build that identifies an iteration of the bundle. A string composed of one to three period-separated integers,
containing numeric characters (0-9) and periods only. Default 1.0 .
bundleShortVersion
A user-visible string for the release or version number of the bundle. A string composed of one to three period-separated integers,
containing numeric characters (0-9) and periods only. Default 1.0 .
and that were used by the provisioning profile development or distribution of the given app. When not provided, the plugin will
try to find a valid installed provisioning profile that can be used to sign the app, including wildcards.
skipSigning
Boolean that can be used to skip signing macOS/iOS apps. This will prevent any deployment, but can be useful to run tests without
an actual device.
simulatorDevice
https://docs.gluonhq.com/#_introduction 39/191
30/09/2023, 18:48 Gluon Documentation
A string with a valid name of an iOS simulator device. It can be found from Xcode → Window → Devices and Simulators . If not
provided or invalid, a default simulator device will be used.
4.5.5. Android
appLabel
A user-visible short name for the app, if not set, the Maven project’s name will be used.
versionCode
A positive integer used as an internal version number, by default is set to 1.
versionName
A string used as the version number shown to users, like <major>.<minor>.<point> . By default is 1.0 .
providedKeyStorePath : A string with the path to a keystore file that can be used to sign the Android apk/aab bundles
Note that it can be convenient to define the values for these options in the ~/.m2/settings.xml file, using Maven profiles.
Prefix for all goals has been renamed from client:* to gluonfx:* . For example: to build a native image, use mvn
gluonfx:build instead of mvn client:build
https://docs.gluonhq.com/#_introduction 40/191
30/09/2023, 18:48 Gluon Documentation
5. Platforms
Gluon applications can run on various platforms. These applications can run directly on the JVM on all desktop and embedded
platforms without any additional requirement.
x86 Windows
x64 Linux
Mac OS
Windows
arm32 Linux
AArch64 Linux
Mac OS
Windows
Gluon applications can also be converted to a native image (a binary or an executable) that can target a specific platform. Some
native image targets have a dependency on the platform on which they can be built. For example, iOS images can currently be
only produced on a MacOS.
In this section, we will discuss the requirements, procedure, and restrictions for development and deployment of Gluon
applications across platforms. We will also try to build HelloFX (https://github.com/gluonhq/gluon-samples/tree/master/HelloFX), a simple
JavaFX application, on each platform.
Native image builds for a specific target platform have to be created from a specific host platform (e.g. Windows native build has
to be done on Windows, an iOS native build on macOS). This hurdle can be overcome by using a build automation tool like Github
Actions (https://github.com/features/actions), which provides build 'runners' for every major OS. Each platform section below contains
an example of a Github Actions Workflow. You can also have a look at the Hello Gluon CI Sample
(https://github.com/gluonhq/hello-gluon-ci) which combines a workflow for all supported platforms.
The following matrix tables will help to list features and platforms supported across native-image using Gluon:
Windows
Mac OS
Linux
Android
iOS
Table 3. Platform feature matrix for Native Images
Platform controls/fxml media web
Windows
Mac OS
https://docs.gluonhq.com/#_introduction 41/191
30/09/2023, 18:48 Gluon Documentation
Linux
Android
iOS
- Supported via Attach (https://github.com/gluonhq/attach/)
5.1. Linux
5.1.1. Pre-requisites
GraalVM
Additional packages (more information on this later)
GraalVM
Gluon applications can run on JVM without any additional requirement. However, to create native images for your Gluon
application, you will need the latest version of the Gluon built version of GraalVM.
The latest version of Gluon’s GraalVM for Linux can be found at https://github.com/gluonhq/graal/releases/latest.
Download the graalvm-svm-java17-linux-gluon-22.1.0.1-Final.zip file, unzip and extract to a proper location, and finally set the
GRAALVM_HOME environment variable to point to the GraalVM directory:
SHELL
export GRAALVM_HOME=/path/to/graalvm-svm-java17-linux-gluon-22.1.0.1-Final
For convenience, you can add the above to your .bashrc file.
Additional packages
In addition to GraalVM, the following packages are also required:
5.1.2. CentOS
Required packages
Execute the following command to install the required yum packages:
https://docs.gluonhq.com/#_introduction 42/191
30/09/2023, 18:48 Gluon Documentation
Run the mvn gluonfx:link goal to produce the native image. As a result, target/gluonfx/x86_64-linux/hellofx is created.
It can be executed directly or with mvn gluonfx:nativerun .
https://docs.gluonhq.com/#_introduction 43/191
30/09/2023, 18:48 Gluon Documentation
https://docs.gluonhq.com/#_introduction 44/191
30/09/2023, 18:48 Gluon Documentation
YAML
jobs:
build:
runs-on: ubuntu-latest
steps:
# Checkout your code
- uses: actions/checkout@v2
# Upload the staging directory as a build artifact. You will be able to download this after the build finishes.
- name: Upload
uses: actions/upload-artifact@v2
with:
name: Package
path: staging
You can see this workflow in action in the Hello Gluon CI Sample (https://github.com/gluonhq/hello-gluon-ci).
https://docs.gluonhq.com/#_introduction 45/191
30/09/2023, 18:48 Gluon Documentation
To test the shared library, from the HelloSharedLib’s root, run ./run.sh to compile and run the sample sample/example.cpp
that makes use of the library:
Sum: 3
Diff: -1
Text: Hello from Java
5.2. Mac OS
Gluon applications can run on JVM and as native image on macOS with Intel chip (x86_64) and with Apple Silicon chip (M1,
AArch64).
5.2.1. Pre-requisites
GraalVM
Xcode
GraalVM
Gluon applications can run on JVM without any additional requirement. However, to create native-images for your Gluon
application, you will need the latest version of the Gluon built version of GraalVM.
The latest version of Gluon’s GraalVM for Mac OS X can be found at https://github.com/gluonhq/graal/releases/latest.
x86_64
If you have Intel, download the graalvm-svm-java17-darwin-gluon-22.1.0.1-Final.zip file, unzip and extract to a proper location,
and finally set the GRAALVM_HOME environment variable to point to the GraalVM directory:
SHELL
export GRAALVM_HOME=/path/to/graalvm-svm-java17-darwin-gluon-22.1.0.1-Final/Contents/Home
AArch64
If you have an M1, Download the graalvm-svm-java17-darwin-m1-gluon-22.1.0.1-Final.zip file, unzip and extract to a proper
location, and finally set the GRAALVM_HOME environment variable to point to the GraalVM directory:
SHELL
export GRAALVM_HOME=/path/to/graalvm-svm-java17-darwin-m1-gluon-22.1.0.1-Final/Contents/Home
https://docs.gluonhq.com/#_introduction 46/191
30/09/2023, 18:48 Gluon Documentation
For convenience, you can add the above to your .bash_profile file.
If needed, in both cases there is also a GraalVM build based on Java 11.
Xcode
Xcode version 11 or higher is required and can be installed from the Mac App Store
(https://apps.apple.com/us/app/xcode/id497799835?mt=12). Once installed, open it and accept the license terms.
Run the mvn gluonfx:link goal to produce the native image. As a result, target/gluonfx/x86_64-darwin/hellofx is created.
It can be executed directly or with mvn gluonfx:nativerun .
https://docs.gluonhq.com/#_introduction 47/191
30/09/2023, 18:48 Gluon Documentation
Note that the same procedure applies when building a native image on M1.
Optionally, you can create an app bundle and a pkg or dmg bundle, by running mvn gluonfx:package :
https://docs.gluonhq.com/#_introduction 48/191
30/09/2023, 18:48 Gluon Documentation
The bundles can be signed or not, and the pkg can be signed for distribution through the Mac App Store, based on the release
configuration settings.
https://docs.gluonhq.com/#_introduction 49/191
30/09/2023, 18:48 Gluon Documentation
YAML
jobs:
build:
runs-on: macos-latest
steps:
# Checkout your code
- uses: actions/checkout@v2
# Upload the staging directory as a build artifact. You will be able to download this after the build finishes.
- name: Upload
uses: actions/upload-artifact@v2
with:
name: Package
path: staging
You can see this workflow in action in the Hello Gluon CI Sample (https://github.com/gluonhq/hello-gluon-ci).
So far this only applies for x86_64, since GitHub Actions doesn’t host a runner for AArch64 yet. In the meantime you can run it on
a self hosted runner.
https://docs.gluonhq.com/#_introduction 50/191
30/09/2023, 18:48 Gluon Documentation
To test the shared library, from the HelloSharedLib’s root, run ./run.sh to compile and run the sample sample/example.cpp
that makes use of the library:
Sum: 3
Diff: -1
Text: Hello from Java
5.3. Windows
5.3.1. Pre-requisites
GraalVM
Microsoft Visual Studio
WiX Toolset (optional)
GraalVM
Gluon applications can run on JVM without any additional requirement. However, to create native-images for your Gluon
application, you will need the latest version of the Gluon built version of GraalVM.
The latest version of Gluon’s GraalVM for Windows can be found at https://github.com/gluonhq/graal/releases/latest.
Download the graalvm-svm-java17-windows-gluon-22.1.0.1-Final.zip file, unzip and extract to a proper location, and finally set the
GRAALVM_HOME environment variable to point to the GraalVM directory:
SHELL
set GRAALVM_HOME=C:\path\to\graalvm-svm-java17-windows-gluon-22.1.0.1-Final
For convenience, you can add GRAALVM_HOME to the Environment Variables list (Advanced system settings).
https://docs.gluonhq.com/#_introduction 51/191
30/09/2023, 18:48 Gluon Documentation
Please make sure to choose the English Language Pack. GraalVM might not be able to detect the installed
compiler version in other languages.
During the installation process, make sure to select at least the following individual components:
All build commands, be it with Maven or Gradle, must be executed in a Visual Studio 2019 Command Prompt
called x64 Native Tools Command Prompt for VS 2019 . A shortcut can be found in the "Start Menu", or you
can search the application in the search box. Read the Microsoft documentation
(https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019) for more information.
Wix
In order to create a MSI installer for the native application, WiX 3.0 or later is required.
On a Windows machine, run the gluonfx:compile goal. It produces the following output:
Run the mvn gluonfx:link goal to produce the native image. target\gluonfx\x86_64-windows\hellofx.exe is created. It
can be executed directly or with mvn gluonfx:nativerun .
https://docs.gluonhq.com/#_introduction 52/191
30/09/2023, 18:48 Gluon Documentation
https://docs.gluonhq.com/#_introduction 53/191
30/09/2023, 18:48 Gluon Documentation
https://docs.gluonhq.com/#_introduction 54/191
30/09/2023, 18:48 Gluon Documentation
YAML
build:
runs-on: windows-latest
steps:
# Checkout your code
- uses: actions/checkout@v2
# Upload the staging directory as a build artifact. You will be able to download this after the build finishes.
- name: Upload
uses: actions/upload-artifact@v2
with:
name: Package
path: staging
You can see this workflow in action in the Hello Gluon CI Sample (https://github.com/gluonhq/hello-gluon-ci).
5.4. Android
5.4.1. Pre-requisites
Pre-requisites of Linux Platform
Android SDK and NDK (optional, more information on this later)
Currently, Android can be built only on Linux OS or from Windows WSL2 (https://docs.microsoft.com/en-us/windows/wsl/install-win10).
Alternatively you can use a GitHub Actions workflow.
Both SDK/NDK will be downloaded automatically by the "GluonFX plugin" and configured with the required
packages.
But if you already have a local installation of the Android SDK/NDK, you can override this behaviour by defining environment
variables:
Please make sure you have installed the following required packages:
platform-tools
https://docs.gluonhq.com/#_introduction 55/191
30/09/2023, 18:48 Gluon Documentation
platforms;android-31
build-tools;31.0.0
ndk-bundle
extras;android;m2repository
extras;google;m2repository
To target android devices, <target>android</target> needs to be added to the GluonFX plugin configuration:
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.21</version>
<configuration>
<target>android</target>
<mainClass>${mainClassName}</mainClass>
</configuration>
</plugin>
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.21</version>
<configuration>
<target>${gluonfx.target}</target>
<mainClass>${mainClassName}</mainClass>
</configuration>
</plugin>
<profiles>
<profile>
<id>android</id>
<properties>
<gluonfx.target>android</gluonfx.target>
</properties>
</profile>
</profiles>
The project can be built using mvn -Pandroid gluonfx:build . This will run the compilation phase and link the compiled objects
into an android executable.
By default, the debug profile will be used to sign the APK/AAB bundles. This allows testing the APK bundle on a local device (see
run on device) but not publishing the AAB bundle to a store, which requires a release profile.
To sign the AAB bundle with the correct signing key and keystore, use the releaseConfiguration settings:
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
...
<configuration>
...
<releaseConfiguration>
<versionCode>1</versionCode>
<providedKeyStorePath>${android-keystore-path}</providedKeyStorePath>
<providedKeyStorePassword>${android-keystore-password}</providedKeyStorePassword>
<providedKeyAlias>${android-key-alias}</providedKeyAlias>
<providedKeyAliasPassword>${android-key-password}</providedKeyAliasPassword>
</releaseConfiguration>
...
</configuration>
</plugin>
versionCode is the unique build number of your app. You need to increase it for every upload to the Play
Store.
Please follow these steps in the Android documentation (https://developer.android.com/studio/publish/app-signing) to create a keystore.
https://docs.gluonhq.com/#_introduction 56/191
30/09/2023, 18:48 Gluon Documentation
src/android/AndroidManifest.xml
However, if you would just like to override the icon, there are nice online generators as well (e.g. https://appicon.co/)
then copy the generated Android icon files (starting with mipmap-) to src/android/res
Run on device
"USB debugging" must be enabled on the connected device. To enable USB debugging follow the steps listed
here (https://developer.android.com/training/basics/firstapp/running-app#RealDevice).
To install the application to a connected android device, run mvn -Pandroid gluonfx:install .
Finally, you can call mvn -Pandroid gluonfx:nativerun to launch the application on the device. GluonFX plugin will also start
adb logcat to print out debugging information from the device to the console.
This requires an Android device that has to be plugged in at the run phase.
Clone HelloFX (https://github.com/gluonhq/gluon-samples/tree/master/HelloFX) on a Linux system. Use the android profile, and run mvn
-Pandroid gluonfx:compile . It produces the following output:
Note that the process takes some time. There will be performance improvements, but either way, it is convenient to test first on
desktop (and with HotSpot) as much as possible (i.e. with mvn javafx:run ), so gluonfx:compile doesn’t have to be repeated
due to avoidable errors.
Run mvn -Pandroid gluonfx:link to produce the native image. As a result, target/gluonfx/aarch64-
android/libhellofx.so is created.
https://docs.gluonhq.com/#_introduction 57/191
30/09/2023, 18:48 Gluon Documentation
Finally, run mvn -Pandroid gluonfx:package to bundle the application into an Android APK that can be installed on a device
and also to an Android App Bundle (AAB) that can be submitted to Google Play.
This creates the hellofx.apk and hellofx.aab bundles which are available at target/gluonfx/aarch64-android/gvm/ .
Now we are ready to install and run the application on a plugged-in Android device. Run mvn -Pandroid gluonfx:install
gluonfx:nativerun to install and launch the application on the device.
https://docs.gluonhq.com/#_introduction 58/191
30/09/2023, 18:48 Gluon Documentation
https://docs.gluonhq.com/#_introduction 59/191
30/09/2023, 18:48 Gluon Documentation
YAML
jobs:
build:
runs-on: ubuntu-latest
steps:
# Checkout your project
- uses: actions/checkout@v2
# Setup the Android keystore, based on a repo secret. See the section 'Setup Android Keystore' below.
- name: Setup Android Keystore
id: android_keystore_file
uses: timheuer/base64-to-file@v1
with:
fileName: 'my.keystore'
encodedString: ${{ secrets.GLUON_ANDROID_KEYSTORE_BASE64 }}
# Upload the aab to the Google Play Store. See the section below.
- name: Upload to Google Play
uses: r0adkll/[email protected]
with:
serviceAccountJsonPlainText: ${{ secrets.GLUON_ANDROID_SERVICE_ACCOUNT_JSON }}
packageName: com.gluonhq.samples.hellogluon
releaseFiles: target/gluonfx/aarch64-android/gvm/HelloGluon.aab
track: beta
You can see this workflow in action in the Hello Gluon CI Sample (https://github.com/gluonhq/hello-gluon-ci).
https://docs.gluonhq.com/#_introduction 60/191
30/09/2023, 18:48 Gluon Documentation
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
...
<configuration>
...
<releaseConfiguration>
<versionCode>${env.GITHUB_RUN_NUMBER}</versionCode>
...
</releaseConfiguration>
...
</configuration>
</plugin>
Using env.GITHUB_RUN_NUMBER , Github Actions will set the versionCode to an incremental build number.
a keystore file: you need to base64 encode that file and configure it in the repo secret GLUON_ANDROID_KEYSTORE_BASE64
the keystore will have a password, configure that in the repo secret GLUON_ANDROID_KEYSTORE_PASSWORD
that key will have a password, configure that in the repo secret GLUON_ANDROID_KEYALIAS_PASSWORD
The most important part to configure in this case is the GLUON_ANDROID_SERVICE_ACCOUNT_JSON . To configure a service account
for upload to the Play Store, follow these steps in the Android documentation
(https://developers.google.com/android/management/service-account).
To test the shared library on a regular Android project that includes already C++ code, add the headers:
target/gluonfx/aarch64-android/gvm/HelloSharedLib/graal_isolate.h
target/gluonfx/aarch64-android/gvm/HelloSharedLib/hello.hellosharedlib.h
https://docs.gluonhq.com/#_introduction 61/191
30/09/2023, 18:48 Gluon Documentation
target/gluonfx/aarch64-android/HelloSharedLib.dylib
to the project.
In the Cpp file with the JNI implementations, import the header: --- #include <hello.hellosharedlib.h> ---
assuming the MainActivity class loads the native library and calls the native method:
package com.gluonhq.hellosharedandroidworld;
static {
System.loadLibrary("HelloSharedLib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
Log.v(TAG, "Sum: " + sum(1, 3));
}
Build, making sure the shared library is added to the APK, and deploy to your device and test.
5.5. iOS
5.5.1. Pre-requisites
Pre-requisites of Mac OS Platform
Additional packages (more information on this later)
Currently, iOS packages can be built only on Mac OS X. Alternatively you can use a GitHub Actions workflow.
iOS applications can be locally deployed to a physical device (iPhone and iPad), or distributed via App Store.
While developing, it might also help building native images that can be deployed to the iOS Simulator.
In addition to GraalVM for Mac OS, the following packages are required and can be installed using Homebrew (https://brew.sh):
https://docs.gluonhq.com/#_introduction 62/191
30/09/2023, 18:48 Gluon Documentation
Either way, first of all you will need a unique Apple ID.
Creating an Apple ID
In case you don’t have it yet, create an Apple ID (https://appleid.apple.com/).
You will need a valid email account, and you will receive and email to validate and activate the Apple ID.
In case you are going to use free provisioning, this Apple ID must not be connected to the Apple Developer Program.
Once you have your Apple ID verified and activated, open Xcode, go to Preferences → Accounts . Press the + button at the
bottom left to add an account, select `Apple ID, and include the email address used to create the Apple ID.
https://docs.gluonhq.com/#_introduction 63/191
30/09/2023, 18:48 Gluon Documentation
Xcode project
The first time you start deploying to an iOS device, you need to follow these steps, so Xcode configures your device properly for
future iOS deployment.
Note: If you are using free provisioning, you will have to follow this procedure every time you create a new project.
https://docs.gluonhq.com/#_introduction 64/191
30/09/2023, 18:48 Gluon Documentation
Note: if you are using free provisioning, the bundle ID must match the one defined in your Java project (or the other way
around).
At this point you should plug your iOS device, and select it from the top drop-down list of build schemes that list your iOS device
and iOS simulators.
Make sure you have selected Automatically manage signing , and select a valid Team from the drop-down list.
If you get the error like: The app ID "hellofx.HelloFX" cannot be registered to your develoment team , this means that
the proposed app ID is already in use or has already been registered by the Apple servers, and cannot longer be used. The only
solution is to change the app ID until you get a valid one:
https://docs.gluonhq.com/#_introduction 65/191
30/09/2023, 18:48 Gluon Documentation
Note that the provisioning profile generated by Xcode for that app ID can be found in your
~/Library/MobileDevice/Provisioning Profiles folder.
For free provisioning, this profile will expire after one week.
Deploying to your device
Once everything is in place (there are no visible errors in the General screen), press the Play button that will build and run the
current scheme.
Note: Using free provisioning it is possible that the run fails with a message like: Could not launch "HelloFX" , that prompts
you to verify the Developer App certificate is trusted on your device, as by default the certificate is untrusted. Go to your iPhone,
Settings → General → Device Management , and select the certificate to trust it. Then go back to Xcode and run again. This time,
the app will launch and you will get a white screen.
In this process, default resources are generated under target/gluonfx/arm64-ios/gensrc/ios , including the Default-
Info.plist file and the assets folder with a default iconset.
If needed, you can modify these default values and the iconset, by copying them to src/ios , doing the required changes, and
running mvn gluonfx:package again.
Note that if you are using free provisioning or an explicit provisioning profile, you need to set the exact same bundle ID as the one
in the profile (note it is case sensitive).
If you are using a wildcard, make sure the domain (if any) matches.
This can be done by setting the <appIdentifier/> in the configuration of the GluonFX plugin. Alternatively, it can be done as
well by modifying the default plist.
Note: the bundle identifier key doesn’t need to match your main class.
Checking the logs under target/gluonfx/arm64-ios/gvm/logs or using <verbose>true</verbose> in the GluonFX plugin
can be of help to trace which provisioning profile is used, and to check that a valid one was found:
https://docs.gluonhq.com/#_introduction 66/191
30/09/2023, 18:48 Gluon Documentation
[FINE] Mobile provision asked with bundleId = hello.fx.* (initial bundleId: hello.fx.HelloFX)
[FINE] Checking mobile provision Xcode iOS Wildcard App ID
[FINE] AllInOne matches SigningIdentity{name='Apple Development: ************', sha1='05F2BD84A3************B234CEBC'}
[FINE] Got provisioning profile: AllInOne
Note: If you are using free provisioning, this will deploy your Java app replacing the Xcode app.
You should get your app running on your iOS device and the output of the process will be displayed to the terminal.
To generate a certificate, you need a Certificate Signing Request (CSR) file from your Mac.
https://docs.gluonhq.com/#_introduction 67/191
30/09/2023, 18:48 Gluon Documentation
Upload CSR
Return to the Developer portal and upload the CSR:
Identifiers
https://docs.gluonhq.com/#_introduction 68/191
30/09/2023, 18:48 Gluon Documentation
Go to the Developer portal, and access Certificates, Identifiers & Profiles (https://developer.apple.com/account/resources/certificates/list).
Select Identifiers from the left, and press + , to create a new app identifier.
You can enable app services when you create the App ID or modify these settings later on.
Provide a name and make sure you use the exact Bundle ID from your app, the one listed in your Default-Info.plist file
under the CFBundleIdentifier key.
Alternatively, you can use a wildcard that will let you use a single App ID to match multiple apps. It is recommended to use your
domain name, to filter out other apps.
https://docs.gluonhq.com/#_introduction 69/191
30/09/2023, 18:48 Gluon Documentation
Select any of the required services (if you are using an explicit Bundle ID), and click continue to create the App ID.
Devices
To create a provisioning profile for development, the devices that are allowed to run the application have to be identified.
To add your testing devices, you need to provide their UDID.It can be found from Xcode → Window → Devices and Simulators .
Plug your device, select it from Connected devices, and then select its identifier and copy it.
Go to the Developer portal, and access Certificates, Identifiers & Profiles (https://developer.apple.com/account/resources/certificates/list).
Select Devices from the left, and press + , to add a new device.
https://docs.gluonhq.com/#_introduction 70/191
30/09/2023, 18:48 Gluon Documentation
Profiles
Go to the Developer portal, and access Certificates, Identifiers & Profiles (https://developer.apple.com/account/resources/certificates/list).
Select Profiles from the left, and press + , to add a new provisioning profile.
To add a Development profile (later on you will need a Distribution one), select iOS App Development , and press continue.
If you plan to use services such as Game Center, In-App Purchase, and Push Notifications, or want a Bundle ID unique to a
single app, use an explicit App ID.
If you want to create one provisioning profile for multiple apps or don’t need a specific Bundle ID, select a wildcard App ID.
https://docs.gluonhq.com/#_introduction 71/191
30/09/2023, 18:48 Gluon Documentation
Press continue and select one or more certificates that should be included in this provisioning profile.
Press continue and select one or more devices that should be include in this provisioning profile.
Press continue and finally, give a name to the provisioning profile, it will be used to identify the profile in the portal. Then press
Generate.
To make sure you’re using the correct signing identify and provisioning profile, you can set these using the releaseConfiguration
settings:
https://docs.gluonhq.com/#_introduction 72/191
30/09/2023, 18:48 Gluon Documentation
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
...
<configuration>
...
<releaseConfiguration>
<bundleVersion>1</bundleVersion>
<bundleShortVersion>1.0</bundleShortVersion>
<providedSigningIdentity>iPhone Distribution: Gluon Software BVBA (**********)</providedSigningIdentity>
<providedProvisioningProfile>my-provisioning-profile</providedProvisioningProfile>
</releaseConfiguration>
...
</configuration>
</plugin>
bundleVersion is the unique build number of your app. You need to increase it for every upload to TestFlight.
Note that you can omit providedSigningIdentity and providedProvisioningProfile when running in a
Github Actions workflow, since there will be only 1 valid identity, that one will be used be default.
If you need to set specific iOS settings, copy that file into:
src/ios/Default-Info.plist
and perform the necessary changes. Running again the link goal will now use this plist file.
However, if you would like to override the AppIcon, there are nice online generators as well (e.g. https://appicon.co/)
The next time you run the link goal, this icon set will be used.
src/ios/assets/Base.lproj
and perform the necessary changes. Running again the link goal will now use these storyboards.
src/ios/Entitlements.plist
https://docs.gluonhq.com/#_introduction 73/191
30/09/2023, 18:48 Gluon Documentation
For instance, if your app includes the App Group capability, the file should contain something like:
XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>${your.team.id}.${your.bundle.id}</string>
</array>
</dict>
</plist>
Note that you should replace ${your.team.id} with your Apple Developer account’s Team ID and ${your.bundle.id} with
the App ID of the app.
Clone HelloFX (https://github.com/gluonhq/gluon-samples/tree/master/HelloFX) On a Mac OS X system. Use the ios profile and run mvn -
Pios gluonfx:compile . It produces the following output:
Run mvn -Pios gluonfx:link to produce the native image. As a result, the binary target/gluonfx/arm64-
ios/hellofx.app/hellofx is created.
Run mvn -Pios gluonfx:package to sign and produce the application bundles. As a result, target/gluonfx/arm64-
ios/hellofx.app and target/gluonfx/arm64-ios/hellofx.ipa are created.
https://docs.gluonhq.com/#_introduction 74/191
30/09/2023, 18:48 Gluon Documentation
While the .ipa bundle could be submitted to the App Store, the .app bundle can be deployed to a plugged iOS device with mvn -
Pios gluonfx:install .
And then the app can be launched with mvn -Pios gluonfx:nativerun .
https://docs.gluonhq.com/#_introduction 75/191
30/09/2023, 18:48 Gluon Documentation
YAML
jobs:
build:
runs-on: macos-latest
steps:
# Checkout your code
- uses: actions/checkout@v2
# Setup the signing identify. See the section 'Configuring the signing identity'
- uses: Apple-Actions/import-codesign-certs@v1
with:
p12-file-base64: ${{ secrets.GLUON_IOS_CERTIFICATES_FILE_BASE64 }}
p12-password: ${{ secrets.GLUON_IOS_CERTIFICATES_PASSWORD }}
# Download the appropriate provisining profile using Apple's Appstore Connect API. See the section 'Using the
Appstore Connect API' below
- uses: Apple-Actions/download-provisioning-profiles@v1
with:
bundle-id: com.gluonhq.hello.HelloGluonApp
issuer-id: ${{ secrets.GLUON_IOS_APPSTORE_ISSUER_ID }}
api-key-id: ${{ secrets.GLUON_IOS_APPSTORE_KEY_ID }}
api-private-key: ${{ secrets.GLUON_IOS_APPSTORE_PRIVATE_KEY }}
# Upload the build .ipa file to TestFlight using the Appstore Connect API.
- uses: Apple-Actions/upload-testflight-build@master
with:
app-path: target/gluonfx/arm64-ios/HelloGluon.ipa
issuer-id: ${{ secrets.GLUON_IOS_APPSTORE_ISSUER_ID }}
api-key-id: ${{ secrets.GLUON_IOS_APPSTORE_KEY_ID }}
api-private-key: ${{ secrets.GLUON_IOS_APPSTORE_PRIVATE_KEY }}
You can see this workflow in action in the Hello Gluon CI Sample (https://github.com/gluonhq/hello-gluon-ci).
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
...
<configuration>
...
<releaseConfiguration>
<bundleVersion>${env.GITHUB_RUN_NUMBER}</bundleVersion>
...
</releaseConfiguration>
...
</configuration>
</plugin>
Using env.GITHUB_RUN_NUMBER , Github Actions will set the bundleVersion to an incremental build number.
https://docs.gluonhq.com/#_introduction 76/191
30/09/2023, 18:48 Gluon Documentation
The workflow step Apple-Actions/import-codesign-certs above uses 2 configurations from your repo’s secrets
configuration:
GLUON_IOS_CERTIFICATES_FILE_BASE64
GLUON_IOS_CERTIFICATES_PASSWORD
To generate the values for these secrets, you’ll need a Mac for this one time configuration and follow the steps described in the iOS
Distribution Certificate section.
Once you imported the certificate in Keychain Access, follow these steps:
Make sure to expand the certificate so you can also see the private key that was used to sign it.
Select both the certificate and private key and choose File→Export items
Export it to a .p12 file and choose a password. Set this password as GLUON_IOS_CERTIFICATES_PASSWORD
Base64 encode the .p12 file. Set this value as GLUON_IOS_CERTIFICATES_FILE_BASE64
Next to the signing identify, you will also need to create a provisining profile that can be used for distribution. However, it does
not have to be downloaded. A workflow step will download it using the Appstore Connect API. (see next section)
To generate an Appstore Connect API key, follow these steps as described by Apple
(https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api).
GLUON_IOS_APPSTORE_PRIVATE_KEY : the text contents of the file you downloaded while creating the API key.
https://docs.gluonhq.com/#_introduction 77/191
30/09/2023, 18:48 Gluon Documentation
Using the iOS simulator prevents the need of having a physical device for testing an iOS application. It is also a way to create
screenshots for the multiple formats and resolutions that the App store requires for distribution.
While the iOS app that is deployed to an iPhone or distributed via the Apple Store is exactly the same as the one that runs locally
on the simulator, there is an important difference: the former has AArch64 architecture, while the latter has x86_64.
This means that the native image created with target ios can’t run on the iOS simulator, and a new native image has to be
created, with target ios-sim .
Pre-requisites
Pre-requisites of Mac OS Platform
GraalVM build based on JDK17
Configuration
To target the iOS Simulator, <target>ios-sim</target> needs to be added to the GluonFX plugin configuration:
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.21</version>
<configuration>
<target>ios-sim</target>
<mainClass>${mainClassName}</mainClass>
</configuration>
</plugin>
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.21</version>
<configuration>
<target>${gluonfx.target}</target>
<mainClass>${mainClassName}</mainClass>
</configuration>
</plugin>
<profiles>
<profile>
<id>ios-sim</id>
<properties>
<gluonfx.target>ios-sim</gluonfx.target>
</properties>
</profile>
</profiles>
https://docs.gluonhq.com/#_introduction 78/191
30/09/2023, 18:48 Gluon Documentation
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.21</version>
<configuration>
<target>ios-sim</target>
<mainClass>${mainClassName}</mainClass>
<releaseConfiguration>
<simulatorDevice>iPhone 13 Pro Max</simulatorDevice>
</releaseConfiguration>
</configuration>
</plugin>
HelloFX sample
Clone HelloFX (https://github.com/gluonhq/gluon-samples/tree/master/HelloFX) On a Mac OS X system. Use the ios-sim profile and run
mvn -Pios-sim gluonfx:compile . It produces the following output:
Run mvn -Pios-sim gluonfx:link to produce the native image. As a result, the binary target/gluonfx/x86_64-
ios/hellofx.app/hellofx is created.
Run mvn -Pios-sim gluonfx:package to produce the application bundles. As a result, target/gluonfx/x86_64-
ios/hellofx.app is created.
Run mvn -Pios-sim gluonfx:install to install that app into the iOS simulator. A valid simulator device is required. If
simulatorDevice is not specified, iPhone 13 will be booted as simulator device.
https://docs.gluonhq.com/#_introduction 79/191
30/09/2023, 18:48 Gluon Documentation
Run mvn -Pios gluonfx:link to produce the native image. As a result, the binary target/gluonfx/arm64-
ios/hellofx.app/hellofx is created.
Run mvn -Pios gluonfx:package to sign and produce the application bundles. As a result, target/gluonfx/arm64-
ios/hellofx.app and target/gluonfx/arm64-ios/hellofx.ipa are created.
https://docs.gluonhq.com/#_introduction 80/191
30/09/2023, 18:48 Gluon Documentation
While the .ipa bundle could be submitted to the App Store, the .app bundle can be deployed to a plugged iOS device with mvn -
Pios gluonfx:install .
And then the app can be launched with mvn -Pios gluonfx:nativerun .
https://docs.gluonhq.com/#_introduction 81/191
30/09/2023, 18:48 Gluon Documentation
To test the shared library on a regular iOS project, add the headers:
target/gluonfx/arm64-ios/gvm/HelloSharedLib/graal_isolate.h
target/gluonfx/arm64-ios/gvm/HelloSharedLib/hello.hellosharedlib.h
target/gluonfx/arm64-ios/HelloSharedLib.dylib
into
Add some code that makes use of the shared methods to your controller, like:
if (graal_detach_thread(thread) != 0) {
fprintf(stderr, "graal_detach_thread error\n");
return;
}
}
---
Before building the project, disable bitcode, link the binary with the library, and copy it to frameworks.
https://docs.gluonhq.com/#_introduction 82/191
30/09/2023, 18:48 Gluon Documentation
The following section describes the necessary steps to create and run JavaFX applications on a Raspberry Pi (both 32 and 64 bits),
using a JDK for ARM, while the next section describes the steps to create a native image for AArch64.
Of course, JavaFX is capable of running on a large number of other hardware and operating systems. Please contact us if you
want more information about a specific configuration.
The distribution of JavaFX 21-ea for embedded is tested on a Raspberry Pi 4, using the Raspberry Pi OS
(https://www.raspberrypi.org/software/) distribution.
The Raspberry Pi (https://www.raspberrypi.org/documentation) site contains clear documentation about the product itself. Installing an
operating system for the Raspberry Pi is described at https://www.raspberrypi.org/documentation/installation/installing-
images/README.md.
The following documentation has been tested to work with Raspberry Pi OS (both 32-bit and 64-bit) with desktop and
recommended software, with images that can be downloaded from https://www.raspberrypi.com/software/operating-systems/.
However, it is highly recommended to use the Raspberry Pi Imager (https://www.raspberrypi.org/downloads/) (available for Windows,
Mac OS and Linux), to download and install the image to the SDCard.
Once the image is installed, the first boot will be on X11, and a configuration dialog will show up. Follow the instructions to
configure your language, keyboard settings and WiFi. Apply the changes and reboot.
Once you boot again, from the top menu, select Preferences → Raspberry Pi Configuration
From the System tab, select Boot to CLI. Note that the hostname is set to raspberrypi (change it if needed).
From Interfaces tab, enable SSH.
From Performance tab, it is recommended to set 512 MB for GPU Memory, depending of course on how graphics-intensive
versus how cpu-intensive your application is.
Once the Pi is back online, it is convenient to check the SSH access from your machine:
SHELL
ssh [email protected]
5.6.2. Java
The Raspberry Pi OS might contain an up-to-date JDK 17 distribution for ARM. You can verify that by running java -version .
If you run on a distribution without Java installed (like Raspberry Pi OS Lite), you can easily install it with:
SHELL
pi@raspberrypi:~ $ sudo apt update
$ sudo apt-get install openjdk-17-jdk
$ java -version
openjdk version "17.0.4" 2022-07-19
OpenJDK Runtime Environment (build 17.0.4+8-Debian-1deb11u1)
OpenJDK 64-Bit Server VM (build 17.0.4+8-Debian-1deb11u1, mixed mode, sharing)
https://docs.gluonhq.com/#_introduction 83/191
30/09/2023, 18:48 Gluon Documentation
You can still use JDK 11, but you will need to use a JavaFX version lower than 20. If needed, install it with:
5.6.3. JavaFX
A reference implementation of JavaFX 21-ea for embedded devices, with support for DRM, can be downloaded for the Raspberry
Pi 4 from https://gluonhq.com/products/javafx/#ea.
You can choose the JavaFX SDK for 32 or 64 bits, based on the OS installed on your device.
This SDK should work on other similar systems. If you have an embedded system that you want to be
supported or if you need specific builds, contact us (https://gluonhq.com/about-us/contact-us/).
In order to support hardware-accelerated rendering, JavaFX relies on a number of low-level drivers and
libraries that are not always installed by default on all embedded systems. That is the case of the Raspberry Pi
OS Lite distribution, for instance, and you can install additional required libraries with:
SHELL
pi@raspberrypi:~ $ sudo apt install libegl-mesa0 libegl1 libgbm1 libgles2 libpango-1.0-0 libpangoft2-1.0-
0
SHELL
scp ~/Downloads/openjfx-21-ea+9.1_linux-arm32_bin-sdk.zip [email protected]:/home/pi/Downloads
Now back to your Pi (via SSH or directly), move the SDK to /opt and unzip it:
SHELL
pi@raspberrypi:~ $ sudo mv ~/Downloads/openjfx-21-ea+9.1_linux-arm32_bin-sdk.zip /opt
$ cd /opt
$ sudo unzip openjfx-21-ea+9.1_linux-arm32_bin-sdk.zip
$ sudo rm openjfx-21-ea+9.1_linux-arm32_bin-sdk.zip
Note that you should find the SDK under the folder /opt/javafx-sdk-21 .
SHELL
scp ~/Downloads/openjfx-21-ea+9.1_monocle-linux-aarch64_bin-sdk.zip [email protected]:/home/pi/Downloads
Now back to your Pi (via SSH or directly), move the SDK to /opt and unzip it:
SHELL
pi@raspberrypi:~ $ sudo mv ~/Downloads/openjfx-21-ea+9.1_monocle-linux-aarch64_bin-sdk.zip /opt
$ cd /opt
$ sudo unzip openjfx-21-ea+9.1_monocle-linux-aarch64_bin-sdk.zip
$ sudo rm openjfx-21-ea+9.1_monocle-linux-aarch64_bin-sdk.zip
Note that you should find the SDK under the folder /opt/javafx-sdk-21 .
DRM library
JavaFX requires the DRM library to work without a windows manager.
This library is already bundled within the JavaFX SDK (for the ea versions), and it can be used without limitations for non-
commercial applications. After installing JavaFX, check that you have it:
SHELL
$ ls -l /opt/javafx-sdk-21/lib/libgluon_drm*
-rwxr-xr-x 1 root root 34208 Dec 12 20:42 javafx-sdk-21/lib/libgluon_drm-1.1.7.so
-rwxr-xr-x 1 root root 67448 Dec 12 20:42 javafx-sdk-21/lib/libgluon_drm_debug-1.1.7.so
https://docs.gluonhq.com/#_introduction 84/191
30/09/2023, 18:48 Gluon Documentation
Legal notice
JavaFX support for DRM is a commercial extension from Gluon. See license file (http://download2.gluonhq.com/drm/gluon.md).
You can enable it by setting the environment variable ENABLE_GLUON_COMMERCIAL_EXTENSIONS , either if your application is non-
commercial or if you obtained a valid license from Gluon (https://gluonhq.com/contact-embedded).
SHELL
pi@raspberrypi:~ $ export ENABLE_GLUON_COMMERCIAL_EXTENSIONS=true
And if you want to export it permanently, you can add the following line to your .bashrc file:
SHELL
ENABLE_GLUON_COMMERCIAL_EXTENSIONS=true
Testing JavaFX
JavaFX on embedded works with X11 as well, but first we want to demonstrate it works using the DRM driver
to manage the framebuffer, without X.
Compile:
SHELL
pi@raspberrypi:~ $ cd ~/Downloads/samples/CommandLine/Modular/CLI/hellofx
$ javac --module-path /opt/javafx-sdk-21/lib --add-modules=javafx.controls src/hellofx/HelloFX.java -d dist
SHELL
pi@raspberrypi:~ $ sudo -E java -Dmonocle.platform=EGL -Dembedded=monocle -Dglass.platform=Monocle -Duse.egl=true -
Degl.displayid=/dev/dri/card1 -Dmonocle.egl.lib=/opt/javafx-sdk-21/lib/libgluon_drm-1.1.7.so --module-path /opt/javafx-
sdk-21/lib --add-modules javafx.controls -cp dist/. hellofx.HelloFX
https://docs.gluonhq.com/#_introduction 85/191
30/09/2023, 18:48 Gluon Documentation
If running the sample works but shows a black screen, you need to use vc4-fkms-v3d overlay:
SHELL
pi@raspberrypi:~ $ sudo nano /boot/config.txt
...
From your SSH session, you can click Ctrl+C to finish the process.
X11
If you are running with X11, the command line should be now:
SHELL
pi@raspberrypi:~ $ sudo -E java --module-path /opt/javafx-sdk-21/lib --add-modules javafx.controls -cp dist/.
hellofx.HelloFX
This application was created in 2014, in order to demonstrate the use of lambda’s. The author, Stephen Chin, wrote a blogpost
(http://steveonjava.com/java-8-released-lambdas-tutorial/) about this. The application was demonstrated on embedded devices as well.
https://docs.gluonhq.com/#_introduction 86/191
30/09/2023, 18:48 Gluon Documentation
The original code of the application is at https://github.com/steveonjava/MaryHadALittleLambda. We forked it and made some
minor modifications in order to make it work with the JavaFX 11+ and Java 11+ APIs. The new code is at
https://github.com/gluonhq/MaryHadALittleLambda.
It is important to mention that you would typically do all your development on your development system (desktop or laptop). You
can use your IDE and common tools to create, compile and test applications. Once you are happy with the result, you can transfer
your class files over to the embedded device, and run them there.
Download code
The first step is to get the code to your development system and to compile the application.
it is highly recommended doing this on your desktop/laptop, and not on your Raspberry Pi, as it requires much
more resources than typically available on embedded devices. However, the Raspberry Pi 4 is a much more
powerful device than its predecesors, and it can run the same desktop tasks.
It is good practice to test your application on desktop or laptop before transfering the class files to your device. You can run the
application on desktop using:
mvn javafx:run
Quit the application, and check if the class files are in the target/classes directory. There should be about 3 class files in the sample
package.
cd target
scp -r classes [email protected]:/home/pi/Downloads
SHELL
cd ~/Downloads
sudo -E java -Dmonocle.platform=EGL -Dmonocle.egl.lib=/opt/javafx-sdk-21/lib/libgluon_drm-1.1.7.so --module-path
/opt/javafx-sdk-21/lib --add-modules javafx.controls -cp classes/ sample.Main
https://docs.gluonhq.com/#_introduction 87/191
30/09/2023, 18:48 Gluon Documentation
X11
If you use X11, then the demo can be run with:
cd ~/Downloads
sudo -E java --module-path /opt/javafx-sdk-sample.Main/lib --add-modules javafx.controls -cp classes/ sample.Main
In theory, you could install GraalVM for Linux-AArch64 from https://github.com/graalvm/graalvm-ce-builds/releases/, and then
run the GluonFX plugin directly on the Pi. However, given its hardware limitation, and the high CPU/memory requirements of the
native-image process, the recommended way is building the image from a Linux machine (x86-64).
In addition to the Linux requirements, "g++ crosscompiler" needs to be installed on the host machine:
You also need to install the static version of the DRM library to work without a windows manager. Download it from here:
XML
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.21</version>
<configuration>
<target>${gluonfx.target}</target>
<mainClass>${mainClassName}</mainClass>
<remoteHostName>[email protected]</remoteHostName>
<remoteDir>/home/pi/Downloads/native/</remoteDir>
<runtimeArgs>
<arg>-Dmonocle.platform=EGL</arg>
<arg>-Dembedded=monocle</arg>
<arg>-Dglass.platform=Monocle</arg>
<arg>-Degl.displayid=/dev/dri/card1</arg>
</runtimeArgs>
</configuration>
</plugin>
<profiles>
<profile>
<id>pi</id>
<properties>
<gluonfx.target>linux-aarch64</gluonfx.target>
</properties>
</profile>
</profiles>
The native image can be built using mvn -Ppi gluonfx:build . This will run the compilation phase and link the compiled objects
into an executable.
Once the process is finished, you can deploy the binary to your Pi, providing you have correctly defined remoteHostName and
remoteDir :
SHELL
mvn -Ppi gluonfx:install
The install goal makes use of scp and ssh commands to transfer the native image, so SSH must be
enabled on the remote device. It is convenient to add the SSH public key
(https://www.ssh.com/academy/ssh/public-key-authentication#setting-up-public-key-authentication-for-ssh) of your
developing machine to the device, so these commands won’t prompt for password:
ssh-copy-id [email protected]
https://docs.gluonhq.com/#_introduction 88/191
30/09/2023, 18:48 Gluon Documentation
making sure the runtime arguments are properly defined in the pom’s configuration as shown above. To finish the process, press
Ctrl+C.
Or alternatively, you can you can run the native image directly on your Pi from command line with:
SHELL
pi@raspberrypi:~ $ export ENABLE_GLUON_COMMERCIAL_EXTENSIONS=true
pi@raspberrypi:~ $ cd ~/Downloads/native
pi@raspberrypi:~ $ sudo -E ./HelloFX -Dmonocle.platform=EGL -Dembedded=monocle -Dglass.platform=Monocle -
Degl.displayid=/dev/dri/card1
The UI output will be directly sent to the framebuffer, leveraging the KMS/DRM components in the Linux kernel and low-level
graphical drivers.
SHELL
pi@raspberrypi:~ $ export ENABLE_GLUON_COMMERCIAL_EXTENSIONS=true
pi@raspberrypi:~ $ cd ~/Downloads/native
pi@raspberrypi:~ $ sudo -E ./HelloFX
5.7. Web
Experimental
Web port is currently experimental and under active development.
Gluon applications can be compiled to run on the browser. Cross compilation is supported on Linux, Mac and Windows.
CSS is currently not supported. Any instance of adding stylesheets needs to be removed/commented out from
the source.
The main method in HelloFX needs to be updated to pass Application class to the launch method:
JAVA
public static void main(String[] args) {
launch(HelloFX.class, args);
}
XML
<profiles>
...
<profile>
<id>web</id>
<properties>
<gluonfx.target>web</gluonfx.target>
</properties>
</profile>
</profiles>
SHELL SCRIPT
mvn -Pweb gluonfx:build
It produces the index.html and a number of required javascript files under target/gluonfx/x86_64-web/gvm/web .
https://docs.gluonhq.com/#_introduction 89/191
30/09/2023, 18:48 Gluon Documentation
SHELL SCRIPT
mvn -Pweb gluonfx:nativerun
The web profile along with changes required for main method are already in place.
SHELL SCRIPT
mvn -Pweb gluonfx:build gluonfx:nativerun
https://docs.gluonhq.com/#_introduction 90/191
30/09/2023, 18:48 Gluon Documentation
Javadoc
Glisten Javadoc (https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/module-summary.html) contains API
documentation for Gluon Mobile UI toolkit, controls and animation.
Let’s have a look at the hierarchy of components added to generate the user interface.
GlassPane
GlassPane is the root node added automatically by Glisten to the primary scene.
It can be seen as the invisible container for all the nodes that will be added: views, layers, dialogs or toolbars.
Usually, there won’t be any need to access this container directly. But it can be retrieved with
MobileApplication.getInstance().getGlassPane() , if needed.
The first children of the GlassPane container will always be a View and the AppBar .
The nodes on top will be layers (like a side menu), popups or dialogs.
In between, there is a semi-transparent node that will ensure that the node on top appears distinct from the content beneath it,
whenever this is shown. Otherwise it won’t be visible.
https://docs.gluonhq.com/#_introduction 91/191
30/09/2023, 18:48 Gluon Documentation
AppBar
AppBar is a special node acting as a toolbar for branding, navigation, search and other actions.
It is placed at the top of the layout and is generally made up of some buttons (nav icon and action items), a title and a menu.
The content (in terms of nodes and their respective actions) will be managed directly by each of the different views, so the
AppBar will be like a toolbar placeholder for each one of them.
Typically, the developer sets up the AppBar for a given View by overriding its updateAppBar method:
JAVA
public class HomeView extends View {
public HomeView() {
FloatingActionButton fab = new FloatingActionButton();
fab.showOn(this);
}
@Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("nav icon")));
appBar.setTitleText("The AppBar");
appBar.getActionItems().addAll(
MaterialDesignIcon.SEARCH.button(e -> System.out.println("search")),
MaterialDesignIcon.FAVORITE.button(e -> System.out.println("fav")));
appBar.getMenuItems().addAll(new MenuItem("Settings"));
}
}
https://docs.gluonhq.com/#_introduction 92/191
30/09/2023, 18:48 Gluon Documentation
If the developer doesn’t require the AppBar for a given view, it can be hidden by setting its visibility to false:
appBar.setVisible(false) .
Another way to update the AppBar will be adding a listener to each view’s showingProperty :
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> {
View view = new View(new Label("Hello Glisten!"));
view.showingProperty().addListener((obs, oldValue, newValue) -> {
if (newValue) {
AppBar appBar = MobileApplication.getInstance().getAppBar();
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("nav icon")));
}
});
return view;
});
}
}
View
View is a Glisten container that will allow adding nodes in its top, left, right, bottom, and center positions.
Usually a View instance is created by providing a node for its content. This instance is added to a factory of views with a name, so
the Glisten UI can load and unload them on demand.
Home View
By default, the home view will be the first view displayed when the stage is shown.
It has no predefined content, so this view has to be designed by the developer, but its name is already assigned:
MobileApplication.HOME_VIEW .
https://docs.gluonhq.com/#_introduction 93/191
30/09/2023, 18:48 Gluon Documentation
This short snippet will create a very simple mobile application with a single view:
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> new View(new Label("Hello Glisten!")));
}
Typically, the developer of a Glisten application will only override the init() method, in order to add one or more View objects,
and provide them as factories that can be called on-demand. The MobileApplication implementation will take care of the rest:
when start() is called, it will create a Scene , adding a root node to it. Finally, it will put the scene in the primary stage and
show it.
When the runtime calls init() , we just provide a Supplier<View> for HOME_VIEW , but the view is not instantiated at this point
yet.
Then start(Stage) is called. At this moment, MobileApplication creates an instance of Scene , sets the root an empty
instance of a GlassPane and adds the scene to the primary stage.
After some internal settings, like adding the default Swatch , it calls switchView("HOME_VIEW") . This is the moment when an
instance of the home view is created and added to the pane.
https://docs.gluonhq.com/#_introduction 94/191
30/09/2023, 18:48 Gluon Documentation
Before showing the stage, there’s a call to the postInit(Scene) method, that can be used by the developer for one time
initialization.
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> new View(new CheckBox("I like Glisten")));
}
@Override
public void postInit(Scene scene) {
Swatch.GREEN.assignTo(scene);
}
In case the developer wants to change the swatch for each view, this can be done by listening to the changes in the
viewProperty of a MobileApplication instance, and assigning the corresponding Swatch:
https://docs.gluonhq.com/#_introduction 95/191
30/09/2023, 18:48 Gluon Documentation
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> new View(new Label("Hello Glisten!")) {
{
FloatingActionButton fab = new FloatingActionButton(MaterialDesignIcon.ADD_BOX.text, e ->
switchView(OTHER_VIEW));
fab.showOn(this);
}
});
addViewFactory(OTHER_VIEW, () -> new View(new CheckBox("I like Glisten")) {
{
FloatingActionButton fab = new FloatingActionButton(MaterialDesignIcon.ADD_CIRCLE_OUTLINE.text, e ->
switchView(HOME_VIEW));
fab.showOn(this);
}
});
Another way to accomplish the same will be by adding a listener to each view’s showingProperty :
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> {
View view = new View(new RadioButton("Glisten style"));
FloatingActionButton fab = new FloatingActionButton(MaterialDesignIcon.ADD_BOX.text, e ->
switchView(OTHER_VIEW));
fab.showOn(view);
view.showingProperty().addListener((obs, oldValue, newValue) -> {
if (newValue) {
Swatch.RED.assignTo(view.getScene());
}
});
return view;
});
addViewFactory(OTHER_VIEW, () -> {
View view = new View(new CheckBox("I like Glisten"));
FloatingActionButton fab = new FloatingActionButton(MaterialDesignIcon.ADD_CIRCLE_OUTLINE.text, e ->
switchView(HOME_VIEW));
fab.showOn(view);
view.showingProperty().addListener((obs, oldValue, newValue) -> {
if (newValue) {
Swatch.TEAL.assignTo(view.getScene());
}
});
return view;
});
}
}
https://docs.gluonhq.com/#_introduction 96/191
30/09/2023, 18:48 Gluon Documentation
Creating a View
As we have already seen in the previous code snippets, there are several possible ways to create a View .
Extending View
A custom view can be created by extending View . This allows for more complex views, for adding a view transition, customizing
the AppBar…
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> new HomeView());
addViewFactory(OTHER_VIEW, () -> new View(new CheckBox("I like Glisten")));
}
@Override
public void postInit(Scene scene) {
Swatch.LIGHT_GREEN.assignTo(scene);
}
public HomeView() {
setCenter(new Label("Hello Glisten!"));
}
@Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> switchView(OTHER_VIEW)));
appBar.setTitleText("Home View");
}
}
}
https://docs.gluonhq.com/#_introduction 97/191
30/09/2023, 18:48 Gluon Documentation
Adding content
A View can be created by using one of its constructors, where the content is set. Any Node will work as content for the View .
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> new View(new Home()) {
@Override protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> switchView(OTHER_VIEW)));
appBar.setTitleText("Home View");
}
});
}
public Home() {
setSpacing(30);
setAlignment(Pos.CENTER);
getChildren().addAll(new Label("Hello Glisten!"), new Button("Click me"));
}
}
}
https://docs.gluonhq.com/#_introduction 98/191
30/09/2023, 18:48 Gluon Documentation
XML
<?xml version="1.0" encoding="UTF-8"?>
<?import com.gluonhq.charm.glisten.mvc.View?>
<?import javafx.scene.control.Button?>
Load the fxml file using the FXMLLoader . Assuming the home.fxml file is under the same package as the application, but in the
'resources' directory:
https://docs.gluonhq.com/#_introduction 99/191
30/09/2023, 18:48 Gluon Documentation
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> {
try {
return (View)FXMLLoader.load(getClass().getResource("views/home_1.fxml"));
} catch (Exception ex) { }
return null;
});
addViewFactory(OTHER_VIEW, () -> new View(new CheckBox("I like Glisten")));
viewProperty().addListener((obs, ov, nv) -> {
AppBar appBar = MobileApplication.getInstance().getAppBar();
switch(nv.getName()) {
case HOME_VIEW:
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> switchView(OTHER_VIEW)));
appBar.setTitleText("Home View");
Swatch.TEAL.assignTo(appBar.getScene());
break;
case OTHER_VIEW:
appBar.setVisible(false);
break;
}
});
}
}
https://docs.gluonhq.com/#_introduction 100/191
30/09/2023, 18:48 Gluon Documentation
Afterburner framework
Adding the dependency to the build.gradle script, allows using this MVP framework from Adam Bien
(http://afterburner.adam-bien.com).
GROOVY
dependencies {
compile 'com.airhacks:afterburner.mfx:1.6.3'
}
The view i.e. HomeView . An empty class that just extends FXMLView .
In the presenter, controls can be added to the view, like a Button to trigger some action when the user clicks on it.
A transition can be set for switching views from a large list of available transitions (see the Charm JavaDoc
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/com/gluonhq/charm/glisten/animation/package-summary.html)). In case
no transition is desired, the developer can select NoTransition() .
JAVA
<View fx:id="home" xmlns="http://javafx.com/javafx/11" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="HomePresenter">
<center>
<StackPane>
<Button text="Click!" onAction="#onClick"/>
</StackPane>
</center>
</View>
The presenter can be created to directly interact with the nodes in the FXML.
https://docs.gluonhq.com/#_introduction 101/191
30/09/2023, 18:48 Gluon Documentation
JAVA
public class HomePresenter implements Initializable {
@FXML
private View home;
@Override
public void initialize(URL url, ResourceBundle rb) {
FloatingActionButton fab = new FloatingActionButton();
fab.setOnAction(e -> {
System.out.println("FAB click");
});
fab.showOn(home);
Swatch.PURPLE.assignTo(home.getScene());
}
});
}
@FXML
public void onClick() {
System.out.println("click");
}
}
JAVA
public class HomeView extends FXMLView {
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> {
final HomeView homeView = new HomeView();
return (View) homeView.getView();
});
}
}
https://docs.gluonhq.com/#_introduction 102/191
30/09/2023, 18:48 Gluon Documentation
In order to perform some actions while the transition is running or when it finishes, a custom ActionEvent can be provided to
the end of the transition.
This can be done as well based on the LifecycleEvent events. The following code snippet will set the view transparent to mouse
clicks just during the time it is added to the scene and the transition ends.
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> {
final HomeView homeView = new HomeView();
final View view = (View) homeView.getView();
view.addEventHandler(LifecycleEvent.SHOWING, e ->
view.setMouseTransparent(true));
view.addEventHandler(LifecycleEvent.SHOWN, e ->
view.setMouseTransparent(false));
return view;
});
}
}
6.1.3. Layers
A Layer is an overlay that can be shown above any View.
https://docs.gluonhq.com/#_introduction 103/191
30/09/2023, 18:48 Gluon Documentation
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
addViewFactory(HOME_VIEW, () -> new View(new Label("Hello Glisten!")) {
@Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> showLayer("New Layer")));
}
});
Layers can also be be shown and hidden, without the use of factories, by calling show() and hide() respectively.
JAVA
SidePopupView sidePopupView = new SidePopupView(stackPane);
sidePopupView.show();
By calling setBackgroundFade(double) the developer will be able to fade the background of a layer to a darker color, obscuring
the main application and drawing focus to the popup.
Creating a Layer
Developers can create custom Layer nodes. This is a minimal implementation, including a faded background when the layer is
shown.
https://docs.gluonhq.com/#_introduction 104/191
30/09/2023, 18:48 Gluon Documentation
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
{
setBackgroundFade(0.5);
root = new StackPane(new Button("A custom layer"));
root.setStyle("-fx-background-color: white;");
getChildren().add(root);
}
@Override
public void layoutChildren() {
super.layoutChildren();
root.setVisible(isShowing());
if (!isShowing()) {
return;
}
root.resize(size, size);
resizeRelocate((glassPane.getWidth() - size)/2, (glassPane.getHeight()- size)/2, size, size);
}
});
}
}
Layers can also be created and shown without using the factory methods.
https://docs.gluonhq.com/#_introduction 105/191
30/09/2023, 18:48 Gluon Documentation
JAVA
public class MyApp extends MobileApplication {
@Override
public void init() {
{
setBackgroundFade(0.5);
root = new StackPane(new Button("A custom layer"));
root.setStyle("-fx-background-color: white;");
getChildren().add(root);
}
@Override
public void layoutChildren() {
super.layoutChildren();
root.setVisible(isShowing());
if (!isShowing()) {
return;
}
root.resize(size, size);
resizeRelocate((glassPane.getWidth() - size)/2, (glassPane.getHeight()- size)/2, size, size);
}
};
}
}
https://docs.gluonhq.com/#_introduction 106/191
30/09/2023, 18:48 Gluon Documentation
However, Glisten already provides a series of built-in layers, so creating custom layers won’t be necessary in most of the
occasions.
MenuPopupView
MenuSidePopupView
PopupView
SidePopupView
For a description of each layer, check the API documentation: Glisten layers
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/com/gluonhq/charm/glisten/layout/layer/package-summary.html).
Many Glisten controls use layers internally, including FloatingActionButton, NavigationDrawer, Snackbar and Toast.
6.1.4. UI Controls
Glisten comes with a collection of cross platform UI controls based on the Material Design Specification: Glisten Controls
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/module-summary.html).
https://docs.gluonhq.com/#_introduction 107/191
30/09/2023, 18:48 Gluon Documentation
An overview of the CSS style classes and properties that are available to users of the Gluon Charm Glisten library. Users of Glisten
CSS should be familiar with the JavaFX CSS functionality (https://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html).
Light Theme
CSS
.root {
-fx-background: white;
-fx-text-fill: -text-light;
-fx-prompt-text-fill: rgba(0,0,0,.3);
-text-disabled: -text-disabled-light;
-background-disabled:rgba(0,0,0,.12);
-background-fill: -text-light;
-flat-button-hover-background: rgba(#999999,.2);
-flat-button-pressed-background: rgba(#999999,.4);
-flat-button-disabled-fill: rgba(#000000,.26);
}
Dark Theme
CSS
.root {
-fx-background: #333333;
-fx-text-fill: -text-dark;
-fx-prompt-text-fill: rgba(255,255,255,.3);
-text-disabled: -text-disabled-dark;
-background-disabled:rgba(255,255,255,.12);
-background-fill: -text-dark;
-flat-button-hover-background: rgba(#CCCCCC,.15);
-flat-button-pressed-background: rgba(#CCCCCC,.25);
-flat-button-disabled-fill: rgba(#FFFFFF,.3);
}
Swatches
Perhaps most importantly, Glisten supports swatches, where each swatches populates a series of pre-specified CSS properties
which can be used within your own CSS. The properties that are populated for each swatch are the following:
CSS
-primary-swatch-50
-primary-swatch-100
-primary-swatch-200
-primary-swatch-300
-primary-swatch-400
-primary-swatch-500
-primary-swatch-600
-primary-swatch-700
-primary-swatch-800
-primary-swatch-900
-alternate-swatch-100
-alternate-swatch-200
-alternate-swatch-400
-alternate-swatch-700
Each of these properties is simply a color along a certain color spectrum. All swatches provided by Glisten are based on the
Material Design color style guide (https://www.google.com/design/spec/style/color.html). The Glisten CSS files do not typically make use of
all swatch colors, so it is also advised that any use of these colors be restrained, outside of the -primary-swatch-500 , and
possibly -primary-swatch-200 , -primary-swatch-600 , and -primary-swatch-700 .
An example of how such a property could be used is shown in the sample code below:
https://docs.gluonhq.com/#_introduction 108/191
30/09/2023, 18:48 Gluon Documentation
CSS
.button {
-fx-background-color: -primary-swatch-500;
}
.button:hover {
-fx-background-color:-primary-swatch-600;
}
Other Properties
There are a number of other properties that are available to use. Some of these are custom Glisten properties, but many are
standard JavaFX CSS properties that Glisten simply modifies to the appropriate value. Some notable properties include the
following (refer to the JavaFX CSS Reference Guide (https://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html) for more
details of any that start with -fx- ) :
-fx-text-fill : This is populated based on the theme that is currently set (i.e. light or dark).
Text Fill
It is important to understand how text fill works in Glisten, as the underlying JavaFX CSS engine is significantly more powerful
than normal CSS engines. In particular, when it comes to deciding what color text fill to use, you can use JavaFX CSS laddering to
decide. In other words, it is never a good idea to use -fx-text-fill directly, as -fx-text-fill does not take into account the
background color behind the text (so it is possible that the text is unreadable).
In cases where a custom text fill is desired, it is much better to do something such as the following:
CSS
.button {
-fx-background-color: -primary-swatch-500;
-fx-text-fill: ladder(-primary-swatch-500, -text-dark 49%, -text-light 50%)
}
This code states to use -text-dark or -text-light , depending on the darkness of the first value, in this case -primary-
swatch-500 . The result of this is that when -primary-swatch-500 is a very light color (such as a bright yellow), the -fx-text-
fill will be -text-light (and therefore appear as a dark color). When -primary-swatch-500 is a very dark color, -text-
dark is used, and is therefore a light color that is readable on a dark background.
There exists a class called GlistenStyleClasses that is located in the com.gluonhq.glisten.visual package. This class
provides a number of predefined style classes that can be applied to a control, via one of two methods:
/*
* TOGGLE_BUTTON_SWITCH is a static import from GlistenStyleClasses.
* It is simply a String consisting of 'switch'.
*/
toggleVisibilityButton.getStyleClass.add(TOGGLE_BUTTON_SWITCH);
/*
* Both applyStyleClass and TOGGLE_BUTTON_SWITCH are static
* imports from GlistenStyleClasses
*/
applyStyleClass(toggleVisibilityButton, TOGGLE_BUTTON_SWITCH);
Both approaches are more or less equivalent, but the second approach is recommended.
Once these additional style classes have been applied, both Glisten CSS and your own CSS can be applied as applicable. For
example, a button that has been styled to be flat (using GlistenStyleClasses.BUTTON_FLAT ) will be able to receive alternate
styling via css such as the following:
https://docs.gluonhq.com/#_introduction 109/191
30/09/2023, 18:48 Gluon Documentation
CSS
.button.flat {
...
}
Of course, as noted, any styling of UI controls based on style classes from the GlistenStyleClasses class will be styled
differently by Glisten CSS, so there is no need (unless desired) to apply additional styling.
What follows is a list of additional CSS style classes that are available to some UI controls:
Button
Buttons have the CSS style class .button . There are the following additional style classes that are available in Glisten:
Toggle Button
Toggle buttons have the CSS style class .toggle-button .
switch TOGGLE_BUTTON_SWITCH The switch style class results in toggle button that
matches the Material Design Switch
(http://www.google.com/design/spec/components/selection-
controls.html#selection-controls-switch)
representation.
https://docs.gluonhq.com/#_introduction 110/191
30/09/2023, 18:48 Gluon Documentation
This page provides information about the releases of Charm Glisten, including known issues, limitations, and general advisories.
Please review the notes before using the library.
To discuss issues or ideas with other developers, please reach out to us (http://gluonhq.com/about-us/contact-us/).
6.1.0
Glisten 6.1.0 deprecates MobileApplication and provides a new AppManager that will manage the JavaFX Application flow and
integrate the Glisten features.
The following code snippet shows the implementation of a typical Application class that includes the application manager:
JAVA
public class MyApplication extends Application {
@Override
public void init() throws Exception {
appManager.addViewFactory(HOME_VIEW, () -> new View() {...});
}
@Override
public void start(Stage primaryStage) throws Exception {
appManager.start(primaryStage);
}
This change is backward compatible, and you can still use Charm 6.1.0+ with MobileApplication , which will be marked as
deprecated on your IDE.
If you have an existing project, you can simply bump your Glisten dependencies, without needing to modify your code.
If you use the Glisten-Afterburner framework, GluonPresenter has been deprecated too. Any presenter class doesn’t need to
extend from GluonPresenter<Application> , but it is still supported for compatibility reasons.
However, it is advisable to adapt to the new API and introduce the AppManager as shown above or in the different Gluon Samples
(https://github.com/gluonhq/gluon-samples).
Migration guidelines
The required steps to do the migration are:
Application class
Change MobileApplication to Application
Add the AppManager and initialize it, passing the postInit callback.
Remove the @Override annotation from the postInit method, and optionally make it private.
Override the Application::start method, which should simply call the start method of the application manager and pass
it the stage parameter.
The home view name should be taken from AppManager.HOME_VIEW , and the view factories can be added from
AppManager::addViewFactory (same for AppManager::addLayerFactory ).
If you use an AppViewManager to manage the view creation, you don’t need to pass it the Application instance, as the
AppManager instance can be always accessed via AppManager.getInstance() .
Presenter class
Remove extends GluonPresenter<YourApplication>
6.0.0
Glisten 6.0.0 comes with JavaFX 11 support.
5.0.0
Glisten 5.0.0 release has a significant number of breaking changes. For a detailed document on how to migrate to 5.0.0, please
refer Migration Guide to Gluon Mobile 5 (https://docs.gluonhq.com/charm/6.0.0/migration_guide_5.html).
New Features
https://docs.gluonhq.com/#_introduction 111/191
30/09/2023, 18:48 Gluon Documentation
Package Changes
FAB has been moved from com.gluonhq.charm.glisten.layout.layer to com.gluonhq.charm.glisten.control
API changes
MobileLayoutPane has been removed
GlassPane and View extend from BorderPane instead of MobileLayoutPane
GlassPane and View no longer expose the list of layers. The method getLayers() has been removed
View no longer exposes a name property
View’s show transition factory has been changed from Function<View,Transition> to
Function<View,MobileTransition>
Layers can be shown using the new API. In order to show and hide a layer, call show()
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/com/gluonhq/charm/glisten/layout/Layer.html#show) and hide()
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/com/gluonhq/charm/glisten/layout/Layer.html#hide) respectively
ActionItems
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/com/gluonhq/charm/glisten/control/BottomNavigation.html#getActionItems)
in BottomNavigation only accept instances of BottomNavigationButton instead of Node
Deprecated method createButton()
(http://docs.gluonhq.com/charm/javadoc/4.4.0/com/gluonhq/charm/glisten/control/BottomNavigation.html#createButton-java.lang.String-
javafx.scene.Node-javafx.event.EventHandler-)
has been removed from BottomNavigation
New constructor has been added to most of the Transitions to help developers define custom duration
PopupView gives more control to the developer by allowing them to control the side
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/com/gluonhq/charm/glisten/layout/layer/PopupView.html#sideProperty)
and padding
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/com/gluonhq/charm/glisten/layout/layer/PopupView.html#popupPaddingProperty)
of the popup. Additionally, height and width of the popup can now be changed using the pref*, min* and max* properties.
PopupView has dropped autofix property
(http://docs.gluonhq.com/charm/javadoc/4.4.0/com/gluonhq/charm/glisten/layout/layer/PopupView.html#autoFixProperty). AutoFix is now set
to true for all usage of PopupView.
AutoCompleteTextField has a new converter
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/com/gluonhq/charm/glisten/control/AutoCompleteTextField.html#converterProperty)
for easy conversions between strings and objects.
FAB can bind to a View using showOn(View view)
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/com/gluonhq/charm/glisten/control/FloatingActionButton.html#showOn-
com.gluonhq.charm.glisten.mvc.View-)
New methods have been added to NavigationDrawer to open and close the drawer - open()
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/com/gluonhq/charm/glisten/control/NavigationDrawer.html#open)
and close()
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.charm.glisten/com/gluonhq/charm/glisten/control/NavigationDrawer.html#close)
Bug Fixes
MenuPopupView and AutoCompletePopup support text wrapping
https://docs.gluonhq.com/#_introduction 112/191
30/09/2023, 18:48 Gluon Documentation
AutoCompleteTextField selection of a node from the popup, converts the selected object to a string and shows it in the
TextField.
Animation duration for PopupView and SidePopupView has been reduced to match Material Design specification
Floating text translates to the top when TextField has text, irrespective of state of focus property
Nag window no longer throws exception when no home view has been defined
ToggleButtonGroup minWidth should never outgrow prefWidth
SettingsPane is updated after any change in the options list
Layer has been updated to fix multiple issues
Javadoc has been updated to fix multiple issues
https://docs.gluonhq.com/#_introduction 113/191
30/09/2023, 18:48 Gluon Documentation
7. Device Interface
Open Source
Attach is open source, and licensed under the GPL license. Its source code is hosted under Gluon organization in Github
(https://github.com/gluonhq/attach).
Gluon Attach addresses the integration with low-level platform APIs. Using Attach, you write code that accesses device and
hardware features using a uniform, platform-independent API. At runtime, the appropriate implementation (desktop, android,
ios) makes sure the platform specific code is used to deliver the functionality.
The following sections provide a high-level overview of the current Attach features.
More information can be found in the Gluon website (https://gluonhq.com/products/mobile/attach/), and you can find different samples
(https://github.com/gluonhq/gluon-samples) using different Attach services.
This library is being actively extended, so if you think an important feature is missing, feel free to log an issue or contribute a pull
request at our Attach repository (https://github.com/gluonhq/attach).
Attach project is split up into different services. Each service takes care of implementing a certain hardware or device feature,
like access to general device information, information about the display, outputs of different sensors that are found on the device,
etc.
When creating a project with the Gluon IDE plugin, the attachList is already available and pre-configured with the following
four services: display, lifecycle, statusbar and storage.
The list of services can be extended with any of the available services.
For instance, the Position service, that allows accessing the device’s GPS, can be added as follows:
XML
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>position</artifactId>
<version>${attach.version}</version>
</dependency>
...
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.21</version>
<configuration>
<target>${gluonfx.target}</target>
<attachList>
...
<list>position</list>
</attachList>
<mainClass>${main.class}</mainClass>
</configuration>
</plugin>
Each service can be accessed via its create() method, which returns an Optional which contains an instance of the requested
service.
The returned optional object might be empty if the runtime platform has no available implementation for that specific service.
https://docs.gluonhq.com/#_introduction 114/191
30/09/2023, 18:48 Gluon Documentation
JAVA
PositionService positionService = PositionService.create().orElseThrow(() -> new RuntimeException("PositionService not
available."));
positionService.positionProperty().addListener((obs, ov, nv) -> {
System.out.println("Latest known GPS coordinates from device: " + nv.getLatitude() + ", " + nv.getLongitude());
});
positionService.start();
Another useful class is the enum com.gluonhq.attach.util.Platform , which provides an easy way to detect what platform the
application is currently running on: ANDROID , IOS or DESKTOP .
https://docs.gluonhq.com/attach/javadoc/4.0.18
Android
For instance, the Dialer service
(https://docs.gluonhq.com/attach/javadoc/4.0.18/com.gluonhq.attach.dialer/com/gluonhq/attach/dialer/DialerService.html) requires a
CALL_PHONE permission included in the Android manifest file:
XML
<manifest ...>
<uses-permission android:name="android.permission.CALL_PHONE"/>
...
</manifest>
The AndroidManifest.xml file is generated for the project with the gluonfx:package goal, and it is available at
target/gluonfx/aarch64-android/gensrc/android .
GluonFX plugin takes care of most of these modifications, and usually, there is no need to modify this manifest.
Only in case you need to make any change, copy this file to src/android and make any modification that might be needed. For
every new run of gluonfx:package , the manifest found at src/android will be used.
iOS
For instance, the Position service
(https://docs.gluonhq.com/attach/javadoc/4.0.18/com.gluonhq.attach.position/com/gluonhq/attach/position/PositionService.html) requires a few
keys included in the Default-Info.plist file:
XML
<plist ...>
<dict>
...
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location services</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs location services</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs bluetooth services</string>
</dict>
</plist>
The Default-Info.plist file is generated for the project with the gluonfx:link goal, and it is available at
target/gluonfx/arm64-ios/gensrc/ios .
GluonFX plugin takes care of most of these modifications, and usually, there is no need to modify this plist file.
Only in case you need to make any change, for instance, adding a new key or modifying the description of an existing one, you
can create a partial plist file under src/main/resources/META-INF/substrate/ios/Partial-Info.plist , and apply the
required changes, like:
https://docs.gluonhq.com/#_introduction 115/191
30/09/2023, 18:48 Gluon Documentation
XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>My custom description</string>
</dict>
</plist>
Alternatively, you can copy target/gluonfx/arm64-ios/gensrc/ios/Default-Info.plist into src/ios and make any
modification that might be needed. For every new run of gluonfx:link , the plist found at src/ios will be used.
If you want to build Attach from code, you need JDK 11+, Xcode 11+, the Android SDK 29 and the Android NDK.
export ANDROID_SDK=$ANDROID_HOME
export ANDROID_NDK=$ANDROID_HOME/ndk-bundle
./gradlew clean build publishToMavenLocal
It will build all services for all possible platforms (desktop, iOS and Android), and it will install them to your .m2 local repository.
You can try to build from Linux or Windows, however the iOS implementation won’t be built.
Single service builds can be done as well. For instance, to build and install locally the Display service, run:
./gradlew :display:publishToMavenLocal
The goal is to produce an artifact that can be used as dependency by the GluonFX plugin
(https://docs.gluonhq.com/#_gluonfx_plugin_for_maven) when creating a native image that will be deployed to the target platform.
Such artifact (a jar file), bundles Java classes, configuration files and native libraries.
The builds are done with the nativeBuild task. For instance, to build the native libraries for the three platforms, run:
./gradlew :display:nativeBuild
./gradlew :display:iosBuild
Desktop
For a given service, its Java code (GraalVM) is compiled against JDK 11+, and with the desktopJar task it is added to the
${service}-${version}-desktop.jar file.
Reflection and jni configuration json files are added under META-INF/substrate/config (see config files
(https://docs.gluonhq.com/#_jni_and_reflection)).
Native code, if present, will be compiled, and the native library will be added to the jar to a native folder.
iOS
For a given service, its Java code (GraalVM) is compiled against JDK 11+, and with the iosJar task it is added to the
${service}-${version}-ios.jar file.
Reflection and jni configuration json files are added under META-INF/substrate/config (see config files
(https://docs.gluonhq.com/#_jni_and_reflection)).
https://docs.gluonhq.com/#_introduction 116/191
30/09/2023, 18:48 Gluon Documentation
Native code using Objective-C and found for each service under:
def osSources = []
osSources = "$projectDir/src/main/native/ios/${name}.m"
is compiled and linked, using the iOS SDK with certain flags and iOS frameworks, to create a native library under:
Android
For a given service, its Java code (GraalVM) is compiled against JDK 11+, and with the androidJar task it is added to the
${service}-${version}-android.jar file.
Reflection and jni configuration json files are added under META-INF/substrate/config (see config files
(https://docs.gluonhq.com/#_jni_and_reflection)).
def nativeSourcesDir = []
nativeSourcesDir = "$projectDir/src/main/native/android/c/*.c"
is compiled and linked, using the Android SDK with certain flags, to create a native library under:
Finally, Java code for Android (Dalvik) is compiled against JDK 1.7, using the Android SDK. An Android library project is generated
and bundled under META-INF/substrate/dalvik/${name}.aar . It will contain mainly a jar with classes and an
AndroidManifest.xml file with the service requirements (like permissions or activities).
XML
<!-- dependencies -->
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>display</artifactId>
<version>4.0.18</version>
</dependency>
If needed, the platform classifier can be used to run the project on HotSpot with the JavaFX Maven plugin:
XML
<!-- dependencies -->
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>display</artifactId>
<version>4.0.18</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>display</artifactId>
<version>4.0.18</version>
<classifier>desktop</classifier>
<scope>runtime</scope>
</dependency>
This can be done with the Maven profiles, so these platform dependencies are only activated for the correct profile.
When running the GluonFX plugin (https://docs.gluonhq.com/#_gluonfx_plugin_for_maven) goals, for each Attach service, the plugin will
apply the correct classifier based on the target and resolve the artifact.
https://docs.gluonhq.com/#_introduction 117/191
30/09/2023, 18:48 Gluon Documentation
Then, for every ${service}-${version}-${platform}.jar file found in the classpath, the plugin will:
add the Java classes (GraalVM) to the native-image classpath to be compiled with gluonfx:compile ,
merge the configuration json files with others found in the classpath,
extract the native libraries into target/gluonfx/$arch-$os/gvm/lib/lib${name}.a , so they can be linked with
gluonfx:link ,
and when targeting Android, extract the Android libraries ( .aar ) into
target/gluonfx/$arch-$os/gvm/android_project/libs . These libraries can be added as regular dependencies for the
Android project when creating the apk/aab bundles in the gluonfx:package goal.
https://docs.gluonhq.com/#_introduction 118/191
30/09/2023, 18:48 Gluon Documentation
8. Data Binding
Open Source
Connect is open source, and licensed under the BSD-3 license. Its source code is hosted under Gluon organization in Github
(https://github.com/gluonhq/connect).
Gluon Connect is a client-side library that simplifies binding your data from any source and format to JavaFX UI controls. It works
by retrieving data from a data source and converting that data from a specific format into JavaFX observable lists and objects. It is
designed to allow developers to easily add support for custom data sources and data formats.
By default, Gluon Connect already provides easy-to-use implementations for the most commonly used data sources:
File provider
REST provider
languages.json
JSON
[
{"name":"Java","ratings":20.956},
{"name":"C","ratings":13.223},
{"name":"C++","ratings":6.698},
{"name":"C#","ratings":4.481},
{"name":"Python","ratings":3.789}
]
And the following POJO that will map the JSON objects from the file above to a Java object:
Language.java
JAVA
public class Language {
private String name;
private double ratings;
We can then assign a list of programming language objects to a JavaFX ListView control with the following code:
JAVA
// create a FileClient to the specified File
FileClient fileClient = FileClient.create(new File("languages.json"));
// create a JSON converter that converts the nodes from a JSON array into language objects
InputStreamIterableInputConverter<Language> converter = new JsonIterableInputConverter<>(Language.class);
https://docs.gluonhq.com/#_introduction 119/191
30/09/2023, 18:48 Gluon Documentation
Retrieving a single object from a file resource looks similar to retrieving a list. Assume that we have a user.json file with the
following JSON content:
user.json
JSON
{"name":"Duke","subscribed":true}
And the following POJO for mapping the JSON object to a Java object:
User.java
JAVA
public class User {
private String name;
private boolean subscribed;
The user object can then be retrieved from the JSON file with the following code:
JAVA
// create a FileClient to the specified File
FileClient fileClient = FileClient.create(new File("user.json"));
// create a JSON converter that converts a JSON object into a user object
InputStreamInputConverter<User> converter = new JsonInputConverter<>(User.class);
JAVA
// create an instance of a User to store
User user = new User();
user.setName("Duchess");
user.setSubscribed(false);
// create a JSON converter that converts the user object into a JSON object
OutputStreamOutputConverter<User> outputConverter = new JsonOutputConverter<>(User.class);
https://docs.gluonhq.com/#_introduction 120/191
30/09/2023, 18:48 Gluon Documentation
JAVA
// create a RestClient to the specific URL
RestClient restClient = RestClient.create()
.method("GET")
.host("https://api.stackexchange.com")
.path("/2.2/errors");
As you can see, we didn’t specify any Converter. That is because the RestClient will try to find a suitable Converter based on the
Content-Type response header. If the response header is not specified, it assumes that the response will be formatted in JSON.
Sometimes, the automatic detection of the Converter fails or you need to use a custom Converter. In that case, you use the second
method for creating a ListDataReader where you provide the converter that you want to use.
JAVA
// create a RestClient to the specific URL
RestClient restClient = RestClient.create()
.method("GET")
.host("https://api.stackexchange.com")
.path("/2.2/errors");
JAVA
// create a RestClient to the specific URL
RestClient restClient = RestClient.create()
.method("GET")
.host("https://api.stackexchange.com")
.path("/2.2/questions/36243147")
.queryParam("order", "desc")
.queryParam("sort", "activity")
.queryParam("site", "stackoverflow");
8.3.1. Concepts
Gluon Connect consists of the following basic concepts:
DataSource
The DataSource defines where Gluon Connect should read and/or store the data. The DataSource makes use of the standard
java.io.InputStream and java.io.OutputStream classes. It is split up into two parts: the InputDataSource
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/source/InputDataSource.html) that provides an
InputStream to read the data from; the OutputDataSource
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/source/OutputDataSource.html) that provides an
https://docs.gluonhq.com/#_introduction 121/191
30/09/2023, 18:48 Gluon Documentation
OutputStream to write the data into. For convenience purposes, there is also an IODataSource
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/source/IODataSource.html) that has access to both
the InputStream and the OutputStream .
Gluon Connect includes by default two DataSource implementations:
FileDataSource (https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/source/FileDataSource.html):
reads and writes data from a File that is accessible from the local system
RestDataSource (https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/source/RestDataSource.html):
reads and writes data from an HTTP URL resource
Converter
The Converter is able to convert data from an Object into a specific data format or convert data from a certain data format back
into an Object. The Converter is split up into three different parts:
InputConverter (https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/converter/InputConverter.html)
: converts data into an object
OutputConverter
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/converter/OutputConverter.html): converts an
object into data
IterableInputConverter
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/converter/IterableInputConverter.html): provides
an Iterator that converts data into a list of objects
All three interfaces do not specify where the data is coming from. This allows for maximum extensibility. Gluon Connect provides
an abstract implementation for these Converters. The InputConverter and IterableInputConverter both have an
implementation where the data to convert is taken from an InputStream . The OutputConverter has an analogous
implementation that converts the object by writing into an OutputStream .
Gluon Connect provides Converter implementations for JSON and String out of the box.
DataProvider
The DataProvider (https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/provider/DataProvider.html) is
the class that will ultimately provide the observable lists or objects that you can use with your JavaFX UI controls. Gluon Connect
provides a custom observable list and observable object called GluonObservableList
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/GluonObservableList.html) and
GluonObservableObject
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/GluonObservableObject.html) respectively.
retrieveList
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/provider/DataProvider.html#retrieveList-
com.gluonhq.connect.provider.ListDataReader-)
: this retrieves a GluonObservableList using a ListDataReader
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/provider/ListDataReader.html)
storeObject
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/provider/DataProvider.html#storeObject-T-
com.gluonhq.connect.provider.ObjectDataWriter-)
: this stores an object using an ObjectDataWriter
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/provider/ObjectDataWriter.html) and responds
with a GluonObservableObject
retrieveObject
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/provider/DataProvider.html#retrieveObject-
com.gluonhq.connect.provider.ObjectDataReader-)
: this retrieves an existing Object using an ObjectDataReader
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/provider/ObjectDataReader.html) and responds
with a GluonObservableObject
removeObject
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/provider/DataProvider.html#removeObject-
com.gluonhq.connect.GluonObservableObject-com.gluonhq.connect.provider.ObjectDataRemover-)
: this removes a GluonObservableObject using an ObjectDataRemover
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/provider/ObjectDataRemover.html)
https://docs.gluonhq.com/#_introduction 122/191
30/09/2023, 18:48 Gluon Documentation
All these methods will return the GluonObservableList or GluonObservableObject instances immediately. The actual process
of retrieving, storing or removing the list or object happens asynchronously in a background thread. For example, when
retrieving a list or object you can listen for the initialized property
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/GluonObservable.html#initializedProperty--) to know
when the list or object is fully initialized by the provided reader.
If we for instance look at the retrieveObject method, we see that it has an ObjectDataReader as parameter. The
ObjectDataReader is an interface that is able to create a new instance of GluonObservableObject and read an object of a
certain type. The source where the object is read from and the format of the data is completely left open to the actual
implementing classes. Usually though, you will combine a DataSource with a Converter to implement this functionality. The most
basic DataProvider that you can use as an ObjectDataReader is the InputStreamObjectDataReader . This class takes an
InputSource as the DataSource and an InputStreamConverter as the Converter. When an instance of
InputStreamObjectDataReader is passed into the Dataprovider.retrieveObject method, the object will be retrieved by
getting the InputStream from the InputSource and then pass the InputStream to the InputStreamConverter , which will read
the data from the InputStream and convert it into the desired object.
8.3.2. Sample
The following sample will use the three concepts by providing a DataSource that reads from a classpath resource, a Converter
that converts JSON into objects and a DataProvider that combines the DataSource with the Converter to get access to
GluonObservable objects. The complete sample for this can be found in our gluon-samples repository on GitHub:
https://github.com/gluonhq/gluon-samples. Inside the repository, look for the folder named gluon-connect-basic-usage .
Retrieving a list
Let’s presume we have the following simple languages.json file that is accessible from the root of the classpath.
/languages.json
JSON
[
{"name":"Java","ratings":20.956},
{"name":"C","ratings":13.223},
{"name":"C++","ratings":6.698},
{"name":"C#","ratings":4.481},
{"name":"Python","ratings":3.789}
]
And the following POJO that will map the JSON objects from the list above to a Java object:
Language.java
JAVA
public class Language {
private String name;
private double ratings;
We can then assign a list of programming language objects to a JavaFX ListView control with the following code:
https://docs.gluonhq.com/#_introduction 123/191
30/09/2023, 18:48 Gluon Documentation
JAVA
// create a DataSource that loads data from a classpath resource
InputDataSource dataSource = new BasicInputDataSource(Main.class.getResourceAsStream("/languages.json"));
// create a ListDataReader that will read the data from the DataSource and converts
// it from json into a list of objects
ListDataReader<ProgrammingLanguage> listDataReader = new InputStreamListDataReader<>(dataSource, converter);
Retrieving an object
Retrieving an object looks somewhat similar to retrieving a list. However, instead of converting a JSON array into a list, we will
convert a JSON object directly into a Java object. Below we have the user.json file and the POJO that will hold the information
in the JSON object:
/user.json
JSON
{"name":"Duke","subscribed":true}
User.java
JAVA
public class User {
private StringProperty name = new SimpleStringProperty();
private BooleanProperty subscribed = new BooleanProperty();
As you can see, we use JavaFX properties here instead of native Java types. This allows us to bind the properties to a JavaFX UI
control, e.g. a Label. To retrieve the object from the JSON file, we use the following code:
https://docs.gluonhq.com/#_introduction 124/191
30/09/2023, 18:48 Gluon Documentation
JAVA
// create a DataSource that loads data from a classpath resource
InputDataSource dataSource = new BasicInputDataSource(Main.class.getResourceAsStream("/user.json"));
// create an ObjectDataReader that will read the data from the DataSource and converts
// it from json into an object
ObjectDataReader<User> objectDataReader = new InputStreamObjectDataReader<>(dataSource, converter);
// when the object is initialized, bind its properties to the JavaFX UI controls
Label lbName = new Label();
CheckBox cbSubscribed = new CheckBox("Subscribed?");
user.initializedProperty().addListener((obs, oldValue, newValue) -> {
if (newValue) {
lbName.textProperty().bind(user.get().nameProperty());
cbSubscribed.selectedProperty().bindBidirectional(user.get().subscribedProperty());
}
});
https://docs.gluonhq.com/#_introduction 125/191
30/09/2023, 18:48 Gluon Documentation
9. CloudLink
Gluon CloudLink enables enterprise and mobile developers to easily connect their disparate services and applications together,
enabling bi-directional communications between mobile apps, enterprise infrastructure, and cloud systems.
Data storage, synchronization (to the back-end or across devices) and connectors to other back-ends.
User management, including login methods for popular identity providers.
Usage analytics
Push notifications to Android and iOS devices.
https://docs.gluonhq.com/#_introduction 126/191
30/09/2023, 18:48 Gluon Documentation
The first step in enabling Gluon CloudLink in your application is to sign up for a Gluon CloudLink account. If you already have a
Gluon CloudLink subscription you can safely skip this part. If not, go to the Gluon CloudLink Product page
(https://gluonhq.com/products/cloud/buy/) and choose a subscription that matches your needs. There is also an option to sign up for a
30-day trial account. Enter your billing information or login with your existing account when you have signed up for one of our
other products before.
Once you are successfully signed up, a Gluon CloudLink application will be created for you automatically. You will also receive an
email that contains a link to access the Gluon Dashboard.
Select any of the items from the menu on the left to begin configuring your Gluon Application.
https://docs.gluonhq.com/#_introduction 127/191
30/09/2023, 18:48 Gluon Documentation
Server Configuration
Communication between your enterprise application and Gluon CloudLink is done by using the designated Gluon CloudLink
Enterprise REST endpoints. Each of these endpoints is described in the appropriate sections below. For your convenience, we also
provide a Java Client that calls on these same endpoints. The Java Client currently has two implementations that you can choose
from. The Java EE client is most suited when your enterprise application is running inside a Java EE application container. The
Spring client is more suited for enterprise applications that are running inside the Spring framework (https://spring.io).
JavaDocs for the Gluon CloudLink Enterprise SDK can be found at the following URL:
Content Encoding
All data that is written to Gluon CloudLink by using the enterprise REST endpoints, either directly or by use of the Java Client
must be encoded in UTF-8 . This is the only encoding that is supported by Gluon CloudLink. If your data you sent looks garbled,
please verify that you correctly applied UTF-8 encoding.
Dependencies
The following maven dependencies should be added to your enterprise project to make use of the Gluon CloudLink Enterprise
SDK. Note that the Eclipse Yasson dependency is only required when you are running inside a Java EE 7 container. Java EE 8
containers should automatically ship with an implementation of the JSON-Binding API.
Java EE
Maven
https://docs.gluonhq.com/#_introduction 128/191
30/09/2023, 18:48 Gluon Documentation
XML
<dependencies>
<dependency>
<groupId>com.gluonhq</groupId>
<artifactId>cloudlink-enterprise-sdk-javaee</artifactId>
<version>1.2.1</version>
</dependency>
<!-- only required when running inside a Java EE 7 container -->
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0</version>
<scope>runtime</scope>
</dependency>
</dependencies>
gradle
GROOVY
repositories {
mavenCentral()
}
dependencies {
compile 'com.gluonhq:cloudlink-enterprise-sdk-javaee:1.2.1'
Spring
Maven
XML
<dependencies>
<dependency>
<groupId>com.gluonhq</groupId>
<artifactId>cloudlink-enterprise-sdk-spring</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>
gradle
GROOVY
repositories {
mavenCentral()
}
dependencies {
compile 'com.gluonhq:cloudlink-enterprise-sdk-spring:1.2.1'
}
Authentication
The REST endpoints themselves require an HTTP Authorization header that is used to authenticate the requests to Gluon
CloudLink. The value of the Authorization header is as follows:
The SERVER_KEY needs to be replaced with the actual server key of your Gluon CloudLink application and can be found in the
Gluon Dashboard, in the Server tab of the Credentials section.
https://docs.gluonhq.com/#_introduction 129/191
30/09/2023, 18:48 Gluon Documentation
JavaEE
When using the Java Client, authentication is done by providing the server key when you create an instance of the Java Client:
Manual instantiation
JAVA
CloudLinkClientConfig config = new CloudLinkClientConig("MHwwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
CloudLinkClient client = new CloudLinkClient(config);
Alternatively, when running inside a CDI aware environment, you can inject an instance of the JavaEE client as follows:
Using injection
JAVA
@Inject
@CloudLinkConfig(serverKey = "MHwwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
private CloudLinkClient client;
Spring
Authentication with the Spring Client is done in the same way as the JavaEE Client:
Manual instantiation
JAVA
CloudLinkClientConfig config = new CloudLinkClientConig("MHwwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
CloudLinkClient client = new CloudLinkClient(config);
When you are using Spring Boot, you can make use of autowiring to inject an instance of the Spring Client. An application
property is then required that contains the server key of your Gluon CloudLink Application.
application.properties
PROPERTIES
gluon.cloudlink.serverKey=MHwwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Using autowiring
JAVA
private CloudLinkClient client;
@Autowired
public MyService(CloudLinkClient client) {
this.client = client;
}
Client Configuration
Gluon Mobile’s CloudLink Client is used for handling the communication between your Mobile application and Gluon CloudLink.
It is automatically added as a dependency to the main Gluon Mobile artifact, but can also be added separately.
Maven Configuration
https://docs.gluonhq.com/#_introduction 130/191
30/09/2023, 18:48 Gluon Documentation
We recommend using Maven as the build tool for building and provisioning a Gluon Mobile application. Maven project can make
use of the GluonFX plugin (https://github.com/gluonhq/gluonfx-maven-plugin), and the associated pom.xml needs to be configured with
the following dependencies and Attach configuration.
XML
<repositories>
<repository>
<id>Gluon</id>
<url>https://nexus.gluonhq.com/nexus/content/repositories/releases</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.gluonhq</groupId>
<artifactId>charm</artifactId>
<version>6.2.3</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>device</artifactId>
<version>4.0.18</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>push-notifications</artifactId>
<version>4.0.18</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>storage</artifactId>
<version>4.0.18</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>util</artifactId>
<version>4.0.18</version>
</dependency>
</dependencies>
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.21</version>
<configuration>
<target>${gluonfx.target}</target>
<attachList>
<list>device</list>
<list>push-notifications</list>
<list>storage</list>
</attachList>
<mainClass>${main.class}</mainClass>
</configuration>
</plugin>
Authentication
Gluon Mobile uses the application specific credentials to sign all requests that are made to Gluon CloudLink. This allows Gluon
CloudLink to know on behalf of which application the request is initiated.
To apply the client credentials to your Gluon Mobile project, create a JSON configuration file called
gluoncloudlink_config.json and save it under the directory src/main/resources . This file will automatically be picked up
by Gluon Mobile when needed. Insert the content below, making sure that you replace the values for the applicationKey and
applicationSecret with the correct credentials for your application:
JSON
{
"gluonCredentials": {
"applicationKey": "b916XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"applicationSecret": "9c11XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}
}
From the Gluon Dashboard, select the Credentials item from the menu on the left. You will find the key and secret tokens of
your Gluon CloudLink application inside the Client tab. You can either manually copy and paste them in the configuration file
or you can directly download the configuration file by clicking the download button.
https://docs.gluonhq.com/#_introduction 131/191
30/09/2023, 18:48 Gluon Documentation
https://docs.gluonhq.com/#_introduction 132/191
30/09/2023, 18:48 Gluon Documentation
Applications often use data that needs to be stored. Some data is only relevant to a specific instance of the application (i.e. local
settings), other data is relevant to all instances of the application (i.e. chat data) and some data is relevant to some instances (i.e.
user preferences for a user who has a number of devices).
Gluon CloudLink Client is the component that manages data on the client. It provides an API that allows users to store and
synchronize data and provides a number of options for developers to choose from for each data entity:
Gluon CloudLink Client communicates via an efficient protocol with Gluon CloudLink to achieve the different goals. Gluon
CloudLink provides a scalable and persistent data store that is used to store data and to update clients when data changes.
Communication between your Gluon Mobile application and Gluon CloudLink works in two directions:
your mobile data is stored in the cloud when you want to, and
your mobile data is updated on the device whenever it is updated in the cloud.
In addition, Gluon CloudLink provides the ability to link your Gluon Mobile application with another back-end or cloud
infrastructure by configuring one or more Connectors.
DataClient
The DataClient
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/data/DataClient.html)
class is the access point to the Data Storage. You can get a reference to a DataClient instance by using the DataClientBuilder
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/data/DataClientBuilder.html)
:
JAVA
DataClient dataClient = DataClientBuilder.create().build();
Operation Mode
When working with the DataClient, there are currently three operation modes you can choose from:
CLOUD_ONLY
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/data/OperationMode.html#CLOUD_ONLY)
: data will only be persisted on and retrieved from the Gluon CloudLink service
LOCAL_ONLY
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/data/OperationMode.html#LOCAL_ONLY)
: data will only be persisted on and retrieved from the local file system of the device where the application is running on
CLOUD_FIRST
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/data/OperationMode.html#CLOUD_FIRST)
: data will be persisted on and retrieved from the Gluon CloudLink service as the primary data source, but a local copy will be
kept in sync
The default operation mode is CLOUD_FIRST , but can be explicitly specified when creating the DataClient instance:
JAVA
// specify LOCAL_ONLY operation mode
DataClient dataClient = DataClientBuilder.create()
.operationMode(OperationMode.LOCAL_ONLY)
.build();
Authentication
You can configure the DataClient to link data with an authenticated user. The following authentication methods are currently
available:
https://docs.gluonhq.com/#_introduction 133/191
30/09/2023, 18:48 Gluon Documentation
JAVA
// enable user authentication
UserClient authenticationClient = new UserClient();
DataClient dataClient = DataClientBuilder.create()
.authenticateWith(authenticationClient)
.build();
Data Storage
Once you have a DataClient reference, you can start storing and retrieving data. There are two different types of data that can
be managed in Gluon CloudLink:
Because these objects and lists are maintained remotely, we will call them remote entities. Every remote entity is identified by a
unique string identifier.
Retrieving lists
For example, retrieving a remote list with the identifier notes can be done with the following code:
JAVA
GluonObservableList<Note> notes = DataProvider.retrieveList(dataClient.createListDataReader("notes", Note.class));
ListView<Note> notesListView = new ListView<>(notes);
You may have noticed that DataClient doesn’t provide a method for creating a new list. That is because a Gluon CloudLink list
always exists. When a list is retrieved the first time, an empty list will automatically be created for you.
Retrieving objects
A remote object works a bit differently than a list, because in contrast to a list, an object does have the notion of existence. This
explains why we have three methods for managing remote objects: createObjectDataReader
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/data/DataClient.html#createObject
java.lang.String-java.lang.Class-com.gluonhq.cloudlink.client.data.SyncFlag…
-)
, createObjectDataWriter
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/data/DataClient.html#createObject
java.lang.String-java.lang.Class-com.gluonhq.cloudlink.client.data.SyncFlag…
-)
and createObjectDataRemover
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/data/DataClient.html#createObject
-)
https://docs.gluonhq.com/#_introduction 134/191
30/09/2023, 18:48 Gluon Documentation
JAVA
// store the object
Note note = new Note();
note.setContent("This is the content for the note.");
GluonObservableObject<Note> gluonNote = DataProvider.storeObject(note, dataClient.createObjectDataWriter("a-single-note",
Note.class));
GluonObservable ConnectState
All the operations on the DataProvider are asynchronous in nature and are executed in a separate background thread. You can
listen for changes on the stateProperty
(http://docs.gluonhq.com/charn/javadoc/6.2.3/com/gluonhq/connect/GluonObservable.html#stateProperty--) of the returned GluonObservable
object to monitor the progress of the background operation. To know when your object or list is ready to be used, you can also
listen for the initializedProperty
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/GluonObservable.html#initializedProperty--) instead.
Listed below you’ll find a number of common use cases when working with remote entities.
When retrieving an object from Gluon CloudLink, you can detect if this object was already stored previously by using the
following pattern:
JAVA
GluonObservableObject<Note> gluonNote = DataProvider.retrieveObject(dataClient.createObjectDataReader("a-single-note",
Note.class));
gluonNote.initializedProperty().addListener((observable, ov, nv) -> {
if (nv) {
if (gluonNote.get() == null) {
// object not yet stored, initiate it now with a new object and store it
gluonNote.set(new Note("This is some text for the note"));
dataClient.push(gluonNote);
} else {
// object already stored previously
Note note = gluonNote.get();
System.out.println("Stored note: " + note.getContent());
}
}
});
When you retrieve a list for the first time, an empty list will be created for you by the Gluon CloudLink service. Sometimes you
wish to populate this empty list with default objects. You can do that with the following pattern:
JAVA
GluonObservableList<Note> gluonNotes = DataProvider.retrieveList(dataClient.createListDataReader("notes", Note.class));
gluonNotes.initializedProperty().addListener((observable, ov, nv) -> {
if (nv && gluonNotes.isEmpty()) {
// initialize the list with some default notes
gluonNotes.addAll(
new Note("Text for note number 1."),
new Note("Text for note number 2.")
);
dataClient.push(gluonNotes);
}
});
If you notice that data isn’t stored or retrieved correctly, it might be that an exception occurred during the process. You can check
the exceptionProperty
(https://docs.gluonhq.com/connect/javadoc/2.0.1/com.gluonhq.connect/com/gluonhq/connect/GluonObservable.html#exceptionProperty--) on the
GluonObservable object to see what exactly went wrong.
https://docs.gluonhq.com/#_introduction 135/191
30/09/2023, 18:48 Gluon Documentation
JAVA
GluonObservableObject<Note> gluonNote = DataProvider.retrieveObject(dataClient.createObjectDataReader("a-single-note",
Note.class));
gluonNote.stateProperty().addListener((observable, oldState, newState) -> {
if (newState == ConnectState.FAILED) {
if (gluonNote.getException() != null) {
gluonNote.getException().printStackTrace();
}
}
});
The JavaFX Property types are a requirement when a remote entity is retrieved in combination with the OBJECT_WRITE_THROUGH
synchronization flag. See the Data Synchronization section for more information on these flags.
String
The String data type is the most basic of the three supported types. It simply stores and retrieves instances of string.
Map
The Map represents a convenient key/value store in which you can store arbitrary data. It is the most flexible data type, but is less
type safe. The keys of the map must be strings, while the value can be any of the supported field types that are listed above. If the
map contains a value that is not supported, those values will be ignored when storing or retrieving data.
Custom Class
As a final option, you can define your data structure inside a Custom Class. The DataClient will inspect the provided class for all
declared fields of which the type matches any of the supported field types. Note that only non-static fields and non-final primitive
fields will be considered. All other field declarations will be ignored when storing or retrieving data.
Data Synchronization
By default, no synchronization flags are configured when calling any of the methods we mentioned above. To enable
synchronization, you can pass any of the SyncFlag
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/data/SyncFlag.html) enum constants to
the method. There are four different types of SyncFlag :
OBJECT_READ_THROUGH : changes that occur on an object in Gluon CloudLink will be reflected to the fields on the local object
OBJECT_WRITE_THROUGH : changes on JavaFX Property fields will be automatically written to the object in Gluon CloudLink
LIST_READ_THROUGH : adding and removing objects on a list in Gluon CloudLink will be reflected to the local list
LIST_WRITE_THROUGH : adding and removing objects locally will automatically add and remove them to the list in Gluon
CloudLink
Note that the OBJECT_READ_THROUGH and LIST_READ_THROUGH flags don’t have any effect when used in combination with the
LOCAL_ONLY operation mode.
Also note that the OBJECT_WRITE_THROUGH flag will only work on non-static Observable fields of a Custom Class.
JAVA
GluonObservableList<Note> notes = DataProvider.retrieveList(dataClient.createListDataReader("notes", Note.class,
SyncFlag.LIST_READ_THROUGH, SyncFlag.LIST_WRITE_THROUGH));
https://docs.gluonhq.com/#_introduction 136/191
30/09/2023, 18:48 Gluon Documentation
1. Call into the Gluon CloudLink REST endpoints from an enterprise system to retrieve and manage data. You can either directly
call the REST endpoints or use an implementation of the Gluon CloudLink Enterprise SDK that best suits your existing
enterprise environment.
2. Use Connectors to let Gluon CloudLink automatically push and/or pull data to and from an enterprise system.
REST endpoints
Get object
Retrieve an object from the data service.
GET https://cloud.gluonhq.com/3/data/enterprise/object/{objectIdentifier}
Path Parameters
Name Description
Curl sample
BASH
curl -X GET "https://cloud.gluonhq.com/3/data/enterprise/object/sample-object" \
-H "Authorization: Gluon YOUR_SERVER_KEY"
Java Client
JAVA
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);
Add object
Add a new object into the data service with the defined payload.
POST https://cloud.gluonhq.com/3/data/enterprise/object/{objectIdentifier}/add
Path Parameters
Name Description
Body
The body of the request must be a UTF-8 encoded JSON string and will be used as the payload for the newly added object.
Curl sample
BASH
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/object/sample-object/add" \
-H "Authorization: Gluon YOUR_SERVER_KEY" \
-H "Content-Type: application/json; charset=utf-8" \
--data '{"text":"someField","number":123}'
Java Client
JAVA
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);
Update object
Update an existing object in the data service with the defined payload.
POST https://cloud.gluonhq.com/3/data/enterprise/object/{objectIdentifier}/update
Path Parameters
Name Description
Body
The body of the request must be a UTF-8 encoded JSON string and will be used as the payload for the object that is being updated.
https://docs.gluonhq.com/#_introduction 137/191
30/09/2023, 18:48 Gluon Documentation
Curl sample
BASH
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/object/sample-object/update" \
-H "Authorization: Gluon YOUR_SERVER_KEY" \
-H "Content-Type: application/json; charset=utf-8" \
--data '{"text":"someOtherText","number":321}'
Java Client
JAVA
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);
Remove object
Remove an existing object from the data service.
POST https://cloud.gluonhq.com/3/data/enterprise/object/{objectIdentifier}/remove
Path Parameters
Name Description
Curl sample
BASH
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/object/sample-object/remove" \
-H "Authorization: Gluon YOUR_SERVER_KEY"
Java Client
JAVA
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);
client.removeObject("sample-object");
Get list
Retrieve a list of objects from the data service.
GET https://cloud.gluonhq.com/3/data/enterprise/list/{listIdentifier}
Path Parameters
Name Description
Curl sample
BASH
curl -X GET "https://cloud.gluonhq.com/3/data/enterprise/list/sample-list" \
-H "Authorization: Gluon YOUR_SERVER_KEY"
Java Client
JAVA
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);
POST https://cloud.gluonhq.com/3/data/enterprise/list/{listIdentifier}/add/{objectIdentifier}
Path Parameters
Name Description
listIdentifier The unique identifier of the list to add the object into.
Body
https://docs.gluonhq.com/#_introduction 138/191
30/09/2023, 18:48 Gluon Documentation
The body of the request must be a UTF-8 encoded JSON string and will be used as the payload for the object that is being added
into the list.
Curl sample
BASH
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/list/sample-list/add/sample-object-1" \
-H "Authorization: Gluon YOUR_SERVER_KEY" \
-H "Content-Type: application/json; charset=utf-8" \
--data '{"text":"someField","number":123}'
Java Client
JAVA
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);
POST https://cloud.gluonhq.com/3/data/enterprise/list/{listIdentifier}/update/{objectIdentifier}
Path Parameters
Name Description
listIdentifier The unique identifier of the list where the object to update is
stored.
Body
The body of the request must be a UTF-8 encoded JSON string and will be used as the payload for the object that is being updated
in the list.
Curl sample
BASH
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/list/sample-list/update/sample-object-1" \
-H "Authorization: Gluon YOUR_SERVER_KEY" \
-H "Content-Type: application/json; charset=utf-8" \
--data '{"text":"someOtherText","number":321}'
Java Client
JAVA
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);
POST https://cloud.gluonhq.com/3/data/enterprise/list/{listIdentifier}/remove/{objectIdentifier}
Path Parameters
Name Description
listIdentifier The unique identifier of the list where the object to remove is
stored.
objectIdentifier The unique identifier of the object to remove from the list.
Curl sample
BASH
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/list/sample-list/remove/sample-object-1" \
-H "Authorization: Gluon YOUR_SERVER_KEY"
Java Client
JAVA
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);
client.removeFromList("sample-list", "sample-object-1");
Connectors
https://docs.gluonhq.com/#_introduction 139/191
30/09/2023, 18:48 Gluon Documentation
A Connector can be used for automatic pushing and pulling of data from Gluon CloudLink to an enterprise back end system.
push: data that is updated in Gluon CloudLink is sent through to the enterprise back end
pull: data is requested from the enterprise back end by Gluon CloudLink
Different connector implementations are provided by Gluon CloudLink out of the box. Depending on the configured Connector,
some extra code will be required on the back end application as well. E.g. when linking to Gluon CloudLink with the REST
Connector, a handler must exist on the back end application that listens for HTTP requests that are called by Gluon CloudLink.
Configuring a Connector for a Gluon CloudLink Application is done in the Gluon Dashboard. The following Connectors are
available for use within Gluon CloudLink. If you have a specific requirement for a custom Connector, please let us know
(http://gluonhq.com/about-us/contact-us/).
CloudLink Remote Function This connector invokes a remote function that is defined in
your CloudLink application.
REST Connector
The REST Connector sends and receives data over a network connection using the standard HTTP protocol.
The connector can be set from the Gluon Dashboard (https://gluon.io), Data Management, Connectors tab.
https://docs.gluonhq.com/#_introduction 140/191
30/09/2023, 18:48 Gluon Documentation
When using the REST Connector to link to a back end system, the Gluon CloudLink Application only needs to be configured with
the URL where the requests from Gluon CloudLink need to be sent to.
Push endpoints
When a client application requests data to be added, updated or removed from Gluon CloudLink, those requests will be mapped
with the REST Controller by making an HTTP request to one of the following six endpoints. Each of them should be implemented
on the back end application to be able to handle the request.
URL /object/{objectIdentifier}/add
Method POST
Request Body JSON payload of the new object. If the object is a String , the payload will use a key named v .
Description A new object is added to Gluon CloudLink. The objectIdentifier is the identifier that is passed in
from the application client when retrieving or storing the object.
URL /object/{objectIdentifier}/update
Method POST
Description An existing object is updated in Gluon CloudLink. The objectIdentifier is the identifier that is
passed in from the application client when retrieving or storing the object.
URL /object/{objectIdentifier}/remove
Method POST
Description An existing object is removed from Gluon CloudLink. The objectIdentifier is the identifier that is
passed in from the application client when retrieving or storing the object.
URL /list/{listIdentifier}/add/{objectIdentifier}
https://docs.gluonhq.com/#_introduction 141/191
30/09/2023, 18:48 Gluon Documentation
Method POST
Request Body JSON payload of object that is being added to the list
Description A new object is added to a list. The objectIdentifier is an identifier that is assigned to the object
specific to Gluon CloudLink, i.e. the client application is not aware of this identifier. This is in contrast
to the listIdentifier , which is the identifier that is passed in from the application client when
retrieving the list.
URL /list/{listIdentifier}/update/{objectIdentifier}
Method POST
Request Body JSON payload of object that is being updated in the list
Description An existing object in the list is updated. The objectIdentifier is an identifier that is assigned to
the object specific to Gluon CloudLink, i.e. the client application is not aware of this identifier. This is
in contrast to the listIdentifier , which is the identifier that is passed in from the application
client when retrieving the list.
URL /list/{listIdentifier}/remove/{objectIdentifier}
Method POST
Description An existing object is removed from a list. The objectIdentifier is an identifier that is assigned to
the object specific to Gluon CloudLink, i.e. the client application is not aware of this identifier. This is
in contrast to the listIdentifier , which is the identifier that is passed in from the application
client when retrieving the list.
Pull endpoints
When a client application requests an object or a list that is not yet known inside Gluon CloudLink, Gluon CloudLink calls one of
the following two endpoints on the back end application to retrieve the initial object or list information.
URL /object/{objectIdentifier}
Method GET
Description A new object is being requested from the client application with the specified objectIdentifier.
URL /list/{listIdentifier}
Method GET
Response Body JSON payload of the list to retrieve. The payload is a JSON array containing a list of zero or more
JSON objects. Each JSON object in the array defines two keys: id that defines the object identifier
and payload which is the JSON payload of the object, represented as a JSON string.
Description A new list is being requested from the client application with the specified listIdentifier.
https://docs.gluonhq.com/#_introduction 142/191
30/09/2023, 18:48 Gluon Documentation
When a client application requests data to be added, updated or removed from Gluon CloudLink, those requests will be provided
with the remote function invocation as a JSON string. For instance, when invoking a REST Remote Function, the payload is
provided as the raw body of a POST request.
Pushing Objects
A new object is added
{
"operation": "objectAdded",
"objectIdentifier": "01234567-89ab-cdef-0123-456789abcdef",
"payload" : "{\"firstName\":\"John\",\"lastName\":\"Doe\"}"
}
Pushing Lists
A new object is added to a list
{
"operation": "itemAddedToList",
"listIdentifier": "fedcba98-7654-3210-fedc-ba9876543210",
"objectIdentifier": "01234567-89ab-cdef-0123-456789abcdef",
"payload" : "{\"firstName\":\"John\",\"lastName\":\"Doe\"}"
}
https://docs.gluonhq.com/#_introduction 143/191
30/09/2023, 18:48 Gluon Documentation
{
"operation": "itemRemovedFromList",
"listIdentifier": "fedcba98-7654-3210-fedc-ba9876543210",
"objectIdentifier": "01234567-89ab-cdef-0123-456789abcdef"
}
Couchbase Connector
The Couchbase Connector is able to send data to an existing Couchbase Server (https://couchbase.com). The only requirement on the
Couchbase Server is an existing bucket (http://developer.couchbase.com/documentation/server/4.1/clustersetup/create-bucket.html) that will
hold the lists and/or objects from Gluon CloudLink.
When activating the Couchbase Connector inside the Dashboard, you will need to provide the following information to let Gluon
CloudLink be able to setup a connection with the Couchbase Server:
Nodes: a list of nodes that the Couchbase Client on Gluon CloudLink uses to setup the connection to a Couchbase Cluster. You
can specify more than one node, by separating them with a semicolon.
Bucket Name: the name of the Couchbase bucket that will hold the lists and/or objects
Bucket Password: the password of that Couchbase bucket
https://docs.gluonhq.com/#_introduction 144/191
30/09/2023, 18:48 Gluon Documentation
Pushing Objects
Objects are stored in the Couchbase bucket using a key named objects/{objectIdentifier} , where objectIdentifier is the
identifier that is passed in by the client application when storing or retrieving the object.
The document itself will be a JSON document that represents the JSON payload of the object. An example of such an object can be
seen below:
objects/notes-settings
JSON
{
"fontSize": 10,
"sortingId": 2,
"ascending": true,
"showDate": false
}
Pushing Lists
Lists are also stored as a document with a key named lists/{listIdentifier} , where listIdentifier is the identifier that is
passed in by the client application when retrieving the list.
For each object in the list, the document will contain a key that matches the identifier of the object. The value that is mapped to
that key is a JSON document that represents the JSON payload of the object. Below is an example of a list that contains two objects:
lists/notes
JSON
{
"af52f4c6-a64b-4823-b9fb-3cbef79d7577": {
"creationDate": 1463062055,
"title": "new note",
"text": "sample 2"
},
"f880774a-20e9-11e6-b67b-9e71128cae77": {
"creationDate": 1463054952,
"title": "another note",
"text": "and also another sample text"
}
}
Pulling Data
Gluon CloudLink can also pull data from the same Couchbase Server when a list and/or object is retrieved that is not yet known
within the Gluon CloudLink data store. It will try to retrieve a list or object from the configured bucket, by using the same
identifiers as described in the push section above: lists/{listIdentifier} for lists and objects/{objectIdentifier} for
objects. The format of the documents stored inside the Couchbase bucket must also follow the same format as described in the
previous section.
https://docs.gluonhq.com/#_introduction 145/191
30/09/2023, 18:48 Gluon Documentation
Almost all mobile applications that exist today interact with a back end infrastructure for managing their data. In theory, an
application can directly make requests to these back ends, but there are a number of drawbacks for doing this:
Mobile devices are not always connected to the internet. It takes lots of boilerplate code to check connectivity and handle
rescheduling of requests when connectivity is restored.
Applications on mobile devices have specific lifecycles and need to behave according to specific policies. Some resources are
conditionally available. The battery might be low, the application might be running in the background, the device is connected
with a paid cellular network, etc. Depending on those conditions, an application must behave differently.
Mobile devices have less resources than the regular server, and those resources need to shared with other applications.
CloudLink provides Remote Functions to give the application a reliable and secure way for linking with existing back end
systems.
Sign in to the Gluon Dashboard (https://gluon.io) and navigate to API Management. You will find the following sections:
https://docs.gluonhq.com/#_introduction 146/191
30/09/2023, 18:48 Gluon Documentation
Function Name
The function name is a unique identifier for the remote function. The name is used in the client application when a call needs to
be triggered to the remote function.
Method
The method defines what HTTP method to use when creating the request. The following methods are supported: GET, POST, PUT
and DELETE.
Endpoint
The endpoint is the URI to use when creating the request.
Read Timeout
Specify the timeout, in milliseconds, for reading from the remote function endpoint. If the value is zero, the default timeout will
be used.
Connect Timeout
Specify the timeout, in milliseconds, for connecting to the remote function endpoint. If the value is zero, the default timeout will
be used.
Authentication Method
Specifies the authentication method that must be used when executing the request to the remote function. The authentication
method can be selected from a list of authentication methods that are configured in the Authentication section.
Body Type
The body type can be specified when the POST or PUT method is selected. The body type defines what kind of data will be sent to
the remote function. The following types are supported:
When the raw body type is chosen, two extra fields will be available to specify the data and the media type of the raw body
content.
Caching Enabled
If caching is enabled, CloudLink caches each successful response from invocations to the remote function for one hour. CloudLink
caching rules are based on standard HTTP caching mechanisms. In closer detail, two HTTP response headers are currently
inspected:
https://docs.gluonhq.com/#_introduction 147/191
30/09/2023, 18:48 Gluon Documentation
ETag: if an entity tag is provided, it will be used in any subsequent request to the configured endpoint for cache validation.
Cache-Control: if cache control contains the words private or no-store , the response is not cached. If it contains public
(default value) or a max-age value, the response is cached for the specified duration.
Both HTTP response headers can be combined to improve the caching mechanism.
Navigate back to the API Management section and click the + button to add a new remote function while choosing Amazon AWS
Lambda. A dialog will be shown where the following components can be configured:
Function Name
The function name is a unique identifier for the remote function. The name is used in the client application when a call needs to
be triggered to the remote function.
https://docs.gluonhq.com/#_introduction 148/191
30/09/2023, 18:48 Gluon Documentation
AWS Credentials
The AWS Access Key to use when listing the available AWS Lambda functions.
AWS Region
The AWS region where the AWS Lambda functions must be listed from.
Payload Type
An optional payload that should be sent along when executing the AWS Lambda function. The following types are supported:
Payload
When the string payload type is chosen, an extra text area will be available to specify the data for the string content. The resulting
data string must be valid JSON. If this is not the case, the request to the remote function will be aborted with a Bad Request status.
Read Timeout
Specify the timeout, in milliseconds, for reading from the remote function endpoint. If the value is zero, the default timeout will
be used.
Connect Timeout
Specify the timeout, in milliseconds, for connecting to the remote function endpoint. If the value is zero, the default timeout will
be used.
https://docs.gluonhq.com/#_introduction 149/191
30/09/2023, 18:48 Gluon Documentation
Function Name
The function name is a unique identifier for the remote function. The name is used in the client application when a call needs to
be triggered to the remote function.
Method
The method defines what HTTP method to use when creating the request. The following methods are supported: GET, POST, PUT
and DELETE.
Function URL
The Function URL that points to the Azure function.
API Key
Define the Function Key to use for authorizing the invocation to the Azure function. The key is passed down to the function using
the x-functions-key HTTP header. Make sure that you copy the value of the Function Key and not its name. Azure functions using
Anonymous authorization can leave this field empty.
Read Timeout
Specify the timeout, in milliseconds, for reading from the remote function endpoint. If the value is zero, the default timeout will
be used.
Connect Timeout
Specify the timeout, in milliseconds, for connecting to the remote function endpoint. If the value is zero, the default timeout will
be used.
Body Type
The body type can be specified when the POST or PUT method is selected. The body type defines what kind of data will be sent to
the remote function. The following types are supported:
When the raw body type is chosen, two extra fields will be available to specify the data and the media type of the raw body
content.
https://docs.gluonhq.com/#_introduction 150/191
30/09/2023, 18:48 Gluon Documentation
Function Name
The function name is a unique identifier for the remote function. The name is used in the client application when a call needs to
be triggered to the remote function.
Docker Registry
The name of the docker image as it has been pushed to Docker Hub. You can optionally specify a tag for the image, for instance:
gluonhq/helloworld:0.0.2.
Enable Input
When input is enabled, two extra fields will be available to specify the data and the media type of the input. The content of the
text area will be passed down to the Fn Function during invocation.
Timeout
Specify the timeout, in seconds, for executing the remote function on the Fn Project platform. If the value is zero, the default
timeout will be used.
Click the + button to add a new remote function and choose Gluon Function. A dialog will be shown in which the following
components can be configured:
https://docs.gluonhq.com/#_introduction 151/191
30/09/2023, 18:48 Gluon Documentation
Function Name
The function name is a unique identifier for the remote function. The name is used in the client application when a call needs to
be triggered to the remote function.
Entrypoint
The entrypoint defines what method should be invoked when the Gluon Function is triggered. The syntax consists of the fully
qualified class name and the method name to be invoked, separated with a double colon, i.e.:
com.gluonhq.sample.function.GluonFunction::methodName
Java Runtime
Specify the Java Runtime environment that must be used for running the Gluon Function. You can choose between Java 8 and
Java 9.
Memory
Define the maximum amount of memory that should be provided when running the Gluon Function. You can choose a value
between 128MB and 1GB with intervals of 128MB.
Bundle
The bundle contains the actual classes that are needed for executing the Gluon Function. The bundle is a zip file containing one or
more jar files that will be added to the classpath of the Gluon Function.
Read Timeout
Specify the timeout, in milliseconds, for reading from the remote function endpoint. If the value is zero, the default timeout will
be used.
Connect Timeout
Specify the timeout, in milliseconds, for connecting to the remote function endpoint. If the value is zero, the default timeout will
be used.
Parameters
Each remote function can be configured with additional parameters. Each parameter consists of a type, a name and optional
default and test values. The name is used by the client application to define the value for the parameter that will be passed on
when building the request for the remote function. In the image below, a query parameter is configured with the name tagged .
Double clicking inside the grid will activate the edit view for the selected function parameter.
https://docs.gluonhq.com/#_introduction 152/191
30/09/2023, 18:48 Gluon Documentation
Query
A query parameter will be sent as part of the query string. The query string is the part of the URI that comes after the question
mark.
Form
A form parameter can be chosen for remote functions that are configured with the POST method. Form parameters are sent as
form url encoded parameters in the body of the request.
Header
A header parameter can be used to send custom HTTP request headers when building the request for the remote function.
Variable
Variable parameters can be used to add custom variables to certain fields of a remote function. Remote functions of type HTTP
Request can have custom variables in the Endpoint and Raw Data fields; Remote functions of type Amazon AWS Lambda can have
custom variables in the Payload field. Also, each custom variable that is added to an Amazon AWS Lambda Remote Function will
be passed along with the JSON payload as well.
For example, the following URI endpoint contains a single variable called userIdentifier : https://foo.bar/user/$userIdentifier.
The variable will be replaced with the value that was passed on by the client application, before the actual request is executed.
9.3.2. Authentication
The endpoint of a remote function sometimes requires that the request is authenticated. The Authentication section provides
three different authentication mechanisms that can be used together with a remote function.
https://docs.gluonhq.com/#_introduction 153/191
30/09/2023, 18:48 Gluon Documentation
Basic Authentication
This will add a basic Authorization HTTP header when creating the request to the remote function. The username and password
are both required.
A token key and secret can be provided as well when necessary, but can be left empty if the endpoint only requires that the
request must be signed with consumer credentials.
When making a request to the defined endpoint of the remote function, it will first try to get an access token using the
configuration details of the authentication method. The access token will then be passed along with the actual request to the
endpoint of the remote function.
When testing the remote function, the response of the endpoint will be printed so it can be verified against the expected value.
Call Log
Useful information from each call that is being invoked by a remote function is stored in the Call Log and can be accessed in
Gluon Dashboard. Each request records the response code, the request and response timestamps and the body of the request and
response. The body is capped at 8k.
https://docs.gluonhq.com/#_introduction 154/191
30/09/2023, 18:48 Gluon Documentation
CloudLink Client
For calling a remote function from the client application we use the RemoteFunctionBuilder . The RemoteFunctionBuilder
can generate three different implementations of a RemoteFunction , each handling the response of the call to the remote
function in their own way:
JAVA
// create an instance of remote function
RemoteFunctionList remoteFunction = RemoteFunctionBuilder.create("myFunction")
.param("myParameter", "parameterValue")
.list();
Local Caching
Every response that is returned by a call to a remote function will by default be cached locally in the private storage of the device.
The next time the remote function is called, it will first load and return the cached data before making the actual call to the
remote function in Gluon CloudLink. This allows the application to already present the user with data from the last time the
remote function was called. When the response from the call to the actual remote function in Gluon CloudLink is completed, it
will overwrite the cached data with the data from the new response.
JAVA
// create an instance of remote function without caching locally
RemoteFunctionObject remoteFunction = RemoteFunctionBuilder.create("anotherFunction")
.cachingEnabled(false)
.object();
The cached data itself can also be cleared by using the clearCache() method:
JAVA
// clear the locally cached data
remoteFunction.clearCache();
https://docs.gluonhq.com/#_introduction 155/191
30/09/2023, 18:48 Gluon Documentation
At the client side, you do need to use a different implementation of RemoteFunction that is able to handle chunked encoding:
RemoteFunctionChunkedList
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/data/RemoteFunctionChunkedList.htm
.
JAVA
// create an instance of a chunked remote function
RemoteFunctionChunkedList chunkedFunction = RemoteFunctionBuilder.create("chunkedFunction")
.param("myParameter", "parameterValue")
.chunkedList();
// call the remote function to fetch an observable list. Gluon CloudLink will add a
// new item to this list, for each chunk it receives from the remote function
GluonObservableList<MyChunk> responses = chunkedFunction.call(MyChunk.class);
JAVA
// retrieve bytes from a classpath resource
byte[] rawBody = {};
try (ByteArrayOutputStream os = new ByteArrayOutputStream();
InputStream is = Main.class.getResourceAsStream("/sample.wav")) {
byte[] bytes = new byte[4096];
int read;
while ((read = is.read(bytes)) != -1) {
os.write(bytes, 0, read);
}
rawBody = os.toByteArray();
} catch (IOException e) {
// handle exception
}
Here is an overview of the login methods that are currently supported by Gluon CloudLink:
Facebook Login
Google Sign-In
Twitter
GitHub
Email and Password
https://docs.gluonhq.com/#_introduction 156/191
30/09/2023, 18:48 Gluon Documentation
Enabling the login methods that should be available for your application can be done from the Gluon Dashboard (https://gluon.io).
Navigate to the User Management link, and select the Login Methods tab. From here you can add and configure one or more login
methods.
The login methods for identity providers all need a key and a secret from an application that is created on the respective identity
provider. We provide a step-by-step guide to creating and configuring an application for each of the supported identity providers.
Initiate authentication
A typical workflow to authenticate a user would be coded as follows:
JAVA
UserClient userClient = new UserClient();
userClient.authenticate(user -> {
System.out.println("User authenticated successfully: " + user.getName());
});
When no authenticated user exists yet, the authentication process will be started. This is handled by taking the user to the
implementation of the AuthenticationView . The default AuthenticationView implementation looks like this:
https://docs.gluonhq.com/#_introduction 157/191
30/09/2023, 18:48 Gluon Documentation
The user can select one of the presented login methods which will start the authentication flow for the selected login method.
When a user was successfully authenticated, or when an authenticated user was already present, the provided consumer in the
authenticate
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/user/UserClient.html#authenticate
java.util.function.Consumer-)
method will be called, passing in the authenticated user.
Handling failed or aborted authentication
In case the user aborted the authentication process or when an unexpected error occurred, you can use the authenticate variant
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/user/UserClient.html#authenticate-
java.util.function.Consumer-java.util.function.Consumer-)
which takes an extra failure consumer.
JAVA
userClient.authenticate(user -> System.out.println("User authenticated successfully!"),
failure -> System.out.println("Authentication failed or aborted: " + failure));
Signing out
Once a user is successfully authenticated, that user will not need to authenticate again the next time the application is started. To
be able to restart the authentication process , you will first need to call the signOut
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/user/UserClient.html#signOut-
-)
method.
User
The authenticated user can be retrieved from the UserClient by calling the getAuthenticatedUser
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/user/UserClient.html#getAuthentic
-)
method. This returns an instance of User
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/user/User.html)
that has the following fields available:
key: the unique identifier of the user within the entire application
name: the full name of the user
nick: an optional nick name for the user
picture: an optional URL to the profile picture of the user
networkId: the identifier of the user at the identity provider that was used for authentication
Data Authentication
As mentioned in the Data Storage section, you can also use a UserClient to make sure that only authenticated users have access
to data that is loaded by a DataClient . To enable this, you need to pass in an instance of UserClient when building the
DataClient:
JAVA
UserClient userClient = new UserClient();
DataClient dataClient = DataClientBuilder.create()
.authenticateWith(userClient)
.operationMode(OperationMode.CLOUD_FIRST)
.build();
https://docs.gluonhq.com/#_introduction 158/191
30/09/2023, 18:48 Gluon Documentation
The first time that DataClient instance is used to access data, the authentication process will be initiated when an authenticated
user was not yet present on the provided UserClient instance.
Media: refers to images, video and audio that can be used in the mobile application
Resource Bundles: refers to i18n resource bundle property files for translating application copy
9.5.1. Media
Each media resource is defined by a unique name. The client application will request the media resource by specifying that name.
Each media is further made up of one or more media variants. The variant contains the actual media file, together with metadata
to define for which platform the media should be made available. That way, it is for instance possible to define a different version
of a media resource for Android and iOS.
Uploading Media
From the Gluon Dashboard (https://gluon.io), selecting the Media Management link will present you with a view that is divided into
two grids. The top grid holds the media, while the bottom grid will show the media variants that are linked with the selected
media from the top grid.
Add a new media resource by clicking the plus button from the top grid. This will create the media container as well as the first
associated media variant. The following fields can be defined in the form dialog:
Media Name
This defines the unique name for the media resource. The client application will use this name to get a reference to the media
resource.
Platform
Associates the media variant with a specific platform. When the client application requests a media resource and a specific
variant exists that matches the platform where the application is running at, that media variant will be returned. Leave the
platform empty to define the fallback resource that will be returned when no variant was found for a specific platform and/or
platform version.
Platform Version
You can further specialize the media variant by defining a matching platform version. This media resource will only be returned
when both the platform and the version of the platform where the application is running on match with the specified values.
Media File
This is the ultimate resource file that is linked with the media variant. It’s also this file that is returned to the client application in
the form of an InputStream.
loadMedia
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/media/MediaClient.html#loadMed
java.lang.String-)
: loads an arbitrary media resource and returns it’s data as an InputStream
loadImage
(https://docs.gluonhq.com/charm/javadoc/6.2.3/com.gluonhq.cloudlink.client/com/gluonhq/cloudlink/client/media/MediaClient.html#loadIma
java.lang.String-)
: loads an image media resource into a JavaFX Image
The following code snippet shows an example of how to show a media resource into a Glisten View:
JAVA
public void initialize() {
MediaClient mediaClient = new MediaClient();
Image image = mediaClient.loadImage("backgroundImage");
setCenter(pane);
}
https://docs.gluonhq.com/#_introduction 159/191
30/09/2023, 18:48 Gluon Documentation
The resource bundle consists of a resource file for each supported locale. When adding a new resource bundle, you specify the
locale that defines the associated language, country, script, etc. When the client application requests the resource bundle, it also
passes down a locale so that Gluon CloudLink can return the resource bundle that matches the given locale.
Note: it is best practice to always provide a version of the resource bundle with an empty locale. This way, when no matching
resource bundle could be found for a given locale, the resource bundle with the empty locale will be used as a fallback.
JAVA
public void initialize() {
MediaClient mediaClient = new MediaClient();
ResourceBundle resourceBundle = mediaClient.loadResourceBundle("com.gluonhq.sample.BasicView",
Locale.getDefault());
setCenter(pane);
}
https://docs.gluonhq.com/#_introduction 160/191
30/09/2023, 18:48 Gluon Documentation
The Usage Analytics service is responsible for gathering statistics on the devices that are running your Gluon Mobile application.
That information can then be visualised and analysed from within the Gluon Dashboard web application.
The data that is being gathered contains information about the requests that the Gluon Mobile application makes to the Gluon
CloudLink services. It also contains general information about the device itself, like the platform, the model, the version of the
application, etc.
. The method can be called at any time, but ideally it should be called as soon as the application is launched.
JAVA
UsageClient usageClient = new UsageClient();
usageClient.enable();
This will trigger a call to the Gluon CloudLink Usage service that stores the general device information. The trigger will only be
sent the first time, so any subsequent calls to the enable method will do nothing.
pom.xml
Don’t forget to add the Attach device plugin in the pom.xml file of your Gluon Mobile project.
XML
...
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>device</artifactId>
<version>4.0.18</version>
</dependency>
...
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.21</version>
<configuration>
...
<attachList>
<list>device</list>
...
</attachList>
<mainClass>${main.class}</mainClass>
</configuration>
</plugin>
https://docs.gluonhq.com/#_introduction 161/191
30/09/2023, 18:48 Gluon Documentation
https://docs.gluonhq.com/#_introduction 162/191
30/09/2023, 18:48 Gluon Documentation
The Push Notifications service enables sending push notifications to the devices that installed your Gluon Mobile application. A
push notification is a notification message that can be sent to the device, even when the application is not running. This can be
used to unobtrusively notify a user that an application specific event has triggered.
Sign in to the Firebase Console (https://console.firebase.google.com) with your Google Account and create a new project, or choose one
of your existing projects to enable FCM for that project.
https://docs.gluonhq.com/#_introduction 163/191
30/09/2023, 18:48 Gluon Documentation
The next step will allow enabling Google Analytics, which is optional. Press continue and wait until the project has been created.
https://docs.gluonhq.com/#_introduction 164/191
30/09/2023, 18:48 Gluon Documentation
Let’s add Firebase support to an Android app, by selecting the Android icon. Fill in the package name of the android application.
The package name should match the name of the package that is configured in Android Manifest of your Gluon Mobile
application.
Click Register app to continue and then download the configuration file, it should be added to the src/main/resources folder
of your project.
https://docs.gluonhq.com/#_introduction 165/191
30/09/2023, 18:48 Gluon Documentation
Press next twice (we don’t need to add the Firebase SDK, as Gluon Attach takes care of it), and finally press Continue to the
console .
Back to the project’s console, in here you can configure which Google services should be enabled in the Google Application.
Select the settings icon to the right of Project Overview , and choose the Cloud Messaging service.
https://docs.gluonhq.com/#_introduction 166/191
30/09/2023, 18:48 Gluon Documentation
A Server API Key and Sender ID are generated for the Android app.
Gluon Dashboard
Browse to the Gluon Dashboard (https://gluon.io), select the Push Notifications link and navigate to the Configuration tab. Paste the
Server API Key into the textfield in the Android section at the top. Don’t forget to click the Save button to apply your changes.
In both cases you need a valid account in the Apple Developer portal. More information about iOS notifications can be found here
(https://developer.apple.com/notifications/).
Certificate p12
https://docs.gluonhq.com/#_introduction 167/191
30/09/2023, 18:48 Gluon Documentation
Go to the Apple Developer portal (https://developer.apple.com/account/), sign in with your credentials, and create a certificate for your
app following these steps:
https://docs.gluonhq.com/#_introduction 168/191
30/09/2023, 18:48 Gluon Documentation
Confirm you App ID: make sure your App ID information is correct, and click the Register button.
https://docs.gluonhq.com/#_introduction 169/191
30/09/2023, 18:48 Gluon Documentation
Under Identifiers → App IDs, now the created app ID it will be listed. Click on it, and at the end of the expanded info click on
the Edit button.
Go to the Push Notifications section and click on Create Certificate for develpment, production or both.
Follow the instructions on how to generate a Certificate Signing Request (CSR) file on your Mac.
Open Keychain Access app and select Keychain Access > Certificate Assistant > Request a Certificate from a Certificate
Authority.
Add your email, name, select Save to disk, click continue.
Save the file, i.e. CSR_PushNotes.certSigningRequest .
https://docs.gluonhq.com/#_introduction 170/191
30/09/2023, 18:48 Gluon Documentation
Download the certificate aps_development.cer and double click on it to install the certificate in Keychain Access.
Once Keychain Access shows the certificate, expand it, select it and your name, and right click, selecting Export 2 items , and
save the file on your disk, i.e. PushNotes_Certificate.p12 providing a password for it.
https://docs.gluonhq.com/#_introduction 171/191
30/09/2023, 18:48 Gluon Documentation
Important note: This file and the password will be required later on the push notifications configuration tab of the Gluon
Dashboard (https://gluon.io).
Provisioning profile
One last step is required to be able to sign your app: get a provisioning profile for it.
Back again to the Apple Developer Center, under Provisioning Profiles (Development or Distribution), click on the + button to
add a new profile.
Select iOS App Development or App Store, and press Continue.
Select the App ID from the combobox, and press Continue.
Select the certificates you wish to include in this provisioning profile, and press Continue. These will be used later
( iosSignIdentity ).
Select the devices you wish to include in this provisioning profile, and press Continue.
Give a name to the profile, and press Continue
The provisioning profile is ready to be downloaded.
https://docs.gluonhq.com/#_introduction 172/191
30/09/2023, 18:48 Gluon Documentation
Build and sign your application using this profile. See iOS configuration.
Gluon Dashboard
When you’ve managed to prepare your application for both FCM and APNs, you can configure your Gluon Mobile application in
the Gluon Dashboard (https://gluon.io). Select the Push Notifications link from the menu, go the Configuration tab, where you can
enter the FCM Server API key and upload your APNs certificate.
With the proper certificates, the Push Notifications tab can be used to send a push notification. Clicking on the + button will pop
up a dialog from which you can enter the details of the notification.
https://docs.gluonhq.com/#_introduction 173/191
30/09/2023, 18:48 Gluon Documentation
The checkbox labelled invisible can be selected to send silent push notifications to the user, without a visible notification. The
Runtime Args
(https://docs.gluonhq.com/attach/javadoc/4.0.18/com.gluonhq.attach.runtimeargs/com/gluonhq/attach/runtimeargs/RuntimeArgsService.html)
service will be able to process it and execute certain action.
POST https://cloud.gluonhq.com/3/push/enterprise/notification
Form Parameters
Name Type Description Default
https://docs.gluonhq.com/#_introduction 174/191
30/09/2023, 18:48 Gluon Documentation
Java Client
JAVA
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new CloudLinkClient(config);
JAVA
PushClient pushClient = new PushClient();
pushClient.enable(); // enable push notifications
This will trigger a message on an iOS device asking the user to confirm that push notifications are allowed for the application. On
Android, if the user has not yet installed or activated Google Play services, a message will be shown to ask for permission to install
and/or activate Google Play services on the device.
pom.xml
Don’t forget to add the Attach device , push-notifications and runtime-args services in the pom.xml file of your Gluon
Mobile project.
pom.xml
https://docs.gluonhq.com/#_introduction 175/191
30/09/2023, 18:48 Gluon Documentation
XML
<dependencies>
...
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>device</artifactId>
<version>${attach.version}</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>push-notifications</artifactId>
<version>${attach.version}</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>runtime-args</artifactId>
<version>${attach.version}</version>
</dependency>
...
</dependencies>
...
<plugin>
<groupId>com.gluonhq</groupId>
...
<configuration>
...
<target>${gluonfx.target}</target>
<attachList>
<list>device</list>
<list>display</list>
<list>lifecycle</list>
<list>push-notifications</list>
<list>runtime-args</list>
...
...
</plugins>
Android configuration
For Android, we need to add the google-services.json file to the src/main/resources folder. This file can be downloaded
from the project’s Firebase console.
iOS configuration
First make sure to configure your app so it can use Push notifications in the Apple Developer Center. You can follow this step-by-
step guide.
As signing identity, use the certificate selected during the provisioning profile generation.
When deploying to your iOS device, the provisioning profile will be downloaded. If this is not the case, you still can install it
manually: Open Xcode, connect your device, go to Window → Device, and at the bottom left there is a small engine icon, click to
see the installed provisioning profiles, and then click on the + button to add this one.
Note that this provisioning profile contains the entitlements that match those installed within the app, required to enable push
notifications.
The apsEnvironment property needs to match the match the used environment ( development or production ).
https://docs.gluonhq.com/#_introduction 176/191
30/09/2023, 18:48 Gluon Documentation
10. Samples
10.1. HelloFX - Native application
To learn how to build and run the HelloFX (https://github.com/gluonhq/gluon-samples/tree/master/HelloFX) application sample natively
on each platform, using GluonFX plugin for Maven, check the "HelloFX Sample" section under each of the platforms:
Linux
MacOS
Windows
Android
iOS
Linux
MacOS
Android
iOS
https://docs.gluonhq.com/#_introduction 177/191
30/09/2023, 18:48 Gluon Documentation
https://docs.gluonhq.com/#_introduction 178/191
30/09/2023, 18:48 Gluon Documentation
The latest version of Scene Builder can be downloaded from the Gluon website (http://gluonhq.com/labs/scene-builder/).
Open Source
Scene Builder is open-sourced, and licensed under the BSD-3 license. Its source code is hosted under Gluon organization in
Github (https://github.com/gluonhq/scenebuilder).
11.1. Installation
Download the correct installer for your platform from the Scene Builder download page (http://gluonhq.com/labs/scene-builder/). The
installation details are different for each platform but should be straight-forward.
As of Scene Builder 8.3.0, the Windows installer will let you choose the installation folder, but please note that
you will need to run as administrator (right-click, run as administrator) if you want to install in a system-
wide location.
From Scene Builder version 8.2.0, a new function was added, allowing the user not only to import local jar or FXML files as
before, but also to import jars from a number of repositories, remote and local, public and even private ones.
To import libraries either from disk or from repositories, the menu item JAR/FXML Manager gives access to a new dialog, and
replaces the old menu item.
https://docs.gluonhq.com/#_introduction 179/191
30/09/2023, 18:48 Gluon Documentation
For each library, the user can edit or delete it. Editing an FXML will open it in Scene Builder. Editing a jar file will open a dialog
where the user can preview and select or unselect different components (if any) of that jar that will be added to the Custom panel.
On the lower part of the dialog, there are different actions that the user can perform.
Search Repositories
The user can type a name of a library: full name or part of its group id, or full name or part of it of the artifact id, following the
usual naming convention (https://maven.apache.org/guides/mini/guide-naming-conventions.html).
https://docs.gluonhq.com/#_introduction 180/191
30/09/2023, 18:48 Gluon Documentation
For instance, if the user wants to download and install the latest release of com.gluonhq:charm , he can search just for charm :
All the results listed from all possible artifacts with that keyword, are retrieved from a given set of repositories:
Maven Central
Jcenter
Sonatype (releases)
Gluon Nexus (releases)
Local M2 (releases)
The results don’t include the version number, and this is only retrieved if the artifact is finally installed.
Note: Only latest releases will be resolved with this option. For any other version, including snapshots, the user has to use the
option Manually Add Libraries from repository (see below).
By selecting the desired artifact, and clicking Add JAR , the artifact will be resolved from one of the repositories, downloading the
latest release version, and installing it into the local M2 repository.
https://docs.gluonhq.com/#_introduction 181/191
30/09/2023, 18:48 Gluon Documentation
Then the jar will be scanned and a dialog will show any component that can be added to the Custom panel, typically classes that
are assignable from Node . The user can select or unselect those components that should be added or excluded from the Custom
panel. Also, some components can be previewed. The user has to click on Import Components to finish the process.
https://docs.gluonhq.com/#_introduction 182/191
30/09/2023, 18:48 Gluon Documentation
Once the dialog is closed, the new library will show up on the list. Again, it can be edited, to modify the list of included
components, or deleted, to remove the jar and its components from the Custom panel.
Note: When an artifact is removed from the list, it will just be removed from Scene Builder, but the artifact won’t be removed
from the local M2 repository.
Maven Central
Jcenter
Sonatype (releases and snapshots)
Gluon Nexus (releases)
Local M2 (releases and snapshots)
https://docs.gluonhq.com/#_introduction 183/191
30/09/2023, 18:48 Gluon Documentation
Once a version is selected, clicking Add JAR will resolve the artifact, downloading and installing it into the local M2 repository.
The jar will be scanned and available components can be imported, after the user clicks on Import Components .
https://docs.gluonhq.com/#_introduction 184/191
30/09/2023, 18:48 Gluon Documentation
Manage Repositories
Finally, the user can manage the repositories where artifacts are resolved from.
https://docs.gluonhq.com/#_introduction 185/191
30/09/2023, 18:48 Gluon Documentation
Initially, the preset list of remote repositories is listed. These are not editable and can’t be removed.
By clicking on Add Repository , the user can add new repositories to the list, both public or private.
A new repository requires a name and a valid URL. If it is private, the credentials are required as well. The test button will
perform a connection to the given URL to check if it is valid or not, and if private, if the credentials are valid as well.
https://docs.gluonhq.com/#_introduction 186/191
30/09/2023, 18:48 Gluon Documentation
Note: The credentials will be stored locally in the user preferences. They will be used only when installing libraries from the
private repository.
Finally, the user repository will be added to the list, with the possibility of edition or deletion.
https://docs.gluonhq.com/#_introduction 187/191
30/09/2023, 18:48 Gluon Documentation
When using Gluon controls, don’t forget to use the Gluon Mobile preview theme as shown in the screenshot below, or controls
might not work correctly.
As of Scene Builder 8.4.0 you can also preview your controls using a Gluon Swatch and Theme. The theme can either be Gluon
Mobile Light or Gluon Mobile Dark, the Swatch is the primary color used, it is what affects the appearance of the controls the
most. In your code you should then use the Swatch and Theme API to effectively have the same appearance.
https://docs.gluonhq.com/#_introduction 188/191
30/09/2023, 18:48 Gluon Documentation
If you want to create your View in FXML with an AppBar also defined, you should disable the globally provided AppBar in your
code by toggling its visibility:
MobileApplication.getInstance().getAppBar().setVisible(false);
View also has a bottom property, for instance you can set a BottomNavigation on that position.
https://docs.gluonhq.com/#_introduction 189/191
30/09/2023, 18:48 Gluon Documentation
As you can see on the previous image there are sizes for Desktop, Tablet and Mobile Phones. The default size can be changed in
the Preferences window.
If you want to preview your design live, you can by selecting the Preview → Show Preview in Window (or Ctrl + P) menu item.
This will open up a window with a Scene containing the FXML you defined.
With the preview window open you can change it’s size by dragging the window borders or to a specific value from the menu:
https://docs.gluonhq.com/#_introduction 190/191
30/09/2023, 18:48 Gluon Documentation
12. Conclusion
In case you have any questions, your first stop should be the Gluon support page (https://gluonhq.com/support/), where you can
access the latest samples, documentation and more. Gluon also recommends the community to support each other over at the
Gluon StackOverflow (https://stackoverflow.com/tags/gluon/) page. Finally, Gluon offers commercial support (https://gluonhq.com/services/)
as well, to kickstart your projects.
We encourage you to start developing new projects using Gluon offering. We can’t wait to see what you create!
https://docs.gluonhq.com/#_introduction 191/191