且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何签署 JavaFX 应用程序并将其部署到单个 .JAR 中?

更新时间:2022-12-21 13:53:25

在将我的头骨和其中的内容砸成一团难以辨认的连贯思想后,我设法编写了一个脚本来完成我设定的任务去完成.其中大部分内容来自其他人的贡献以及查阅 文档.另一个主要贡献是这里(该线程上的最后一条评论,它链接到另一个 SO 答案,但该 SO 答案对我没有太大帮助).感谢我能够从中提取解决方案部分的所有内容.我希望这对需要/想要完成此任务的其他人有所帮助.

After bashing my skull and the contents therein into a slurry of something hardly recognizable as coherent thought I have managed to compose a script that accomplishes the task I have set out to accomplish. Most of this is taken from other peoples contributions and from consulting the docs. The other major contribution is found here (The last comment on the thread, it links to another SO answer, but that SO answer wasn't much help to me). Thanks go to everything from which I was able to extract the parts of the solution. I hope this is helpful for everyone else who needs/wants to accomplish this task.

无论如何:首先:属性:

Anyway: First things first: Properties:

<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. -->

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

You can change the property names to something more meaningful to you if you want but make sure that they are consistent throughout the script.

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

Next, we want to clean out the last build:

<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>

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

Then we want to re-create the directories for a new clean build...

<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 文件至关重要:

This part is critical to get a functioning JavaFX JAR file:

<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 应用程序,这可能没有必要.我不知道我没有测试了一下.

This will store all parts correctly into their locations in the JAR (including any CSS and JFXML file you may have. If you aren't creating a JFXML application this may not be necessary. I don't know I haven't tested it out.

然后我们要对 JavaFX JAR 进行签名:

Then we want to sign the 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 个目标负责处理 zip 的来源,然后设置该 zip,还有一个目标用于唱最后一个 jar:

After that there are 2 more targets that handle sourcing a zip and then setting up that zip, and one final for singing the last 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,但请注意这不使用单罐(我用单罐试过,但没有用.它没有引入 CSS 或应用它).

I can't really explain a whole lot of this because I'm nowhere near an expert on this subject. I was able to basically extract the sense of what I was looking at from the example code and the sources I found and put it together to get this: One final bit of information that was semi-helpful was this, but please note this does NOT use one-jar (I tried it with one-jar but it didn't work. It wasn't bringing in the CSS or applying it).

还有一点警告:这对我有用.我不能保证它会适合你,但我想修改它会产生与我类似的结果(一个单独的 .JAR JavaFX 应用程序,可以在你放置的任何地方运行).

Also, a bit of warning: This worked for me. I can't guarantee it will for you, but I imagine tinkering around with it would produce results similar to mine (a single .JAR JavaFX application that runs where ever you put it).