3

The gradle build of Gluon plugin (in Netbeans 8.0.2) for porting JavaFX to Android creates the following directory structures:

  1. Source Packages [Java]
  2. Android/Java Packages
  3. Desktop/Java Packages
  4. Ios/Java Packages

Each of these directories contain java packages inside them. Generally Gluon build would create the "main" class for us in one java package inside "Source Packages" directory [the name Packages with "Source Packages" might be misleading since it is not a Java package, its just a file system directory]. This main class extends Javafx Application class and thus is the entry point into our application.

The Android API is accessible only in Android/Java Packages directory for any java package created inside it. Say, the android.Vibrator class is only referr-able here.

The problem is, we cannot refer to a class created inside any Java package inside Android/Java directory to any java package created inside Source Packages [Java] directory!! If this is the case then how would we take the application forward from the start() method of javafx.Application into say android.Vibrator.

The gluon project structure has a snapshot at: How to reference android.jar in Gluon Project

Community
  • 1
  • 1

1 Answers1

2

As you know, JavaFXPorts project allows deploying JavaFX apps in Desktop, Android and iOS devices. When it's just pure JavaFX code, the project is added on the Main scope, and from there it will be visible in all those platforms.

Only in the case you need some platform specific code, you should add it on the corresponding package.

As you have mentioned, by default from the Main package you won't see the added code in a platform package, so you have to provide a way for that.

If you check the HelloPlatform sample on JavaFXPorts repository, you will find a PlatformService class to load the packages using ServiceLoader.

Another possibility is using Class.forName() to load dynamically the classes at runtime, once we know the platform where the app is running.

I suggest you have a look at the Gluon Down project, that manages for you several platform specific services, and provides you with uniform, platform-independent API.

For those services not available yet in Down (feel free to contribute), you can implement them like in this simple app created using Gluon Plugin.

Source Packages [Java]

First, create a getPlatform() method, and add the referred classes to each specific platform. For instance, add org.gluonoss.vibrator.GluonAndroidPlatform.java on Android package.

public class GluonPlatformFactory {

    public static GluonPlatform getPlatform() {
        try {
            String platform = System.getProperty("javafx.platform", "desktop");
            String path = "org.gluonoss.vibrator.GluonDesktopPlatform";
            if(platform.equals("android")) {
                path = "org.gluonoss.vibrator.GluonAndroidPlatform";
            } else if(platform.equals("ios")) {
                path = "org.gluonoss.vibrator.GluonIosPlatform";
            }
            return (GluonPlatform) Class.forName(path).newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            System.out.println("Platform Error "+e.getMessage());
        }
        return null;
    }
}

Now, create an interface, with the method you want on all your platforms:

public interface GluonPlatform {

    void vibrate();

}

Finally, on your main class retrieve the platform and call your method:

    @Override
    public void start(Stage stage) {
        final Button button = new Button("Click me!");

        button.setOnAction(e-> GluonPlatformFactory.getPlatform().vibrate());

        StackPane root = new StackPane(button);

        Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
        Scene scene = new Scene(root, visualBounds.getWidth(), visualBounds.getHeight());

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

Desktop/Java Packages

Add the vibrate method. For now leave it empty, but you could add a Timeline to move the button, for instance.

 public class GluonDesktopPlatform implements GluonPlatform {

    @Override
    public void vibrate() {
        System.out.println("Vibrating!");
    }

}

Android/Java Packages

Add the vibrate method. Notice that we have to use FXActivity, which is the bridge between the JavaFX thread and the Android activity.

public class GluonAndroidPlatform implements GluonPlatform {

    @Override
    public void vibrate() {
        Vibrator v = (Vibrator) FXActivity.getInstance().getSystemService(Context.VIBRATOR_SERVICE);
        v.vibrate(500);
    }

}

Don't forget to add the required permission on your AndroidManifest file (you will find it under src/android/AndroidManifest.xml.

Now you can deploy the project and run it on Desktop (gradlew run) and it will work, and install it on Android (gradlew androidInstall), and it will work too.

José Pereda
  • 44,311
  • 7
  • 104
  • 132
  • Thanks a lot @Jose Pereda. Since it is essential for java.util.ServiceLoader to expressly indicate the service provider implementations through a recognizing file inside META-INF/services directory and this directory structure should be present at runtime classpath of the application, then what modifications are needed to be made in gradle build script in order to set runtime classpath to point to META-INF/services. I am very new to gradle, so any input would be great. – nawazish-stackoverflow Sep 03 '15 at 19:48
  • I don't think you need any modification. HelloPlatform example works with ServiceLoader without any change in [build.gradle](https://bitbucket.org/javafxports/samples/src/tip/build.gradle). Anyway, I prefer the Class.forName() approach, where the classes names are inserted in code, so you don't need extra text files. Did you try the Vibrator sample' – José Pereda Sep 03 '15 at 20:08
  • @JosePereda.Thanks a lot for your help and explanation. I tried the code above and it worked like "charm"; i used Class.forName(String) instead of ServiceLoader. Since you are already working on Charm Down and as you say there are services yet to be created, I would love to contribute towards the same now as I now feel some level of confidence with JavaFXPorts. Professionally I work on JavaFX for UI in conjunction with EJB as server components with standards like RMI and JMS for integration. I would love to discuss with you, i would like to know which service should I start with. – nawazish-stackoverflow Sep 05 '15 at 19:37
  • Good to know! We can move the discussion to [Gluon Charm forum](http://gluonhq.com/forums/forum/gluon-charm/). Also I suggest you have a look to [Gluon Charm](http://gluonhq.com/products/charm/), since it includes, besides Down, Connect for cloud services, and Glisten for UI. – José Pereda Sep 05 '15 at 19:46
  • Pereda, I have started a thread at: http://gluonhq.com/forums/topic/willing-to-contribute-towards-not-yet-created-charm-down-services/ Could you please provide your inputs. – nawazish-stackoverflow Sep 18 '15 at 09:09