Compare commits
21 Commits
v26.0.32
...
b96b018f70
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b96b018f70 | ||
|
|
65a65939a7 | ||
|
|
25723b7f07 | ||
|
|
10683ebc73 | ||
|
|
393bcf27e1 | ||
|
|
839a513fde | ||
|
|
77e82753ba | ||
|
|
bbb0b580b0 | ||
|
|
dd225b2b8e | ||
|
|
76b01352ac | ||
|
|
fcca8cee38 | ||
|
|
94d1b3fec4 | ||
|
|
4352ae1476 | ||
|
|
846e0b149b | ||
|
|
11ca4dbede | ||
|
|
1d8bdfe491 | ||
|
|
4f5a07822f | ||
|
|
67709dfda6 | ||
|
|
6753226087 | ||
|
|
a3671acf38 | ||
|
|
0aa773a0b3 |
@@ -9,6 +9,8 @@ final class SparkleUpdater: NSObject, ObservableObject {
|
||||
}()
|
||||
private let logger = Logger(subsystem: "net.24unix.iKeyMon", category: "Sparkle")
|
||||
private let verboseLogging: Bool
|
||||
@Published var logMessages: [String] = []
|
||||
@Published var showLogs: Bool = false
|
||||
|
||||
override init() {
|
||||
self.verboseLogging = ProcessInfo.processInfo.environment["SPARKLE_VERBOSE_LOGGING"] == "1"
|
||||
@@ -34,6 +36,7 @@ final class SparkleUpdater: NSObject, ObservableObject {
|
||||
|
||||
private func log(_ message: String) {
|
||||
logger.log("\(message, privacy: .public)")
|
||||
addLogMessage("[INFO] \(message)")
|
||||
if verboseLogging {
|
||||
print("[Sparkle] \(message)")
|
||||
}
|
||||
@@ -41,11 +44,21 @@ final class SparkleUpdater: NSObject, ObservableObject {
|
||||
|
||||
private func logError(_ message: String) {
|
||||
logger.error("\(message, privacy: .public)")
|
||||
addLogMessage("[ERROR] \(message)")
|
||||
if verboseLogging {
|
||||
fputs("[Sparkle][error] \(message)\n", stderr)
|
||||
}
|
||||
}
|
||||
|
||||
private func addLogMessage(_ message: String) {
|
||||
let timestamp = DateFormatter.localizedString(from: Date(), dateStyle: .none, timeStyle: .medium)
|
||||
let timestampedMessage = "[\(timestamp)] \(message)"
|
||||
logMessages.append(timestampedMessage)
|
||||
if logMessages.count > 100 {
|
||||
logMessages.removeFirst()
|
||||
}
|
||||
}
|
||||
|
||||
private func describe(update item: SUAppcastItem) -> String {
|
||||
let short = item.displayVersionString
|
||||
let build = item.versionString
|
||||
@@ -53,41 +66,58 @@ final class SparkleUpdater: NSObject, ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
extension SparkleUpdater: SPUUpdaterDelegate {
|
||||
func updater(_ updater: SPUUpdater, didFinishLoading appcast: SUAppcast) {
|
||||
log("Loaded Sparkle appcast containing \(appcast.items.count) item(s).")
|
||||
nonisolated func updater(_ updater: SPUUpdater, didFinishLoading appcast: SUAppcast) {
|
||||
Task { @MainActor in
|
||||
log("Loaded Sparkle appcast containing \(appcast.items.count) item(s).")
|
||||
}
|
||||
}
|
||||
|
||||
func updater(_ updater: SPUUpdater, didFindValidUpdate item: SUAppcastItem) {
|
||||
log("Found valid update \(describe(update: item))")
|
||||
nonisolated func updater(_ updater: SPUUpdater, didFindValidUpdate item: SUAppcastItem) {
|
||||
Task { @MainActor in
|
||||
log("Found valid update \(describe(update: item))")
|
||||
}
|
||||
}
|
||||
|
||||
func updaterDidNotFindUpdate(_ updater: SPUUpdater) {
|
||||
log("No updates available.")
|
||||
nonisolated func updaterDidNotFindUpdate(_ updater: SPUUpdater) {
|
||||
Task { @MainActor in
|
||||
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")")
|
||||
nonisolated func updater(_ updater: SPUUpdater, willDownloadUpdate item: SUAppcastItem, with request: NSMutableURLRequest) {
|
||||
Task { @MainActor in
|
||||
log("Downloading \(describe(update: item)) from \(request.url?.absoluteString ?? "unknown URL")")
|
||||
}
|
||||
}
|
||||
|
||||
func updater(_ updater: SPUUpdater, didDownloadUpdate item: SUAppcastItem) {
|
||||
log("Finished downloading \(describe(update: item))")
|
||||
nonisolated func updater(_ updater: SPUUpdater, didDownloadUpdate item: SUAppcastItem) {
|
||||
Task { @MainActor in
|
||||
log("Finished downloading \(describe(update: item))")
|
||||
}
|
||||
}
|
||||
|
||||
func updater(_ updater: SPUUpdater, failedToDownloadUpdate item: SUAppcastItem, error: Error) {
|
||||
logError("Failed to download \(describe(update: item)): \(error.localizedDescription)")
|
||||
nonisolated func updater(_ updater: SPUUpdater, failedToDownloadUpdate item: SUAppcastItem, error: Error) {
|
||||
Task { @MainActor in
|
||||
logError("Failed to download \(describe(update: item)): \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
func userDidCancelDownload(_ updater: SPUUpdater) {
|
||||
log("User cancelled Sparkle download.")
|
||||
nonisolated func userDidCancelDownload(_ updater: SPUUpdater) {
|
||||
Task { @MainActor in
|
||||
log("User cancelled Sparkle download.")
|
||||
}
|
||||
}
|
||||
|
||||
func updater(_ updater: SPUUpdater, willInstallUpdate item: SUAppcastItem) {
|
||||
log("Will install update \(describe(update: item))")
|
||||
nonisolated func updater(_ updater: SPUUpdater, willInstallUpdate item: SUAppcastItem) {
|
||||
Task { @MainActor in
|
||||
log("Will install update \(describe(update: item))")
|
||||
}
|
||||
}
|
||||
|
||||
func updater(_ updater: SPUUpdater, didAbortWithError error: Error) {
|
||||
logError("Sparkle aborted: \(error.localizedDescription)")
|
||||
nonisolated func updater(_ updater: SPUUpdater, didAbortWithError error: Error) {
|
||||
Task { @MainActor in
|
||||
logError("Sparkle aborted: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,11 +257,64 @@ private struct UpdatesPreferencesView: View {
|
||||
.foregroundColor(.secondary)
|
||||
.padding(.top, 4)
|
||||
|
||||
Divider()
|
||||
.padding(.vertical, 8)
|
||||
|
||||
Button(action: { sparkleUpdater.showLogs.toggle() }) {
|
||||
Label(sparkleUpdater.showLogs ? "Hide Logs" : "Show Logs", systemImage: "terminal.fill")
|
||||
}
|
||||
|
||||
if sparkleUpdater.showLogs {
|
||||
logsView
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.toggleStyle(.switch)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
private var logsView: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("Update Logs")
|
||||
.font(.caption)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
if sparkleUpdater.logMessages.isEmpty {
|
||||
Text("No logs yet. Check for updates to see activity.")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.italic()
|
||||
} else {
|
||||
ForEach(sparkleUpdater.logMessages, id: \.self) { message in
|
||||
Text(message)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(3)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(8)
|
||||
}
|
||||
.frame(height: 200)
|
||||
.background(Color(nsColor: .controlBackgroundColor))
|
||||
.cornerRadius(6)
|
||||
.border(.separator, width: 1)
|
||||
|
||||
Button(action: {
|
||||
sparkleUpdater.logMessages.removeAll()
|
||||
}) {
|
||||
Label("Clear Logs", systemImage: "trash")
|
||||
.font(.caption)
|
||||
}
|
||||
.disabled(sparkleUpdater.logMessages.isEmpty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct NotificationsPreferencesView: View {
|
||||
|
||||
14
Sparkle/appcast-local.xml
vendored
Normal file
14
Sparkle/appcast-local.xml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<rss xmlns:ns0="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
|
||||
<channel>
|
||||
<title>iKeyMon</title>
|
||||
<item>
|
||||
<title>26.0.37 (reinstall)</title>
|
||||
<pubDate>Mon, 08 Dec 2025 18:17:55 +0000</pubDate>
|
||||
<ns0:shortVersionString>26.0.37</ns0:shortVersionString>
|
||||
<ns0:version>1077</ns0:version>
|
||||
<ns0:minimumSystemVersion>15.2</ns0:minimumSystemVersion>
|
||||
<enclosure url="https://git.24unix.net/tracer/iKeyMon/releases/download/v26.0.37/iKeyMon-26.0.37.zip" length="4813994" type="application/octet-stream" ns0:edSignature="C65NrwvB2vwPx9qh/Tu1Xqbfljk1zKaKHVRedOX0nINbhKMbOHerY28HxX0veybUWSFEOu6RGi2yDXumQQVMBA==" />
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
30
Sparkle/appcast.xml
vendored
30
Sparkle/appcast.xml
vendored
@@ -3,28 +3,28 @@
|
||||
<channel>
|
||||
<title>iKeyMon</title>
|
||||
<item>
|
||||
<title>26.0.31</title>
|
||||
<pubDate>Sun, 07 Dec 2025 17:52:44 +0100</pubDate>
|
||||
<sparkle:version>65</sparkle:version>
|
||||
<sparkle:shortVersionString>26.0.31</sparkle:shortVersionString>
|
||||
<title>26.0.41</title>
|
||||
<pubDate>Tue, 30 Dec 2025 13:18:56 +0100</pubDate>
|
||||
<sparkle:version>86</sparkle:version>
|
||||
<sparkle:shortVersionString>26.0.41</sparkle:shortVersionString>
|
||||
<sparkle:minimumSystemVersion>15.2</sparkle:minimumSystemVersion>
|
||||
<enclosure url="https://git.24unix.net/tracer/iKeyMon/releases/download/v26.0.31/iKeyMon-26.0.31.zip" length="4811475" type="application/octet-stream" sparkle:edSignature="zFNwVms0WwT5CBYX1GjtVg1qKbxoCVvv2DKXoTGZmwx+crg0B1fk3Ytu9K+6yTfbwQYsRISst9g3InMAlJS6BQ=="/>
|
||||
<enclosure url="https://git.24unix.net/tracer/iKeyMon/releases/download/v26.0.41/iKeyMon-26.0.41.zip" length="4847296" type="application/octet-stream" sparkle:edSignature="8ITx6pM0LDVh0IpAz7eej7+eomnLTvRbchNaxSbdfQT/A16Bxg6F+FgtRDJkV5khJTrunpEPal9x3OUi7FO4Bg=="/>
|
||||
</item>
|
||||
<item>
|
||||
<title>26.0.29</title>
|
||||
<pubDate>Sun, 07 Dec 2025 17:07:32 +0100</pubDate>
|
||||
<sparkle:version>61</sparkle:version>
|
||||
<sparkle:shortVersionString>26.0.29</sparkle:shortVersionString>
|
||||
<title>26.0.40</title>
|
||||
<pubDate>Tue, 30 Dec 2025 13:01:18 +0100</pubDate>
|
||||
<sparkle:version>83</sparkle:version>
|
||||
<sparkle:shortVersionString>26.0.40</sparkle:shortVersionString>
|
||||
<sparkle:minimumSystemVersion>15.2</sparkle:minimumSystemVersion>
|
||||
<enclosure url="https://git.24unix.net/tracer/iKeyMon/releases/download/v26.0.29/iKeyMon-26.0.29.zip" length="4811507" type="application/octet-stream" sparkle:edSignature="eRH4M8hEYa9gYiyjAVtTpXN3T1o+OGadDRMQu4kHL/dbJ2vj/5pY1+am9/9qG33Qairt3Od/6/WKLyxxs4mWCw=="/>
|
||||
<enclosure url="https://git.24unix.net/tracer/iKeyMon/releases/download/v26.0.40/iKeyMon-26.0.40.zip" length="4829609" type="application/octet-stream" sparkle:edSignature="RoGONthjaIA8/2Ne84xObiR+0u2KfaIDLCy4TwiQcN4UwzSkfsWM3pbLzByJpO5ID8GV6w7gDGn4oxpaQg0dDA=="/>
|
||||
</item>
|
||||
<item>
|
||||
<title>26.0.28</title>
|
||||
<pubDate>Sun, 07 Dec 2025 17:02:18 +0100</pubDate>
|
||||
<sparkle:version>59</sparkle:version>
|
||||
<sparkle:shortVersionString>26.0.28</sparkle:shortVersionString>
|
||||
<title>26.0.39</title>
|
||||
<pubDate>Tue, 30 Dec 2025 12:48:54 +0100</pubDate>
|
||||
<sparkle:version>81</sparkle:version>
|
||||
<sparkle:shortVersionString>26.0.39</sparkle:shortVersionString>
|
||||
<sparkle:minimumSystemVersion>15.2</sparkle:minimumSystemVersion>
|
||||
<enclosure url="https://git.24unix.net/tracer/iKeyMon/releases/download/v26.0.28/iKeyMon-26.0.28.zip" length="4811473" type="application/octet-stream" sparkle:edSignature="tF188T0m/j22MStCVbVkrf2JllyZ9wiEmc++kgF4GTKhoAuHURYvT/Euy+ivEodmQ/LzeFolN4lViqaVa3y+DQ=="/>
|
||||
<enclosure url="https://git.24unix.net/tracer/iKeyMon/releases/download/v26.0.39/iKeyMon-26.0.39.zip" length="4829477" type="application/octet-stream" sparkle:edSignature="/J0LTgTj5uFa30okaLC7l6+wFUQxu8/E18y8vu3wqCXnM8tCG6TanZaGY69UWTUzaO9858oORy2yY6/MYtERBw=="/>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
@@ -6,5 +6,7 @@
|
||||
<string>https://git.24unix.net/tracer/iKeyMon/raw/branch/master/Sparkle/appcast.xml</string>
|
||||
<key>SUPublicEDKey</key>
|
||||
<string>EgJgrOGQ79L5me616jA7kDCEOgx+Rg11uYLYLLIyzTI=</string>
|
||||
<key>SUEnableInstallerLauncherService</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -4,9 +4,15 @@
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.downloads.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.automation.apple-events</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -322,7 +322,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = iKeyMon.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 65;
|
||||
CURRENT_PROJECT_VERSION = 86;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"Preview Content\"";
|
||||
DEVELOPMENT_TEAM = Q5486ZVAFT;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -337,7 +337,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 26.0.31;
|
||||
MARKETING_VERSION = 26.0.41;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.24unix.iKeyMon;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -353,7 +353,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = iKeyMon.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 65;
|
||||
CURRENT_PROJECT_VERSION = 86;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"Preview Content\"";
|
||||
DEVELOPMENT_TEAM = Q5486ZVAFT;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -368,7 +368,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 26.0.31;
|
||||
MARKETING_VERSION = 26.0.41;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.24unix.iKeyMon;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"marketing_version": "26.0.31"
|
||||
"marketing_version": "26.0.41"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user