Building and Deploying Android Apps Using JavaFX
The original goal of the Java Platform was to provide a software environment for embedded devices. However, a strange loop in history made Java the number one development language for enterprise software. Java on the client received less attention than the lucrative server-market. With JavaFX, the Java platform now has a strong client component that can be used to develop applications for desktops, tablets, mobile and embedded systems. In this article, we will show how to deploy JavaFX Applications on Android devices.
Any software platform for client development has to provide a way to create user interfaces. For the Java platform, AWT (Abstract Window Toolkit) has been the foundation for creating user interfaces. A number of more high-level toolkits (e.g. Swing) are at least partially based on AWT. Since AWT has been part of the Java Platform since the very beginning in 1995, its design principles are rather old and they don't match todays hardware and software capabilities.
The new Java Client component, JavaFX, has been designed from scratch, taking into account experiences from both the Java world as well as from other UI frameworks. One of the key principles of JavaFX is to leverage hardware (e.g. GPU's) as much as possible. Indeed, a requirement for todays user interfaces is a highly responsive and performant toolkit.
JavaFX is an integral part of the Java SE environment, and it is the official “Java on the client” component. It is bundled with the JDK and the JRE on the supported systems. As a consequence, Oracle provides JavaFX as part of the Java SE distributions on Windows, MacOS X, Linux and on embedded ARM systems. There is no official Oracle distribution for JavaFX on iOS or on Android. Good enough, the community is filling this gap. The RoboVM team is adding support for JavaFX on RoboVM, which makes it possible to compile JavaFX applications using the RoboVM compiler and run them on iOS devices.
Having JavaFX available on iOS and Android is very important. Today, we see more and more applications that need to be available not only on a desktop, but also on mobile devices and tablets. It is very expensive to write three versions of the same application in three languages: one for a desktop app, one for iOS, and one for Android. Using JavaFX, the same application can be deployed on all these platforms. Granted, each of these platforms has its own UI characteristics that need to be followed, but the JavaFX Platform provides a number of ways to achieve this, including the usage of CSS and custom skins.
Later in this article, we will highlight another important reason for being able to run JavaFX applications on iOS and Android. But first, we will show how to run existing JavaFX applications on the Android platform.
JavaFX on Android
The remainder of this article is about deploying JavaFX applications on Android. Detailed instructions on how to compile, package and deploy JavaFX applications on Android can be found on the JavaFX porting-team web site.
In general, the following steps must be applied:
- Download the Android SDK and the JavaFX-Android SDK
- Create your JavaFX Application
- Use the JavaFX-Android SDK to create an Android project based on your JavaFX Application
- Use the Ant build system to create Android packages
- Upload to the App Store
Step 1. Download the Android SDK and the JavaFX-Android SDK
In order to compile and build your application, you need to install the Android SDK and the JavaFX-Android SDK.
The Android SDK is provided by Google and can be downloaded from the Android developer-support website. It contains the android.jar API's and the tools to convert Java class files into Dalvik bytecode. The Android SDK also provides tools to communicate with Android devices, which is useful for transferring applications to devices and inspecting logs. Once this is downloaded, you might find it convenient to set the ANDROID_SDK environment variable to the downloaded adt-bundle-xxx/sdk (xxx depending on your version and system.)
The Dalvik JavaFX-Android SDK (provided by the JavaFX Android porting team), can be downloaded from JavaFX Ports on BitBucket. Download and unzip the latest dalvik-sdk-version.zip. (You can set an environment variable DALVIK_SDK to point to the newly unzipped dalvik-sdk). The JavaFX-Android SDK contains a JavaFX implementation that runs on Android, along with some tools to build the Android packages, and a sample JavaFX "Hello, Android" application, which you can find under the DALVIK_SDK/samples directory you just downloaded. You will also need Ant for building the apk file. If you don't already have Ant, download it from the Apache Ant website.
Step 2. Create your JavaFX Application
This step is not different from creating JavaFX Applications for desktop systems. You can use your favorite IDE and build tools to create a JavaFX Application. Doing so, the road to creating Android packages starts easily. There is no need to create a specific JavaFX Application launcher, or to add configurations in this step. The JavaFX-Android SDK provides tools for this, as we will discuss in the next steps.
While it is often best to stick with platform-independent code, there are cases where it is convenient to leverage an Android specific implementation, e.g. where there is no corresponding JavaFX or Java API available. The Android platform provides a number of services (e.g. retrieval of location) that can provide the required functionality to your applications. You can use those by adding a dependency on android.jar (available in the Android SDK) and referring to the contained classes. You should be aware of course that your application won't be able to use the Android specific functionality on other systems (for example your desktop.) Also, keep in mind that a desktop application has a larger UI footprint than a handheld device, so be sure to respect the smaller footprint when creating your Android layout. Have a look at the HelloAndroid class in the samples directory, and how we get the screen bounds and use that to set the Stage and Scene bounds.
If you would like to perform this step using the sample application, cd to the samples/HelloWorld under your DALVIK_SDK directory, downloaded in step 1.
Package your application as a jar. To do so using the sample, first cd to DALVIK_SDK/samples/HelloWorld/javafx, then build the application using ./gradlew
on linux and MacOS or gradlew.bat on Windows. (You do not need to download Gradle; gradlew will do that for you.) This creates a jar file (HelloWorld.jar) in javafx/build/libs. For your own application you don't need to use Gradle; you can use Maven or Ant, or anything else to generate the jar.
Step 3. Use the JavaFX-Android SDK to generate an Android project based on your JavaFX Application
The DALVIK_SDK contains a “samples” directory, containing a build script "convertJavaFXToAndroid.sh that can be used to generate an Android project, which is basically a directory containing some files and build scripts for generating Android packages (apk files).
For building your own project you must provide a number of parameters including the locations of the Android SDK and the JavaFX-Android SDK, the location of your JavaFX Application and the name of the main class file.
The file DALVIK_SDK/samples/HelloWorld/convertJavaFXToAndroid.sh will work by just making one modification: set the ANDROID_SDK variable at the top of that file, to point to your system ANDROID_SDK that you downloaded in step 1. (There is currently not a Windows version convertJavaFXToAndroid.bat but you can make one by copying the .sh version and modifying it for Windows.) For more information on on generating the Android project, see DALVIK_SDK/samples/HelloWorld/README.
Before you can call the convertJavaFXToAndroid.sh script, you must have build.gradle and the other gradle related files in the same directory as the script. Copy all of the gradle related files as well as the entire gradle directory from the samples directory to your JavaFX project root, and make the modifications to the convertJavaFXToAndroid.sh script. Then call that script. The resulting Android project can now be found under samples/HelloWorld/javafx/build.
For building your own project, you can follow the pattern of that script. The parameters are defined as follows:
-PPACKAGE: The Android package name.
-PNAME: The name that will be assigned to the generated android apk
-PANDROID_SDK: The Android SDK
-PJFX_SDK: The Dalvik SDK
-PJFX_APP: The directory containing the jar that contains your packaged JavaFX application
-PJFX_MAIN: The main JavaFX "Launcher" class name.
Step 4. Use the Ant build system to create Android Packages
The Android project directory "build" that was generated in Step 3 (the directory you specified in ‑PDIR) now contains a build.xml file. cd to the build directory and call “ant debug”. This produces an Android “debug package” that is ready to be used on an Android device.
Using the Android tools in the Android SDK, this .apk file can now be sent to the device, e.g. by calling
$ANDROID_SDK/platform-tools/adb -r install /path/to/the.apk
It is recommended that you capture the log by running the following command:
JavaFX bundled applications, a perfect fit for application stores.
There is another important reason to have JavaFX running on both iOS and Android, and that is because of the distribution model via the application stores (Apple AppStore and Google Play Store). One of the frustrations many Java client developers had in the past, was how difficult it was to publish a Java application to a variety of mobile phones. Despite all standardization efforts (e.g. MIDP), it was never easy to deploy a J2ME application to a large number of devices without the help of either the device manufacturer, the network operator, or both. Today, the creation of applications and the installation of applications on mobile devices are much easier. Both iOS and Android have their own application store, where developers can upload applications and end-users can download and run applications. Both the iOS AppStore and the Android Play Store have a number of requirements and design guidelines that should be fulfilled by applications. As there are already JavaFX applications in both the AppStore and the Google Play Store, it is proven that JavaFX based applications can be accepted in the stores. This creates a huge market for Java client application developers.
Your JavaFX Android application is not different from any other Android application. You can upload it to the Google Play Store the same way you would upload other Android applications. And similarly to other Android applications, there are a number of guidelines that you should take into account before doing so. These guidelines should not be seen as annoying rules, but rather as an aid for JavaFX developers to make their applications consistent with other Android applications, and which will make them more acceptable for end-users.
Step 5. App store deployment (a work in progress)
Uploading a JavaFX Application to the Google Play Store is not that hard, but at this moment there are a number of steps that should be followed. The path between writing a JavaFX application using your favourite IDE and the submission to the Play Store is too long. Also, too many different systems are being used. In case you develop your JavaFX Application using Maven, you need to use 3 build systems: Maven for your application development, Gradle for creating the Android project, and Ant for building the Android package.
Work is in progress to improve this. There are a number of ways this can be improved, and some of them are being investigated. For example, Android recently switched to Gradle as the preferred building environment. The Android Gradle plugin could make it easier to compile JavaFX applications, but there are still a number of issues that need to be solved.
Similarly, the JavaFXPackager, which is distributed with the JDK, aims to provide bundles for different target environments. It would be great if we could integrate this with the JavaFX-Android SDK.
Also, some IDE's (NetBeans, Eclipse, IntelliJ IDEA) already contains plugins for Android development. Integrating JavaFX support with those IDE's would make the life of developers familiar with these IDE's much easier.
The JavaFX Android porting team has chosen to provide an end-to-end toolset first, allowing developers to upload their Applications to the Play Store. This proves that there are no technical or legal hurdles preventing you from writing JavaFX applications for Android.
As a next step, the different parts in the end-to-end deployment are being enhanced.
Under the hood
The JavaFX Platform is developed in the OpenJFX project, which is a sub-project of OpenJDK, the home for the development of the Java Platform in general. All code development and the discussions are done in an open environment.
The OpenJFX codebase contains the JavaFX API's and implementations for a number of platforms. The JavaFX architecture itself is modular, and the platform-specific parts are isolated from the general parts. This is not an easy achievement, as one of the design principles of JavaFX is to leverage hardware acceleration as much as possible.
The JavaFX-Android SDK is created from the code in the OpenJFX codebase. There are two major challenges in this porting effort:
- the OpenJFX code contains some native code, that has to be cross-compiled for the Android system
- the Dalvik runtime, available on Android, contains only a subset of Java 7. However it does support lambda expressions.
The first challenge is completely solved in OpenJFX. All code that is required to implement the native functionality for JavaFX on Android is part of OpenJFX.
The second challenge is mainly solved because the OpenJFX developers agreed not to use Java 8-specific functionality for the JavaFX 8u20 release. Still, a number of calls to Java 7 API's are used that are not available on Android. The good news is that the JavaFX-Android SDK contains its own implementations for these missing API's. You can use lambda expressions because the RetroLambda project (included in the distribution) allows for replacement of the invokedynamic bytecode inside class files. Just be careful, java.util.Streams are not currently supported.
Mapping Android concepts
The lifecycle of Android applications is different from the lifecycle of typical desktop applications. Android uses the concept of an Activity. The translation between the Android concepts and the JavaFX concepts is done as part of the JavaFX-Android SDK. The JavaFX-Android SDK contains a class called FXActivity that is a subclass of Activity that will be instantiated for a JavaFX Application.
The whole JavaFX application is part of that single activity. The moment the JavaFX application starts, JavaFX takes over. This has the advantage that the JavaFX lifecycle events and the organisation of the application, including navigation, can be done in a similar manner to desktop applications. No Android-specific knowledge is required for doing lifecycle management.
While it is often desirable to be device-independent, in a number of cases a developer might want to leverage Android-specific features. For those cases, the JavaFX-Android SDK provides the required hooks that allow JavaFX developers to access the Android API's, the first of which is the Android manifest file that is generated by the JavaFX-Android SDK. That manifest is suitable for the basic applications, but it can be configured by the developer as well. In this manifest file, permissions are requested, and the basic Android configuration parameters are set.
Next the Android Platform provides a number of services that compliment the JavaFX Platform and that are more tied with the Android devices, e.g. location services, communicating with NFC readers etc. In a typical Android application, these services are accessed via the Android Activity and Context classes. Those are Android specific classes and do not exist in the JavaFX Platform. However the JavaFX-Android SDK provides a static
Context context = FXActivity.getInstance();
method that gives access to the Context instance associated with the Activity that is created and that runs our JavaFX application.
The returned Context instance can be used to retrieve Android-specific services. An example on how to use the NFC reader is described here. A similar example on how to use the GPS services can be found in the open-source OpenMapFX Project.
If you have questions, the JavaFX Android forum on Google groups is quite useful.
About the Author
Johan Vos started to work with Java in 1995. He was part of the Blackdown team helping port Java to Linux. With LodgON, the company he co-founded, he is mainly working on Java based solutions for social networking software. Because he can't make a choice between embedded development and enterprise development, his main focus is on end-to-end Java, combining the strengths of back-end systems and embedded devices. His favourite technologies are currently Java EE / Glassfish at the backend and JavaFX at the front-end. Johan is a Java Champion, a member of the BeJUG steering group, the Devoxx steering group and he is a JCP member. He is the lead author of the Pro JavaFX 8 book, and he has been a speaker at numerous conferences on Java (including JavaOne and Devoxx). You can read his blog and follow his tweets.
In the step 3 you say : "The DALVIK_SDK contains a tools directory, containing a build script "convertJavaFXToAndroid.sh". I donwloaded dalvik-sdk-8u20b2.zip on bitbucket.org/javafxports/android/downloads and installed it but I don't find any "tools" directory. I will try to go further with the convertJavaFXToAndroid.sh file which is in the HelloWorld sample.
Re: Step 3
Thanks for pointing this out!
Do people really want desktop experience on Android
Re: Do people really want desktop experience on Android
JavaFX allows for this, by having different stylesheets and skin classes. With DataFX-Flow, you can also create separate flows for desktop or mobile.
Agreed, it takes some effort, but at least it will always be more integrated than a mobile website.
Also, we will cover this in a JavaOne session: oracleus.activeevents.com/2014/connect/sessionD...
JavaFX "light" on Android, iOS, browsers & co.
Well "nothing" - there is nice styling alá CSS. But that is available in HTML as well. FX comes with scenegraph - but honestly, do you really need it? Is not it better to empower all the good HTML5 libraries out there?
These thoughts lead me to investigate HTML+Java client side synergy (sometimes nicknamed "FX light"). I believe it is now in good shape.
Plus, those who cry for a video may check my yesterday's screencast and give HTML+Java a try.
Re: JavaFX "light" on Android, iOS, browsers & co.
I don't think application size is really an issue with today's phones and tablets. I was running BrickBreaker on my Samsung tablet, and really, you can't see a performance difference with a native game.
That doesn't mean that classes should be added just for the sake of adding them. In the end, however, it's all just about bytecode being executed. You can easily screw an application in any language.
Having a deeper look into "FX light" is still definitely on my todo-list :)