Pakiet niemodułowej aplikacji JavaFX

Mam aplikację Java 8, która używa JavaFX i gdzie główna klasa rozszerza javafx.podanie.Zastosowanie . Obecnie dostarczam go jako fat jar i działa dobrze na Oracle Java 8.

Teraz chcę, aby mógł działać na OpenJDK 11. Aby dodać JavaFX, dodałem już artefakty z org.openjfx do classpath i włączam je do fat jar. Jeśli uruchamiam jar z linii poleceń, otrzymuję

Error: JavaFX runtime components are missing, and are required to run this
application

Znalazłem dwa możliwe sposoby na obejście tego problem:

  1. brudny: napisz specjalny launcher, który nie rozszerza aplikacji i omija sprawdzanie modułu. Zobacz http://mail.openjdk.java.net/pipermail/openjfx-dev/2018-June/021977.html
  2. czysty: Dodaj --module-path I --add-modules do mojego wiersza poleceń. Problem z tym rozwiązaniem polega na tym, że chcę, aby moi użytkownicy końcowi mogli po prostu uruchomić aplikację, klikając ją dwukrotnie.
/ Align = "left" / jako obejście, ja zastanawiam się, jaki jest obecnie (OpenJDK 11) zamierzony sposób na budowanie / dostarczanie plików wykonywalnych fat jars niemodułowych aplikacji JavaFX. Czy ktoś może pomóc?
Author: Naman, 2019-01-06

1 answers

Oto kilka opcji pakowania/dystrybucji (niemodułowej)aplikacji JavaFX 11. Większość z nich jest wyjaśniona w oficjalnych dokumentach OpenJFX .

Użyję tej próbki jako odniesienia. Użyję też Gradle ' a. Podobnie można zrobić z Maven (różne wtyczki), a nawet bez narzędzi do budowania (ale nie jest to zalecane...). Narzędzia do budowania są obecnie koniecznością.

Słoik Tłuszczu

Jest to nadal ważna opcja, ale nie preferowana, ponieważ łamie modułową konstrukcję i łączy wszystko razem, a nie jest wieloplatformowy, chyba że się tym zajmiesz.

Dla danej próbki, masz budowę.gradle file like this:

plugins {
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.5'
}

repositories {
    mavenCentral()
}

dependencies {
}

javafx {
    modules = [ 'javafx.controls' ]
}

mainClassName = 'hellofx.HelloFX'

jar {
    manifest {
        attributes 'Main-Class': 'hellofx.Launcher'
    }
    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

Zwróć uwagę na użycie klasy Launcher. Jak wspomniano w OP lub wyjaśnione tutaj, Klasa launcher, która nie rozciąga się od {[9] } jest teraz wymagana do utworzenia fat jar.

Uruchomienie ./gradlew jar tworzy fat jar (~8 MB), który zawiera klasy JavaFX i natywne biblioteki z Twojej obecnej platformy.

Możesz uruchomić java -jar build/libs/hellofx.jar Jak zwykle, ale tylko na tej samej platformie.

Jak wyjaśniono w dokumentach OpenJFX lub tutaj , nadal możesz utworzyć wieloplatformowy jar.

W tym przypadku możemy dołączyć trzy słoiki graficzne, ponieważ są to te, które mają zależny od platformy kod i biblioteki. Moduły Base, controls i FXML są niezależne od platformy.

dependencies {
    compile "org.openjfx:javafx-graphics:11.0.1:win"
    compile "org.openjfx:javafx-graphics:11.0.1:linux"
    compile "org.openjfx:javafx-graphics:11.0.1:mac"
}

./gradlew jar wyprodukuje słoik tłuszczu (19 MB), który może być znajdują się TU 3 perony.

(Uwaga Media i Internet mają również zależne od platformy biblioteki kodowe / natywne).

Więc to działa tak jak w Javie 8. Ale jak powiedziałem wcześniej, łamie to, jak działają moduły, i nie dopasowuje się do tego, jak biblioteki i aplikacje są obecnie dystrybuowane.

I nie zapominaj, że użytkownicy tych słoików nadal będą musieli zainstalować JRE.

Jlink

Więc co z dystrybucją niestandardowego obrazu z twojego projektu, że już zawiera natywny JRE i launcher?

Powiesz, że jeśli masz projekt niemodułowy, to nie zadziała. Prawda. Ale przyjrzyjmy się tutaj dwóm opcjom, zanim porozmawiamy o jpackage.

Runtime-plugin

The badass-runtime-plugin jest wtyczką Gradle, która tworzy obrazy uruchomieniowe z projektów niemodułowych.

Z tą konstrukcją.gradle:

plugins {
    id 'org.openjfx.javafxplugin' version '0.0.5'
    id 'org.beryx.runtime' version '1.0.0'
    id "com.github.johnrengelman.shadow" version "4.0.3"
}

repositories {
    mavenCentral()
}

dependencies {
}

javafx {
    modules = [ 'javafx.controls' ]
}

mainClassName = 'hellofx.Launcher'

runtime {
    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
}

Po uruchomieniu ./gradlew runtime utworzy runtime, z jego launcherem, dzięki czemu można przebieg:

cd build/image/hellofx/bin
./hellofx

Zauważ, że opiera się na wtyczce shadow i wymaga również klasy Launchera.

Jeśli uruchomisz ./gradlew runtimeZip, możesz uzyskać zip Dla tego niestandardowego obrazu o wielkości około 32,5 MB.

Ponownie, możesz rozpowszechniać ten zip każdemu użytkownikowi z tą samą platformą, ale teraz nie ma potrzeby instalowania JRE.

Zobacz targetPlatform do budowania obrazów dla innych platform.

Going Modular

Ciągle myślimy, że mamy projekt niemodułowy i tego nie da się zmienić... a jeśli to zmienimy?

Przejście modularne nie jest zbyt dużą zmianą: dodajesz deskryptor module-info.java i dołączasz do niego wymagane moduły, nawet jeśli są to słoiki niemodułowe (oparte na automatycznych nazwach).

Na podstawie tej samej próbki dodam deskryptor:

module hellofx {
    requires javafx.controls;

    exports hellofx;
}

I teraz mogę użyć jlink w wierszu poleceń, lub użyć do tego wtyczki. Badass-Gradle-pluginjest pluginem gradle, od tego samego autora, co ten wspomniany wcześniej, który pozwala na tworzenie niestandardowego środowiska wykonawczego.

Z tym plikiem budowy:

plugins {
    id 'org.openjfx.javafxplugin' version '0.0.5'
    id 'org.beryx.jlink' version '2.3.0'
}

repositories {
    mavenCentral()
}

dependencies {
}

javafx {
    modules = [ 'javafx.controls' ]
}

mainClassName = 'hellofx/hellofx.HelloFX'

Możesz uruchomić teraz:

./gradlew jlink
cd build/image/bin/hellofx
./hellofx

Lub ./gradlew jlinkZip dla skompresowanej wersji (31 MB), która może być dystrybuowana i uruchamiana na maszynach tej samej platformy, nawet jeśli nie ma zainstalowanego JRE.

Jak widać, nie ma potrzeby używania wtyczki shadow lub klasy Launcher. Możesz również kierować na inne platformy lub zawierać zależności niemodułowe, jak w tym pytaniu .

Jpackage

Wreszcie, jest nowe narzędzie do tworzenia wykonywalnych instalatorów, które można wykorzystać do dystrybucji aplikacji.

Na razie nie ma jeszcze wersji GA (prawdopodobnie będziemy musieli poczekać na Javę 13), ale są dwie opcje, aby użyć jej teraz z Javą 11 lub 12:

W Javie / JavaFX 11 znajduje się Port tylny z początkowej pracy nad Jpackagerem w Javie 12, który można znaleźć tutaj. Jest tu fajny artykuł o używaniu go , A projekt gradle, aby go użyć tutaj .

W Javie / JavaFX 12 istnieje już build 0 version narzędzia jpackage, które będzie dostępne w Javie 13.

Jest to bardzo wstępne użycie narzędzia:]}
plugins {
    id 'org.openjfx.javafxplugin' version '0.0.5'
}

repositories {
    mavenCentral()
}

dependencies {
}

javafx {
    version = "12-ea+5"
    modules = [ 'javafx.controls' ]
}

mainClassName = 'hellofx/hellofx.HelloFX'

def java_home = '/Users/<user>/Downloads/jdk-12.jdk/Contents/Home'
def installer = 'build/installer'
def appName = 'HelloFXApp'

task copyDependencies(type: Copy) {
    dependsOn 'build'
    from configurations.runtime
    into "${buildDir}/libs"
}

task jpackage(type: Exec) {
    dependsOn 'clean'
    dependsOn 'copyDependencies'

    commandLine "${java_home}/bin/jpackage", 'create-installer', "dmg",
            '--output', "${installer}", "--name", "${appName}",
            '--verbose', '--echo-mode', '--module-path', 'build/libs',
            '--add-modules', "${moduleName}", '--input', 'builds/libraries',
            '--class', "${mainClassName}", '--module', "${mainClassName}"
}

Teraz uruchomiony ./gradlew jpackage generuje dmg (65 MB), który mogę dystrybuować do zainstalowania:

instalator

Podsumowanie

Podczas gdy można trzymać się klasycznych słoików tłuszczu, podczas przechodzenia do Java 11 i poza nią, wszystko powinno być modułowe. Nowe (wkrótce) dostępne narzędzia i wtyczki, w tym obsługa IDE, pomagają podczas tego przejścia.

Wiem, że przedstawiłem tutaj najprostszy przypadek użycia, i że podczas próbowania bardziej złożonych rzeczywistych przypadków, będzie kilka problemów... Ale powinniśmy lepiej pracować nad rozwiązaniem tych problemów, a nie używać przestarzałych rozwiązań.

 38
Author: José Pereda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-06 20:11:39