Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: differentiate every push event handler installed in app #743

Merged
merged 4 commits into from
Jun 21, 2024

Conversation

levibostian
Copy link
Contributor

@levibostian levibostian commented Jun 17, 2024

https://linear.app/customerio/issue/MBL-383/[bug]-customer-unable-to-handle-push-notification-event-on-ios-with

At runtime when PushEventHandlerProxy.addPushEventHandler is called, the given push event handler will overrwrite any previously added push event handlers. This results in the SDK only being aware of 1 push event handler even if the iOS app has N number installed.

Testing

  • In Flutter sample app, install CIO SDK, FlutterFire, and set UNNotificationCenterDelegate.current().delegate = self in AppDelegate for the host app to also handle pushes. This reproduces the bug because we now have at least 2 other push click handlers besides the CIO SDK installed. Set a Xcode breakpoint in PushEventHandlerProxy.addPushEventHandler and check what dictionary key is generated.
  • I added new automated tests around PushEventHandlerProxy.addPushEventHandler function.

https://linear.app/customerio/issue/MBL-383/[bug]-customer-unable-to-handle-push-notification-event-on-ios-with

In a Flutter app, when `PushEventHandlerProxy.addPushEventHandler` is called, `String(describing:)` is generating a non-unique String which results in only 1 entry existing in the `nestedDelegates` entry. This results in the SDK only being aware of 1 push event handler even if the iOS app has N number installed.

Testing
* In Flutter sample app, install CIO SDK, FlutterFire, and set `UNNotificationCenterDelegate.current().delegate = self` for the host app to also handle pushes. Set a Xcode breakpoint in `PushEventHandlerProxy.addPushEventHandler` and check what key String is generated. After this PR, the key is unique.
* The automated test suite already contains a test that should be catching this. Keeping this PR as a draft while I determine why that happened and get it fixed to prevent scenarios like this again.
@levibostian levibostian self-assigned this Jun 17, 2024
Copy link

github-actions bot commented Jun 17, 2024

Sample app builds 📱

Below you will find the list of the latest versions of the sample apps. It's recommended to always download the latest builds of the sample apps to accurately test the pull request.


  • CocoaPods-FCM: levi/v2-multiple-push-handlers (1718981011)
  • APN-UIKit: levi/v2-multiple-push-handlers (1718980978)

@@ -3,7 +3,7 @@ import Foundation
import SharedTests
import XCTest

class PushEventHandlerProxyTest: UnitTest {
class PushEventHandlerProxyTest: IntegrationTest {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only changed so the class had access to the new getNewPushEventHandler() function. Should have no effect on the tests besides that.

@@ -12,13 +12,47 @@ class PushEventHandlerProxyTest: UnitTest {
proxy = PushEventHandlerProxyImpl()
}

// MARK: addPushEventHandler
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These new tests catch the bug that this PR fixes.

Copy link

codecov bot commented Jun 18, 2024

Codecov Report

Attention: Patch coverage is 76.92308% with 3 lines in your changes missing coverage. Please review.

Please upload report for BASE (v2@949b05c). Learn more about missing BASE report.

Files Patch % Lines
...gingPush/UserNotificationsFramework/Wrappers.swift 40.00% 3 Missing ⚠️
Additional details and impacted files
@@          Coverage Diff          @@
##             v2     #743   +/-   ##
=====================================
  Coverage      ?   57.69%           
=====================================
  Files         ?      132           
  Lines         ?     3806           
  Branches      ?        0           
=====================================
  Hits          ?     2196           
  Misses        ?     1610           
  Partials      ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -120,6 +120,10 @@ public struct UNNotificationWrapper: PushNotification {
class UNUserNotificationCenterDelegateWrapper: PushEventHandler {
private let delegate: UNUserNotificationCenterDelegate

var identifier: String {
String(describing: delegate)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By returning the instance description of the nested delegate, this is what will uniquely identify UNUserNotificationCenterDelegateWrapper instances from 1 another. Since UNUserNotificationCenterDelegateWrapper is just a wrapper, it's the nested delegate that we really care about.

@@ -21,6 +21,10 @@ class IOSPushEventListener: PushEventHandler {
self.logger = logger
}

var identifier: String {
"Cio.iOSPushEventListener"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CIO SDK has it's own PushEventHandler instance so we must add the new protocol identifier getter.

This string should uniquely identify the CIO SDK from other push click handlers installed in the app.

@@ -27,7 +27,7 @@ class PushEventHandlerProxyImpl: PushEventHandlerProxy {
public static let shared = PushEventHandlerProxyImpl()

// Use a map so that we only save 1 instance of a given handler.
@Atomic private var nestedDelegates: [String: PushEventHandler] = [:]
@Atomic var nestedDelegates: [String: PushEventHandler] = [:]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made internal for tests to access

@@ -37,7 +37,7 @@ class PushEventHandlerProxyImpl: PushEventHandlerProxy {
}

func addPushEventHandler(_ newHandler: PushEventHandler) {
nestedDelegates[String(describing: newHandler)] = newHandler
nestedDelegates[newHandler.identifier] = newHandler
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bug fix.

At runtime, multiple UNUserNotificationCenterDelegateWrapper instances will call this function. Using identifier makes sure that each handler is uniquely identified.

@levibostian levibostian marked this pull request as ready for review June 18, 2024 14:50
@levibostian levibostian requested a review from a team June 18, 2024 14:53
Copy link
Contributor

@Shahroz16 Shahroz16 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@levibostian
Copy link
Contributor Author

added do not merge label until this is resolved

@levibostian levibostian merged commit c3573fc into v2 Jun 21, 2024
9 checks passed
@levibostian levibostian deleted the levi/v2-multiple-push-handlers branch June 21, 2024 15:22
github-actions bot pushed a commit that referenced this pull request Jun 21, 2024
## [2.13.2](2.13.1...2.13.2) (2024-06-21)

### Bug Fixes

* differentiate every push event handler installed in app ([#743](#743)) ([c3573fc](c3573fc))
levibostian added a commit that referenced this pull request Jun 25, 2024
https://linear.app/customerio/issue/MBL-383/[bug]-customer-unable-to-handle-push-notification-event-on-ios-with

(This PR is identical to the one merged into v2: #743)

Summary of bug: The iOS SDK had a bug where it was only able to store 1 3rd party push click handing SDK and ignore others that were installed. After this fix, all 3rd party SDKs installed in the app are called for push events in the app.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants