Pull to refresh

Быстрый способ создать установщик для Java программы

Reading time4 min
Views18K
Вам никогда не надо было быстро создать установщик для своего Java-приложения, но не хотелось тратить на это кучу времени, создавая свой собственный? Возможно, вы удивитесь, но в стандартной поставке JDK7 такой инструмент уже присутствует.

Краткое описание


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-скрипты. Что для этого надо сделать?
  1. Добавить поддержку ant-javafx: в корневом элементе xml-дерева project установить параметр
    xmlns:fx="javafx:com.sun.javafx.tools.ant"
    , а в его теле добавить
     <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"/>
    
    , при этом у вас должна быть установлена переменная ${java.sdk} в корень JDK.
  2. 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>
    
  3. 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>
    


  4. 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.
Tags:
Hubs:
Total votes 31: ↑30 and ↓1+29
Comments12

Articles