7.6 KiB
Native distributions & local execution
What is covered
In this tutorial, we'll show you how to create native distributions (installers/packages) for all the supported systems. We will also demonstrate how to run an application locally with the same settings as for distributions.
Gradle plugin
org.jetbrains.compose Gradle plugin simplifies the packaging of applications into native distributions and running an application locally.
Currently, the plugin uses jpackage for packaging self-contained applications.
Basic usage
The basic unit of configuration in the plugin is an application.
An application defines a shared configuration for a set of final binaries.
In other words, an application in DSL allows you to pack a bunch of files,
together with a JDK distribution, into a set of compressed binary installers
in various formats (.dmg, .deb, .msi, .exe, etc).
import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("jvm")
id("org.jetbrains.compose")
}
dependencies {
implementation(compose.desktop.currentOS)
}
compose.desktop {
application {
mainClass = "example.MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
}
}
}
The plugin creates the following tasks:
package<FormatName>(e.g.packageDmgorpackageMsi) are used for packaging the app into the corresponding format. Note, that there is no cross-compilation support available at the moment, so the formats can only be built using the specific OS (e.g. to build.dmgyou have to use macOS). Tasks that are not compatible with the current OS are skipped by default.packageis a lifecycle task, aggregating all package tasks for an application.packageUberJarForCurrentOSis used to create a single jar file, containing all dependencies for current OS. The task is available starting from the M2 release. The task expectscompose.desktop.currentOSto be used as acompile/implementation/runtimedependency.runis used to run an app locally. You need to define amainClass— an fq-name of a class, containing themainfunction. Note, thatrunstarts a non-packaged JVM application with full runtime. This is faster and easier to debug, than creating a compact binary image with minified runtime. To run a final binary image, userunDistributableinstead.createDistributableis used to create a prepackaged application image a final application image without creating an installer.runDistributableis used to run a prepackaged application image.
Note, that the tasks are created only if the application block/property is used in a script.
After a build, output binaries can be found in ${project.buildDir}/compose/binaries.
Available formats
The following formats available for the supported operating systems:
- macOS —
.dmg(TargetFormat.Dmg),.pkg(TargetFormat.Pkg) - Windows —
.exe(TargetFormat.Exe),.msi(TargetFormat.Msi) - Linux —
.deb(TargetFormat.Deb),.rpm(TargetFormat.Rpm)
Customizing JDK version
The plugin uses jpackage, which is available since JDK 14.
Make sure you meet at least one of the following requirements:
JAVA_HOMEenvironment variable points to the compatible JDK version.javaHomeis set via DSL:
compose.desktop {
application {
javaHome = System.getenv("JDK_14")
}
}
Customizing output dir
compose.desktop {
application {
nativeDistributions {
outputBaseDir.set(project.buildDir.resolve("customOutputDir"))
}
}
}
Customizing launcher
The following properties are available for customizing the application startup:
mainClass— a fully-qualified name of a class, containing the main method;args— arguments for the application's main method;jvmArgs— arguments for the application's JVM.
compose.desktop {
application {
mainClass = "MainKt"
jvmArgs += listOf("-Xmx2G")
args += listOf("-customArgument")
}
}
Customizing metadata
The following properties are available in the nativeDistributions DSL block:
packageName— application's name (default value: Gradle project's name);version— application's version (default value: Gradle project's version);description— application's description (default value: none);copyright— application's copyright (default value: none);vendor— application's vendor (default value: none).
compose.desktop {
application {
nativeDistributions {
packageName = "ExampleApp"
version = "0.1-SNAPSHOT"
description = "Compose Example App"
copyright = "© 2020 My Name. All rights reserved."
vendor = "Example vendor"
}
}
}
Customizing content
The plugin can configure itself, when either org.jetbrains.kotlin.jvm or org.jetbrains.kotlin.multiplatform plugins
are used.
- With
org.jetbrains.kotlin.jvmthe plugin includes content from themainsource set. - With
org.jetbrains.kotlin.multiplatformthe plugin includes content a single jvm target. The default configuration is disabled if multiple JVM targets are defined. In this case, the plugin should be configured manually, or a single target should be specified (see below).
If the default configuration is ambiguous or not sufficient, the plugin can be configured:
- Using a Gradle source set
plugins {
kotlin("jvm")
id("org.jetbrains.compose")
}
val customSourceSet = sourceSets.create("customSourceSet")
compose.desktop {
application {
from(customSourceSet)
}
}
- Using a Kotlin JVM target:
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose")
}
kotlin {
jvm("customJvmTarget") {}
}
compose.desktop {
application {
from(kotlin.targets["customJvmTarget"])
}
}
- manually:
disableDefaultConfigurationcan be used to disable the default configuration;dependsOncan be used to add task dependencies to all plugin's tasks;fromFilescan be used to specify files to include;mainJarfile property can be specified to point to a jar, containing a main class.
compose.desktop {
application {
disableDefaultConfiguration()
fromFiles(project.fileTree("libs/") { include("**/*.jar") })
mainJar.set(project.file("main.jar"))
dependsOn("mainJarTask")
}
}
App icon
The app icon needs to be provided in OS-specific formats:
.icnsfor macOS;.icofor Windows;.pngfor Linux.
compose.desktop {
application {
nativeDistributions {
macOS {
iconFile.set(project.file("icon.icns"))
}
windows {
iconFile.set(project.file("icon.ico"))
}
linux {
iconFile.set(project.file("icon.png"))
}
}
}
}