Skip to content

Commit

Permalink
♻️ Add deferred handling for push notifications received without a se…
Browse files Browse the repository at this point in the history
…ssion
  • Loading branch information
mmaatttt committed May 6, 2024
1 parent 1c17330 commit d2945d6
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 5 deletions.
3 changes: 3 additions & 0 deletions Sources/AppcuesKit/Appcues.swift
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,9 @@ public class Appcues: NSObject {
storage.isAnonymous = isAnonymous
storage.userSignature = properties?.removeValue(forKey: "appcues:user_id_signature") as? String
analyticsPublisher.publish(TrackingUpdate(type: .profile(interactive: true), properties: properties, isInternal: false))

let pushMonitor = container.resolve(PushMonitoring.self)
pushMonitor.attemptDeferredNotificationResponse()
}
}

Expand Down
51 changes: 46 additions & 5 deletions Sources/AppcuesKit/Push/PushMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ internal protocol PushMonitoring: AnyObject {
func refreshPushStatus(publishChange: Bool, completion: ((UNAuthorizationStatus) -> Void)?)

func didReceiveNotification(response: UNNotificationResponse, completionHandler: @escaping () -> Void) -> Bool
@discardableResult
func attemptDeferredNotificationResponse() -> Bool
}

internal class PushMonitor: PushMonitoring {
Expand All @@ -40,6 +42,8 @@ internal class PushMonitor: PushMonitoring {
pushAuthorizationStatus == .notDetermined
}

private var deferredNotification: ParsedNotification?

init(container: DIContainer) {
self.appcues = container.owner
self.config = container.resolve(Appcues.Config.self)
Expand Down Expand Up @@ -110,13 +114,52 @@ internal class PushMonitor: PushMonitoring {
return true
}

// If there's no active session or a user ID mismatch, don't do anything with the notification
guard appcues.isActive && parsedNotification.userID == storage.userID else {
// If there's no active session store the notification for potential handling after the next user is identified
guard appcues.isActive else {
deferredNotification = parsedNotification

completionHandler()
return true
}

// If there's an active session and a user ID mismatch, don't do anything with the notification
guard parsedNotification.userID == storage.userID else {
completionHandler()
return true
}

let analyticsPublisher = appcues.container.resolve(AnalyticsPublishing.self)
executeNotificationResponse(
appcues: appcues,
parsedNotification: parsedNotification,
completionHandler: completionHandler
)

return true
}

@discardableResult
func attemptDeferredNotificationResponse() -> Bool {
guard let parsedNotification = deferredNotification, let appcues = appcues else { return false }

defer {
deferredNotification = nil
}

guard parsedNotification.userID == storage.userID else {
config.logger.info("Deferred notification response skipped")
return false
}

executeNotificationResponse(appcues: appcues, parsedNotification: parsedNotification) {}

return true
}

private func executeNotificationResponse(
appcues: Appcues,
parsedNotification: ParsedNotification,
completionHandler: @escaping () -> Void
) {
analyticsPublisher.publish(TrackingUpdate(
type: .event(name: Events.Push.pushOpened.rawValue, interactive: false),
properties: [
Expand Down Expand Up @@ -145,8 +188,6 @@ internal class PushMonitor: PushMonitoring {
} else {
completionHandler()
}

return true
}

#if DEBUG
Expand Down

0 comments on commit d2945d6

Please sign in to comment.