Skip to content

Subscription stuck at NO_PERMISSION after reinstall when notification permission already granted #2621

@tp26610

Description

@tp26610

Environment

  • react-native-onesignal: 5.4.2
  • OneSignal Android SDK: 5.7.7
  • Platform: Android

Steps to Reproduce

  1. Install app and grant notification permission
  2. Reinstall the app (or clear app data)
  3. Reopen — do NOT toggle the notification permission

Expected Behavior

Notifications work normally after reinstall. Subscription status becomes SUBSCRIBED.

Actual Behavior

OneSignal dashboard shows "Permission Not Granted". getOptedInAsync() returns false.
The state may eventually recover (hours later), or never recover at all.

Root Cause

After reading the SDK source, the chain is:

1. NotificationsManager.permission is initialized correctly:

// NotificationsManager.kt
override var permission: Boolean = NotificationHelper.areNotificationsEnabled(appContext)

After reinstall, permission is already granted → permission = true from the start.

2. Fresh subscription has status = NO_PERMISSION:

// UserSwitcher.kt — createAndSwitchToNewUser()
status = currentPushSubscription?.status ?: SubscriptionStatus.NO_PERMISSION

After data clear, no previous subscription exists → status = NO_PERMISSION.

3. retrievePushTokenAndUpdateSubscription() — the function that fixes status — has only two triggers:

// DeviceRegistrationListener.kt
override fun onNotificationPermissionChange(permission: Boolean) {
    retrievePushTokenAndUpdateSubscription()  // trigger A
}
override fun onModelReplaced(model: ConfigModel, tag: String) {
    if (tag != ModelChangeTags.HYDRATE) return
    retrievePushTokenAndUpdateSubscription()  // trigger B
}

4. Neither trigger fires:

  • Trigger A (onNotificationPermissionChange): never fires because setPermissionStatusAndFire() only fires when oldPermission != newPermission. Since permission starts as true (correctly read at init), and the system permission never changes, no event is emitted.
  • Trigger B (onModelReplaced(HYDRATE)): only fires when the ConfigModel is re-fetched from the backend. If the config cache is still valid, no re-fetch occurs → never fires.

Result: status stays NO_PERMISSION indefinitely. The subscription is optedIn = model.optedIn && status != NO_PERMISSION = false.

Suggested Fix

In DeviceRegistrationListener.start(), add a startup check:

override fun start() {
    _configModelStore.subscribe(this)
    _notificationsManager.addPermissionObserver(this)
    _subscriptionManager.subscribe(this)

    // Fix: if permission is already granted but subscription status is NO_PERMISSION,
    // trigger token retrieval immediately on startup.
    if (_notificationsManager.permission) {
        retrievePushTokenAndUpdateSubscription()
    }
}

This is safe — retrievePushTokenAndUpdateSubscription() is idempotent and already handles the case where a token exists.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions