bigywater.tech
Java · 267

jpackage:把 Java 应用做成系统安装包

jpackage 把 Java 应用连同裁剪的运行时打成系统原生的应用包。生成的 .app 里有什么?配置怎么改?体积怎么压?签名到什么程度?这篇在 macOS 上真实打包、运行并逐项检查。

155 → 30 MB
默认打包的 Demo.app → 指定 --add-modules java.base 并用 jlink 压缩选项
Demo.cfg
启动配置文件(JVM 选项与默认参数),修改后下次启动立即生效
adhoc
app-image 的签名状态

app-image 的结构

实测 · 本机执行输出
  jpackage 返回码 0,耗时 3.7 s;
  Demo.app 目录大小 155 MB
  Demo.app 内的结构(两层):
    Contents/
      Info.plist  (1 KB)
      MacOS/
        Demo  (176 KB)
      PkgInfo  (0 KB)
      Resources/
        Demo.icns  (369 KB)
      _CodeSignature/
        CodeResources  (50 KB)
      app/
        .jpackage.xml  (0 KB)
        Demo.cfg  (0 KB)
        demo.jar  (1 KB)
      runtime/
        Contents/
  Demo.cfg 的内容:
    [Application]
    app.classpath=$APPDIR/demo.jar
    app.mainclass=demo.Main
    
    [JavaOptions]
    java-options=-Djpackage.app-version=1.2.3
    java-options=-Xmx64m
    java-options=-Dcustom.prop=hello
    
    [ArgOptions]
    arguments=first
    arguments=second
  Info.plist 的主要键: {'CFBundleName': 'Demo', 'CFBundleIdentifier': 'demo', 'CFBundleVersion': '1.2.3', 'CFBundleExecutable': 'Demo', 'LSMinimumSystemVersion': '10.11', 'NSHighResolutionCapable': 'true'}
  自动生成的运行时(jpackage 内部用 jlink 裁剪):release 文件里的 MODULES 有 63 个:['java.base', 'java.compiler', 'java.datatransfer', 'java.xml', 'java.prefs', 'java.desktop', 'java.instrument', 'java.logging', 'java.management', 'java.security.sasl', 'java.naming', 'java.rmi', 'java.management.rmi', 'java.net.http', 'java.scripting', 'java.security.jgss', 'java.smartcardio', 'java.transaction.xa', 'java.sql', 'java.sql.rowset', 'java.xml.crypto', 'jdk.accessibility', 'jdk.internal.jvmstat', 'jdk.attach', 'jdk.charsets', 'jdk.internal.opt', 'jdk.zipfs', 'jdk.compiler', 'jdk.crypto.ec', 'jdk.crypto.cryptoki', 'jdk.dynalink', 'jdk.internal.ed', 'jdk.editpad', 'jdk.httpserver', 'jdk.incubator.vector', 'jdk.internal.le', 'jdk.jartool', 'jdk.javadoc', 'jdk.management', 'jdk.management.agent', 'jdk.jconsole', 'jdk.jdeps', 'jdk.jdwp.agent', 'jdk.jdi', 'jdk.jfr', 'jdk.jlink', 'jdk.jpackage', 'jdk.jshell', 'jdk.jsobject', 'jdk.jstatd', 'jdk.localedata', 'jdk.management.jfr', 'jdk.naming.dns', 'jdk.naming.rmi', 'jdk.net', 'jdk.nio.mapmode', 'jdk.random', 'jdk.sctp', 'jdk.security.auth', 'jdk.security.jgss', 'jdk.unsupported', 'jdk.unsupported.desktop', 'jdk.xml.dom']
  运行时里没有 bin/java 可执行文件: True ;有 lib/modules: True (120 MB)
  --add-modules java.base:jpackage 返回码 0,Demo.app 43 MB,运行时模块 1 个
  --add-modules java.base + --jlink-options "--strip-debug --compress zip-9":jpackage 返回码 0,Demo.app 30 MB,运行时模块 1 个

运行与配置

实测 · 本机执行输出
  Contents/MacOS/Demo(不带参数):
    args = [first, second]
    java.home = <实验目录>
    user.dir = /
    app.path = <实验目录>
    custom.prop = hello
    max heap = 64 MB
    ProcessHandle command = <实验目录>
  带命令行参数 extra1 extra2:
    args = [extra1, extra2]
  改 Demo.cfg 里的 -Xmx64m 为 -Xmx256m 后: ['max heap = 256 MB']
  环境变量 JAVA_TOOL_OPTIONS 对启动器的影响: ['Picked up JAVA_TOOL_OPTIONS: -Dfrom.env=1']
  启动到退出的时间(中位,去掉前 2 次):app-image 启动器 64 ms;直接 java -cp demo.jar 38 ms(完整 JDK,有 CDS)

签名、dmg 与 pkg

实测 · 本机执行输出
  codesign -dv: ['Identifier=demo', 'CodeDirectory v=20400 size=541 flags=0x2(adhoc) hashes=11+3 location=embedded', 'Signature=adhoc', 'TeamIdentifier=not set']
  codesign --verify --deep:返回码 0 (无输出,验证通过)
  --type dmg:返回码 0,耗时 132 s,生成 Demo-1.2.3.dmg 58 MB
  --type pkg:返回码 0,耗时 8 s,生成 Demo-1.2.3.pkg 52 MB
  --main-jar 写错(文件不存在)→ 返回码 1 ; Advice to fix: The main jar must be specified relative to the input directory (not an absolute path), and must exist within that directory
  --main-class 写错 → jpackage 返回码 0 ;运行启动器: 返回码 1 ; Error: Could not find or load main class demo.NoSuchMain

分步演示

jpackage
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12 的 jpackage,macOS Apple Silicon;一个只打印信息的 Demo 程序
    • 没有验证:Windows(MSI/EXE)与 Linux(DEB/RPM)的打包、开发者证书签名与公证(notarization)、自动更新、文件关联与图标定制、--mac-package-identifier 等选项、安装包的实际安装与卸载过程、dmg 耗时较长的原因(这台机器上 dmg 需要 132 秒)
    京ICP备2026067502号-1京公网安备11010502063487号