feat(dev): add notification debug panel and native pending inspector
Add a dev-only Notification Debug Panel at /dev/notifications for testing predictive refresh and WAKEUP_PING without a backend. - Gate route and Advanced Settings entry on import.meta.env.DEV - NotificationDebugService drives mock refresh, flood test, clear, and wake simulation via existing handleCapacitorPushNotificationReceived and applyNotificationRefreshPayload (shared with refreshNotifications) - Add NotificationInspector Capacitor plugin: iOS lists pending UNNotificationRequest identifiers and next trigger; Android stub returns empty pending for safe registration
This commit is contained in:
@@ -29,6 +29,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
||||
attempts += 1
|
||||
if registerSharedImagePlugin() {
|
||||
print("[AppDelegate] ✅ Plugin registration successful on attempt \(attempts)")
|
||||
_ = registerNotificationInspectorPlugin()
|
||||
} else if attempts < maxAttempts {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + Double(attempts) * 0.5) {
|
||||
tryRegister()
|
||||
@@ -64,6 +65,20 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
||||
return true
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
private func registerNotificationInspectorPlugin() -> Bool {
|
||||
guard let window = self.window,
|
||||
let bridgeVC = window.rootViewController as? CAPBridgeViewController,
|
||||
let bridge = bridgeVC.bridge else {
|
||||
return false
|
||||
}
|
||||
|
||||
let pluginInstance = NotificationInspectorPlugin()
|
||||
bridge.registerPluginInstance(pluginInstance)
|
||||
print("[AppDelegate] ✅ Registered NotificationInspectorPlugin (exposed as 'NotificationInspector')")
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||
|
||||
51
ios/App/App/NotificationInspectorPlugin.swift
Normal file
51
ios/App/App/NotificationInspectorPlugin.swift
Normal file
@@ -0,0 +1,51 @@
|
||||
import Foundation
|
||||
import Capacitor
|
||||
import UserNotifications
|
||||
|
||||
@objc(NotificationInspector)
|
||||
public class NotificationInspectorPlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
public var identifier: String { "NotificationInspector" }
|
||||
public var jsName: String { "NotificationInspector" }
|
||||
public var pluginMethods: [CAPPluginMethod] {
|
||||
[
|
||||
CAPPluginMethod(#selector(getPendingNotifications(_:)), returnType: .promise)
|
||||
]
|
||||
}
|
||||
|
||||
@objc public func getPendingNotifications(_ call: CAPPluginCall) {
|
||||
UNUserNotificationCenter.current().getPendingNotificationRequests { requests in
|
||||
let pending: [[String: Any]] = requests.map { req in
|
||||
var nextTriggerMs: NSNumber? = nil
|
||||
var triggerType: String? = nil
|
||||
|
||||
if let trigger = req.trigger as? UNCalendarNotificationTrigger {
|
||||
triggerType = "calendar"
|
||||
if let next = trigger.nextTriggerDate() {
|
||||
nextTriggerMs = NSNumber(value: Int64(next.timeIntervalSince1970 * 1000))
|
||||
}
|
||||
} else if let trigger = req.trigger as? UNTimeIntervalNotificationTrigger {
|
||||
triggerType = "timeInterval"
|
||||
if let next = trigger.nextTriggerDate() {
|
||||
nextTriggerMs = NSNumber(value: Int64(next.timeIntervalSince1970 * 1000))
|
||||
}
|
||||
} else if req.trigger != nil {
|
||||
triggerType = "other"
|
||||
} else {
|
||||
triggerType = nil
|
||||
}
|
||||
|
||||
var obj: [String: Any] = [
|
||||
"identifier": req.identifier
|
||||
]
|
||||
obj["nextTriggerDate"] = nextTriggerMs ?? NSNull()
|
||||
obj["triggerType"] = triggerType ?? NSNull()
|
||||
return obj
|
||||
}
|
||||
|
||||
call.resolve([
|
||||
"pending": pending
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user