diff --git a/com.onesignal.unity.android/Runtime/AndroidNotificationsManager.cs b/com.onesignal.unity.android/Runtime/AndroidNotificationsManager.cs index 4c4808b5..fe1f99ea 100644 --- a/com.onesignal.unity.android/Runtime/AndroidNotificationsManager.cs +++ b/com.onesignal.unity.android/Runtime/AndroidNotificationsManager.cs @@ -47,9 +47,61 @@ public AndroidNotificationsManager(AndroidJavaClass sdkClass) } public event EventHandler ForegroundWillDisplay; - public event EventHandler Clicked; public event EventHandler PermissionChanged; + // Only set the native listener once + private bool _clickNativeListenerSet; + + private readonly object _clickRegistrationLock = new object(); + + private EventHandler _clicked; + + /// + /// The native click listener is registered lazily on the first subscription. The native SDK + /// queues clicks that occur before a listener is added (e.g. a cold start from a notification + /// tap) and replays them when one is registered, so deferring registration until a C# handler + /// exists ensures those events are not dropped. The handler must be attached before the + /// native call, since the replay fires as soon as the listener registers. The flag is only + /// set after a successful native call so a transient failure can retry on the next + /// subscription. + /// + public event EventHandler Clicked + { + add + { + lock (_clickRegistrationLock) + { + _clicked += value; + + if (!_clickNativeListenerSet) + { + try + { + _notifications.Call( + "addClickListener", + new InternalNotificationClickListener(this) + ); + } + catch + { + // Roll back so a failed subscription has no effect; retrying won't + // add the same handler twice. + _clicked -= value; + throw; + } + _clickNativeListenerSet = true; + } + } + } + remove + { + lock (_clickRegistrationLock) + { + _clicked -= value; + } + } + } + public bool Permission { get => _notifications.Call("getPermission"); @@ -91,7 +143,6 @@ public void Initialize() "addForegroundLifecycleListener", new InternalNotificationLifecycleListener(this) ); - _notifications.Call("addClickListener", new InternalNotificationClickListener(this)); } private sealed class InternalPermissionObserver : OneSignalAwaitableAndroidJavaProxy @@ -194,7 +245,7 @@ public void onClick(AndroidJavaObject clickEvent) result ); - EventHandler handler = _parent.Clicked; + EventHandler handler = _parent._clicked; if (handler != null) { UnityMainThreadDispatch.Post(state => handler(_parent, args));