Using jpackage
I can't get a pkg
to run on macOS. The installation goes as expected however when I launch the installed application it starts then immediately stops.
Attempting to launch it via CLI and it throws
Error: Could not find or load main class com.example.Application
Caused by: java.lang.ClassNotFoundException: com.example.Application
I've passed the MainClass
argument as com.example.Application
, and I can see it in the installed bundle under Contents/app/example.jar
.
Using the Gradle plugin id "org.panteleyev.jpackageplugin" version "1.3.1"
to build the native installer:
def os = org.gradle.internal.os.OperatingSystem.current()
def pkgType = os.windows ? 'msi' : os.linux ? 'deb' : 'pkg'
def inputDir = "$buildDir/input"
task copyDependencies (type: Copy) {
from configurations.runtimeClasspath
into inputDir
}
task copyJar (type: Copy) {
from tasks.jar
into inputDir
}
jpackage {
dependsOn clean
dependsOn bootJar
dependsOn copyDependencies
dependsOn copyJar
type = pkgType
input = inputDir
destination = "$buildDir/dist"
appName = 'Example'
vendor = 'com.example'
mainJar = tasks.jar.getArchiveFileName().get()
mainClass = 'com.example.Application'
javaOptions = ['-Dfile.encoding=UTF-8']
}
The jar runs just fine when launched via IntelliJ/via CLI.
What else do I need to do here?
Since I'm trying to run a Springboot app, the trick is to not try and launch your main class as you'd typically do but instead to use org.springframework.boot.loader.JarLauncher
This is more properly explained in a blog post by the Spring team
So a complete working example with Springboot looks like:
plugins {
id 'org.springframework.boot' version '2.6.0-SNAPSHOT'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'org.panteleyev.jpackageplugin' version '1.3.1'
id 'application'
}
group = 'space.forloop'
version = '1.0.6'
compileJava.options.encoding = 'UTF-8'
compileTestJava.options.encoding = 'UTF-8'
javadoc.options.encoding = 'UTF-8'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
application {
mainClass = 'com.example.Application'
applicationDefaultJvmArgs = ["-Dfile.encoding=UTF-8"]
}
bootJar {
manifest {
attributes 'Implementation-Version': "${project.version}"
attributes 'Implementation-Title': "${project.name}"
}
}
// Not required but useful if you want to configure a little more.
def os = org.gradle.internal.os.OperatingSystem.current()
def pkgType = os.windows ? 'msi' : os.linux ? 'deb' : 'pkg'
jpackage {
dependsOn "bootJar"
type = pkgType
input = "${buildDir}/libs"
destination = "${buildDir}/dist"
appName = 'Example'
vendor = 'com.example'
mainJar = bootJar.archiveFileName.get()
mainClass = "org.springframework.boot.loader.JarLauncher"
javaOptions = ['-Dfile.encoding=UTF-8']
macPackageName = bootJar.archiveBaseName.get()
}