17

我尝试在 Android 上运行一个简单的 JavaFX 应用程序。因此,我使用 gradle 阅读了javafxports 入门指南来构建应用程序,但我被困在了某个地方。我可以使用installDebugEclipse 中的 gradle 任务在 Android 设备上构建和安装该应用程序,但是,当我启动该应用程序时出现黑屏。当我提取.apk文件时,它不包含 JavaFX 应用程序的 jar 文件。我假设 apk 应该包含 JavaFX 应用程序 jar 文件,但我不知道如何将它包含到.apk.

我还尝试使用 gradle 来构建 JavaFX 应用程序本身(jar 文件),效果很好。但是,我不知道将这个 jar 文件放在哪里,它可以包含在 apk 文件中。我读到我必须把它放到一个dist目录中,但我认为这只会在 Netbeans 中使用,对吧?我正在使用 Eclipse gradle 集成来构建项目。

这是我尝试过的。由于 JavaFX 应用程序与 HelloWorld 示例应用程序一样简单,并且工作起来很吸引人,因此我预计我的 gradle 构建文件中存在配置错误。

build.gradle - 构建 apk

apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'android'

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:2.5.0'
        classpath 'com.android.tools.build:gradle:1.0.1'
    }
}
repositories {
    jcenter()
}
ext {
    dalvikSdkHome = getProjectProperty('dalvikSDK')
    dalvikSdkLib = dalvikSdkHome + '/rt/lib'
}

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.1"
    dexOptions {
        preDexLibraries = false
    }
    sourceSets {
        main {
            jniLibs.srcDir file("${dalvikSdkLib}/")
            assets.srcDirs = ['assets']
        }
    }
    lintOptions {
        abortOnError false
    }
}

dependencies {
    compile files ("${dalvikSdkLib}/ext/jfxrt.jar",
                   "${dalvikSdkLib}/ext/jfxdvk.jar",
                   "${dalvikSdkLib}/ext/compat-1.0.0.jar")
}

project.tasks.withType(com.android.build.gradle.tasks.Dex) {
    additionalParameters=['--core-library']
}

String getProjectProperty(String propertyName) {
    project.hasProperty(propertyName) ? project.property(propertyName) : null
}

build.gradle - 构建 jar

// Declares binary plugin and its required JavaFX classpath
apply from: "http://dl.bintray.com/content/shemnon/javafx-gradle/0.4.0/javafx.plugin"

// Configures plugin
javafx {
    // Points to JDK and its JavaFX libraries, also declares target runtime JDK
    javaRuntime = getProjectProperty('javaJDKPath')

    // Application name and ID presented by target OS
    appID 'HelloWorldApp'
    appName 'Hello World Application'

    // Main class of application
    mainClass 'helloworld.HelloWorld'

    // JVM arguments, system properties, application command line arguments
    jvmArgs = ['-XX:+AggressiveOpts', '-XX:CompileThreshold=1']
    systemProperties = ['prism.disableRegionCaching':'true']
    arguments = ['-l', '--fast']

    // Keystore credentials for signing JAR
    // Generate key: keytool -genkey -alias release -keyalg RSA -keystore keystore.jks -keysize 2048
    releaseKey {
        alias = 'release'
        keyStore = file(getProjectProperty('keystoreJKSFile')) // keyStore = file("${System.properties['user.home']}/keystore/keystore.jks")
        keyPass = getProjectProperty('keyStorePassword')
        storePass = getProjectProperty('storePassword')
    }

    signingMode 'release'
    // ...
}

String getProjectProperty(String propertyName) {
    project.hasProperty(propertyName) ? project.property(propertyName) : null
}

gradle.properties

javaJDKPath=D:/Java/jdk1.8.0_20
dalvikSDK=D:/Java/dalvik-sdk-8u20b3/dalvik-sdk
keystoreJKSFile=D:/Java/jre1.8.0_20/bin/keystore.jks
keyStorePassword=password
storePassword=password

本地属性

sdk.dir=D:/programme/Android/adt-bundle-windows-x86_64-20130917/sdk

这是我的项目结构

HelloWorld
-- src\main
    -- java\helloworld\HelloWorld.java
    -- res\
    -- AndroidManifest.xml
-- assets\
    -- javafx.platform.properties
    -- javafx.properties
-- build.gradle
-- gradle.properties
-- local.properties

我需要使用dist目录吗?我会将我的 JavaFX 应用程序的 jar 文件放在哪里,它将包含在 apk 文件中?

4

2 回答 2

11

现在回答我自己的问题。正如我的问题中所发布的,gradle setup 的配置已经在运行。在我的问题中,我没有向您展示我正在使用 .fxml 文件进行布局。所以我没有让它运行的原因是因为 .fxml 布局没有放置在正确的位置以与 apk 文件打包(LogCat 显示错误Location Not Found并且我的设备上出现黑屏)。

首先,这是 HelloWorld.java 的工作示例(请参阅我的问题中的结构和 gradle 设置等):

package helloworld;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class HelloWorld extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Hello World!");
        Button btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });

        StackPane root = new StackPane();
        root.getChildren().add(btn);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }
}

使用 fxml 布局在 Android 上运行 JavaFX

如果您想使用.fxml文件,则需要稍微更改项目的结构。所有.fxml文件、.css文件、图形等都属于该resources\assets目录或子目录。这样可以确保将 .fxml 文件等打包在 apk 中。

HelloWorld
-- src\main
    -- java\helloworld\
        -- HelloWorld.java
        -- MyController.java
    -- resources\assets\
        -- sample_layout.fxml
    -- AndroidManifest.xml
-- assets\
    -- javafx.platform.properties
    -- javafx.properties
-- build.gradle
-- gradle.properties
-- local.properties

我没有检查是否仍然需要assets包含javafx.platform.properties和(都来自 dalvikVM sdk)的文件夹。javafx.properties如果我检查 .apk 文件的内容,apk 包含两个文件两次。似乎 dalvikVM 库会自动复制这些文件。

注意:如果您需要检查 apk 的内容,请提取 apk 文件,然后提取作为 apk 一部分的 classes.dex(有关详细信息,请参阅此帖子

以下是使用 .fxml 文件的示例:

HelloWorld.java

package helloworld;

import java.io.IOException;
import java.net.URL;

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

public class HelloWorld extends Application {

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

    @Override
    public void start(Stage primaryStage) {
        try {
            URL fxmlFile = getClass().getResource("/assets/sample_layout.fxml");
            FXMLLoader loader = new FXMLLoader(fxmlFile);
            AnchorPane page = (AnchorPane) loader.load();
            MyController controller = (MyController) loader.getController();
            Scene scene = new Scene(page);
            primaryStage.setScene(scene);
            primaryStage.setTitle("JavaFX Sample");
            primaryStage.show();
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

}

MyController.java

package helloworld;

import java.net.URL;
import java.util.ResourceBundle;

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

public class MyController {

    @FXML
    private ResourceBundle resources;
    @FXML
    private URL location;
    @FXML
    private Label label_Counter;
    @FXML
    private Button button_IncrementCounter;
    @FXML
    private Button button_DecrementCounter;

    private static final String OUTPUT_PREFIX = "Counter: ";
    private static int counter = 0;

    @FXML
    void onIncrementButtonPressed(ActionEvent event) {
        label_Counter.setText(OUTPUT_PREFIX + ++counter);
    }

    @FXML
    void onDecrementButtonPressed(ActionEvent event) {
        label_Counter.setText(OUTPUT_PREFIX + --counter);
    }

    @FXML
    void initialize() {
        assert label_Counter != null : "fx:id=\"label_Counter\" was not injected: check your FXML file 'sample_layout.fxml'.";
        assert button_IncrementCounter != null : "fx:id=\"button_IncrementCounter\" was not injected: check your FXML file 'sample_layout.fxml'.";
        assert button_DecrementCounter != null : "fx:id=\"button_DecrementCounter\" was not injected: check your FXML file 'sample_layout.fxml'.";
        label_Counter.setText(OUTPUT_PREFIX + 0);
    }

}

sample_layout.fxml

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

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

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="helloworld.MyController">
   <children>
      <VBox layoutX="332.0" layoutY="71.0" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <children>
            <Label text="Please click on the buttons to increment or decrement the counter:" />
            <Button fx:id="button_IncrementCounter" mnemonicParsing="false" onAction="#onIncrementButtonPressed" text="Increment Counter">
               <VBox.margin>
                  <Insets top="10.0" />
               </VBox.margin>
               <padding>
                  <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
               </padding>
            </Button>
            <Button fx:id="button_DecrementCounter" mnemonicParsing="false" onAction="#onDecrementButtonPressed" text="Decrement Counter">
               <VBox.margin>
                  <Insets top="10.0" />
               </VBox.margin>
               <padding>
                  <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
               </padding>
            </Button>
            <Label fx:id="label_Counter" text="&lt;output-placeholder&gt;">
               <VBox.margin>
                  <Insets top="20.0" />
               </VBox.margin>
            </Label>
         </children>
         <padding>
            <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
         </padding>
      </VBox>
   </children>
</AnchorPane>

希望这可以帮助其他所有人在 Android 上开始使用 JavaFX。

于 2015-01-21T21:50:01.760 回答
3

如何在android上运行javafx:

  1. 下载dalvik sdk
  2. 转到samples\HelloWorld\javafx- 这是 gradle 项目
  3. local.properties
    在我的 Windows 系统上修改示例中 dalvik-sdk 和 android-sdk 的位置:
    sdk.dir=C\:\\dev\\android-sdk javafx.dir=C\:\\dev\\dalvik-sdk
  4. 运行gradlew installDebug以在设备上构建和安装 apk。build您还可以在文件夹中找到输出
  5. 在设备上启动应用程序。(第一次启动前我看到黑屏超过 10 秒)
  6. 在 Eclipse 或 Idea 中打开项目作为标准 gradle 项目
于 2015-01-07T15:35:21.323 回答