DuoUpdater 原生 macOS 菜单栏更新列表,旁边是猫咪图标和按渠道识别的应用更新行。

DuoUpdater:尊重各应用分发渠道的原生 macOS 更新器

DuoUpdater 会扫描 Mac 上的应用,沿用每个应用自己的 Sparkle、App Store、Homebrew、GitHub 或厂商渠道,验证替换结果,并保留回滚路径。

要点摘要
  • DuoUpdater 是面向 macOS 15+ Apple Silicon 的原生 Swift 菜单栏应用,会扫描已安装应用及其真实更新渠道。
  • 它按固定顺序检查 Mac App Store、Xcode Releases、Sparkle、Homebrew、GitHub Releases、Alcove 和精选厂商 endpoint。
  • 替换 bundle 前,它可以检查签名、Team ID、bundle ID 和可运行架构,创建备份、重新检查来源,并在需要时回滚。
  • 最新的 v0.4.1 notarized macOS ZIP 通过 GitHub Releases 分发;首次安装后,应用会通过自己的 Sparkle appcast 自更新。

Mac 上的应用更新不应该都走同一条下载路径。Sparkle 应用有自己的 appcast,App Store 应用由 Apple 管理,Homebrew 和 GitHub 项目又有各自的发布方式;有些应用甚至必须打开自己的更新器。DuoUpdater 的出发点很明确:先识别每个应用真正使用的渠道,再用该渠道允许的方式更新。

项目仓库是 jizhi0v0/duo-updater,使用 Swift 编写,许可证是 MIT。当前核对到的最新发行版是 DuoUpdater 0.4.1,目标平台是 Apple Silicon Mac 上的 macOS 15 或更高版本。

它解决的是什么问题

DuoUpdater 是一个菜单栏应用,会扫描 /Applications、/Applications/Utilities 和 ~/Applications,把你已经安装的应用列出来。每一行不只显示“有更新”,还显示当前版本、目标版本、更新渠道,以及点击按钮后真正会发生的动作。磁盘上的应用已经更新但运行中的副本还没重启时,按钮会变成 Relaunch,而不是再次下载同一版本。

它也会把 Homebrew 安装的非 .app 项目单独列出,包括命令行 formula、字体和驱动。能安装应用包的 cask 仍然作为普通应用处理,不会在菜单中重复计算。这个细节让“我安装的东西”不再只等于 Finder 里能看到的 .app。

应用详情还包含 release notes。Sparkle appcast 和 GitHub Release 通常可以直接解析出版本、日期和逐条变更;对于其他来源,项目使用按应用维护的 recipe。供应商页面不适合解析时,则退回到非持久化的 WKWebView 页面,而不是假装已经读懂了发布说明。

按应用自己的渠道更新

项目 README 给出的检查顺序是有意固定的:Mac App Store、Xcode Releases、Sparkle、Homebrew Cask、GitHub Releases、Alcove,最后才是精选的厂商 endpoint。第一个能够识别该应用的来源负责回答,返回“不适用”才会继续尝试下一个来源。JetBrains Toolbox 管理的应用和 TestFlight 构建则在这条链路外单独处理。

“尊重渠道”意味着 DuoUpdater 不会把所有应用都下载成一个 ZIP 再硬替换。Sparkle 走原生安装并使用 EdDSA(应用提供公钥时),自更新应用会被打开并交给它自己的 updater,Homebrew 应用使用 cask,App Store 更新通过 mas 和特权 helper,GitHub 与厂商下载则只在明确规则验证了可安装资产时执行。

更新前的安全检查

对于 DuoUpdater 自己负责安装的 bundle,项目会在来源验证之外检查代码签名、Team ID、bundle ID 和可运行架构,并阻止原生 Apple Silicon 应用被换成 Intel-only 版本。安装前会重新读取磁盘上的 bundle 并重新查询来源,避免一个过时的列表触发重复安装。

更新可以先保存回滚备份,设置里也能决定是否自动重新启动应用。DuoUpdater 不会强制终止正在运行的应用:它调用普通的 terminate(),应用可以弹出保存提示并拒绝退出。如果拒绝,更新后的文件仍在磁盘上,界面会保留 Restart 操作,不会为了完成一次更新丢掉未保存的工作。

大版本升级会先显示警告,因为商业应用可能需要重新购买许可证。另一个需要知道的边界是 .pkg/.mpkg:系统安装器接管后,DuoUpdater 能检查包签名、Team ID、目标位置和系统版本,但不会检查安装包内部每一个 Mach-O 的架构,也不会在安装器完成后自动回滚架构变化。

App Store、TestFlight 与权限

App Store 应用并不是普通下载链接。DuoUpdater 可以通过 mas 和后台 helper 处理完整下载;如果 helper 尚未批准,或应用受地区限制,则会退回到深链接或 App Store 的更新页面,并把地区锁定标出来。后台 helper 需要在 macOS 的 Login Items & Extensions 中允许。

TestFlight beta 是单独的开关。关闭时,DuoUpdater 不读取 TestFlight 数据;打开后,刷新或按小时检查可能会在后台短暂启动 TestFlight。读取 TestFlight 可用构建和 CotEditor 渠道需要 Full Disk Access,而不是查看普通应用更新所必需的权限。

权限按功能拆开:不授予任何权限也能看到应用列表、版本检查和 release notes;App Management 负责替换 /Applications 里的应用,Notifications 只影响提醒和 Dock badge,Accessibility 只在设置为用图形界面走 App Store 或关闭安装器窗口时需要。DuoUpdater 不会把“能检测”混淆成“能安装”。

Release Log 不只是一张更新列表

它会记录每次看到的版本,从而逐渐形成软件发布日志。项目对时间精度比较克制:Sparkle、GitHub、Alcove 或 electron-builder manifest 明确给出时间时,才显示精确时间;只有版本号的来源,只能显示上一次看到旧版本和第一次看到新版本之间的估计窗口,并用 ≈ 标记。

这种设计的好处是热力图不会把猜测当成事实。一个厂商可能确实发布了新版本,但没有告诉客户端发布时间;DuoUpdater 记录“看见变化”的证据,却不把检测时间伪装成发布时间。选中的应用如果提供结构化 release notes,右侧会以原生文本呈现,而不是把一个网页塞进窗口。

v0.4.1 的 Release 说明也体现了这种持续维护:Sogou 输入法现在可以一键更新并备份词典与设置,JetBrains Air 使用 Toolbox 实际提供的 build,重命名后的 App Store 副本会说明真正由哪一个副本负责更新,Markdown 发布说明也会被格式化为原生列表。

同一套引擎也有 duo CLI

仓库不只有菜单栏 UI。duo CLI 链接真实的 DuoUpdaterCore,使用相同的来源顺序、安装策略、忽略规则和跳过规则,因此命令行与 GUI 出现不同判断应该被当成 bug,而不是两套产品逻辑。常用命令包括 duo list、duo check --json、duo install Cursor、duo doctor 和 duo backups。

duo list                     # 无网络访问地列出已安装应用
duo check --json             # 每行输出一个 JSON 对象
duo install Cursor           # 安装一个更新,也可以使用 --all
duo doctor                   # 检查这台 Mac 是否能安装
duo backups                  # 列出或恢复回滚点

CLI 也支持 --source sparkle,github,…、--include-hidden、duo ignore 和 duo skip。但它会明确拒绝 App Store 更新,因为命令行没有应用 bundle、特权 helper 或 Accessibility 路径;它也不会强行抢占菜单栏应用的安装锁。拒绝半完成的流程,正是它的安全边界之一。

隐私:没有自建遥测服务器

项目声明没有 telemetry、analytics SDK 或自建服务器。网络请求直接发往正在检查的厂商,或者 api.github.com、formulae.brew.sh,请求中只携带完成版本检查所需的信息。这个模型比把所有应用版本集中上传到一个云端数据库更容易解释。

但“没有遥测”不等于“不读取任何外部数据”。如果安装了 CleanShot X,DuoUpdater 会读取其偏好中的 activationKey,向 CleanShot 自己的 endpoint 请求个性化 appcast;TablePlus 的 beta 开关、部分应用的渠道设置也会被读取。GitHub token 可能来自环境变量或 gh auth token,只发送给 api.github.com,离开该域名的重定向会移除它。

这些读取都应按功能理解,而不是笼统地称为本地隐私。凭据由用户主动输入的 GitHub token 或 Alcove license 会存进登录 Keychain;厂商 release notes 使用非持久化 WKWebView,不会在重新启动后保留厂商 cookie。首次使用前,最好按自己安装的应用检查隐私说明和权限开关。

如何安装

目前没有找到 DuoUpdater 自己的 App Store 页面,官方安装路径是 GitHub Releases。仓库说明公开发布的是经过 notarize 的构建;当前最新的 DuoUpdater 0.4.1 macOS ZIP 适用于 Apple Silicon 和 macOS 15 或更高版本。

# 打开最新 Release 页面:
open https://github.com/jizhi0v0/duo-updater/releases/latest

# 或直接下载 v0.4.1 Apple Silicon ZIP:
open https://github.com/jizhi0v0/duo-updater/releases/download/v0.4.1/DuoUpdater-0.4.1-macos.zip

下载 ZIP 后解压,把 DuoUpdater.app 放到 /Applications,首次启动时按需要授予 App Management、通知或其他功能权限。它可以在没有权限时继续检测应用;只有执行对应安装路线时,macOS 才会要求相关权限。Apple Silicon 是硬性要求,Intel Mac 不在当前产品范围内。

需要改代码时再从源码构建

普通用户应优先使用上面的 Release ZIP。想研究更新引擎或修改菜单栏界面时,仓库把核心、应用和 CLI 分成了三个部分:DuoUpdaterCore/ 是可独立测试的 Swift Package,App/ 是由 XcodeGen 生成的 SwiftUI MenuBarExtra 应用,CLI/ 是 duo 命令。

# 构建并测试核心 package:
cd DuoUpdaterCore
swift build
swift test

# 生成 macOS 应用工程:
cd ../App
xcodegen generate
open DuoUpdater.xcodeproj

当前源码构建要求 Swift 6.4,也就是 Xcode 27 的工具链;部署目标仍是 macOS 15。要把自己的构建安装到 /Applications,仓库提供 make install,它会构建 Release、使用稳定的 Developer ID 签名并部署到标准位置。Fork 如果使用自己的团队,可以先设置 DUO_TEAM_ID=YOURTEAMID。

源码构建并不等于可以绕过签名。项目的特权 helper 和应用会在运行时根据实际签名推导 Team ID;未签名或 ad-hoc 构建会拒绝连接,避免一个未固定身份的应用与 root helper 通信。生产发布流程还需要 Apple notarytool 凭据,普通安装者不需要配置这些内容。

它的边界

DuoUpdater 不是一个保证所有 Mac 软件都能自动更新的万能数据库。GitHub Release、厂商 endpoint 和 recipe 会随页面结构变化;项目选择维护经过验证的应用规则,而不是对所有软件做近似猜测。没有明确可安装资产时,它会保持检测或打开原页面,而不是随便挑一个下载文件。

另外,系统安装器、地区限制、App Store helper、TestFlight 数据权限和应用自身的保存提示都会影响最终结果。它可以把流程统一到一个界面,却不能替厂商解决许可证、网络、账户或 macOS 权限本身的问题。

许可证

DuoUpdater 使用 MIT License。你可以查看、修改和在商业项目中使用代码,但再分发时要保留版权和许可证声明。仓库里的 mas、Sparkle、swift-subprocess、厂商服务以及被更新的第三方应用各自有自己的许可证或服务条款,不能因为主仓库是 MIT 就把它们视为同一授权。

适合安装吗

如果你使用 Apple Silicon Mac,希望集中查看应用更新,又不想把 Sparkle、Homebrew、GitHub 和 App Store 强行塞进同一个下载模型,DuoUpdater 值得从 v0.4.1 Release 开始试用。它的价值在于渠道识别、安装前复核和失败后的回滚边界;它的限制也很明确:只支持 Apple Silicon,部分安装路线仍依赖 macOS 权限,recipe 维护和厂商页面变化无法被完全消除。

项目概况

许可证
MIT
平台
macOS 15+ / 仅 Apple Silicon
开发语言
Swift 6.4、SwiftUI、AppKit、Swift Package Manager
查看版本
v0.4.1(GitHub Release,2026-09-21 核对)

安装

# 打开最新的 GitHub Release:
open https://github.com/jizhi0v0/duo-updater/releases/latest

# 直接下载当前 Apple Silicon macOS ZIP:
open https://github.com/jizhi0v0/duo-updater/releases/download/v0.4.1/DuoUpdater-0.4.1-macos.zip

许可说明

仓库使用 MIT License。再分发代码时需要保留版权和许可证声明;打包的工具、框架、厂商 feed 以及第三方应用仍有各自的条款。