I've been able to create a surprisingly full-featured push verification system for the debugger. And once we hook it up to the send test push API that can return some backend diagnostics, we should be able to provide one-tap E2E verification of an Appcues push setup.
PushVerifier is the doing all the heavy lifting. Since it has several dependencies and since PushMonitor needs to call the verifier, I've added it into the main DI container unlike APIVerifier and DeepLinkVerifier.
Overview of what's being verified (and how), corresponding to the Error numbers:
Verify Appcues.setPushToken(:) is called. I could add an additional check that didRegisterForRemoteNotificationsWithDeviceToken is implemented, but these are tightly coupled, so it seems like overkill. The docs (when we write them) about these errors should make it clear.
When the notification authorization status is .notDetermined. If this error occurs, if a second attempt to verify the status is made, we'll trigger the push notification permission prompt.
This is intended to be a helpful way to test quickly without having to create a permission primer flow (since we want to encourage people to create such a flow and not hardcode a permission request).
Push notification permission prompt was denied. User will need to use the system settings app to change the permissions.
.ephemeral (app clip only) or unknown permission status. Should never happen.
UNUserNotificationCenter.current().delegate is nil. It needs to be assigned—usually the value is the `AppDelegate. Without this value, we can't check anything else about the implementation.
Note that this check isn't 100% accurate, since iOS requires that "You must assign your delegate object to the UNUserNotificationCenter object before your app finishes launching." (ref), but we're only checking it when the debugger action is triggered.
userNotificationCenter(_:didReceive:withCompletionHandler:) is not implemented. The function is an optional method of UNUserNotificationCenterDelegate, so we need to check it's implemented. It's required to process the user's response to a delivered notification.
Verifies that the completion handler in userNotificationCenter(_:didReceive:withCompletionHandler:) isn't called more than once. I added this because the Appcues handler calls it if the SDK handles the response, but the app might call it too. I'm not sure the consequences of multiple completions, but better safe than sorry.
Verify the user response is passed to Appcues.didReceiveNotification(response:completionHandler:).
We generate a synthetic response object (approach reference) that matches our push payload (with the addition of _appcues_internal: true) to call the response handler. This is super handy since it removes the need for the user to actually tap on the incoming notification to verify this part of the system.
Errors 10/11 are internal to the test loop.
Once the backend push test endpoint is implemented, we'll call that and display any diagnostics that are returned.
I've been able to create a surprisingly full-featured push verification system for the debugger. And once we hook it up to the send test push API that can return some backend diagnostics, we should be able to provide one-tap E2E verification of an Appcues push setup.
PushVerifier
is the doing all the heavy lifting. Since it has several dependencies and sincePushMonitor
needs to call the verifier, I've added it into the main DI container unlikeAPIVerifier
andDeepLinkVerifier
.Overview of what's being verified (and how), corresponding to the Error numbers:
Appcues.setPushToken(:)
is called. I could add an additional check thatdidRegisterForRemoteNotificationsWithDeviceToken
is implemented, but these are tightly coupled, so it seems like overkill. The docs (when we write them) about these errors should make it clear..notDetermined
. If this error occurs, if a second attempt to verify the status is made, we'll trigger the push notification permission prompt. This is intended to be a helpful way to test quickly without having to create a permission primer flow (since we want to encourage people to create such a flow and not hardcode a permission request)..ephemeral
(app clip only) or unknown permission status. Should never happen.UNUserNotificationCenter.current().delegate
is nil. It needs to be assigned—usually the value is the `AppDelegate. Without this value, we can't check anything else about the implementation. Note that this check isn't 100% accurate, since iOS requires that "You must assign your delegate object to the UNUserNotificationCenter object before your app finishes launching." (ref), but we're only checking it when the debugger action is triggered.userNotificationCenter(_:didReceive:withCompletionHandler:)
is not implemented. The function is an optional method ofUNUserNotificationCenterDelegate
, so we need to check it's implemented. It's required to process the user's response to a delivered notification.userNotificationCenter(_:didReceive:withCompletionHandler:)
isn't called more than once. I added this because the Appcues handler calls it if the SDK handles the response, but the app might call it too. I'm not sure the consequences of multiple completions, but better safe than sorry.Appcues.didReceiveNotification(response:completionHandler:)
. We generate a synthetic response object (approach reference) that matches our push payload (with the addition of_appcues_internal: true
) to call the response handler. This is super handy since it removes the need for the user to actually tap on the incoming notification to verify this part of the system.Errors 10/11 are internal to the test loop.
Once the backend push test endpoint is implemented, we'll call that and display any diagnostics that are returned.