preLogoutCleanup method

Future<void> preLogoutCleanup({
  1. Duration timeout = const Duration(seconds: 5),
})

Performs pre-logout cleanup for notifications.

IMPORTANT: Call this BEFORE signing out the user, while they are still authenticated. This allows the token unregistration to succeed on the backend.

This method:

  1. Attempts to unregister the current FCM token on the backend (best-effort)
  2. Stops the token refresh listener
  3. Deletes the FCM token from Firebase
  4. Clears cached tokens (both new and legacy keys)

If backend unregister fails (offline/server error), the method still proceeds with local cleanup. The server should handle stale tokens on send failures.

Note on automatic cleanup: If you use connectToAuthService, local cleanup (steps 2-4) happens automatically when logout is detected. However, the backend unregister (step 1) cannot run automatically because the user is already logged out when the auth stream fires. If you need backend unregister, call this method manually before AuthServiceInt.signOut. The server should prune stale tokens when push sends fail, so manual pre-logout cleanup is optional but recommended.

timeout is the maximum time to wait for backend unregister (default: 5 seconds).

Example:

// In your logout flow (recommended for backend token cleanup):
await notificationService.preLogoutCleanup();
await authService.signOut();

// Or rely on automatic local cleanup (server prunes stale tokens):
await authService.signOut(); // Local cleanup happens via connectToAuthService

Implementation

Future<void> preLogoutCleanup({Duration timeout = const Duration(seconds: 5)}) async {
  logd('Starting pre-logout cleanup');

  // Step 1: Best-effort backend unregister while still authenticated
  // Skip if DeviceService is registered - it handles cleanup by deleting the
  // device doc via its onAboutToLogOut callback
  if (GetIt.I.isRegistered<DeviceServiceInt>()) {
    logd('DeviceService registered, skipping token persistence '
        '(device doc will be deleted by DeviceService)');
  } else if (_onTokenChanged != null && _cachedFcmToken != null) {
    try {
      await _onTokenChanged!(null, _cachedFcmToken).timeout(
        timeout,
        onTimeout: () {
          logw('Pre-logout token unregister timed out after $timeout');
        },
      );
      logd('Successfully unregistered FCM token on backend');
    } catch (e) {
      logw('Failed to unregister FCM token on backend (continuing with local cleanup): $e');
      // Continue with cleanup even if backend fails
    }
  }

  // Step 2: Stop token refresh subscription
  await _tokenRefreshSubscription?.cancel();
  _tokenRefreshSubscription = null;

  // Step 3: Delete FCM token from Firebase
  try {
    await FirebaseMessaging.instance.deleteToken();
    logd('Deleted FCM token from Firebase');
  } catch (e) {
    logw('Failed to delete FCM token from Firebase: $e');
  }

  // Step 4: Clear cached tokens
  await clearFcmToken();

  logi('Pre-logout cleanup completed');
}