JVx' JavaFX UI with JavaFXPorts

Post to Twitter

A few hours ago, we published a screenshot from our Demo ERP application running on Nexus 9 (an Android tablet).
It wasn't a fake!

Before we'll show you more screenshots, we want say that we've reached a long awaited goal!

Use JVx and write an application for all polpular platforms and devices.
This is real "write once run anywhere".

Create an application for Windows, Linux, Mac, iOS, or Android, PS4, OUYA or WiiU. Run it as desktop application, as html5 application in web browsers, as native iOS or Android application or as JavaFX application on Android and iOS devices. There's nothing like JVx in the world - not with only one framework with such a small footprint as JVx and certainly not Open Source!

Here are the screenshots:

Maximized frame with charts

Maximized frame with charts

Frame with tree

Frame with tree

Also in portrait mode:

Portrait mode

Portrait mode


And now a very strange one. It's the application with our styled stage. It's crazy because you can drag the window around (makes no sense, but it just works):

Styled stage with tabset desktop

Styled stage

Sure, the application wasn't optimized for mobile devices. It has the same style as the desktop application. The mobile version should have bigger frame buttons and a bigger frame header :) To be honest - MDI on mobile devices? We were positively surprised about the usability. But, whatever. You have the option and decide what's best for your application (but please don't use MDI for smartphones).

Are you interested in some details?

We've used Netbeans IDE because there's a very useful plugin from gluon. We're Eclipse users but it was easier to use a preconfigured environment without doing everything manually. It was simple to configure Netbeans with gluon plugin and there's a video for your first steps. A "bigger" problem was gradle because the project was a gradle project and we've never used gradle. We love using ant.

We had a bad start with Hello World application because it didn't work. There were different problems: Missing ANDROID_HOME or DEX compiler problems. After reading the documentation it was possible to start compilation. The DEX problem was very strange because we had JVM 1.8 u31 and JVM 1.8 u40 configured in Netbeans, but Netbeans didn't use our configured JVM 1.8 u40. We removed the JVM 1.8 u31 from Netbeans and after that we successfully compiled our Hello World application. Very strange!

The next step was using JVx as library dependency for our project, but how did this work with gradle? We had the library in the libs directory of the project, in the file system. We didn't use a maven lib because it was easier to replace the library after recreation. We tried to find a solution in the official gradle documentation and found Chapter 51. C'mon gradle is a build tool and not a programming language! So much documentation means: complexity. Sure, ant wasn't the holy grale but it it's simple to understand and doesn't hide anything.

Our current gradle script:

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

    }
}

apply plugin: 'org.javafxports.jfxmobile'

repositories {
    jcenter()
}

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    runtime fileTree(dir: 'libs', include: '*.jar')
}

mainClassName = 'com.sibvisions.gluon.JVxGluonApp'
   
jfxmobile {
   
    ios {
        forceLinkClasses = [ 'com.sibvisions.gluon.**.*' ]
    }
   
    android {
      androidSdk = 'C:/tools/android/android-sdk_r04-windows'
      compileSdkVersion = 21  
    }
}

It's short but we ddin't know what happened behind the scenes without additional research. But if it works it's good enough for many developers.

The integration of JVx was simple because JVx was compiled with JVM 1.6. The Dalvik VM or DART do support 1.6 and 1.7 syntax. It was cool to see that JVx and especially the communication worked without problems - Great job from Johan Vos and all people behind JavaFXPorts!

Our next step was the integration of additional dependencies like our JavaFX UI. It was based on JVM 1.8 u40 and heavily used lambdas. But lambda expressions weren't supported from Dalvik or ART. We thought that gluon plugin solves the problem for us, but it didn't. It contains retrolambda but only for project source files and it doesn't touch your dependencies. There was no additional gradle build task for that, so we had to convert the libs manually. Not a problem but you must be aware of it.

After we solved all dependency problems, we had the first version of our desktop ERP running on our android device. But don't think everything was trouble-free. We had problems with method references, Java Preferences because of write problems, new Date API, forEach calls, scene size and much more. We did solve most problems but not all - yet.

19 Responses to “JVx' JavaFX UI with JavaFXPorts”

  1. Javier Godino says:

    Hello:

    How did you fix the DEX error?

    Thanks

    Javier

    Output file C:\DesarrollosAndroid\Portabilidad\demo\HelloPlatform\build\javafx
    ports\tmp\android\dex\classes.dex has been removed.
    [ant:java] Java Result: 1
    :HelloPlatform:dex FAILED
    :HelloPlatform:dex (Thread[main,5,main]) completed. Took 0.701 secs.

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':HelloPlatform:dex'.
    > org.gradle.api.GradleException (no error message)

    * Try:
    Run with --stacktrace option to get the stack trace. Run with --debug option to
    get more log output.

    BUILD FAILED

    Total time: 2 mins 54.237 secs
    Stopped 0 compiler daemon(s).

  2. rjahn says:

    We had a different DEX error!

    Be sure that JVM 1.8 u40 is configured. In our case, the problem was 1.8 u31 altaugh we had 1.8 u40 as project JVM. Do you use SDK Version 21?
    (We removed the JVM 1.8 u31 configuration).

    We checked the prerequisites: http://javafxports.org/page/Getting_Started
    and set the plugin version to: 1.0.0-b7 in our gradle build file. It was -b5 before.

  3. Javier Godino says:

    RESOLVED!!!

    I had JAVA_HOME pointing to 32bits and PATH pointing to 64bits.
    Now both JAVA_HOME and PATH point to C:\Program Files\Java\jdk1.8.0_40

    Another thing that I changed was JDK1.8. I had installed JDK1.8 U40 early access. I reinstaled the last U40

    Thanks!!!

    Javier

  4. Rakesh says:

    Hi, I am facing Problem

    [ant:java] Java Result: 1
    :dex FAILED

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':dex'.
    > org.gradle.api.GradleException (no error message)

    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

    BUILD FAILED

    Total time: 1 mins 2.916 secs

    Build failure (see the Notifications window for stacktrace): gradle :androidInstall

  5. rjahn says:

    I can't tell you what's the main cause, but try same steps as Javier and:

    Check if you have JDK 1.8 u40 installed properly and your gradle project is configured to use it!

    In our case, the DEX problems were related to a wrong configured JVM/project.

  6. charles okunrin says:

    i get this error after i run my project . pls help

    Error: Could not find or load main class Main.java
    :run FAILED

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':run'.
    > Process 'command 'C:\Program Files\Java\jdk1.8.0_45\bin\java.exe'' finished with non-zero exit value 1

    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

  7. rjahn says:

    Do you use a JVx project or standard JavaFX project with JavaFXports libs?

    If you need help for JavaFXPorts, simply use the google group: https://groups.google.com/forum/#!forum/javafxports

  8. charles okunrin says:

    i use JavaFX project with JavaFXports libs

  9. rjahn says:

    OK, so the best place for you is: https://groups.google.com/forum/#!forum/javafxports

    We had a similar problem on a OSX with an EarlyAccess JDK, but the version looks good in your case. Be sure that your Main class was configured in your gradle build file. There's a nice example application: https://github.com/jperedadnr/Game2048FX

  10. charles okunrin says:

    this is another error am getting

    FAILURE: Build failed with an exception.

    * What went wrong:
    ANDROID_HOME not specified. Either set it as a gradle property, a system environment variable or directly in your build.gradle by setting the extension jfxmobile.android.androidSdk.

    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

    BUILD FAILED

  11. rjahn says:

    Please read: http://javafxports.org/page/Getting_Started
    (Prerequisites, Android)

    e.g.

    android {
    androidSdk = 'C:/tools/android/android-sdk'
    compileSdkVersion = 21
    }

  12. charles okunrin says:

    this is the new error after following the steps

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':mergeClassesIntoJar'.
    > Cannot expand ZIP 'C:\Tools\android\android-sdk_r24.3.3-windows\android-sdk-windows\extras\android\support\multidex\library\libs\android-support-multidex.jar' as it does not exist.

    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

  13. rjahn says:

    Please use https://groups.google.com/forum/#!forum/javafxports for JavaFXPorts questions!

  14. charles okunrin says:

    please help with this error

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':androidInstall'.
    > com.android.builder.testing.api.DeviceException: java.lang.RuntimeException: No connected devices!

    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

  15. rjahn says:

    Please use https://groups.google.com/forum/#!forum/javafxports for JavaFXPorts questions!

  16. keti says:

    gluon convert to androin only in sdk new and for on 64bit
    I try in 32bit os windows not yet ready

  17. rjahn says:

    Not sure what you mean, but jdk with 32bit isn't a problem.

  18. ANU CHAUHAN says:

    Issue 1
    --------

    Requested project: C:\Users\anu\Documents\NetBeansProjects\net

    Stack trace:
    org.gradle.tooling.BuildException: Could not execute build using Gradle distribution 'https://services.gradle.org/distributions/gradle-2.2.1-all.zip'.
    at org.gradle.tooling.internal.consumer.ResultHandlerAdapter.onFailure(ResultHandlerAdapter.java:59)
    at org.gradle.tooling.internal.consumer.async.DefaultAsyncConsumerActionExecutor$1$1.run(DefaultAsyncConsumerActionExecutor.java:57)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
    at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
    at org.gradle.tooling.internal.consumer.BlockingResultHandler.getResult(BlockingResultHandler.java:46)
    at org.gradle.tooling.internal.consumer.DefaultBuildLauncher.run(DefaultBuildLauncher.java:72)
    at org.netbeans.gradle.project.tasks.AsyncGradleTask.runBuild(AsyncGradleTask.java:369)
    at org.netbeans.gradle.project.tasks.AsyncGradleTask.doGradleTasksWithProgressIgnoreTaskDefCancel(AsyncGradleTask.java:492)
    at org.netbeans.gradle.project.tasks.AsyncGradleTask.doGradleTasksWithProgressIgnoreTaskDefCancel(AsyncGradleTask.java:402)
    at org.netbeans.gradle.project.tasks.AsyncGradleTask.doGradleTasksWithProgress(AsyncGradleTask.java:393)
    at org.netbeans.gradle.project.tasks.AsyncGradleTask.access$400(AsyncGradleTask.java:84)
    at org.netbeans.gradle.project.tasks.AsyncGradleTask$BuildExecutionItem$1.run(AsyncGradleTask.java:775)
    at org.netbeans.gradle.project.tasks.GradleDaemonManager.runBlockingGradleTask(GradleDaemonManager.java:52)
    at org.netbeans.gradle.project.tasks.GradleDaemonManager.access$200(GradleDaemonManager.java:23)
    at org.netbeans.gradle.project.tasks.GradleDaemonManager$2.execute(GradleDaemonManager.java:129)
    at org.jtrim.concurrent.AbstractTaskExecutorService$FunctionWrapper.execute(AbstractTaskExecutorService.java:270)
    at org.jtrim.concurrent.AbstractTaskExecutorService$TaskOfAbstractExecutor.execute(AbstractTaskExecutorService.java:340)
    at org.jtrim.concurrent.Tasks$RunOnceCancelableTask.execute(Tasks.java:342)
    at org.jtrim.concurrent.ThreadPoolTaskExecutor$ThreadPoolTaskExecutorImpl$QueuedItem.runTask(ThreadPoolTaskExecutor.java:1213)
    at org.jtrim.concurrent.ThreadPoolTaskExecutor$ThreadPoolTaskExecutorImpl$Worker.executeTask(ThreadPoolTaskExecutor.java:1049)
    at org.jtrim.concurrent.ThreadPoolTaskExecutor$ThreadPoolTaskExecutorImpl$Worker.run(ThreadPoolTaskExecutor.java:1179)
    at org.jtrim.concurrent.ThreadPoolTaskExecutor$ThreadPoolTaskExecutorImpl$Worker$1.run(ThreadPoolTaskExecutor.java:998)
    at java.lang.Thread.run(Thread.java:745)
    Caused by: org.gradle.internal.exceptions.LocationAwareException: Execution failed for task ':dex'.
    at org.gradle.initialization.DefaultExceptionAnalyser.transform(DefaultExceptionAnalyser.java:77)
    at org.gradle.initialization.MultipleBuildFailuresExceptionAnalyser.transform(MultipleBuildFailuresExceptionAnalyser.java:47)
    at org.gradle.initialization.StackTraceSanitizingExceptionAnalyser.transform(StackTraceSanitizingExceptionAnalyser.java:30)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:108)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:80)
    at org.gradle.tooling.internal.provider.BuildModelAction.run(BuildModelAction.java:43)
    at org.gradle.tooling.internal.provider.BuildModelAction.run(BuildModelAction.java:30)
    at org.gradle.tooling.internal.provider.ConfiguringBuildAction.run(ConfiguringBuildAction.java:119)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:36)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
    at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:47)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:34)
    at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
    at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:35)
    at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
    at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:24)
    at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
    at org.gradle.launcher.daemon.server.exec.StartStopIfBuildAndStop.execute(StartStopIfBuildAndStop.java:33)
    at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:71)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:69)
    at org.gradle.util.Swapper.swap(Swapper.java:38)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:69)
    at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
    at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:34)
    at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
    at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:70)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:34)
    at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
    at org.gradle.launcher.daemon.server.exec.DaemonHygieneAction.execute(DaemonHygieneAction.java:39)
    at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
    at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:46)
    at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:246)
    at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
    Caused by: org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':dex'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:69)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:305)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:23)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:88)
    at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:29)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
    at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:68)
    at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:55)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)
    ... 32 more
    Caused by: org.gradle.api.GradleException:
    at org.javafxports.jfxmobile.plugin.android.task.Dex.dex(Dex.groovy:57)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:218)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:211)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:200)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:579)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:562)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
    ... 55 more

    help me please...

  19. rjahn says:

    The better place for help is gluon forum: http://gluonhq.com/forums

    Simply follow the documentation: http://docs.gluonhq.com/javafxports/
    Could be a problem with your JRE or Android SDK version.

Leave a Reply

Spam protection by WP Captcha-Free