Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ace1a008ef | ||
|
|
354488d623 | ||
|
|
61392a16a2 | ||
|
|
d46e0450bf | ||
|
|
5905ae5aa7 |
2
NOTES.md
2
NOTES.md
@@ -5,5 +5,5 @@
|
|||||||
|
|
||||||
add a marker for "reboot required"
|
add a marker for "reboot required"
|
||||||
|
|
||||||
dummy2
|
dummy22
|
||||||
|
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -81,6 +81,16 @@ Preferences expose Sparkle’s built-in toggles for “Automatically check” an
|
|||||||
|
|
||||||
> Build settings include `INFOPLIST_KEY_SUFeedURL` and `INFOPLIST_KEY_SUPublicEDKey`. Make sure to fill both before shipping a build so Sparkle knows where to fetch updates and how to verify them.
|
> Build settings include `INFOPLIST_KEY_SUFeedURL` and `INFOPLIST_KEY_SUPublicEDKey`. Make sure to fill both before shipping a build so Sparkle knows where to fetch updates and how to verify them.
|
||||||
|
|
||||||
|
#### Debugging Sparkle updates
|
||||||
|
|
||||||
|
Launch the shipped app via CLI with `SPARKLE_VERBOSE_LOGGING=1` to mirror Sparkle’s activity in stdout/stderr:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SPARKLE_VERBOSE_LOGGING=1 /Applications/iKeyMon.app/Contents/MacOS/iKeyMon
|
||||||
|
```
|
||||||
|
|
||||||
|
Sparkle’s installer helper runs in a separate `SUPipedBinary` process. If the installer fails, collect additional details with `log show --process SUPipedBinary --last 5m`.
|
||||||
|
|
||||||
### Automated release push
|
### Automated release push
|
||||||
|
|
||||||
If you want `git push origin master` to build/sign/notarize/upload automatically, enable the provided pre-push hook:
|
If you want `git push origin master` to build/sign/notarize/upload automatically, enable the provided pre-push hook:
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
import Sparkle
|
import Sparkle
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import OSLog
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
final class SparkleUpdater: NSObject, ObservableObject {
|
final class SparkleUpdater: NSObject, ObservableObject {
|
||||||
let controller: SPUStandardUpdaterController
|
private lazy var controller: SPUStandardUpdaterController = {
|
||||||
|
SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: self, userDriverDelegate: nil)
|
||||||
|
}()
|
||||||
|
private let logger = Logger(subsystem: "net.24unix.iKeyMon", category: "Sparkle")
|
||||||
|
private let verboseLogging: Bool
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
self.controller = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil)
|
self.verboseLogging = ProcessInfo.processInfo.environment["SPARKLE_VERBOSE_LOGGING"] == "1"
|
||||||
super.init()
|
super.init()
|
||||||
|
_ = controller
|
||||||
|
log("Sparkle updater initialized (verbose=\(verboseLogging)).")
|
||||||
}
|
}
|
||||||
|
|
||||||
var automaticallyChecksForUpdates: Bool {
|
var automaticallyChecksForUpdates: Bool {
|
||||||
@@ -21,6 +28,66 @@ final class SparkleUpdater: NSObject, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkForUpdates() {
|
func checkForUpdates() {
|
||||||
|
log("Manual check for updates triggered.")
|
||||||
controller.checkForUpdates(nil)
|
controller.checkForUpdates(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func log(_ message: String) {
|
||||||
|
logger.log("\(message, privacy: .public)")
|
||||||
|
if verboseLogging {
|
||||||
|
print("[Sparkle] \(message)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func logError(_ message: String) {
|
||||||
|
logger.error("\(message, privacy: .public)")
|
||||||
|
if verboseLogging {
|
||||||
|
fputs("[Sparkle][error] \(message)\n", stderr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func describe(update item: SUAppcastItem) -> String {
|
||||||
|
let short = item.displayVersionString
|
||||||
|
let build = item.versionString
|
||||||
|
return "\(short) (build \(build))"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
extension SparkleUpdater: SPUUpdaterDelegate {
|
||||||
|
func updater(_ updater: SPUUpdater, didFinishLoading appcast: SUAppcast) {
|
||||||
|
log("Loaded Sparkle appcast containing \(appcast.items.count) item(s).")
|
||||||
|
}
|
||||||
|
|
||||||
|
func updater(_ updater: SPUUpdater, didFindValidUpdate item: SUAppcastItem) {
|
||||||
|
log("Found valid update \(describe(update: item))")
|
||||||
|
}
|
||||||
|
|
||||||
|
func updaterDidNotFindUpdate(_ updater: SPUUpdater) {
|
||||||
|
log("No updates available.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func updater(_ updater: SPUUpdater, willDownloadUpdate item: SUAppcastItem, with request: NSMutableURLRequest) {
|
||||||
|
log("Downloading \(describe(update: item)) from \(request.url?.absoluteString ?? "unknown URL")")
|
||||||
|
}
|
||||||
|
|
||||||
|
func updater(_ updater: SPUUpdater, didDownloadUpdate item: SUAppcastItem) {
|
||||||
|
log("Finished downloading \(describe(update: item))")
|
||||||
|
}
|
||||||
|
|
||||||
|
func updater(_ updater: SPUUpdater, failedToDownloadUpdate item: SUAppcastItem, error: Error) {
|
||||||
|
logError("Failed to download \(describe(update: item)): \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func userDidCancelDownload(_ updater: SPUUpdater) {
|
||||||
|
log("User cancelled Sparkle download.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func updater(_ updater: SPUUpdater, willInstallUpdate item: SUAppcastItem) {
|
||||||
|
log("Will install update \(describe(update: item))")
|
||||||
|
}
|
||||||
|
|
||||||
|
func updater(_ updater: SPUUpdater, didAbortWithError error: Error) {
|
||||||
|
logError("Sparkle aborted: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -310,7 +310,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = iKeyMon.entitlements;
|
CODE_SIGN_ENTITLEMENTS = iKeyMon.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 51;
|
CURRENT_PROJECT_VERSION = 56;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = Q5486ZVAFT;
|
DEVELOPMENT_TEAM = Q5486ZVAFT;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
@@ -325,7 +325,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 26.0.22;
|
MARKETING_VERSION = 26.0.26;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = net.24unix.iKeyMon;
|
PRODUCT_BUNDLE_IDENTIFIER = net.24unix.iKeyMon;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
@@ -341,7 +341,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = iKeyMon.entitlements;
|
CODE_SIGN_ENTITLEMENTS = iKeyMon.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 51;
|
CURRENT_PROJECT_VERSION = 56;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = Q5486ZVAFT;
|
DEVELOPMENT_TEAM = Q5486ZVAFT;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
@@ -356,7 +356,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 26.0.22;
|
MARKETING_VERSION = 26.0.26;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = net.24unix.iKeyMon;
|
PRODUCT_BUNDLE_IDENTIFIER = net.24unix.iKeyMon;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"marketing_version": "26.0.22"
|
"marketing_version": "26.0.26"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user