Last active
January 11, 2023 00:37
-
-
Save helje5/835cc98dc0cb003e572ab7a23024d501 to your computer and use it in GitHub Desktop.
How to hookup Sparkle in SwiftUI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SparkleCommands.swift | |
// Past for iChat | |
// | |
// Created by Helge Heß on 08.04.21. | |
// | |
import SwiftUI | |
#if SPARKLE && canImport(Sparkle) | |
import Sparkle | |
/** | |
* Adds the "Check for Updates" menu if Sparkle is enabled (i.e. can be | |
* imported and the `SPARKLE` compilation condition is set. | |
* | |
* Using it in an app: | |
* | |
* @main | |
* struct PastApp: App { // https://zeezide.de/en/products/past/ | |
* var body: some Scene { | |
* DocumentGroup(viewing: PastDocument.self) { file in | |
* ContentView(document: file.$document) | |
* } | |
* .commands { | |
* TextFormattingCommands() | |
* SparkleCommands() // Just drop it in here | |
* } | |
* } | |
* } | |
* | |
* One may want to make settings like `automaticallyChecksForUpdates` user | |
* configurable in the app preferences: | |
* | |
* @main | |
* struct PastApp: App { // https://zeezide.de/en/products/past/ | |
* | |
* @AppStorage("autoUpdate") var doAutoUpdates = true | |
* | |
* var body: some Scene { | |
* DocumentGroup(viewing: PastDocument.self) { file in | |
* ContentView(document: file.$document) | |
* } | |
* .commands { | |
* TextFormattingCommands() | |
* SparkleCommands( | |
* automaticallyChecksForUpdates: doAutoUpdates | |
* ) | |
* } | |
* | |
* Settings { | |
* YourSettingsView(doAutoUpdates: $doAutoUpdates) | |
* } | |
* } | |
* } | |
*/ | |
struct SparkleCommands: Commands { | |
private var automaticallyChecksForUpdates : Bool | |
private var automaticallyDownloadsUpdates : Bool | |
private var updateCheckInterval : TimeInterval | |
private var userAgentString : String? | |
private var httpHeaders : [ String : String ]? | |
private var sendsSystemProfile : Bool | |
init(automaticallyChecksForUpdates : Bool = true, | |
automaticallyDownloadsUpdates : Bool = false, | |
sendsSystemProfile : Bool = false, | |
updateCheckInterval : TimeInterval = 24 * 60 * 60 /*daily*/, | |
userAgentString : String? = nil, | |
httpHeaders : [ String : String ]? = nil) | |
{ | |
self.automaticallyChecksForUpdates = automaticallyChecksForUpdates | |
self.automaticallyDownloadsUpdates = automaticallyDownloadsUpdates | |
self.sendsSystemProfile = sendsSystemProfile | |
self.updateCheckInterval = updateCheckInterval | |
self.userAgentString = userAgentString | |
self.httpHeaders = httpHeaders | |
let me = self | |
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { | |
SparkleCommands.update(with: me) | |
} | |
} | |
var body: some Commands { | |
CommandGroup(after: .appInfo) { | |
Button("Check for Updates …") { | |
SparkleCommands.updater?.checkForUpdates() | |
} | |
} | |
} | |
fileprivate static var updater : SPUUpdater? | |
private final class SparkleDelegate: | |
NSObject, SPUUpdaterDelegate, SPUStandardUserDriverDelegate {} | |
private static let delegate = SparkleDelegate() | |
private static func update(with configuration: SparkleCommands) { | |
func configure(updater: SPUUpdater) { | |
updater.automaticallyChecksForUpdates = | |
configuration.automaticallyChecksForUpdates | |
updater.automaticallyDownloadsUpdates = | |
configuration.automaticallyDownloadsUpdates | |
updater.sendsSystemProfile = configuration.sendsSystemProfile | |
updater.updateCheckInterval = configuration.updateCheckInterval | |
if let v = configuration.userAgentString { updater.userAgentString = v } | |
if let v = configuration.httpHeaders { updater.httpHeaders = v } | |
} | |
if let updater = SparkleCommands.updater { | |
configure(updater: updater) | |
} | |
else { | |
let updateDriver = SPUStandardUserDriver(hostBundle: .main, | |
delegate: delegate) | |
let updater = SPUUpdater(hostBundle: .main, applicationBundle: .main, | |
userDriver: updateDriver, delegate: delegate) | |
configure(updater: updater) | |
SparkleCommands.updater = updater | |
do { | |
try updater.start() | |
updater.checkForUpdatesInBackground() | |
} | |
catch { | |
print("ERROR: failed to start Sparkle updater:", error) | |
} | |
} | |
} | |
} | |
#else // No Sparkle | |
/** | |
* Sparkle is inactive, this will yield no commands. | |
*/ | |
struct SparkleCommands: Commands { | |
let body = EmptyCommands() | |
} | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@main | |
struct PastApp: App { // https://zeezide.de/en/products/past/ | |
var body: some Scene { | |
DocumentGroup(viewing: PastDocument.self) { file in | |
ContentView(document: file.$document) | |
} | |
.commands { | |
TextFormattingCommands() | |
AboutCommands() | |
SparkleCommands() // Just drop it in here | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment