Вам никогда не надо было быстро создать установщик для своего Java-приложения, но не хотелось тратить на это кучу времени, создавая свой собственный? Возможно, вы удивитесь, но в стандартной поставке JDK7 такой инструмент уже присутствует.
javafxpackager — утилита, созданная для того, чтобы создавать пакеты из программ написанных с помощью JavaFX. Через некоторое время после создания в Oracle решили, что эта же утилита может создавать пакеты и для программ, написанных чисто на Java. Название решили не менять.
Что подаётся на вход? Вы можете подавать на вход как директорию с уже скомпилированными исходниками, так и уже собранный jar. Дальше jar упаковывается вместе с JRE и вы можете подавать это пользователю с ещё не установленной java. Это позволяет не заставлять пользователя устанавливать JRE самостоятельно. Итак, как этим пользоваться?
Предположим, у нас есть некий HelloWorld-проект: просто директория src с вложенной директорией helloworld и в ней HelloWorld.java:
В корне лежит простейший ant'овый build.xml, который умеет только собирать class-файлы:
Итак, просто соберём проект:
С помощью javafxpackager можно собирать jar'ы, что мы и сделаем (предварительно создав директорию dist):
Если посмотреть на содержимое созданного jar'a, мы увидим, что он несколько отличается от стандартно создаваемого:
Распаковав его и открыв MANIFEST.MF, мы также увидим, что метод включения тоже несколько отличается от стандартного (он характерен для JavaFX):
Далее, перейдём к самому созданию пакетов. По умолчанию директива deploy создаёт только jnlp и html с встроенным плагином.
Но если указать директиву -native all, то создаётся пакет, специфичный для данной операционной системы: deb и rpm для Linux (любых, содержащих dpkg или rpmbuild для каждого из пакетов соответственно), exe и msi для Windows (к сожалению, здесь существует ограничение и должны быть установлены следующие утилиты: Inno Setup для создания exe и WiX Toolset для msi) и app с dmg для MacOS X. Давайте сразу создавать нативные пакеты (jar мы уже, предположительно, создали):
После этого некоторое время будет происходить сборка. Теперь у нас в директории dist появились различные bundle'ы: 2 пакетных (для разных ОС — разные) и 1, который является по сути распакованным пакетом: директория HelloWorld, в которой лежит бинарник HelloWorld, запуская который мы получаем сразу результат:
Этот код запускается с уже запакованной в директории JRE.
А пакеты можно уже устанавливать.
Есть 2 способа: можно использовать тот же самый javafxpackager, добавляя его в ваши, например, ant-скрипты, с помощью, например, exec'a. Но можно сделать куда круче. В ту же поставку java входит пакет ant-javafx.jar, который позволяет всё это же добавлять в ваши ant-скрипты. Что для этого надо сделать?
Краткое описание
javafxpackager — утилита, созданная для того, чтобы создавать пакеты из программ написанных с помощью JavaFX. Через некоторое время после создания в Oracle решили, что эта же утилита может создавать пакеты и для программ, написанных чисто на Java. Название решили не менять.
Что подаётся на вход? Вы можете подавать на вход как директорию с уже скомпилированными исходниками, так и уже собранный jar. Дальше jar упаковывается вместе с JRE и вы можете подавать это пользователю с ещё не установленной java. Это позволяет не заставлять пользователя устанавливать JRE самостоятельно. Итак, как этим пользоваться?
Примеры использования
Предположим, у нас есть некий HelloWorld-проект: просто директория src с вложенной директорией helloworld и в ней HelloWorld.java:
package helloworld;
public class HelloWorld {
public static void main (String[] args) {
System.out.println ("Hello, world!");
}
}
В корне лежит простейший ant'овый build.xml, который умеет только собирать class-файлы:
<?xml version="1.0" encoding="UTF-8"?>
<project name="Generic" default="compile" basedir=".">
<target name="compile">
<mkdir dir="build/classes"/>
<javac srcdir="src" destdir="build/classes" executable="${java.sdk}/bin/javac"/>
</target>
</project>
Итак, просто соберём проект:
$ ant compile
С помощью javafxpackager можно собирать jar'ы, что мы и сделаем (предварительно создав директорию dist):
$ javafxpackager -createjar -srcdir build/classes -outfile dist/HelloWorld.jar -appclass helloworld.HelloWorld
Если посмотреть на содержимое созданного jar'a, мы увидим, что он несколько отличается от стандартно создаваемого:
$ unzip -l dist/HelloWorld.jar
Archive: dist/HelloWorld.jar
Length Date Time Name
--------- ---------- ----- ----
0 2013-04-29 15:50 META-INF/
158 2013-04-29 15:50 META-INF/MANIFEST.MF
0 2013-04-29 15:50 helloworld/
353 2013-04-29 15:50 helloworld/HelloWorld.class
0 2013-04-29 15:50 com/
0 2013-04-29 15:50 com/javafx/
0 2013-04-29 15:50 com/javafx/main/
2671 2013-04-29 15:50 com/javafx/main/Main$1.class
5633 2013-04-29 15:50 com/javafx/main/NoJavaFXFallback.class
19218 2013-04-29 15:50 com/javafx/main/Main.class
1747 2013-04-29 15:50 com/javafx/main/Main$2.class
--------- -------
29780 11 files
Распаковав его и открыв MANIFEST.MF, мы также увидим, что метод включения тоже несколько отличается от стандартного (он характерен для JavaFX):
Manifest-Version: 1.0
JavaFX-Version: 2.2
JavaFX-Application-Class: helloworld.HelloWorld
Created-By: JavaFX Packager
Main-Class: com/javafx/main/Main
Далее, перейдём к самому созданию пакетов. По умолчанию директива deploy создаёт только jnlp и html с встроенным плагином.
Но если указать директиву -native all, то создаётся пакет, специфичный для данной операционной системы: deb и rpm для Linux (любых, содержащих dpkg или rpmbuild для каждого из пакетов соответственно), exe и msi для Windows (к сожалению, здесь существует ограничение и должны быть установлены следующие утилиты: Inno Setup для создания exe и WiX Toolset для msi) и app с dmg для MacOS X. Давайте сразу создавать нативные пакеты (jar мы уже, предположительно, создали):
$ javafxpackager -deploy -v -srcdir dist -outdir dist -outfile HelloWorld -appclass helloworld.HelloWorld -native all
После этого некоторое время будет происходить сборка. Теперь у нас в директории dist появились различные bundle'ы: 2 пакетных (для разных ОС — разные) и 1, который является по сути распакованным пакетом: директория HelloWorld, в которой лежит бинарник HelloWorld, запуская который мы получаем сразу результат:
Hello, world!
Этот код запускается с уже запакованной в директории JRE.
А пакеты можно уже устанавливать.
Но как добавлять такую сборку в проект?
Есть 2 способа: можно использовать тот же самый javafxpackager, добавляя его в ваши, например, ant-скрипты, с помощью, например, exec'a. Но можно сделать куда круче. В ту же поставку java входит пакет ant-javafx.jar, который позволяет всё это же добавлять в ваши ant-скрипты. Что для этого надо сделать?
- Добавить поддержку ant-javafx: в корневом элементе xml-дерева project установить параметр
xmlns:fx="javafx:com.sun.javafx.tools.ant"
, а в его теле добавить
, при этом у вас должна быть установлена переменная ${java.sdk} в корень JDK.<taskdef resource="com/sun/javafx/tools/ant/antlib.xml" uri="javafx:com.sun.javafx.tools.ant" classpath=".${path.separator}${java.sdk}/lib/ant-javafx.jar"/>
- jar:
<fx:jar destfile="dist/HelloWorld.jar"> <fx:application name="HelloWorld" mainClass="helloworld.HelloWorld" /> <fx:fileset dir="build/classes" /> <fx:manifest> <fx:attribute name="Implementation-Vendor" value="meAndMyCompany"/> <fx:attribute name="Implementation-Title" value="HelloWorld"/> <fx:attribute name="Implementation-Version" value="1.0"/> </fx:manifest> </fx:jar>
- deploy:
<fx:deploy width="100" height="100" nativeBundles="all" outdir="dist" outfile="HelloWorld"> <fx:application name="HelloWorld" mainClass="helloworld.HelloWorld"/> <fx:resources> <fx:fileset dir="dist" includes="*.jar"> </fx:resources> <fx:info title="HelloWorld" vendor="myAndMyCompany"/> </fx:deploy> </pre>
docs.oracle.com/javafx/2/deployment/javafxpackager001.htm — документация по javafxpackager
docs.oracle.com/javafx/2/deployment/javafx_ant_task_reference001.htm — документация по антовым таскам
docs.oracle.com/javafx/2/deployment/self-contained-packaging.htm — дополнительная информация
UPD: Всё те, что указано неработающим здесь, работает в современных версиях JDK.