一篇文章让你学会 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 = "[email protected]"
  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 = "[email protected]":联系邮箱。

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 了解并下载。

相关推荐
用户2018792831676 小时前
通俗易懂的讲解:Android系统启动全流程与Launcher诞生记
android
二流小码农6 小时前
鸿蒙开发:资讯项目实战之项目框架设计
android·ios·harmonyos
用户2018792831677 小时前
WMS 的核心成员和窗口添加过程
android
用户2018792831677 小时前
PMS 创建之“软件包管理超级工厂”的建设
android
用户2018792831677 小时前
通俗易懂的讲解:Android APK 解析的故事
android
渣渣_Maxz7 小时前
使用 antlr 打造 Android 动态逻辑判断能力
android·设计模式
Android研究员8 小时前
HarmonyOS实战:List拖拽位置交换的多种实现方式
android·ios·harmonyos
恋猫de小郭8 小时前
Flutter 应该如何实现 iOS 26 的 Liquid Glass ,它为什么很难?
android·前端·flutter
葱段8 小时前
【Compose】Android Compose 监听TextField粘贴事件
android·kotlin·jetbrains