JavaFX on Android with JavaFXPorts

Nowadays there is a tool that allows to deploy your JavaFX application easily and run it on Android and iOS devices (thus making the phrase “write once run everywhere” true) and it’s called JavaFXPorts. I’ve encountered a few small issues while experimenting with this tool and researching on the internet I came to the conclusion that I’m not the only one and there is no (at least I couldn’t find it) tutorial on Windows (not that there’s much difference, but I’ve seen some complains).

I’m going to show step by step how to do this and show solutions to some problems I’ve seen people complaining or asking about. These are the things you need:

I’ve created a simple JavaFX project using fxml and it consists of a button and a label. The button says click me and each time you click the button the label says how many times the button was clicked. I did not even put the .fxml file in a different package. There are three files: Main.java, MainLayoutController.java and MainLayout.fxml in the com.wordpress.breekmd.java package.

Main.java:

package com.wordpress.breekmd.java;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class Main extends Application {

	Stage mainStage;

	@Override
	public void start(Stage primaryStage) {
		try {
			this.mainStage = primaryStage;
			FXMLLoader loader = new FXMLLoader();
			AnchorPane pane = loader.load(getClass().getResourceAsStream("/com/wordpress/breekmd/java/MainLayout.fxml"));

			Scene mainScene = new Scene(pane);
			mainStage.setTitle("JavaFXPorts example!");
			mainStage.setScene(mainScene);
			mainStage.show();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		launch(args);
	}
}

MainLayoutController.java

package com.wordpress.breekmd.java;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;

public class MainLayoutController {

	int counter;

	@FXML
	Button clickBtn;

	@FXML
	Label clickLabel;

	@FXML
	public void initialize(){
		counter = 0;
	}

	public void onButtonClick(){
		counter++;
		clickLabel.setText("You've clicked this button " + counter + " times!");
	}
}

MainLayout.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="334.0" prefWidth="524.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.wordpress.breekmd.java.MainLayoutController">
   <children>
      <VBox alignment="CENTER" layoutX="194.0" layoutY="141.0" spacing="10.0">
         <children>
            <Button fx:id="clickBtn" layoutX="229.0" layoutY="142.0" mnemonicParsing="false" onAction="#onButtonClick" text="Click me!" />
            <Label fx:id="clickLabel" layoutX="201.0" layoutY="180.0" text="You've clicked this button 0 times!" />
         </children>
      </VBox>
   </children>
</AnchorPane>

Now, follow these steps:

  1. First of all, from eclipse, build and run with ant.
  2. Open cmd and go to the folder where you extracted your JavaFX Android SDK and open “android-tools” folder. Now write your gradle code. It should look like this: gradlew –stacktrace –info createProject -PDEBUG -PDIR=D:\JavaFXPortsAndroid -PPACKAGE=com.wordpress.breekmd.java -P NAME=JavaFXPortsAndroid -PANDROID_SDK=C:\Users\breek\android-sdks -PJFX_SDK=D:\dalvik-sdk -PJFX_APP=D:\JavaFXPortsAndroid\build\dist -PJFX_MAIN=com.wordpress.breekmd.java.Main
    PDIR is where your project will be created;
    PPACKAGE is the package of the JavaFX app;
    NAME is the name of the app;
    PANDROID_SDK is where the Android SDK is stored;
    PJFX_SDK is the address of the JavaFX Android SDK folder;
    PJFX_APP is where the app was build with ant, the address of the “dist” folder;
    PJFX_MAIN is the name of the main class.
  3. Within cmd go to PDIR and open the folder with your newly created project and run “ant clean debug”. Wait for about 2 minutes. Please be sure you have ant installed and added to the PATH variable in system environment variables.
  4. Now, in the folder of your new project, open “bin” folder and you will find two .apk files. Move the on your phone and install them. Be advised, it does not work on virtual devices!
  5. You can install the app on your phone using ADB. Using cmd go to the Android SDK folder and then to “platform-tools” folder and write: “adb install app_name.apk”. To see the log, connect your device to the computer and open the “LogCat” view in Eclipse. If it does not show your phone, write this in the cmd:
    “adb kill-server” and then “adb start-server”. Do not forget to place the app_name.apk in the “platform-tools” folder.

Please, be sure there are no spaces in any folders name and that you added the Android SDK address and the tools folder address (from the Android SDK folder) to PATH variable in the system environment variables menu. To check the latter just write in cmd “android” and it should open the ADB. Otherwise you will get an error about android.bat being unable to run.

Okay, please stay tuned. I know it does not seem so easy as I have promised, but this is because now is an even easier way!!

Create a “build.gradle” file and place it in the root folder of the project in Eclipse. This is what it should contain:

task wrapper(type: Wrapper) {
    gradleVersion = '2.3'
}

buildscript {
    repositories {
        jcenter()
    }

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

apply plugin: 'org.javafxports.jfxmobile'

mainClassName = 'java.Main'

repositories {
    jcenter()
}

jfxmobile {
    ios {
        forceLinkClasses = ['java.**.*']
    }
    android {
        applicationPackage = 'com.wordpress.breekmd.java'
    }
}

Now, go in cmd to the folder containing the project and run the following command “gradle wrapper”. After it is installing everything, run “gradlew android”. Go to “/build/javafxports/android” from the project folder and there you will find your apks. Now install them on your phone the way I described earlier or any other method.

Here’s how it should look on your phone:

JavaFX app on Android device

JavaFX app on Android device

37 comments

  1. I builded an ant file but i have no “dist” Folder.. Where do i find it or what did I do wrong ?

    1. When creating the ant file you must specify the directory of the build (under ”Build directory”) as well as other information like app name and version, so be sure you check that folder of the build for the ”dist” folder. Try this and let me know if it works.

  2. I got that to work by installing android api 21. I am now building the apk…but when I try to run it on the device, it says “There is a problem parsing the package”. I have confirmed this device is running api level 21.

  3. now it is saying:
    C:\Users\cnorris\android-sdks\platform-tools>adb -s 5df05440 install c:\cwcode\j
    avafx_example\build\javafxports\android\javafx_example.apk
    1895 KB/s (6188986 bytes in 3.188s)
    pkg: /data/local/tmp/javafx_example.apk
    Failure [INSTALL_FAILED_INVALID_APK]

    1. just place javafx_example.apk in platform-tools folder and then run adb install javafx_example.apk
      Also check the manifest file for any errors.

  4. Any ideas? I really want to be able to use this method to build for Android and Java FX on windows mobile (already accomplished) so that the same code can run on both

    1. C:\Users\cnorris\android-sdks\platform-tools>adb -s 8DZTJFEM99999999 install jav
      afx_example.apk
      4305 KB/s (6188986 bytes in 1.403s)
      pkg: /data/local/tmp/javafx_example.apk
      Failure [INSTALL_FAILED_INVALID_APK]

      (had to change devices – coworker went home)

    1. try the first method. I know it is more time consuming and looks scary but there have been a lot of reports of problems with the gradle way.

  5. Sorry man, I was busy the whole day. Which method did you use and did you try to logcat your device via Eclipse while running the app? I know second method can get you a black screen sometimes.

  6. I just built in eclipse with an

    Buildfile: C:\cwcode\javafx_example\build.xml
    build-subprojects:
    init:
    build-project:
    [echo] javafx_example: C:\cwcode\javafx_example\build.xml
    build:
    BUILD SUCCESSFUL
    Total time: 1 second

    1.  
      <?xml version="1.0" encoding="UTF-8"?>
      	<project name="JavaFXPortsAndroid" default="do-deploy" basedir="."  xmlns:fx="javafx:com.sun.javafx.tools.ant">
      	<target name="init-fx-tasks">
      		<path id="fxant">
      			<filelist>
      				<file name="${java.home}\..\lib\ant-javafx.jar"/>
      				<file name="${java.home}\lib\jfxrt.jar"/>
      			</filelist>
      		</path>
      	
      		<taskdef resource="com/sun/javafx/tools/ant/antlib.xml"
      			uri="javafx:com.sun.javafx.tools.ant"
      			classpathref="fxant"/>
      	</target>
      	<target name="setup-staging-area">
      		<delete dir="externalLibs" />
      		<delete dir="project" />
      		<delete dir="projectRefs" />
      	
      		<mkdir dir="externalLibs" />
      	
      	
      		<mkdir dir="project" />
      		<copy todir="project">
      			<fileset dir="D:\Projects workspace\JavaFXPortsAndroid">
      				<include name="src/**" />
      			</fileset>
      		</copy>
      	
      		<mkdir dir="projectRefs" />
      	</target>
      	<target name='do-compile'>
      		<delete dir="build" />
      		<mkdir dir="build/src" />
      		<mkdir dir="build/libs" />
      		<mkdir dir="build/classes" />
      	
      		<!-- Copy project-libs references -->
      		<copy todir="build/libs">
      			<fileset dir="externalLibs">
      			</fileset>
      		</copy>
      	
      		<!-- Copy project references -->
      	
      		<!-- Copy project sources itself -->
      		<copy todir="build/src">
      			<fileset dir="project/src">
      				<include name="**/*"/>
      			</fileset>
      		</copy>
      	
      		<javac includeantruntime="false" source="1.8" target="1.8" srcdir="build/src" destdir="build/classes" encoding="Cp1252">
      			<classpath>
      				<fileset dir="build/libs">
      					<include name="*"/>
      				</fileset>
      			</classpath>
      		</javac>
      	
      		<!-- Copy over none Java-Files -->
      		<copy todir="build/classes">
      		<fileset dir="project/src">
      			<exclude name="**/*.java"/>
      		</fileset>
      		</copy>
      	
      	
      	</target>
      	<target name="do-deploy" depends="setup-staging-area, do-compile, init-fx-tasks">
      		<delete file="dist"/>
      		<delete file="deploy" />
      	
      		<mkdir dir="dist" />
      		<mkdir dir="dist/libs" />
      	
      		<copy todir="dist/libs">
      			<fileset dir="externalLibs">
      				<include name="*" />
      			</fileset>
      		</copy>
      	
      	
      		<fx:resources id="appRes">
      			<fx:fileset dir="dist" includes="JavaFXPortsAndroid.jar"/>
      			<fx:fileset dir="dist" includes="libs/*"/>
      		</fx:resources>
      	
      		<fx:application id="fxApplication"
      			name="JavaFXPortsAndroid"
      			mainClass="com.wordpress.breekmd.java.Main"
      		/>
      	
      		<mkdir dir="build/classes/META-INF" />
      	
      	
      	
      		<fx:jar destfile="dist/JavaFXPortsAndroid.jar">
      			<fx:application refid="fxApplication"/>
      			<fileset dir="build/classes">
      			</fileset>
      			<fx:resources refid="appRes"/>
      	
      			<manifest>
      				<attribute name="Implementation-Vendor" value=""/>
      				<attribute name="Implementation-Title" value="JavaFXPortsAndroid"/>
      				<attribute name="Implementation-Version" value="1.0"/>
      				<attribute name="JavaFX-Feature-Proxy" value="None"/>
      			</manifest>
      		</fx:jar>
      	
      	
      		<mkdir dir="deploy" />
      		<!-- Need to use ${basedir} because somehow the ant task is calculating the directory differently -->
      		<fx:deploy
      			embedJNLP="false"
      			extension="false"
      			width="500" height="300"
      			includeDT="false"
      			offlineAllowed="true"
      			outdir="${basedir}/deploy"
      			outfile="JavaFXPortsAndroid" 
      			updatemode="background" >
      	
      			<fx:platform basedir="${java.home}"/>
      			<fx:info title="JavaFXPortsAndroid" vendor=""/>
      	
      			<fx:application refId="fxApplication"/>
      			<fx:resources refid="appRes"/>
      		</fx:deploy>
      	
      	
      	</target>
      </project>
      
      
  7. I use Netbeans 8.0.2 and jdk 1.8.0_51, when I follows the second method i.e Create a “build.gradle”…, it downloads all files it needs and builds successful. But the folder “/build/javafxports/android” is empty, no .apk created.

    Please what can I do now???

  8. here is my build.gradle content

    task wrapper(type: Wrapper) {
    gradleVersion = ‘2.5’
    }

    buildscript {
    repositories {
    jcenter()
    }

    dependencies {
    classpath ‘org.javafxports:jfxmobile-plugin:1.0.0-b5’
    }
    }

    apply plugin: ‘org.javafxports.jfxmobile’

    mainClassName = ‘javafxandroid.Main’

    repositories {
    jcenter()
    }

    jfxmobile {
    ios {
    forceLinkClasses = [‘java.**.*’]
    }
    android {
    applicationPackage = ‘javafxandroid’
    }
    }

Leave a comment