Loading...
Loading...
Add Sparkle auto-update support to a native macOS app. Use this skill whenever the user wants to add auto-updates, implement Sparkle, set up an appcast feed, add "Check for Updates" to their app, or integrate automatic update checking. Also trigger when the user mentions Sparkle, appcast, SUFeedURL, EdDSA signing, or update notifications. This covers the full setup: adding the Sparkle SPM dependency, creating the UpdaterManager singleton, wiring it into the app delegate and UI, configuring Info.plist, and generating the initial appcast.xml.
npx skill4agent add fayazara/macos-app-skills macos-auto-updateSPUStandardUpdaterControllerSUFeedURLSUPublicEDKeyhttps://github.com/sparkle-project/Sparkle2.0.0SparklePackage.swift.package(url: "https://github.com/sparkle-project/Sparkle", from: "2.0.0")references/UpdaterManager.swiftSPUStandardUpdaterControllerapplicationDidFinishLaunchingcanCheckForUpdatesautomaticallyChecksForUpdates.regularstartingUpdater: falsestart()applicationDidFinishLaunchingstart()checkForUpdates()ObservableObject@Published@Observablepublisher(for:)Info.plist<key>SUFeedURL</key>
<string>https://raw.githubusercontent.com/OWNER/REPO/main/appcast.xml</string>
<key>SUPublicEDKey</key>
<string>YOUR_PUBLIC_EDDSA_KEY_HERE</string>
<key>SUEnableInstallerLauncherService</key>
<true/># Find generate_keys in your DerivedData after building the project with Sparkle
find ~/Library/Developer/Xcode/DerivedData -name "generate_keys" -type f 2>/dev/null | head -1/path/to/generate_keysSUPublicEDKeysign_updatefinal class AppDelegate: NSObject, NSApplicationDelegate {
private let updaterManager = UpdaterManager.shared
func applicationDidFinishLaunching(_ notification: Notification) {
updaterManager.start()
}
}UpdaterManager.sharedSPUStandardUpdaterControllerAppDelegatestruct AboutSettingsPane: View {
@ObservedObject private var updaterManager = UpdaterManager.shared
var body: some View {
Form {
Section("Updates") {
Toggle(isOn: Binding(
get: { updaterManager.automaticallyChecksForUpdates },
set: { updaterManager.automaticallyChecksForUpdates = $0 }
)) {
Text("Automatically check for updates")
}
Button("Check for Updates...") {
updaterManager.checkForUpdates()
}
.disabled(!updaterManager.canCheckForUpdates)
}
}
.formStyle(.grouped)
.scrollContentBackground(.hidden)
}
}Button {
updaterManager.checkForUpdates()
} label: {
Label("Check for Updates...", systemImage: "arrow.down.circle")
}
.disabled(!updaterManager.canCheckForUpdates)appcast.xml<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>YourApp</title>
<description>Most recent changes for YourApp.</description>
<language>en</language>
</channel>
</rss>SUFeedURL.accessory.regularUpdaterManagercheckForUpdates()func checkForUpdates() {
NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
controller.checkForUpdates(nil)
}.accessory<item>
<title>Version 1.2 (Build 5)</title>
<pubDate>Mon, 26 May 2026 12:00:00 +0000</pubDate>
<sparkle:version>5</sparkle:version>
<sparkle:shortVersionString>1.2</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>14.0</sparkle:minimumSystemVersion>
<description><![CDATA[<ul><li>New feature</li><li>Bug fix</li></ul>]]></description>
<enclosure url="https://github.com/OWNER/REPO/releases/download/v1.2/YourApp.dmg"
type="application/octet-stream"
sparkle:edSignature="BASE64_EDDSA_SIGNATURE"
length="FILE_SIZE_BYTES" />
</item>sparkle:versionCFBundleVersionsparkle:shortVersionStringCFBundleShortVersionStringsparkle:edSignaturesign_update YourApp.dmglength