import Foundation import CoreFoundation public final class CoreNotificationCenter { public static let darwin = CoreNotificationCenter(CFNotificationCenterGetDarwinNotifyCenter()) public static let local = CoreNotificationCenter(CFNotificationCenterGetLocalCenter()) #if os(macOS) public static let distributed = CoreNotificationCenter(CFNotificationCenterGetDistributedCenter()) #endif private let center: CFNotificationCenter private var observations: [Notification.Name: (Notification) -> Void] = [:] private init(_ center: CFNotificationCenter) { self.center = center } private func handleNotification(_ notification: Notification) { observations[notification.name]?(notification) } public func addObserver(forName name: Notification.Name, suspensionBehavior: CFNotificationSuspensionBehavior = .deliverImmediately, using block: @escaping (Notification) -> Void) { observations[name] = block let callback: CFNotificationCallback = { (_, observer, optCFName, pObject, optCFDict) in // needs to be an unsafeBitCast here - it's LITERALY the pointer in memory let center = unsafeBitCast(observer, to: CoreNotificationCenter.self) guard let cfName: CFNotificationName = optCFName else { assertionFailure("Nameless notification") return } let name = Notification.Name(cfName.rawValue as String) let object: Any? if let pObject = pObject { object = unsafeBitCast(pObject, to: Any.self) } else { object = nil } let userInfo: [AnyHashable: Any]? if let dictionary = optCFDict as? [String: AnyObject] { userInfo = dictionary } else { userInfo = nil } let notification = Notification(name: name, object: object, userInfo: userInfo) center.handleNotification(notification) } CFNotificationCenterAddObserver( center, Unmanaged.passUnretained(self).toOpaque(), callback, name.rawValue as CFString, nil, suspensionBehavior ) } public func removeObserver(withName name: Notification.Name) { observations.removeValue(forKey: name) CFNotificationCenterRemoveObserver( center, Unmanaged.passUnretained(self).toOpaque(), CFNotificationName(name.rawValue as CFString), nil ) } public func removeAllObservers() { CFNotificationCenterRemoveEveryObserver( center, Unmanaged.passUnretained(self).toOpaque() ) } public func post(name: Notification.Name) { CFNotificationCenterPostNotification( center, CFNotificationName(name.rawValue as CFString), nil, nil, true ) } } // https://www.iphonedevwiki.net/index.php/SpringBoard.app/Notifications // https://employment12werft.blogspot.com/2011/02/ios-detect-monitor-when-system-messages.html // https://developpaper.com/examples-of-the-underlying-notification-framework-library-of-ios-system/ // https://github.com/SCTCoding/LaunchEvents/blob/main/LaunchEvents.csv extension Notification.Name { public static let springboardActiveCallStateChanged = Notification.Name("com.apple.springboard.activeCallStateChanged") public static let springboardAttemptActivation = Notification.Name("com.apple.springboard.attemptactivation") public static let springboardBootedCleanly = Notification.Name("com.apple.springboard.bootedcleanly") public static let springboardCallInterruptedApp = Notification.Name("com.apple.springboard.callinterruptedapp") public static let springboardCurvedBatteryCapacity = Notification.Name("com.apple.springboard.curvedBatteryCapacity") public static let springboardDeviceLockStatusChanged = Notification.Name("com.apple.springboard.DeviceLockStatusChanged") public static let springboardDeviceWillShotDown = Notification.Name("com.apple.springboard.deviceWillShutDown") public static let springboardDoubleHeightMode = Notification.Name("com.apple.springboard.doubleheightmode") public static let springboardFullyCharged = Notification.Name("com.apple.springboard.fullycharged") public static let springboardHasBlankedScreen = Notification.Name("com.apple.springboard.hasBlankedScreen") public static let springboardLockComplete = Notification.Name("com.apple.springboard.lockcomplete") public static let springboardLockInterrupted = Notification.Name("com.apple.springboard.lockinterrupted") public static let springboardLockState = Notification.Name("com.apple.springboard.lockstate") public static let springboardLowPowerAlertPresented = Notification.Name("com.apple.springboard.lowPowerAlertPresented") public static let springboardOrientation = Notification.Name("com.apple.springboard.orientation") public static let springboardPluggedIn = Notification.Name("com.apple.springboard.pluggedin") public static let springboardProximityChanged = Notification.Name("com.apple.springboard.proximity.changed") public static let springboardRawOrientation = Notification.Name("com.apple.springboard.rawOrientation") public static let springboardRentalsExpiredNotification = Notification.Name("com.apple.springboard.RentalsExpiredNotification") public static let springboardResetEnded = Notification.Name("com.apple.springboard.reset-ended") public static let springboardResetReady = Notification.Name("com.apple.springboard.reset-ready") public static let springboardResetWillEnd = Notification.Name("com.apple.springboard.reset-willend") public static let springboardRingerState = Notification.Name("com.apple.springboard.ringerstate") public static let springboardShowingAlertItem = Notification.Name("com.apple.springboard.showingAlertItem") public static let springboardSyncingUnblocked = Notification.Name("com.apple.springboard.syncingUnblocked") public static let springboardUnambiguousOrientation = Notification.Name("com.apple.springboard.unambiguousOrientation") public static let airportUserNotification = Notification.Name("com.apple.airport.userNotification") public static let airportSettingsVisible = Notification.Name("com.apple.airportsettingsvisible") public static let alarmAlarmChanged = Notification.Name("com.apple.alarm.alarmchanged") public static let alarmAlarmFired = Notification.Name("com.apple.alarm.alarmfired") public static let mobileSubstantialTransition = Notification.Name("com.apple.mobile.SubstantialTransition") public static let powerlogExit = Notification.Name("com.apple.powerlog.exit") public static let remoteNotificationDelivered = Notification.Name("com.apple.remotenotification.notificationdelivered") // AppleDatePreferencesChangedNotification // AppleLanguagePreferencesChangedNotification // AppleNumberPreferencesChangedNotification // ApplePreferredContentSizeCategoryChangedNotification // AppleTextBehaviorPreferencesChangedNotification // AppleTimePreferencesChangedNotification // com.apple.frontboard.systemappservices.serverNotifyToken // com.apple.frontboard.workspace.serverNotifyToken // com.apple.hangtracer.prefchangednotification // kCTDaemonReadyNotification // kKeepAppsUpToDateEnabledChangedNotification // PINPolicyChangedNotification // UIBacklightLevelChangedNotification }