使用 Sparkle 实现 macOS 应用自定义更新弹窗

简介

源码 源码1

Sparkle 是 macOS 平台上一个优秀的自动更新框架。虽然 Sparkle 提供了默认的更新界面,但有时我们需要自定义更新弹窗以匹配应用的设计风格。本文将介绍如何使用 Sparkle 实现自定义更新界面。

实现步骤

1. 创建自定义更新窗口

首先需要创建一个继承自 NSPanel 的自定义窗口类:

swift 复制代码
class UpdateNotificationWindow: NSPanel {
    private let stackView = NSStackView()
    private let titleLabel = NSTextField()
    private let messageLabel = NSTextField()
    private let progressBar = NSProgressIndicator()
    private var buttons: [NSButton] = []
    
    init() {
        super.init(contentRect: NSRect(x: 0, y: 0, width: 320, height: 240),
                  styleMask: [.nonactivatingPanel, .titled, .fullSizeContentView],
                  backing: .buffered,
                  defer: false)
        
        setupWindow()
        setupUI()
    }
}

2. 实现自定义用户驱动

需要创建一个实现 SPUUserDriver 协议的类来处理更新流程中的各个状态:

swift 复制代码
final class CustomUserDriver: NSObject, SPUUserDriver {
    private var notificationWindow: UpdateNotificationWindow?
    
    // 检查更新
    func showUserInitiatedUpdateCheck(cancellation: @escaping () -> Void) {
        ensureNotificationWindow().showChecking {
            cancellation()
        }
    }
    
    // 找到更新
    func showUpdateFound(with appcastItem: SUAppcastItem, state: SPUUserUpdateState) async -> SPUUserUpdateChoice {
        return await withCheckedContinuation { continuation in
            DispatchQueue.main.async {
                self.ensureNotificationWindow().showUpdateFound { updateChoice, type in
                    continuation.resume(returning: updateChoice)
                }
            }
        }
    }
    
    // 显示下载进度
    func showDownloadDidReceiveData(ofLength length: UInt64) {
        let progress = Double(currentProgress) / Double(downloadSize) * 100
        ensureNotificationWindow().showDownloadProgress(progress)
    }
}

3. 配置更新控制器

创建一个更新控制器类来管理 Sparkle 更新器:

swift 复制代码
final class UpdateController {
    static let shared = UpdateController()
    let updater: SPUUpdater
    private let userDriver: CustomUserDriver
    
    private init() {
        userDriver = CustomUserDriver()
        updater = SPUUpdater(hostBundle: Bundle.main,
                           applicationBundle: Bundle.main,
                           userDriver: userDriver,
                           delegate: nil)
        
        try? updater.start()
        updater.automaticallyChecksForUpdates = true
        updater.updateCheckInterval = 3600 * 6
        updater.setFeedURL(URL(string: "https://your-update-url/appcast.xml"))
    }
}

主要功能

1. 检查更新界面

  • 显示检查更新状态
  • 提供取消按钮

2. 发现更新界面

  • 显示新版本信息
  • 提供"立即安装"和"下次启动时安装"选项

3. 下载进度界面

  • 显示实时下载进度
  • 进度条可视化展示

4. 安装准备界面

  • 提示用户重启应用进行安装
  • 显示安装确认按钮

界面美化

为了让更新窗口更美观,我们可以:

  1. 添加圆角和阴影:
swift 复制代码
contentView?.layer?.cornerRadius = 12
hasShadow = true
  1. 自定义按钮样式:
swift 复制代码
private func createStyledButton(title: String, isPrimary: Bool = false) -> NSButton {
    let button = NSButton(title: title, target: nil, action: nil)
    button.layer?.cornerRadius = 6
    
    if isPrimary {
        button.contentTintColor = .white
        button.layer?.backgroundColor = NSColor.controlAccentColor.cgColor
    } else {
        button.contentTintColor = .black
        button.layer?.backgroundColor = NSColor.controlBackgroundColor.cgColor
    }
    
    return button
}

总结

通过自定义 Sparkle 的更新界面,我们可以:

  1. 提供与应用一致的设计风格
  2. 更好地控制更新流程
  3. 提供更好的用户体验

完整的实现代码可以参考上面的示例。通过这种方式,我们可以为 macOS 应用提供一个既美观又实用的自动更新体验。

注意事项

  1. 确保正确处理所有更新状态
  2. 适当处理错误情况
  3. 保持界面响应性
  4. 提供清晰的用户反馈

希望这篇文章对你实现自定义 Sparkle 更新界面有所帮助!

相关推荐
大虾写代码7 小时前
vue3+TS项目配置Eslint+prettier+husky语法校验
前端·vue·eslint
wordbaby8 小时前
用 useEffectEvent 做精准埋点:React analytics pageview 场景的最佳实践与原理剖析
前端·react.js
上单带刀不带妹8 小时前
在 ES6 中如何提取深度嵌套的对象中的指定属性
前端·ecmascript·es6
excel8 小时前
使用热力贴图和高斯函数生成山峰与等高线的 WebGL Shader 解析
前端
wyzqhhhh8 小时前
组件库打包工具选型(npm/pnpm/yarn)的区别和技术考量
前端·npm·node.js
码上暴富8 小时前
vue2迁移到vite[保姆级教程]
前端·javascript·vue.js
土了个豆子的9 小时前
04.事件中心模块
开发语言·前端·visualstudio·单例模式·c#
全栈技术负责人9 小时前
Hybrid应用性能优化实战分享(本文iOS 与 H5为例,安卓同理)
前端·ios·性能优化·html5
xw59 小时前
移动端调试上篇
前端
伍哥的传说9 小时前
Lodash-es 完整开发指南:ES模块化JavaScript工具库实战教程
大数据·javascript·elasticsearch·lodash-es·javascript工具库·es模块·按需导入