Skip to content

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

Closed

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.

Activity

  1. tp26610 commented on Apr 23, 2026

    @tp26610
    ContributorAuthor

    Minimal Reproduction (React Native)

    import { OneSignal } from 'react-native-onesignal';
    import { useEffect } from 'react';
    
    export default function App() {
      useEffect(() => {
        OneSignal.initialize('YOUR_APP_ID');
        OneSignal.login('test-user-123');
    
        // Grant permission on first install, then reinstall the app without
        // revoking the permission. The subscription will be stuck at NO_PERMISSION.
        OneSignal.Notifications.requestPermission(false);
    
        // After reinstall: canRequestPermission() returns false (already asked),
        // so requestPermission() is skipped. But the fresh subscription has
        // status = NO_PERMISSION, and no trigger ever calls
        // retrievePushTokenAndUpdateSubscription() to fix it.
    
        setTimeout(async () => {
          const optedIn = await OneSignal.User.pushSubscription.getOptedInAsync();
          const hasPermission = await OneSignal.Notifications.getPermissionAsync();
          const token = await OneSignal.User.pushSubscription.getTokenAsync();
    
          console.log({ optedIn, hasPermission, token });
          // After reinstall:
          //   hasPermission: true   ← system permission is granted
          //   optedIn:       false  ← stuck
          //   token:         null   ← never retrieved
        }, 5000);
      }, []);
    
      return null;
    }

    Repro steps:

    1. Run on Android 13+ device
    2. Launch app → grant notification permission → confirm optedIn: true
    3. Reinstall (adb install -r or clear app data via Settings)
    4. Reopen — do not touch the notification permission toggle
    5. Wait 5 seconds → observe optedIn: false despite hasPermission: true
  2. tp26610 commented on Apr 23, 2026

    @tp26610
    ContributorAuthor

    A fix has been submitted in #2622.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions