initFCM method

Future<void> initFCM()

Implementation

Future<void> initFCM() async {
  logd('Initializing FCM with _hasInitializedFCM = $_hasInitializedFCM');

  try {
    FirebaseMessaging messaging = FirebaseMessaging.instance;

    // Request permission for iOS devices
    await messaging.requestPermission(
      alert: true,
      badge: true,
      sound: true,
    );
    //TODO: do we need to do something with the settings?
    // NotificationSettings settings = await messaging.requestPermission(
    //   alert: true,
    //   badge: true,
    //   sound: true,
    // );

    // For apple platforms, ensure the APNS token is available before making any FCM plugin API calls
    String? apnsToken;
    if (defaultTargetPlatform == TargetPlatform.iOS ||
        defaultTargetPlatform == TargetPlatform.macOS) {
      // Wait for APNS token to be available
      int retries = 0;
      while (apnsToken == null && retries < 30) {
        apnsToken = await messaging.getAPNSToken();
        if (apnsToken == null) {
          logd('APNS token not available yet, waiting...');
          await Future.delayed(const Duration(milliseconds: 250));
          retries++;
        }
      }
      if (apnsToken == null) {
        loge('APNS token was not set after waiting.');
        // Optionally: return or throw here
      }
    }

    SharedPreferences prefs = await SharedPreferences.getInstance();

    String? oldToken = prefs.getString(sharedPrefKeyFcmToken);
    String? newToken;

    try {
      newToken = await messaging.getToken();
    } catch (e) {
      loge('Failed to get FCM token (Firebase Installations Service may be unavailable): $e');
      // Don't propagate the error - FCM is not critical for app functionality
      return;
    }

    if (newToken != null && (newToken != oldToken || !_hasInitializedFCM)) {
      try {
        logd('Updating FCM token on server: $newToken');
        await _updateTokenOnServer(newToken, oldToken ?? "");
        await prefs.setString(sharedPrefKeyFcmToken, newToken);
      } catch (e) {
        loge('Error updating FCM token on server: $e');
      }
    }

    if (!_hasInitializedFCM) {
      messaging.onTokenRefresh.listen((newToken) async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        String? oldToken = prefs.getString(sharedPrefKeyFcmToken);
        try {
          await _updateTokenOnServer(newToken, oldToken ?? "");
          await prefs.setString(sharedPrefKeyFcmToken, newToken);
        } catch (e) {
          loge('Error updating FCM token on server: $e');
        }
      });
    }

    _hasInitializedFCM = true;
  } catch (e) {
    loge('FCM initialization failed: $e');
    // Don't set _hasInitializedFCM to true if initialization failed
    // This allows retry on next auth state change
  }
}