-->

Strange Gluon project structure for JavaFX - Andro

2020-07-20 04:42发布

问题:

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

回答1:

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.