diff --git a/Sources/AppcuesKit/Presentation/Actions/Appcues/AppcuesRequestPushAction.swift b/Sources/AppcuesKit/Presentation/Actions/Appcues/AppcuesRequestPushAction.swift index 9abbf571f..94a3416f4 100644 --- a/Sources/AppcuesKit/Presentation/Actions/Appcues/AppcuesRequestPushAction.swift +++ b/Sources/AppcuesKit/Presentation/Actions/Appcues/AppcuesRequestPushAction.swift @@ -32,14 +32,7 @@ internal class AppcuesRequestPushAction: AppcuesExperienceAction { } let pushMonitor = appcues.container.resolve(PushMonitoring.self) - let analyticsPublisher = appcues.container.resolve(AnalyticsPublishing.self) - - pushMonitor.refreshPushStatus { _ in - analyticsPublisher.publish(TrackingUpdate( - type: .event(name: Events.Device.deviceUpdated.rawValue, interactive: false), - isInternal: true - )) - + pushMonitor.refreshPushStatus(publishChange: true) { _ in completion() } } diff --git a/Sources/AppcuesKit/Presentation/Debugger/PushVerifier.swift b/Sources/AppcuesKit/Presentation/Debugger/PushVerifier.swift index d496b4012..df1437577 100644 --- a/Sources/AppcuesKit/Presentation/Debugger/PushVerifier.swift +++ b/Sources/AppcuesKit/Presentation/Debugger/PushVerifier.swift @@ -10,7 +10,7 @@ import UIKit import Combine // For mock objects -final class KeyedArchiver: NSKeyedArchiver { +private final class KeyedArchiver: NSKeyedArchiver { override func decodeObject(forKey _: String) -> Any { "" } deinit { @@ -136,7 +136,7 @@ internal class PushVerifier { private func requestPush() { let options: UNAuthorizationOptions = [.alert, .sound, .badge] UNUserNotificationCenter.current().requestAuthorization(options: options) { _, _ in - self.pushMonitor.refreshPushStatus { _ in + self.pushMonitor.refreshPushStatus(publishChange: false) { _ in DispatchQueue.main.async { self.verifyPush() } diff --git a/Sources/AppcuesKit/Push/PushMonitor.swift b/Sources/AppcuesKit/Push/PushMonitor.swift index 1cb8cdf4d..515f63d3f 100644 --- a/Sources/AppcuesKit/Push/PushMonitor.swift +++ b/Sources/AppcuesKit/Push/PushMonitor.swift @@ -14,7 +14,7 @@ internal protocol PushMonitoring: AnyObject { var pushBackgroundEnabled: Bool { get } var pushPrimerEligible: Bool { get } - func refreshPushStatus(completion: ((UNAuthorizationStatus) -> Void)?) + func refreshPushStatus(publishChange: Bool, completion: ((UNAuthorizationStatus) -> Void)?) func didReceiveNotification(response: UNNotificationResponse, completionHandler: @escaping () -> Void) -> Bool } @@ -24,6 +24,7 @@ internal class PushMonitor: PushMonitoring { private weak var appcues: Appcues? private let config: Appcues.Config private let storage: DataStoring + private let analyticsPublisher: AnalyticsPublishing private(set) var pushAuthorizationStatus: UNAuthorizationStatus = .notDetermined @@ -43,8 +44,9 @@ internal class PushMonitor: PushMonitoring { self.appcues = container.owner self.config = container.resolve(Appcues.Config.self) self.storage = container.resolve(DataStoring.self) + self.analyticsPublisher = container.resolve(AnalyticsPublishing.self) - refreshPushStatus() + refreshPushStatus(publishChange: false) NotificationCenter.default.addObserver( self, @@ -56,10 +58,10 @@ internal class PushMonitor: PushMonitoring { @objc private func applicationWillEnterForeground(notification: Notification) { - refreshPushStatus() + refreshPushStatus(publishChange: true) } - func refreshPushStatus(completion: ((UNAuthorizationStatus) -> Void)? = nil) { + func refreshPushStatus(publishChange: Bool, completion: ((UNAuthorizationStatus) -> Void)? = nil) { // Skip call to UNUserNotificationCenter.current() in tests to avoid crashing in package tests #if DEBUG guard ProcessInfo.processInfo.environment["XCTestBundlePath"] == nil else { @@ -69,7 +71,16 @@ internal class PushMonitor: PushMonitoring { #endif UNUserNotificationCenter.current().getNotificationSettings { [weak self] settings in + let shouldPublish = publishChange && self?.pushAuthorizationStatus != settings.authorizationStatus self?.pushAuthorizationStatus = settings.authorizationStatus + + if shouldPublish { + self?.analyticsPublisher.publish(TrackingUpdate( + type: .event(name: Events.Device.deviceUpdated.rawValue, interactive: false), + isInternal: true + )) + } + completion?(settings.authorizationStatus) } }