Skip to content

Commit 4712cb8

Browse files
committed
macOS 15.4 update badge fix
Fix for update badge not updating anymore as `LastUpdatesAvailable` in `/Library/Preferences/com.apple.SoftwareUpdate.plist` is not maintained anymore in macOS 15.4. We now use `RecommendedUpdates` and count the elements.
1 parent 0ee975b commit 4712cb8

8 files changed

Lines changed: 26 additions & 29 deletions

File tree

src/Support/AppDelegate.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
135135
defaults.addObserver(self, forKeyPath: "PasswordExpiryLimit", options: .new, context: nil)
136136
defaults.addObserver(self, forKeyPath: "OpenAtLogin", options: .new, context: nil)
137137
restrictionsDefaults?.addObserver(self, forKeyPath: "forceDelayedMajorSoftwareUpdates", options: .new, context: nil)
138-
ASUdefaults?.addObserver(self, forKeyPath: "LastUpdatesAvailable", options: .new, context: nil)
138+
// ASUdefaults?.addObserver(self, forKeyPath: "LastUpdatesAvailable", options: .new, context: nil)
139139
ASUdefaults?.addObserver(self, forKeyPath: "RecommendedUpdates", options: .new, context: nil)
140140

141141
// Observe changes for Extensions A and B
@@ -157,8 +157,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
157157
// Receive notification after password expiry check
158158
NotificationCenter.default.addObserver(self, selector: #selector(setStatusBarIcon), name: Notification.Name.passwordExpiryLimit, object: nil)
159159

160-
// Receive notification after major macOS update check
161-
NotificationCenter.default.addObserver(self, selector: #selector(setStatusBarIcon), name: Notification.Name.majorVersionUpdates, object: nil)
160+
// Receive notification after macOS update check
161+
NotificationCenter.default.addObserver(self, selector: #selector(setStatusBarIcon), name: Notification.Name.recommendedUpdates, object: nil)
162162

163163
// Run functions at startup
164164
runAtStartup()
@@ -337,12 +337,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
337337
// Check if StatusBarItem notifier is enabled
338338
if defaults.bool(forKey: "StatusBarIconNotifierEnabled") {
339339
// Show notification badge in menu bar icon when info item when needed
340-
if ((computerinfo.updatesAvailableToShow == 0 || !infoItemsEnabled.contains("MacOSVersion")) && (appCatalogController.appUpdates == 0 || !infoItemsEnabled.contains("AppCatalog"))) && ((computerinfo.uptimeLimitReached && infoItemsEnabled.contains("Uptime")) || (computerinfo.selfSignedIP && infoItemsEnabled.contains("Network")) || (userinfo.passwordExpiryLimitReached && infoItemsEnabled.contains("Password")) || (computerinfo.storageLimitReached && infoItemsEnabled.contains("Storage")) || (preferences.extensionAlertA && infoItemsEnabled.contains("ExtensionA")) || (preferences.extensionAlertB && infoItemsEnabled.contains("ExtensionB"))) {
340+
if ((computerinfo.recommendedUpdates.count == 0 || !infoItemsEnabled.contains("MacOSVersion")) && (appCatalogController.appUpdates == 0 || !infoItemsEnabled.contains("AppCatalog"))) && ((computerinfo.uptimeLimitReached && infoItemsEnabled.contains("Uptime")) || (computerinfo.selfSignedIP && infoItemsEnabled.contains("Network")) || (userinfo.passwordExpiryLimitReached && infoItemsEnabled.contains("Password")) || (computerinfo.storageLimitReached && infoItemsEnabled.contains("Storage")) || (preferences.extensionAlertA && infoItemsEnabled.contains("ExtensionA")) || (preferences.extensionAlertB && infoItemsEnabled.contains("ExtensionB"))) {
341341

342342
// Create orange notification badge
343343
orangeBadge.isHidden = false
344344

345-
} else if (computerinfo.updatesAvailableToShow > 0 && infoItemsEnabled.contains("MacOSVersion")) || (appCatalogController.appUpdates > 0 && infoItemsEnabled.contains("AppCatalog")) {
345+
} else if (computerinfo.recommendedUpdates.count > 0 && infoItemsEnabled.contains("MacOSVersion")) || (appCatalogController.appUpdates > 0 && infoItemsEnabled.contains("AppCatalog")) {
346346

347347
// Create red notification badge
348348
redBadge.isHidden = false
@@ -439,8 +439,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
439439
Task {
440440
await self.userinfo.getCurrentUserRecord()
441441
}
442-
case "LastUpdatesAvailable":
443-
logger.debug("\(keyPath! as NSObject, privacy: .public) changed to \(self.ASUdefaults!.integer(forKey: "LastUpdatesAvailable"), privacy: .public)")
442+
// case "LastUpdatesAvailable":
443+
// logger.debug("\(keyPath! as NSObject, privacy: .public) changed to \(self.ASUdefaults!.integer(forKey: "LastUpdatesAvailable"), privacy: .public)")
444444
case "RecommendedUpdates":
445445
logger.debug("\(keyPath! as NSObject, privacy: .public) changed, checking update contents...")
446446
self.computerinfo.getRecommendedUpdates()

src/Support/ComputerInfo.swift

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,19 @@ class ComputerInfo: ObservableObject {
6868
var modelIdentifier = String()
6969

7070
// Get Available Software Updates
71-
@AppStorage("LastUpdatesAvailable", store: UserDefaults(suiteName: "com.apple.SoftwareUpdate")) var updatesAvailable: Int = 0
71+
// @AppStorage("LastUpdatesAvailable", store: UserDefaults(suiteName: "com.apple.SoftwareUpdate")) var updatesAvailable: Int = 0
7272

7373
// Number of major macOS Software Updates
7474
@Published var majorVersionUpdates: Int = 0
7575

7676
// Calculate number of updates to show, excluding any major upgrades if hidden using 'forceDelayedMajorSoftwareUpdates' in a restrictions profile
77-
var updatesAvailableToShow: Int {
78-
if forceDelayedMajorSoftwareUpdates {
79-
return updatesAvailable - majorVersionUpdates
80-
} else {
81-
return updatesAvailable
82-
}
83-
}
77+
// var updatesAvailableToShow: Int {
78+
// if forceDelayedMajorSoftwareUpdates {
79+
// return updatesAvailable - majorVersionUpdates
80+
// } else {
81+
// return updatesAvailable
82+
// }
83+
// }
8484

8585
// Get if major OS updates are deferred using a restrictions profile
8686
@AppStorage("forceDelayedMajorSoftwareUpdates", store: UserDefaults(suiteName: "com.apple.applicationaccess")) var forceDelayedMajorSoftwareUpdates: Bool = false
@@ -680,6 +680,7 @@ class ComputerInfo: ObservableObject {
680680
// Remove all updates from UI
681681
DispatchQueue.main.async {
682682
self.recommendedUpdates = []
683+
NotificationCenter.default.post(name: Notification.Name.recommendedUpdates, object: nil)
683684
}
684685

685686
return
@@ -723,11 +724,7 @@ class ComputerInfo: ObservableObject {
723724
self.recommendedUpdates = decodedItems
724725

725726
// Post changes to notification center
726-
if oldMajorVersionUpdates != majorVersionUpdatesTemp {
727-
NotificationCenter.default.post(name: Notification.Name.majorVersionUpdates, object: nil)
728-
} else {
729-
self.logger.debug("Number of Major macOS Updates did not change, no need to reload StatusBarItem")
730-
}
727+
NotificationCenter.default.post(name: Notification.Name.recommendedUpdates, object: nil)
731728
}
732729
}
733730
}

src/Support/Extensions/Extensions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ extension String {
163163
("$LocalMacosVersionName", computerInfo.macOSVersionName),
164164
("$LocalSerialNumber", computerInfo.deviceSerialNumber),
165165
("$LocalIpAddress", computerInfo.ipAddress),
166-
("$LocalUpdatesAvailable", "\(computerInfo.updatesAvailableToShow)"),
166+
("$LocalUpdatesAvailable", "\(computerInfo.recommendedUpdates.count)"),
167167
("\\n", "\n")
168168
]
169169

src/Support/Info.plist

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<key>CFBundlePackageType</key>
1818
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
1919
<key>CFBundleShortVersionString</key>
20-
<string>2.6.1</string>
20+
<string>2.6.2</string>
2121
<key>CFBundleVersion</key>
2222
<string>64</string>
2323
<key>LSApplicationCategoryType</key>
@@ -27,7 +27,7 @@
2727
<key>LSUIElement</key>
2828
<true/>
2929
<key>NSHumanReadableCopyright</key>
30-
<string>© 2024 Root3 B.V. All rights reserved.</string>
30+
<string>© 2025 Root3 B.V. All rights reserved.</string>
3131
<key>NSMainStoryboardFile</key>
3232
<string>Main</string>
3333
<key>NSPrincipalClass</key>

src/Support/NotificationNames.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ extension Notification.Name {
1414
static let storageLimit = Notification.Name("StorageLimit")
1515
static let networkState = Notification.Name("NetworkState")
1616
static let passwordExpiryLimit = Notification.Name("PasswordExpiryLimit")
17-
static let majorVersionUpdates = Notification.Name("MajorVersionUpdates")
17+
static let recommendedUpdates = Notification.Name("RecommendedUpdates")
1818

1919
}

src/Support/Views/ButtonViews/MacOSVersionSubview.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct MacOSVersionSubview: View {
3737

3838
var body: some View {
3939

40-
InfoItem(title: "macOS \(computerinfo.macOSVersionName)", subtitle: computerinfo.macOSVersion, image: "applelogo", symbolColor: Color(NSColor(hex: "\(customColor)") ?? NSColor.controlAccentColor), notificationBadge: computerinfo.updatesAvailableToShow, hoverEffectEnable: true)
40+
InfoItem(title: "macOS \(computerinfo.macOSVersionName)", subtitle: computerinfo.macOSVersion, image: "applelogo", symbolColor: Color(NSColor(hex: "\(customColor)") ?? NSColor.controlAccentColor), notificationBadge: computerinfo.recommendedUpdates.count, hoverEffectEnable: true)
4141
.modify {
4242
if #available(macOS 13, *) {
4343
$0.onTapGesture {
@@ -51,7 +51,7 @@ struct MacOSVersionSubview: View {
5151
}
5252
// Legacy popover for macOS 12
5353
.popover(isPresented: $showUpdatePopover, arrowEdge: .leading) {
54-
UpdateViewLegacy(updateCounter: computerinfo.updatesAvailableToShow, color: Color(NSColor(hex: "\(customColor)") ?? NSColor.controlAccentColor))
54+
UpdateViewLegacy(updateCounter: computerinfo.recommendedUpdates.count, color: Color(NSColor(hex: "\(customColor)") ?? NSColor.controlAccentColor))
5555
}
5656
}
5757
}

src/SupportHelper/Info.plist

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
<plist version="1.0">
44
<dict>
55
<key>CFBundleShortVersionString</key>
6-
<string>2.6.1</string>
6+
<string>2.6.2</string>
77
<key>NSHumanReadableCopyright</key>
8-
<string>© 2024 Root3 B.V. All rights reserved.</string>
8+
<string>© 2025 Root3 B.V. All rights reserved.</string>
99
<key>CFBundleIdentifier</key>
1010
<string>nl.root3.support.helper</string>
1111
<key>CFBundleInfoDictionaryVersion</key>

src/SupportXPC/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<plist version="1.0">
44
<dict>
55
<key>CFBundleShortVersionString</key>
6-
<string>2.6.1</string>
6+
<string>2.6.2</string>
77
<key>CFBundleIdentifier</key>
88
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
99
<key>CFBundleName</key>

0 commit comments

Comments
 (0)