Implementing UIApplicationDelegate.application(_:didRegisterForRemoteNotificationsWithDeviceToken:) to call Appcues.setPushToken(_:).
Because we can safely assume there's always a UIApplicationDelegate, we just need to add the placeholder implementation if there is none, and then swizzle the method.
Ensuring UNUserNotificationCenter.current().delegate is set.
This is the same approach as the UIScrollViewDelegate getter swizzling.
Implementing UNUserNotificationCenterDelegate.userNotificationCenter(_:didReceive:withCompletionHandler:) to call Appcues.didReceiveNotification(response:completionHandler:).
This is swizzled with a placeholder implementation from the getter of the UNUserNotificationCenterDelegate (same ideas as the UIScrollView approach.
This is swizzled with a placeholder implementation from the getter of the UNUserNotificationCenterDelegate (same ideas as the UIScrollView approach.
AppcuesUNUserNotificationCenterDelegate has a static instance that the various swizzled methods call. To properly support multiple SDK instances (that each can be auto configured!) there's a list of pushMonitors that we can operate from (using the weak wrapper approach from AnalyticsPublisher).
Structural Notes
I moved the implementation of Appcues.setPushToken into PushMonitor so that the swizzled implementation can also easy access it.
Instead of having the almost the same long swizzling block for UIScrollViewDelegate, UIApplicationDelegate, and UNUserNotificationCenterDelegate, I created Swizzler with one extra parameter.
What's Next
I've thought about adding config options to control what specifically gets automatically swizzled, but for now I'm comfortable with the all-or-nothing approach.
I'd like tests for the swizzled behaviour (and the various scenarios of what's already implemented in the existing app), but I haven't yet looked into what's doable there.
This PR is very much building on the approach for the
UIScrollViewDelegate
swizzling added and explained in https://github.com/appcues/appcues-ios-sdk/pull/479.As noted in the
Appcues.swift
docs, there's 5 things that need to happen for automatic push config:UIApplication.registerForRemoteNotifications()
.UIApplicationDelegate.application(_:didRegisterForRemoteNotificationsWithDeviceToken:)
to callAppcues.setPushToken(_:)
.UIApplicationDelegate
, we just need to add the placeholder implementation if there is none, and then swizzle the method.UNUserNotificationCenter.current().delegate
is set.UIScrollViewDelegate
getter swizzling.UNUserNotificationCenterDelegate.userNotificationCenter(_:didReceive:withCompletionHandler:)
to callAppcues.didReceiveNotification(response:completionHandler:)
.UNUserNotificationCenterDelegate
(same ideas as theUIScrollView
approach.UNUserNotificationCenterDelegate.userNotificationCenter(_:willPresent:withCompletionHandler:)
.UNUserNotificationCenterDelegate
(same ideas as theUIScrollView
approach.AppcuesUNUserNotificationCenterDelegate
has a static instance that the various swizzled methods call. To properly support multiple SDK instances (that each can be auto configured!) there's a list ofpushMonitors
that we can operate from (using the weak wrapper approach fromAnalyticsPublisher
).Structural Notes
Appcues.setPushToken
intoPushMonitor
so that the swizzled implementation can also easy access it.UIScrollViewDelegate
,UIApplicationDelegate
, andUNUserNotificationCenterDelegate
, I created Swizzler with one extra parameter.What's Next