start method

Future<void> start()

Turn-key enable: permission → token → register → refresh + open handlers. Called automatically when pushEnabled is set. Safe to call again; every failure is caught and logged so push can never break the app.

Implementation

Future<void> start() async {
  try {
    final platform = _detectPlatform();
    if (platform == null) {
      NexusLog.info('push: platform not supported for FCM — skipping');
      return;
    }
    if (!await _ensureFirebase(platform)) return;

    final messaging = FirebaseMessaging.instance;
    if (_cfg.pushAutoRequestPermission) {
      final settings = await messaging.requestPermission();
      NexusLog.debug('push: permission ${settings.authorizationStatus.name}');
    }

    // FCM does not draw a notification while the app is foregrounded — show it
    // ourselves so notifications appear whether the app is open or not.
    if (_cfg.pushForegroundDisplay) await _setupForegroundDisplay(platform, messaging);

    // Android: campaigns arrive as data messages so the SDK renders every
    // notification natively (foreground AND background/killed) with full
    // options + action buttons. Register the background renderer.
    if (platform == PushPlatform.android && _cfg.pushForegroundDisplay) {
      // Single shared background handler — see ensureNexusBackgroundHandler.
      // (Registering nexusPushBackgroundHandler directly would clobber Voice.)
      ensureNexusBackgroundHandler();
    }

    final token = platform == PushPlatform.web
        ? await messaging.getToken(vapidKey: _cfg.pushWebVapidKey)
        : await messaging.getToken();
    if (token != null) {
      await registerToken(token, platform: platform, provider: PushProvider.fcm);
    }

    await _refreshSub?.cancel();
    _refreshSub = messaging.onTokenRefresh.listen(
      (t) => registerToken(t, platform: platform, provider: PushProvider.fcm),
    );

    // Attribute the open that launched / foregrounded the app.
    final initial = await messaging.getInitialMessage();
    if (initial != null) await reportOpen(initial.data);
    await _openSub?.cancel();
    _openSub = FirebaseMessaging.onMessageOpenedApp.listen((m) => reportOpen(m.data));

    NexusLog.info('push: enabled (${platform.name})');
  } catch (e) {
    NexusLog.warn('push: start failed — $e');
  }
}