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
Android
- Add your
google-services.json to android/app/.
- Ensure
minSdkVersion 24 and compileSdkVersion 36 in your app-level build.gradle.
- Add the required permissions in
AndroidManifest.xml:
POST_NOTIFICATIONS (Android 13+)
USE_FULL_SCREEN_INTENT (Android 14+ for call notifications)
iOS
- Enable Push Notifications and Background Modes (Remote notifications, Voice over IP) in Xcode capabilities.
- Upload your APNs certificate/key to the CometChat Dashboard.
- 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
);
| 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();