JavaFX 的奇怪 Gluon 项目结构 - Android 移植

Strange Gluon project structure for JavaFX - Android porting

用于将 JavaFX 移植到 Android 的 Gluon 插件的 gradle 构建(在 Netbeans 8.0.2 中)创建了以下目录结构:

  1. 源包[Java]
  2. Android/Java 包
  3. Desktop/Java 包
  4. Ios/Java 包

这些目录中的每一个都包含 java 个包。通常,Gluon 构建会在 "Source Packages" 目录中的一个 java 包中为我们创建 "main" class [名称为 "Source Packages" 的包可能会产生误导,因为它不是Java 包,它只是一个文件系统目录]。这个 main class 扩展了 Javafx Application class,因此是我们应用程序的入口点。

Android API 只能在 Android/Java Packages 目录中访问其中创建的任何 java 包。比如说,android.Vibrator class 只能在这里引用。

问题是,我们无法将在 Android/Java 目录内的任何 Java 包内创建的 class 引用到在源包 [[=] 内创建的任何 java 包46=]]目录!!如果是这种情况,那么我们如何将应用程序从 javafx.Application 的 start() 方法推进到 android.Vibrator。

gluon 项目结构的快照位于:

如您所知,JavaFXPorts 项目允许在桌面、Android 和 iOS 设备中部署 JavaFX 应用程序。当它只是纯 JavaFX 代码时,项目被添加到 Main 范围,从那里它将在所有这些平台中可见。

只有在您需要一些平台特定代码的情况下,您才应该将其添加到相应的包中。

正如您所提到的,默认情况下,您不会在主包中看到平台包中添加的代码,因此您必须为此提供一种方法。

如果您检查 JavaFXPorts 存储库上的 HelloPlatform sample,您会发现 PlatformService class 使用 ServiceLoader 加载包。

另一种可能性是使用 Class.forName() 在 运行 时间动态加载 classes,一旦我们知道应用所在的平台 运行ning。

我建议你看一下 Gluon Down 项目,它为你管理几个特定于平台的服务,并为你提供统一的、平台无关的 API。

对于 Down (feel free to contribute), you can implement them like in this simple app created using Gluon Plugin 中尚不可用的那些服务。

源包[Java]

首先,创建一个getPlatform()方法,并将引用的classes添加到每个特定平台。例如,在 Android 包上添加 org.gluonoss.vibrator.GluonAndroidPlatform.java

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;
    }
}

现在,创建一个接口,在所有平台上使用您想要的方法:

public interface GluonPlatform {

    void vibrate();

}

最后,在您的主 class 检索平台并调用您的方法:

    @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 套餐

添加振动方法。现在将其留空,但您可以添加一个 Timeline 来移动按钮,例如。

 public class GluonDesktopPlatform implements GluonPlatform {

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

}

Android/Java 套餐

添加振动方法。请注意,我们必须使用 FXActivity,它是 JavaFX 线程和 Android activity.

之间的桥梁
public class GluonAndroidPlatform implements GluonPlatform {

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

}

不要忘记在您的 AndroidManifest 文件中添加所需的权限(您可以在 src/android/AndroidManifest.xml.

下找到它

现在您可以部署项目并将其 运行 部署在桌面 (gradlew run) 上,它会工作,并将其安装在 Android (gradlew androidInstall) 上,并且它也会起作用。