#java #gradle #javafx #exe #executable-jar
#java #gradle #javafx #exe #исполняемый файл-jar
Вопрос:
Я хочу создать приложение на javafx. Я новичок в java fx и gradle, поэтому в настоящее время я просто возился с вещами. Одна из первых вещей, которые я хотел попробовать, это создать приложение для исполняемого файла jar или exe. Я пробовал несколько вещей, но у меня никогда не получается выполнить простой jar. он не выполняется, когда я дважды щелкаю по нему. и когда я пытаюсь выполнить его из командной строки, я получаю эту ошибку: Ошибка: компоненты среды выполнения JavaFX отсутствуют и требуются для запуска этого приложения. Я перепробовал много решений, которые я нашел в Интернете, но безуспешно.
Это код приложения:
package org.example;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
Label label = new Label("hello world");
Scene scene = new Scene(label);
primaryStage.setScene(scene);
primaryStage.show();
}
}
и это мой файл build.gradle:
plugins {
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.9'
}
group 'org.example'
version ''
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
}
javafx {
version = "15.0.1"
modules = [ 'javafx.controls','javafx.fxml' ]
}
mainClassName = 'org.example.Main'
jar {
manifest {
attributes 'Main-Class': 'org.example.Main'
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
кто-нибудь знает, как решить эту проблему?
Ответ №1:
Используется jlink
для создания среды выполнения Java, включающей модули JavaFX.
Используйте jpackage
(из JDK 14 и более поздних версий) для объединения вашего приложения с использованием этой среды выполнения. Это даст вам средство запуска .exe и установщики, зависящие от платформы.
Задачи Gradle ‘Exec’ могут легко запускать оба этих инструмента для вас как часть вашей сборки.
Чтобы упростить задачу, вы можете рассмотреть возможность использования JDK, который включает модули JavaFX, чтобы вам не приходилось возиться с настройкой JavaFX SDK и пути к модулю. Существуют сборки OpenJDK от Azul и Bellsoft, которые включают JavaFX.
Вот пример задачи, которую я использую с jpackage. Моя задача AppImage копирует файлы для подготовки к объединению, моя задача jlink создает образ среды выполнения. Эта задача создает работоспособный образ приложения, который я использую для второго вызова jpackage для создания установщиков. Вы также можете просто заархивировать этот образ, если вам не нужен установщик, но каждый образ зависит от платформы, поскольку он содержит встроенные средства запуска и JRE для использования:
task jpackageImage(type: Exec, dependsOn: [jlink, appImage]) {
workingDir = project.projectDir
inputs.property('consoleApp', project.consoleApp)
inputs.property('vendorName', project.vendorName)
if (project.hasProperty('copyright')) {
inputs.property('copyright', project.copyright)
}
// TODO set input directory
inputs.dir "${buildDir}${File.separator}image${File.separator}app"
inputs.dir "${buildDir}${File.separator}image${File.separator}runtime"
// define outputs
outputs.dir "${buildDir}${File.separator}application"
// in a doFirst in case values change (e.g. archive name gets version bump)
// after configuration phase
doFirst {
// Error: Application output directory XXXXXXXXXXXXXX already exists.
def tmpRoot = "$buildDir/tmp/image"
project.delete tmpRoot
project.delete "${buildDir}${File.separator}application"
// resource directories need to exist
project.mkdir resourceDir
//file("${buildDir}/image/app/README.txt").text = "This file should be installed."
def appName = project.applicationName // project.applicationName.replaceAll(" ","")
def copyrightStr = project.hasProperty('copyright') ? project.copyright.toString() : "Copyright (c) ${year} ${vendorName}".toString().trim()
def tmp = [
"${jpackageTool}",
'--type', 'app-image', // Valid values on Windows are: {"app-image", "exe", "msi"}
'--verbose',
'--temp', tmpRoot,
'--app-version', project.version,
'--input', "${buildDir}${File.separator}image${File.separator}app",
'--runtime-image', "${buildDir}${File.separator}image${File.separator}runtime",
'--name', appName,
'--main-jar', "libs${File.separator}${configurations.runtime.artifacts.files.singleFile.name}",
'--main-class', mainClass,
'--resource-dir', resourceDir,
'--icon', iconFileStr,
'--description', project.description,
'--vendor', vendorName,
//'--category', 'Utility',
'--copyright', copyrightStr,
'--dest', "${buildDir}${File.separator}application",
]
// Use a console app for easier debugging (log messages/debug prints are visible)
if (osName.startsWith('windows')) {
// Windows-specific options
//'--win-menu',
//'--win-menu-group', vendorName,
//'--win-upgrade-uuid', project.upgradeUUID,
//'--win-shortcut',
// for a console application
if (project.consoleApp) {
tmp.addAll(['--win-console'])
}
}
if (osName.startsWith('mac')) {
tmp.addAll([
// macOS-specific options
//This name must be less than 16 characters long and be suitable for displaying in the menu bar and the application Info window.
'--mac-package-name', project.macPkgName,
'--mac-package-identifier', project.macPkgIndentifier,
//'--mac-package-signing-prefix', <prefix string>,
//'--mac-sign', // Request that the bundle be signed
//'--mac-signing-keychain', <file path>,
//'--mac-signing-key-user-name', '<team name>'
])
}
commandLine = tmp
println commandLine
}
// workaround https://bugs.openjdk.java.net/browse/JDK-8254920
doLast {
if (osName.startsWith('windows') amp;amp; jlinkCompression == 2) {
project.copy {
from "${buildDir}\application\${project.applicationName}\runtime\bin\zip.dll"
into "${buildDir}\application\${project.applicationName}"
}
}
}
}
В какой-то момент я действительно должен просто создать подходящий плагин Gradle для этого материала.
Вы можете узнать больше о jpackage на https://docs.oracle.com/en/java/javase/14/docs/specs/man/jpackage.html
Комментарии:
1. у вас есть источник, где я могу узнать, как работает jpackage?
2. @yentepaternotte Я расширил ответ одной из моих задач Gradle для запуска jpackage и предоставил ссылку на документацию.
3. @yentepaternotte Вам не обязательно настраивать все вручную. Проверьте badass-jlink-plugin для Gradle.
Ответ №2:
Если вам нужно кратковременное, несколько нестабильное исправление для примеров, подобных вашему, у вас может быть другой класс в том же пути к классу, что и текущий, с методом main . Что бы вы сделали в теле этого метода, так это выполнили Main.main(аргументы). Это заставит программу не думать, что это приложение Java, и заставит его работать должным образом. Кроме того, вы должны изменить имена основных классов на имя нового класса.
Комментарии:
1. разве нет стабильного и долгосрочного решения?
2. @yentepaternotte есть, но это довольно сложно. тем не менее, если вы этого хотите, оно находится в исходном коде, который я предоставил.