对于希望将 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 如何使用
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.nosys
和 skiko.library.path
的系统属性设置。
3.2 应用通用配置 (app 区块)
在 conveyor.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 ]
:定义应用支持的 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
中的 getJbrReleases
和 downJbrReleases
函数)下载到本地 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 管理 :getJbrReleases
和 downJbrReleases
函数负责从 jbr.yaml
文件中读取 JBR 的下载 URL 和 SHA512 校验和,并下载 JBR 包到指定目录。这些 JBR 文件随后被 Conveyor 捆绑到最终的应用包中。
• JVM 参数 (jvmArgs) :在 nativeDistributions
配置中,可以为所有平台添加 JVM 启动参数,例如 --add-opens
用于模块开放,以及设置系统属性如 loggerLevel
、appEnv
、java.net.preferIPv4Stack
等。
• 平台特定构建逻辑:
- macOS Swift 编译 :CrossPaste 在
build.gradle.kts
中定义了compileSwift
任务,用于编译MacosApi.swift
生成libMacosApi.dylib
,这个动态库对于实现原生 macOS API 交互至关重要。desktopJar
和desktopTest
任务都依赖于此编译步骤。 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 了解并下载。