如何在单个.JAR中签署和部署JavaFX应用程序?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在单个.JAR中签署和部署JavaFX应用程序?相关的知识,希望对你有一定的参考价值。

我还在学习JavaFX的细节。一个主要的区别是在dist文件夹(除了库)之外,我发现.jar文件,html文件和JNLP文件,对我来说既不是也没有用(这将是一个桌面应用程序)。

我找到了以下内容(由于敏感/无关信息,属性被省略):

<delete dir="${store.dir}"/>
<mkdir dir="${store.dir}"/>

<jar destfile="${store.dir}/temp_final.jar" filesetmanifest="skip">
    <zipgroupfileset dir="dist" includes="*.jar"/>
    <zipgroupfileset dir="dist/lib" includes="*.jar"/>

    <manifest>
        <attribute name="Main-Class" value="${main.class}"/>
    </manifest>
</jar>

<zip destfile="${store.jar}">
    <zipfileset src="${store.dir}/temp_final.jar"
    excludes="META-INF/*.SF, META-INF/*.DSA, META-INF/*.RSA"/>
</zip>
    <delete file="${store.dir}/temp_final.jar"/>

    <delete     dir = "${build.output.dir}"/>
    <mkdir      dir = "${build.output.dir}"/>

    <signjar
                jar = "${store.jar}"
          signedjar = "${build.output.dir}/${FileName}"
              alias = "${comodo.key.alias}"
          storepass = "${comodo.key.storepass}"
           keystore = "${comodo.key.store}"
          storetype = "PKCS12"
            keypass = "${comodo.key.pass}"
             tsaurl = "${timestamp.url}"/> 

这是为了将“可执行”MAIN JAR和所有依赖库构建到可以从任何位置运行的单个.JAR中,然后对该JAR进行签名并将其移动到“已签名”目录中。

这对于任何JAR库或Swing GUI应用程序JAR都可以正常工作,但是当我尝试使用JavaFX应用程序执行相同的操作时,它会自行调整:

Error: Could not find or load main class com.javafx.main.Main

发现它不起作用我并不完全惊讶,但这有点问题。我做了一些关于可能部署“自包含”应用程序的研究,但这不符合我们的需求。我的雇主以一定的代价购买了Comodo证书,我很快就碰到了一堵墙,看起来因为苹果恶作剧(除非我在这个推定中弄错了)你必须加入他们的开发者俱乐部,以低廉的成本100美元一个一年(没有发生)。我并没有特别为苹果平台做开发。我做Java开发。无论如何,如果我是正确的,那对我们不起作用,那么Windows,Linux和Mac的自包含部署就会出来(再次,如果我是正确的)。

我希望这很简单。

那么如何将我创建的ANT脚本应用于编译包含所有相关LIB的JAR到代码签名的JAR到JavaFX应用程序?

编辑1:好的,所以肯定说得太早了。不是很接近答案。我已经尝试过frankenstein我所知道的关于编译和签署常规JAR文件的知识,以便包含所有库,并且该符号成功地进入了我能够从manual中挑选出来的内容。我所拥有的是大杂烩和失败。除了主.JAR文件之外,我得到一个包含所有内容的.JAR文件。无论如何这是ANT脚本代码:

属性:

<property  name = "name"
          value = "APPNAME"/>

<property  name = "file"
          value = "APPJAR"/>

<property  name = "MC" 
          value = "MAINPACKAGE.MAINCLASS" />

<property  name = "released.dir"
          value = "released"/>

<property  name = "compiled.dir"
          value = "${released.dir}/compiled"/>

<property  name = "stored.dir"
          value = "${released.dir}/stored"/>

<property  name = "signed.dir"
          value = "${released.dir}/signed"/>

其他一切:

<delete dir = "${released.dir}"/>
        <mkdir dir = "${compiled.dir}"/>

        <fx:jar destfile = "dist/compiled.jar">
            <fx:platform javafx = "8.0+" j2se = "8.0"/>
            <fx:application      name = "${name}"
                            mainClass = "${MC}"/>

            <fileset dir = "build/classes"/>

            <fx:resources>
                <fx:fileset dir = "dist" includes = "lib/*.jar"/>
            </fx:resources>
        </fx:jar>

        <fx:signjar keystore = "${comodo.key.store}"
                       alias = "${comodo.key.alias}"
                   storetype = "PKCS12"
                     keypass = "${comodo.key.pass}"
                   storepass = "${comodo.key.storepass}"
                         jar = "dist/compiled.jar"
                     destdir = "${compiled.dir}"/>

        <mkdir dir = "${stored.dir}"/>

        <jar       destFile = "${stored.dir}/temp_final.jar"
            filesetmanifest = "skip" >
            <zipgroupfileset      dir = "${compiled.dir}"
                             includes = "compiled.jar"/>

            <zipgroupfileset      dir = "dist/lib"
                             includes = "*.jar"/>

            <manifest>
                <attribute name = "Main-Class"
                          value = "${main.class}"/>
            </manifest>
        </jar>

        <zip destfile = "${stored.dir}/${file}">
            <zipfileset src = "${stored.dir}/temp_final.jar"
                   excludes = "META-INF/*.SF, META-INF/*.DSA, META-INF/*.RSA"/>
        </zip>

        <delete file="${stored.dir}/temp_final.jar"/>

        <mkdir dir = "${signed.dir}"/>

        <signjar
            keystore = "${comodo.key.store}"
               alias = "${comodo.key.alias}"
           storetype = "PKCS12"
              tsaurl = "${timestamp.url}"
             keypass = "${comodo.key.pass}"
           storepass = "${comodo.key.storepass}"
                 jar = "${stored.dir}/${file}"
             destdir = "${signed.dir}"/>

这就是我必须展示的时间。如果有人能从中收集到可能让我走上正轨的东西(如果我甚至接近,我感觉不像我),那将是非常棒的。

答案

在将我的头骨和其中的内容砸成一种难以辨认的连贯思想之后,我已经设法编写了一个脚本,完成了我要完成的任务。其中大部分来自其他人的贡献和咨询docs。另一个主要贡献是找到here(线程上的最后一个评论,它链接到另一个SO答案,但SO答案对我没有多大帮助)。谢谢你能够从中提取解决方案部分的所有内容。我希望这对其他需要/想要完成这项任务的人有所帮助。

无论如何:第一件事:属性:

<property name = "JFXProject.name"
         value = "PROJECT"/> <!-- Put your own project name here -->
<property name = "JFXMainClass"
         value = "MAINPACKAGE.MAINCLASS"/> <!--Put your own main class here -->
    <!-- don't edit below this line -->
<property name = "JFX.src.dir"
         value = "src"/>
<property name = "JFX.lib.dir"
         value = "dist/lib"/>
<property name = "JFX.build.dir"
         value = "release/JFXBuild"/>
<property name = "JFX.sign.dir"
         value = "release/JFXSign"/>
<property name = "store.dir"
         value = "release/store"/>
<property name = "sign.dir"
         value = "release/sign"/>
<property name = "comodo.key.store"
         value = "PATH-TO-YOUR-CERTIFICATE" /> <!-- You can name this what you like, but you want to make sure the value points to your certificate or JKS file -->

<property name = "comodo.key.storepass"
         value = "PASSWORD"/> <!-- Above applies here. Make sure it's the right password -->

<property name = "comodo.key.alias"
         value = "ALIAS"/> <!-- Make sure it's your right alias. You can find out how to find that information from [here][3] -->

<property name = "comodo.key.pass"
         value = "PASSWORD"/> <!-- In my own experience this was the same as the storepass but it may be different for you -->

<property name = "timestamp.url"
         value = "TIMESTAMPURL"/> <!-- This will vary for you depending on your certificate. -->

如果需要,可以将属性名称更改为对您更有意义的名称,但要确保它们在整个脚本中保持一致。

接下来,我们要清理最后一个构建:

<target name = "JFXClean">
    <echo>Cleaning ${JFX.build.dir}...</echo>
    <delete dir = "${JFX.build.dir}"/>
    <delete dir = "${JFX.sign.dir}"/>
    <delete dir = "${store.dir}"/>
    <delete dir = "${sign.dir}"/>
</target>

然后我们想为新的干净构建重新创建目录......

<target name = "JFXInit" depends = "JFXClean">
    <echo>Creating the build directory...</echo>
    <mkdir dir = "${JFX.build.dir}"/>
    <mkdir dir = "${JFX.sign.dir}"/>
    <mkdir dir = "${store.dir}"/>
    <mkdir dir = "${sign.dir}"/>
</target>

这部分对于获取正常运行的JavaFX JAR文件至关重要:

<target name = "JFXBuild" depends = "jar, JFXInit">
    <fx:jar destfile = "${JFX.build.dir}/${JFXProject.name}.jar">
        <fx:application name = "${JFXProject.name}"
                   mainClass = "${JFXMainClass}"/>
        <fileset dir = "build/classes"/>
    </fx:jar>
</target>

这会将所有部件正确存储到JAR中的位置(包括您可能拥有的任何CSS和JFXML文件。如果您没有创建JFXML应用程序,则可能没有必要。我不知道我没有测试过它。

然后我们要签署JavaFX JAR:

<target name = "JFXSign" depends = "JFXBuild">
    <fx:signjar  keystore = "${comodo.key.store}"
                    alias = "${comodo.key.alias}"
                storetype = "PKCS12" <!-- This is necessary for me, but may not be for you if you are not using a PFX file -->
                  keypass = "${comodo.key.pass}"
                storepass = "${comodo.key.storepass}"
                      jar = "${JFX.build.dir}/${JFXProject.name}.jar"
                  destdir = "${JFX.sign.dir}"/>
</target>

之后还有2个目标可以处理拉链,然后设置拉链,最后一个用于演唱最后一个jar:

<target name = "build" depends = "JFXSign">
    <jar destfile = "${store.dir}/temp_final.jar"
  filesetmanifest = "skip">
        <zipgroupfileset dir = "${JFX.build.dir}"
                     includes = "*.jar"/>
        <zipgroupfileset dir = "${JFX.lib.dir}"
                    includes = "*.jar"/>
        <manifest>
            <attribute name = "Main-Class"
                      value = "${JFXMainClass}"/>
        </manifest>
    </jar>
</target>

<target name = "store" depends = "build">
    <zip destfile = "${store.dir}/${JFXProject.name}.jar">
        <zipfileset src = "${store.dir}/temp_final.jar"
               excludes = "META-INF/*sf, META-INF/*.DSA, META-INF/*RSA"/>
    </zip>
    <delete file = "${store.dir}/temp_final.jar"/>
</target>

<target name = "BuildStoreAndSign" depends = "store">
    <signjar
         keystore = "${comodo.key.store}"
            alias = "${comodo.key.alias}"
        storetype = "PKCS12" <!-- This is necessary for me, but may not be for you if you are not using a PFX file -->
           tsaurl = "${timestamp.url}"
          keypass = "${comodo.key.pass}"
        storepass = "${comodo.key.storepass}"
              jar = "${store.dir}/${JFXProject.name}.jar"
          destdir = "${sign.dir}"/>
    <delete dir = "${JFX.compile.dir}"/>
    <delete dir = "${JFX.build.dir}"/>
    <delete dir = "${JFX.sign.dir}"/>
    <delete dir = "${store.dir}"/>
</target>

我无法解释这一切,因为我在这个问题上远不是一位专家。我能够从示例代码和我找到的源代码中基本上提取出我所看到的内容,并将它组合在一起得到这个:最后一点半有用的信息是this,但请注意这不是使用one-jar(我尝试使用one-jar但它没有用。它没有引入CSS或应用它)。

还有一点警告:This worked for me。我不能保证它会适合你,但我想用它来修补它会产生类似于我的结果(一个.JAR JavaFX应用程序运行在你放的地方)。

另一答案

甲骨文说:http://www.oracle.com/technetwork/articles/javase/single-jar-141905.html

需要修改

<manifest>
    <attribute name="Main-Class" value="${main.class}"/>
</manifest>

并将其更改为

<manifest>
    CHANGE application.MainClass to 
    <attribute name="JavaFX-Application-Class" value="application.MainClass" />
    <attribute name="Main-Class" value="com/javafx/main/Main" />
</manifest>

但是听上面的Oracle让我得到了一个带有外部jar的JavaFX。

另一答案

我尝试了你的build.xml示例,但未能使它工作。

但是,我确实找到了使用Eclipse的替代方法。

  1. 在Eclipse中打开JavaFX项目。
  2. 右键单击您的项目并将其导出为可运行的JAR文件。
  3. 将所需的库提取到生成的JAR中。

enter image description here

  1. 使用标准jar签名者签署可运行的JAR。

为此,您需要先创建一个密钥库:

keytool -genkey -keyalg RSA -alias Aubrey -keystore keystore.jks -storepass YourPassword

然后签名就像这样:

jarsigner -keystore c:path	oyourkeystore.jks -storepass YourPassword c:path	oyourfile.jar Aubrey
  1. 最后,创建一个javafx jnlp文件。并将您签名的jar和jnlp上传到您的服务器。

例如:

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0" xmlns:jfx="http://javafx.com" codebase="http://aubreigo.info/java/" href="FX-People.jnlp">
<information>
<title>FX-People</title>
<vendor>aubrey</vendor>
<description>Google Contacts Viewer</description>
<offline-allowed/>
</information>

<security>
<all-permissions/>
</security>

<resources>
<j2se version="1.6+" href="http://java.sun.com/products/autodl/j2se"/>
<ja

以上是关于如何在单个.JAR中签署和部署JavaFX应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

使用 maven 部署 javafx hsqldb 项目

部署JavaFx应用程序jar

删除 iOS 配置文件时会发生啥

部署 JavaFX 应用程序、创建 JAR 和自包含应用程序以及本机安装程序的最佳方式是啥

分发/部署 JavaFX 应用程序

如何使用 maven 部署 JavaFX 项目,包括自定义和非模块化依赖项?