一篇文章让你学会 Compose Multiplatform 推荐的桌面应用打包工具 Conveyor

对于希望将 Compose Multiplatform Desktop 应用部构建发布的开发者而言,跨平台打包、签名、更新机制等环节常常是巨大的挑战。本文将深入探讨 Conveyor 这一强大的打包工具,并以我的开源项目 CrossPaste 为例,为您详细解析其在实际项目中的应用,帮助您轻松实现应用的跨平台发布。

1. 为什么选择 Conveyor?

Conveyor 是一个出色的工具,它旨在让桌面应用的发布像发布 Web 应用一样简单。对于 Compose Multiplatform 项目来说,选择 Conveyor 有以下关键优势:

官方推荐与紧密集成 :Compose Multiplatform 的开源项目 文档 中直接提及并列举了 Conveyor 一些列强大功能,这表明它是一个官方推荐的打包工具。Conveyor 特别为 JVM 应用提供了优化,包括捆绑 jlink 优化的 JVM、自定义原生启动器以及大量针对桌面应用的可用性改进。

跨平台打包与自更新:Conveyor 能够为 Windows、macOS 和 Linux 生成并签名自更新的软件包,而且无需您拥有这些操作系统即可完成。它支持平台原生的包格式和更新系统,提供 Chrome 风格的静默后台更新和 Web 风格的同步启动更新,以及高级增量更新功能。这意味着您的应用可以自动更新,且无需修改代码。

简化复杂流程:Conveyor 极大地简化了代码签名、公证、图标生成等繁琐过程。它甚至可以从任何操作系统为所有支持的 OS 签名/公证应用。

出色的 CI/CD 支持:您可以在任何 Linux 构建代理上为所有支持的平台直接打包和部署您的应用,而无需 Mac/Windows 工作机。

免费与定价模式:Conveyor 对开源应用免费,对商业应用则采用简单的按项目定价模式。由于 CrossPaste 是一个开源项目,这使其成为一个经济高效的选择。

conveyor 的安装

使用前你必须先安装 conveyor,conveyor.hydraulic.dev/ 它们提供了 macOS、Windows、Linux 多平台安装包,按照提示安装完毕后,打开应用将 conveyor 命令添加到环境变量即可

2. CrossPaste 中的实践案例

CrossPaste 是一个旨在实现跨设备剪贴板通用同步的开源项目。

接下来以 CrossPaste 项目的配置为例子详细讲解 conveyor 如何使用

conveyor.conf

ini 复制代码
include "#!./gradlew -q printConveyorConfig -PappEnv=PRODUCTION"

include file("extract-native-libraries.conf")

app {
  compression-level = high
  contact-email = "compile.future@gmail.com"
  license = "AGPL-3.0-or-later"
  display-name = "CrossPaste"
  rdns-name = "com.crosspaste"
  url-schemes = [ crosspaste ]
  vcs-url = "https://github.com/CrossPaste/crosspaste-desktop"

  site {
    consistency-checks = warn
  }

  jvm {
    mac.amd64.inputs += "app/jbr/jbrsdk-21.0.7-osx-x64-b968.13.tar.gz"
    mac.aarch64.inputs += "app/jbr/jbrsdk-21.0.7-osx-aarch64-b968.13.tar.gz"
    windows.amd64.inputs += "app/jbr/jbrsdk-21.0.7-windows-x64-b968.13.tar.gz"
    linux.amd64.inputs += "app/jbr/jbrsdk-21.0.7-linux-x64-b968.13.tar.gz"
  }

  mac {
    bundle-extras += "app/script/mac_start.sh" -> "bin/start.sh"

    icons = "app/src/desktopMain/composeResources/drawable/crosspaste_mac.png"

    info-plist.CFBundleIdentifier = "com.crosspaste.mac"
    info-plist.LSMinimumSystemVersion = 13.0.0
    info-plist.LSUIElement = true
    updates = background
    sparkle-options.SUScheduledCheckInterval = 3600
  }

  windows {
    inputs += "app/script/win_start.bat" -> "bin/start.bat"

    icons = "app/src/desktopMain/composeResources/drawable/crosspaste.png"
    updates = {
      launch-check-frequency = 1
      block-start = false
      automatic-updates = true
    }
  }

  linux {
    debian.distribution.name = jammy

    install-path = /usr/lib/crosspaste

    icons = "app/src/desktopMain/composeResources/drawable/crosspaste.png"

    root-inputs += "app/script/linux_start.sh" -> "/usr/lib/crosspaste/bin/start.sh"
  }
}
conveyor.compatibility-level = 18

3.1 基础信息获取与配置

Conveyor 可以从您的 build.gradle.kts 中获取基础信息,避免重复配置。CrossPaste 的配置通过以下方式引入 Gradle 信息:

include "#!./gradlew -q printConveyorConfig -PappEnv=PRODUCTION":这条命令让 Conveyor 在构建时执行 Gradle 任务,获取项目的基本配置信息。

include file("extract-native-libraries.conf"):这用于处理 Mac 在沙箱内运行应用时,需要提前标记可执行文件的问题,以防止应用被 macOS 禁用。在 extract-native-libraries.conf 中,可以看到 app.jvm.extract-native-libraries = true 的配置,以及针对 jna.nosysskiko.library.path 的系统属性设置。

3.2 应用通用配置 (app 区块)

conveyor.confapp 区块中,定义了应用的通用元数据和行为:

compression-level = high:指定包的压缩级别。

contact-email = "compile.future@gmail.com":联系邮箱。

license = "AGPL-3.0-or-later":应用许可证。

display-name = "CrossPaste":应用显示名称。

rdns-name = "com.crosspaste":反向域名,通常用于唯一标识应用。

url-schemes = [ crosspaste ]:定义应用支持的 URL scheme。

vcs-url = "https://github.com/CrossPaste/crosspaste-desktop":版本控制系统 URL,指向 GitHub 仓库。

conveyor.compatibility-level = 18:指定 Conveyor 的兼容性级别,实际也就是 conveyor 的大版本号。

3.3 JVM 特定配置

Conveyor 可以捆绑具体的 JDK,来确保应用在不同系统上的运行环境一致性。CrossPaste 选择使用 JBR (JetBrains Runtime) 作为运行环境,JBR 作为 Jetbrains 一系列 IDE 桌面应用的环境,经过了长期使用验证,并且官方维护合并了许多桌面环境补丁,相比作为服务器环境的很多开源 JDK 版本,它更适合桌面环境,因此也推荐大家选择 JBR

通过 jvm.mac.amd64.inputs 等配置指定了不同操作系统和架构的 JBR 路径:

mac.amd64.inputs += "app/jbr/jbrsdk-21.0.7-osx-x64-b968.13.tar.gz"

mac.aarch64.inputs += "app/jbr/jbrsdk-21.0.7-osx-aarch64-b968.13.tar.gz"

windows.amd64.inputs += "app/jbr/jbrsdk-21.0.7-windows-x64-b968.13.tar.gz"

linux.amd64.inputs += "app/jbr/jbrsdk-21.0.7-linux-x64-b968.13.tar.gz"

这些 JBR 文件通常是通过 Gradle 脚本(如 CrossPaste 的 build.gradle.kts 中的 getJbrReleasesdownJbrReleases 函数)下载到本地 jbr 目录的。

3.4 平台特定配置

Conveyor 允许为每个平台定制详细的配置,以确保应用能够完美融入目标操作系统环境。

macOS (mac 区块)

  • bundle-extras += "app/script/mac_start.sh" -> "bin/start.sh":捆绑额外的启动脚本。
  • icons = "app/src/desktopMain/composeResources/drawable/crosspaste_mac.png":应用图标路径。
  • info-plist.CFBundleIdentifier = "com.crosspaste.mac":CFBundleIdentifier,用于唯一标识 Mac 应用。
  • info-plist.LSMinimumSystemVersion = 13.0.0:最低系统版本要求。
  • info-plist.LSUIElement = true:设置为 true 表示应用不在 Dock 中显示图标,通常用于后台工具或无界面应用。在 build.gradle.kts 中,Compose Desktop 也提供了 infoPlist 区块来配置这些 Info.plist 条目。
  • updates = background:启用后台更新。Conveyor 为 macOS 输出包含 Sparkle 框架的 .app 包,appcast.rss 文件用于广告更新。
  • sparkle-options.SUScheduledCheckInterval = 3600:设置 Sparkle 检查更新的频率(单位秒)。
  • 公证 (Notarization):Mac 应用的公证配置,这些敏感信息通常通过环境变量传入。

Windows (windows 区块)

  • inputs += "app/script/win_start.bat" -> "bin/start.bat":捆绑启动脚本。
  • icons = "app/src/desktopMain/composeResources/drawable/crosspaste.png":应用图标路径。
  • updates:Windows 的更新配置:
    • launch-check-frequency = 1:启动时检查更新频率。
    • block-start = false:不阻塞启动。
    • automatic-updates = true:启用自动更新。
  • Conveyor 使用 Windows 内置的 MSIX 打包技术,它支持增量下载、后台自动升级和轻量级容器化,确保应用安装和卸载的洁净性。
  • Microsoft Store 集成:同样,商店相关的敏感信息通过环境变量设置。

Linux (linux 区块)

  • debian.distribution.name = jammy:指定 Debian/Ubuntu 的发行版,注意此配置直接影响应用与系统的兼容性,不宜选择过高。
  • install-path = /usr/lib/crosspaste:应用安装路径。
  • icons = "app/src/desktopMain/composeResources/drawable/crosspaste.png":应用图标路径。
  • root-inputs += "app/script/linux_start.sh" -> "/usr/lib/crosspaste/bin/start.sh":捆绑启动脚本并指定其在根文件系统中的安装路径。
  • Conveyor 会为 Debian/Ubuntu 生成 .deb 包,并将其放在一个 apt 仓库中。安装 .deb 包会自动安装仓库描述文件,从而实现依赖解析和后续更新。

3.5 Gradle 构建脚本中的 Conveyor 整合

CrossPaste 的 build.gradle.kts 文件展示了 Compose Multiplatform 项目如何与 Conveyor 插件协同工作:

alias(libs.plugins.conveyor):在 plugins 部分声明 Conveyor Gradle 插件。

JBR 管理getJbrReleasesdownJbrReleases 函数负责从 jbr.yaml 文件中读取 JBR 的下载 URL 和 SHA512 校验和,并下载 JBR 包到指定目录。这些 JBR 文件随后被 Conveyor 捆绑到最终的应用包中。

JVM 参数 (jvmArgs) :在 nativeDistributions 配置中,可以为所有平台添加 JVM 启动参数,例如 --add-opens 用于模块开放,以及设置系统属性如 loggerLevelappEnvjava.net.preferIPv4Stack 等。

平台特定构建逻辑

  • macOS Swift 编译 :CrossPaste 在 build.gradle.kts 中定义了 compileSwift 任务,用于编译 MacosApi.swift 生成 libMacosApi.dylib,这个动态库对于实现原生 macOS API 交互至关重要。desktopJardesktopTest 任务都依赖于此编译步骤。
  • targetFormats(TargetFormat.Dmg):macOS 目标格式设置为 DMG。
  • targetFormats(TargetFormat.Msi):Windows 目标格式设置为 MSI。
  • targetFormats(TargetFormat.Deb):Linux 目标格式设置为 Deb。

4. 运行与构建 Conveyor 任务

Conveyor 是一个构建系统,它通过配置和任务来生成最终的应用包和下载站点。

生成打包后的应用目录/Bundle 并执行

  • conveyor run
  • 加速运行 (跳过签名):conveyor -Kapp.sign = false run

将应用目录输出到 output 文件夹

  • conveyor make app

为所有可用平台构建下载站点

  • conveyor make site
  • 生成的下载站点包含各种元数据文件、软件包和一个简单的 HTML 下载页面,所有文件都必须上传以确保更新和增量生成正常工作。

5. 增量更新:优化用户体验

Conveyor 的核心优势之一是其增量更新功能。当 Conveyor 打包的应用在 Windows 和 macOS 上更新时,它们不会从头下载整个应用,而是仅下载已安装版本与最新版本之间的差异。这大大节省了带宽和更新时间。

Windows:MSIX 包会自动进行增量更新。即使用户已经安装了其他通过 Microsoft Store 或 Conveyor 构建的应用,新应用的首次安装也可以复用这些已安装应用的文件或数据块,从而显著提升首次运行时间和降低下载放弃率。

macOS :Conveyor 会自动生成增量补丁文件(*.delta 文件),并作为站点文件的一部分。这些文件支持 Sparkle 框架进行增量更新。

Linux :通过 Debian/Ubuntu 的 apt 仓库机制,用户可以通过 apt-get update; apt-get upgrade 命令无缝更新应用。

6. 结语

Conveyor 为 Compose Multiplatform Desktop 应用提供了一站式的打包、分发和更新解决方案,极大地简化了桌面应用开发的复杂性。通过 CrossPaste 这样一个真实世界的开源项目,您可以更直观地理解 Conveyor 的强大功能和灵活配置。

如果您正在寻求构建和打包 Compose Multiplatform Desktop 应用的解决方案,强烈建议您尝试 Conveyor。

🔥 助力 CrossPaste 项目!

如果您觉得 CrossPaste 这个项目对您有帮助,或者您对跨平台剪贴板同步工具感兴趣,请访问 【CrossPaste 的 GitHub 仓库并为它点亮一颗 Star!您的支持是我们持续开发和维护的最大动力。 👉 CrossPaste GitHub 仓库 此外,CrossPaste 致力于提供无缝的跨设备体验,目前已推出适用于 Android 设备的付费应用。虽然本文的资料主要侧重于桌面应用打包,但 CrossPaste 的愿景是实现所有设备间的剪贴板无缝同步。如果您希望在您的 Android 设备上体验更便捷的剪贴板功能,请前往应用 Google Play CrossPaste 了解并下载。

相关推荐
雨白6 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk6 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING6 小时前
RN容器启动优化实践
android·react native
恋猫de小郭9 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker14 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴14 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe1 天前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农2 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos