当前位置: 首页 > article >正文

如何为 Java 应用程序创建安装程序

在 Java 中编写桌面应用程序时,我们总是希望其外观和感觉能够尽量贴近原生应用程序。因为一个优秀的应用程序应该要能融入其中,为用户提供已经熟悉的体验。

 Swing GUI 的外观和感觉: Metal vs. Native

Swing GUI 的外观和感觉: Metal vs. Native

在桌面上,用户的使用旅程并不是从应用程序本身开始的,而是从安装程序开始的。这是 Java 世界过去落后的地方。但现在已不再如此。

从 Java 16 开始,JDK 附带了 jpackage 工具。该工具可以将应用程序打包成带有内置 JRE 的捆绑包,并将其包装成原生安装程序和可执行文件。

在本篇文章中,我将演示如何将 jpackage 与 JxBrowser 应用程序结合使用。我将创建一个简单的 JxBrowser 应用程序,然后使用 jpackage 将其打包为原生安装程序和可执行程序。我会提供一些代码片段,您可以将其直接复制到您的项目中。

配置 Gradle

我的目标是创建一个简单的 Pomodoro tracker(番茄工作法跟踪器),安装它,并将其作为原生操作系统应用程序启动。它将使用 Gradle 进行构建配置,使用 Swing 进行用户界面设计。

让我们从头开始创建一个空的 Gradle 项目:

$ gradle init --dsl kotlin --type basic --project-name jxbrowser-installer

打开 build.gradle.kts 文件并应用 Java 插件:

plugins {
    java
}
 
group = "com.teamdev.examples"
version = "1.0"

java {
    sourceCompatibility = JavaVersion.VERSION_16
    targetCompatibility = JavaVersion.VERSION_16
}

repositories {
    mavenCentral()
}

我们的应用程序需要两个 JxBrowser 依赖项。其中一个包含带有 Chromium 二进制文件的核心 API,另一个实现 Swing 工具包支持。

让我们使用 JxBrowser Gradle 插件[1]来添加必要的依赖项。

plugins {id("com.teamdev.jxbrowser") version "{gradle_plugin_version}"
}

jxbrowser {
    version = "{version}"
}

dependencies {
    implementation(jxbrowser.swing)
    implementation(jxbrowser.currentPlatform)
}

在上面的代码片段中,我使用了 jxbrowser.currentPlatform 来检测当前平台并仅挑选必要的 Chromium 二进制文件。如果您正在构建一个仅适用于 Windows 的应用程序,您可以明确指定 Windows 平台的 Chromium 二进制文件:

dependencies {
    implementation(jxbrowser.swing)
    implementation(jxbrowser.win64)
}

应用程序代码

我们的应用程序非常简单。它会启动一个 JFrame 窗口,然后在该窗口中添加 BrowserView 组件,用于加载和显示包含 Pomodoro Tracker 的网页。

package com.teamdev.examples;

import com.teamdev.jxbrowser.engine.Engine;
import com.teamdev.jxbrowser.view.swing.BrowserView;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import static com.teamdev.jxbrowser.engine.RenderingMode.HARDWARE_ACCELERATED;
import static javax.swing.SwingConstants.CENTER;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;

/**
 * 一个 Pomodoro tracker.
 *
 * 这款应用程序会显示一个带有集成浏览器组件的窗口,
 * 该组件负责加载并显示 Pomodoro Tracker 的网页应用。
 */
public final class PomodoroTracker {

    public static final String URL = "https://teamdev.com/jxbrowser/docs/tutorials/jpackage/pomodoro.html";

    public static void main(String[] args) {
        var splash = showSplashScreen();
        showBrowser();
        splash.dispose();
    }

    private static void showBrowser() {
        var engine = Engine.newInstance(HARDWARE_ACCELERATED);
        var browser = engine.newBrowser();
        var frame = new JFrame("Pomodoro Tracker");
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                engine.close();
            }
        });
        var view = BrowserView.newInstance(browser);
        frame.add(view, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        frame.setSize(1280, 900);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        browser.navigation().loadUrl(URL);
    }

    private static JWindow showSplashScreen() {
        var splash = new JWindow();
        splash.getContentPane().add(new JLabel("加载中...", CENTER));
        splash.setBounds(500, 150, 300, 200);
        splash.setVisible(true);
        return splash;
    }
}

打包应用程序

用 Java 编写的桌面应用程序需要在运行时携带它们所需的所有必要库。通常的做法是将库与应用程序合并为一个大的 Uber JAR。这需要一些额外的配置,并且不适合模块化项目。

现在有一个更简单的选择:将一堆 JAR 文件收集到一个文件夹中,然后让 jpackage 处理其余部分。

首先,让我们来配置构建主应用程序的 JAR 文件:

val jarDirectory = file("$buildDir/jars")
tasks {
    jar {
        manifest {
            attributes["Main-Class"] = "com.teamdev.examples.PomodoroTracker"
        }
        archiveFileName.set("main.jar")
        destinationDirectory.set(jarDirectory)
    }
}

接着,让我们创建一个任务来收集依赖项的 JAR 文件:

val jarDirectory = file("$buildDir/jars")
tasks {
    …
    register<Copy>("gatherDependencies") {
        from(configurations.runtimeClasspath).into(jarDirectory)
    }
}

这两个任务足以从命令行启动应用程序:

$ ./gradlew jar gatherDependencies
$ java -cp "build/jars/*" com.teamdev.examples.PomodoroTracker

现在一切准备就绪,可以配置 jpackage 了。

jpackage 是一个命令行工具。但是,我更倾向于将所有内容都保留在 Gradle 脚本中。与一堆 .sh 和 .bat 文件相比,Gradle 脚本更容易阅读和维护。

我推荐使用 org.panteleyev.jpackage 插件。 此插件会将 jpackage 的命令行 API 封装到 Gradle DSL 中。应用方法如下:

plugins {
    ...
    id("org.panteleyev.jpackageplugin") version "1.3.1"
}

以下是我如何配置它来生成安装程序的方法:

val jarDirectory = file("$buildDir/jars")
tasks {
    …
    jpackage {
        // 在打包之前收集所有 JAR 文件。
        dependsOn("jar", "gatherDependencies")

        appName = "Pomodoro Tracker"
        appVersion = "${project.version}"

        // 包含 JAR 文件的目录。
        input = jarDirectory.absolutePath

        // 可启动的主要 JAR 文件的名称。
        mainJar = "main.jar"

        // 需要包含到捆绑 JRE 中的必要模块列表。
        // "java.logging"  是 JxBrowser 所必需的。
        addModules = listOf("java.base", "java.desktop", "java.logging")

        // JRE 模块的路径。
        modulePaths = listOf("${System.getProperty("java.home")}/jmods")

        // 安装程序存放的目录。
        destination = "$buildDir/dist"

        linux {
            type = org.panteleyev.jpackage.ImageType.DEB
            linuxPackageName = "pomodoro"
        }

        windows {
            type = org.panteleyev.jpackage.ImageType.MSI
            winDirChooser = true
            winMenu = true
        }

        mac {
            type = org.panteleyev.jpackage.ImageType.DMG
        }
    }
}

完成所有配置后,接下来要做的就是调用 jpackage 任务。任务完成后,我们会在 build/dist 目录下找到安装程序:

$ ./gradlew jpackage

对于 Windows,您将需要 https://wixtoolset.org/releases/

安装程序实操视频

Create installer for Java App

源代码

您可以在 GitHub 存储库[2]中找到该应用程序的源代码。

相关链接

  • JxBrowser 官方页面[3]。
  • GitHub上的这个示例[4]。
  • 其他 JxBrowser 示例[5]。

参考资料:

[1] JxBrowser Gradle 插件: https://plugins.gradle.org/plugin/com.teamdev.jxbrowser?utm_source=csdn&utm_medium=article&utm_campaign=installer-for-java-app

[2] GitHub 存储库: https://github.com/vlad-lubenskyi/jxbrowser-installer/?utm_source=csdn&utm_medium=article&utm_campaign=installer-for-java-app

[3] JxBrowser 官方页面: https://teamdev.cn/jxbrowser/?utm_campaign=installer-for-java-app&utm_medium=article&utm_source=csdn

[4] GitHub上的这个示例: https://github.com/vlad-lubenskyi/jxbrowser-installer/?utm_source=csdn&utm_medium=article&utm_campaign=installer-for-java-app

[5] 其他 JxBrowser 示例: https://github.com/TeamDev-IP/JxBrowser-Examples?utm_source=csdn&utm_medium=article&utm_campaign=installer-for-java-app


http://www.kler.cn/news/309591.html

相关文章:

  • 《深度学习》【项目】 OpenCV 身份证号识别
  • PostgreSQL 的 logger 进程和 Oracle 的 diag 进程对比
  • SDKMAN!软件开发工具包管理器
  • 基于Spark框架实现XGBoost模型
  • ThinkPHP3改造自定义日志输出
  • setup函数子传父普通写法
  • 一般在写SQL时需要注意哪些问题,可以提高查询的效率?
  • adb install失败: INSTALL_PARSE_FAILED_NO_CERTIFICATES
  • JavaScript高级——闭包应用-自定义js模块
  • 『功能项目』窗口可拖拽脚本【59】
  • 设置spring boot禁止日志输出到控制台
  • c++中的二叉搜索树
  • 前端网络层性能优化
  • 【2024华为杯研究生数学建模竞赛】比赛思路、代码、论文更新中.....
  • 使用 Vue 3 和 TypeScript 实现带打字效果的仿 AI 分析展示组件
  • 【C/C++语言系列】指针数组、数组指针、函数声明和函数指针区别
  • Git 中的refs
  • Python异常处理:自定义异常②
  • 智慧体育场馆:科技引领未来运动体验
  • 【C语言进阶】动态内存与柔性数组:C语言开发者必须知道的陷阱与技巧
  • JAVA学习笔记01-变量的初始化
  • Medieval Fantasy Town Village Environment for RPG FPS 中世纪城镇环境
  • 时序数据库 TDengine 的入门体验和操作记录
  • 某oa命令执行漏洞挖掘思路
  • 网络安全。
  • 数学建模笔记——动态规划
  • Vue3中集成高德地图并实现平移缩放功能
  • 如何搭建一个ip池用来做数据抓取用
  • MFC工控项目实例之十四模拟量信号名称从文件读写
  • uniapp上使用document方案之renderjs