cometchat_push_notifications

A Flutter plugin for integrating CometChat push notifications and VoIP calling into your app. Handles FCM (Android) and APNs/PushKit (iOS) token registration, notification display, and incoming/outgoing call UI with a custom Flutter call screen.

Features

  • Push notification handling for chat messages and calls
  • FCM (Android) and APNs + VoIP/PushKit (iOS) token registration
  • Built-in default incoming call screen (or bring your own)
  • In-call controls: mute, speaker, camera toggle
  • Badge count management
  • Notification tap handling with navigation support
  • OEM permission helpers for Android (Xiaomi, Oppo, Vivo, etc.)
  • Foreground notification suppression options

Installation

Add to your pubspec.yaml:

dependencies:
  cometchat_push_notifications: ^1.0.0-beta1

Platform Setup

Android

  1. Add your google-services.json to android/app/.
  2. Ensure minSdkVersion 24 and compileSdkVersion 36 in your app-level build.gradle.
  3. Add the required permissions in AndroidManifest.xml:
    • POST_NOTIFICATIONS (Android 13+)
    • USE_FULL_SCREEN_INTENT (Android 14+ for call notifications)

iOS

  1. Enable Push Notifications and Background Modes (Remote notifications, Voice over IP) in Xcode capabilities.
  2. Upload your APNs certificate/key to the CometChat Dashboard.
  3. Configure a VoIP Services certificate for PushKit.

Quick Start

Import

import 'package:cometchat_push_notifications/cometchat_push_notifications_export.dart';

Initialize

Call init() once in your main() or app startup, after CometChat SDK login:

await CometChatPushNotifications.init(
  CometChatNotificationConfig(
    appId: 'YOUR_APP_ID',
    region: 'us',
    onCallAccepted: (callDetails) {
      // Navigate to your in-call screen, start WebRTC, etc.
      print('Call accepted: ${callDetails.sessionId}');
    },
    onCallDeclined: (callDetails) {
      print('Call declined: ${callDetails.sessionId}');
    },
  ),
);

Register Push Tokens

// Android — FCM
CometChatPushNotifications.registerToken(
  PushPlatform.FCM_FLUTTER_ANDROID,
  providerId: 'your_fcm_provider_id',
  onSuccess: (token) => print('FCM registered: $token'),
  onError: (e) => print('FCM failed: $e'),
);

// iOS — APNs device token
CometChatPushNotifications.registerToken(
  PushPlatform.APNS_FLUTTER_DEVICE,
  providerId: 'your_apns_provider_id',
  onSuccess: (token) => print('APNs registered: $token'),
  onError: (e) => print('APNs failed: $e'),
);

// iOS — VoIP token
CometChatPushNotifications.registerToken(
  PushPlatform.APNS_FLUTTER_VOIP,
  providerId: 'your_apns_provider_id',
  onSuccess: (token) => print('VoIP registered: $token'),
  onError: (e) => print('VoIP failed: $e'),
);

Handle Incoming Push Notifications

Call this from your FCM/APNs background message handler:

final payload = await CometChatPushNotifications.handlePushNotification(
  remoteMessage.data,
);
// payload.notificationDetails contains parsed notification info

API Reference

Lifecycle

Method Description
init(CometChatNotificationConfig config) Initializes the plugin. Must be called once before any other method.
dispose() Disposes all resources, cancels stream subscriptions, and cleans up.

Permissions

Method Returns Description
requestPermission() Future<bool> Requests notification permission from the OS. Returns true if granted.
isPermissionGranted() Future<bool> Checks whether notification permission is currently granted.

Token Registration

Method Description
registerToken(PushPlatform platform, {required String providerId, required Function(String) onSuccess, required Function(CometChatNotificationException) onError}) Registers a push token with CometChat servers for the specified platform.
getPushToken() Returns the platform push token (FCM on Android, APNs on iOS) without registering it.
getVoIPToken() Returns the VoIP/PushKit token (iOS only).

Push Notification Handling

Method Returns Description
handlePushNotification(Map<String, dynamic> messageData, {String? title, String? icon, String? uid, String? guid}) Future<CometChatPushPayload> Parses and handles a raw CometChat push payload end-to-end. Routes chat payloads to notification display and call payloads to call handling.
showNotificationFromDetails(CometChatNotificationDetails details, {NvpNotificationTemplate? template}) Future<bool> Shows a system notification from pre-parsed notification details.
showInAppNotification(CometChatNotificationDetails details, {NvpNotificationTemplate? template}) Future<bool> Shows an in-app banner notification.
cancelNotification(String tag) Future<void> Cancels a notification by its tag (message ID).
clearAll() Future<void> Clears all notifications.

Badge Count

Method Returns Description
setBadgeCount(int count) Future<void> Sets the app badge count.
getBadgeCount() Future<int> Gets the current app badge count.

VoIP Call Handling

Method Returns Description
handleCallNotification(Map<String, dynamic> payload) Future<CometChatCallDetails> Handles a CometChat call notification payload end-to-end. Shows incoming call UI or dismisses it based on call action.
showIncomingCall(CometChatCallDetails callDetails) Future<void> Shows an incoming call UI using the configured call screen.
showOutgoingCall(CometChatCallDetails callDetails) Future<void> Shows an outgoing call UI using the custom Flutter call screen.
setCallConnected(String sessionId) Future<void> Marks a call as connected. Call after WebRTC/media setup completes.
endCall(String sessionId) Future<void> Ends a specific call by session ID.
endAllCalls() Future<void> Ends all active calls. Useful on logout.
getActiveCallIds() Future<List<String>> Returns the list of active call session IDs.
cancelCallNotification(String sessionId) Future<void> Cancels the system call notification for the given session ID.

In-Call Controls

Method Description
toggleMute(String sessionId, {required bool isMuted}) Toggles mute for a call.
toggleSpeaker(String sessionId, {required bool isOn}) Toggles speaker for a call.
toggleCamera(String sessionId, {required bool isOn}) Toggles camera for a video call.

Call Action Handler

Property Description
callActionHandler (setter) Replaces the active CometChatCallActionHandler at runtime. Pass null to reset to default.

Payload Parsing

Method Returns Description
parsePayload(Map<String, dynamic> payload) CometChatPushPayload Parses a raw CometChat push payload into a typed object without handling it.

Call Screen

Method Returns Description
buildCallScreen(CometChatCallDetails callDetails) Widget Returns the call screen widget (custom or default) for the given call details.
handleIncomingCallLaunch(GlobalKey<NavigatorState> navigatorKey) Future<void> Checks if the app was launched from a call notification and navigates to the call screen. Also handles subsequent notification taps while running.

OEM Permissions (Android only)

Method Returns Description
checkCallPermissions() Future<Map<String, bool>> Returns the state of Android permissions affecting call-screen visibility (fullScreenIntent, overlay, batteryOptimized).
openAutoStartSettings() Future<bool> Opens the OEM-specific Autostart permission screen (Xiaomi, Oppo, Vivo, Huawei, Samsung).
openFullScreenIntentSettings() Future<bool> Opens Android 14+ full-screen intent permission screen.
openOverlaySettings() Future<bool> Opens the "Display over other apps" permission screen.
openBatteryOptimizationSettings() Future<bool> Opens the battery optimization exemption request.

Event Streams

Stream Type Description
onNotificationTap Stream<CometChatNotificationDetails> Emits when a notification is tapped. Use to navigate to the relevant conversation.
onCallEvent Stream<CometChatCallEvent> Emits call events: accepted, declined, ended, incoming, timeoutEnded.
onCallStateChanged Stream<NvpCallState> Emits call state changes (mute, speaker, camera, status).
onTokenRefresh Stream<String> Emits when a push token refreshes. The plugin auto-re-registers it.
onPushReceived Stream<Map<String, dynamic>> Emits raw push payloads received in the foreground (iOS only).

Configuration

CometChatNotificationConfig

CometChatNotificationConfig(
  appId: 'YOUR_APP_ID',               // Required
  region: 'us',                        // Required ('us' or 'eu')
  customCallScreenBuilder: (details) => MyCallScreen(details), // Optional
  onCallAccepted: (details) { ... },   // Optional (default screen only)
  onCallDeclined: (details) { ... },   // Optional (default screen only)
  callActionHandler: MyCallActionHandler(), // Optional
  nvpConfig: NvpConfig(...),           // Optional advanced config
  showInAppNotifications: false,       // Show chat notifications in foreground
  showInAppVoIP: false,                // Show call UI in foreground
);

PushPlatform

Value Description
PushPlatform.FCM_FLUTTER_ANDROID FCM token for Android
PushPlatform.APNS_FLUTTER_DEVICE APNs device token for iOS
PushPlatform.APNS_FLUTTER_VOIP VoIP (PushKit) token for iOS

Custom Call Screen

Provide a customCallScreenBuilder to fully control the call UI:

CometChatNotificationConfig(
  appId: 'APP_ID',
  region: 'us',
  customCallScreenBuilder: (callDetails) {
    return MyCustomCallScreen(
      callerName: callDetails.callerName,
      callerAvatar: callDetails.callerAvatar,
      isVideo: callDetails.isVideo,
      onAccept: () async {
        await CometChatPushNotifications.cancelCallNotification(
          callDetails.sessionId,
        );
        // Start your media engine, navigate to in-call screen
      },
      onDecline: () async {
        await CometChatPushNotifications.cancelCallNotification(
          callDetails.sessionId,
        );
        await CometChatPushNotifications.endCall(callDetails.sessionId);
        Navigator.of(context).pop();
      },
    );
  },
);

When using a custom call screen, you are responsible for:

  • Accepting or rejecting the call
  • Cancelling the call notification via cancelCallNotification()
  • Popping the screen when done

Custom Call Action Handler

Override in-call controls to integrate with your media engine:

class MyCallActionHandler extends CometChatCallActionHandler {
  final WebRtcEngine _engine;

  MyCallActionHandler(this._engine);

  @override
  Future<void> onMuteToggled(String sessionId, bool isMuted) async {
    _engine.muteLocalAudio(isMuted);
    await super.onMuteToggled(sessionId, isMuted);
  }

  @override
  Future<void> onSpeakerToggled(String sessionId, bool isOn) async {
    _engine.setSpeakerOn(isOn);
    await super.onSpeakerToggled(sessionId, isOn);
  }

  @override
  Future<void> onCameraToggled(String sessionId, bool isOn) async {
    _engine.enableLocalVideo(isOn);
    await super.onCameraToggled(sessionId, isOn);
  }
}

// Set at runtime (e.g., after joining a call):
CometChatPushNotifications.callActionHandler = MyCallActionHandler(engine);

// Reset to default:
CometChatPushNotifications.callActionHandler = null;

Listening to Events

// Navigate on notification tap
CometChatPushNotifications.onNotificationTap.listen((details) {
  navigateToConversation(details.conversationId, details.receiverType);
});

// Handle call events
CometChatPushNotifications.onCallEvent.listen((event) {
  switch (event.type) {
    case CometChatCallEventType.incoming:
      print('Incoming call: ${event.sessionId}');
    case CometChatCallEventType.accepted:
      print('Call accepted: ${event.sessionId}');
    case CometChatCallEventType.declined:
      print('Call declined: ${event.sessionId}');
    case CometChatCallEventType.ended:
      print('Call ended: ${event.sessionId}');
    case CometChatCallEventType.timeoutEnded:
      print('Call timed out: ${event.sessionId}');
  }
});

// Monitor token refreshes
CometChatPushNotifications.onTokenRefresh.listen((token) {
  print('Token refreshed: $token');
});

Handling App Launch from Call Notification

Set up call-launch handling after your navigator is ready:

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _navigatorKey = GlobalKey<NavigatorState>();

  @override
  void initState() {
    super.initState();
    CometChatPushNotifications.handleIncomingCallLaunch(_navigatorKey);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: _navigatorKey,
      home: HomeScreen(),
    );
  }
}

Error Handling

All errors are thrown as CometChatNotificationException:

try {
  await CometChatPushNotifications.handlePushNotification(data);
} on CometChatNotificationException catch (e) {
  print('Error [${e.code.name}]: ${e.message}');
}

Error codes (CometChatErrorCode):

Code Description
notInitialized init() was not called before use
invalidPayload Push payload is malformed or missing required fields
tokenRegistrationFailed Token registration with CometChat servers failed
unsupportedPlatform Operation not supported on the current platform
pluginError The underlying notification_voip_plugin returned an error
permissionDenied Permission was denied by the user
callOperationFailed A call operation failed

Models

CometChatCallDetails

Property Type Description
sessionId String Unique call session ID
callerUid String UID of the caller
callerName String Display name of the caller
callerAvatar String? Avatar URL of the caller
callType CometChatCallType Audio or video
receiverType CometChatReceiverType User or group
conversationId String Conversation identifier
isVideo bool Whether this is a video call

CometChatNotificationDetails

Property Type Description
title String Notification display title
body String Notification display body
sender String Sender UID
senderName String Sender display name
senderAvatar String? Sender avatar URL
receiver String Receiver UID or GUID
receiverName String Receiver display name
receiverType CometChatReceiverType User or group
tag String Message/notification ID
conversationId String Conversation identifier
type CometChatPayloadType Chat or call
sentAt String Timestamp (ms) as string
callAction CometChatCallAction? Call action (call payloads only)
sessionId String? Call session ID (call payloads only)
callType CometChatCallType? Audio/video (call payloads only)

CometChatCallEvent

Property Type Description
type CometChatCallEventType Event type (accepted, declined, ended, incoming, timeoutEnded)
sessionId String Call session ID
extraData Map<String, dynamic>? Optional extra data

CometChatPushPayload

Property Type Description
toUid String UID of the intended recipient
notificationDetails CometChatNotificationDetails Parsed notification details
rawPayload Map<String, dynamic> Raw payload map for fallback access

Cleanup

Dispose when the user logs out or the app is shutting down:

await CometChatPushNotifications.dispose();