cometchat-flutter-calls
DevelopmentUse when implementing voice calls, video calls, or call UI with CometChat Flutter UIKit v6. Covers CometChatCallButtons, CometChatIncomingCall, CometChatOutgoingCall, CometChatOngoingCall, CometChatCallLogs, CometChatUIKitCalls, CallingConfiguration, CallButtonsBloc, IncomingCallBloc, OutgoingCallBloc, OngoingCallBloc, CallLogsBloc, CallEventService, CallOperationsServiceLocator, call_operations, call_settings, SessionSettingsBuilder, CallAppSettings, initiateCall, acceptCall, rejectCall, endSession, startSession, generateToken, CallNavigationContext, CometChatDisplayIncomingCallOverlay, CallScreenOverlay, native_call_kit, call permissions, audio call, video call, group call, call logs, call history, incoming call screen, outgoing call screen, ongoing call screen, call bubble, or "add calling to my app". Also use when seeing errors like "CallManager not found", "startSession null", "call token null", "session already started", or call-related crashes.
How to use this skill
Bring this guide into your coding agent with a prompt tailored to the tool you use.
- Open your project in Codex.
- Copy and paste the prompt below.
- Review files and risks before approving any action.
Inspect the Agent Skill at https://github.com/cometchat/cometchat-uikit-flutter/blob/HEAD/packages/cometchat_uikit/skills/cometchat-flutter-calls/SKILL.md and all supporting files. Report provenance, permissions, scripts, dependencies, and security risks. Propose an exact installation into .agents/skills/cometchat-flutter-calls, but wait for my approval before writing files or running scripts.
Copying this prompt does not install or run the skill. Review third-party files before use.
CometChat Flutter UIKit — Calls
Voice and video calling for 1:1 and group conversations. Call functionality is built into cometchat_chat_uikit — no separate package needed.
Import
import 'package:cometchat_chat_uikit/cometchat_chat_uikit.dart';
import 'package:cometchat_chat_uikit/cometchat_calls_uikit.dart';
The first import gives you chat components. The second gives you call-specific types.
Rule: CALLS_INIT_AFTER_CHAT_INIT
CometChatUIKitCalls.init() MUST be called after CometChatUIKit.init() completes. The calls SDK needs the chat SDK's auth context.
// ✅ CORRECT — calls init after chat init
CometChatUIKit.init(
uiKitSettings: settings,
onSuccess: (_) {
CometChatUIKitCalls.init(appId, region,
onSuccess: (_) => debugPrint('Calls SDK ready'),
onError: (e) => debugPrint('Calls init failed: ${e.message}'),
);
},
);
// ❌ WRONG — parallel init causes auth token null
CometChatUIKit.init(uiKitSettings: settings);
CometChatUIKitCalls.init(appId, region); // Race condition
Rule: SINGLE_CALLS_INIT
CometChatUIKitCalls.init() must be called exactly once per app lifecycle. Calling it again after logout + re-login can cause "session already started" errors.
Rule: CALLS_REINIT_AFTER_LOGOUT
After CometChatUIKit.logout(), the calls SDK session is invalidated. On the next login, CometChatUIKitCalls.init() must be called again.
Architecture
call_ui/src/
├── call_buttons/ # Voice/video call buttons (CallButtonsBloc)
├── incoming_call/ # Incoming call screen (IncomingCallBloc)
├── outgoing_call/ # Outgoing call screen (OutgoingCallBloc)
├── ongoing_call/ # Active call screen — WebRTC (OngoingCallBloc)
├── call_logs/ # Call history list (CallLogsBloc + Clean Arch)
├── call_operations/ # Shared clean architecture (DI, use cases, repos)
├── call_bubble/ # Call message bubble in chat
├── call_settings/ # CometChatUIKitCalls, CallNavigationContext
├── native_call_kit/ # iOS CallKit / Android ConnectionService
├── utils/ # CallUtils, CallStateService, CallPermissions
├── call_event_service.dart # Centralized call event handling
└── calling_configuration.dart # Top-level config object
Components
CometChatCallButtons
Voice and video call buttons. Typically placed in CometChatMessageHeader's trailing view or standalone.
CometChatCallButtons(
user: user, // For 1:1 calls
group: group, // For group calls (meetings)
hideVoiceCallButton: false,
hideVideoCallButton: false,
voiceCallIcon: Icon(Icons.call),
videoCallIcon: Icon(Icons.videocam),
callButtonsStyle: CometChatCallButtonsStyle(
voiceCallIconColor: colorPalette.iconPrimary,
videoCallIconColor: colorPalette.iconPrimary,
),
outgoingCallConfiguration: CometChatOutgoingCallConfiguration(
outgoingCallStyle: CometChatOutgoingCallStyle(...),
),
)
Call buttons are built into CometChatMessageHeader by default:
CometChatMessageHeader(
user: user,
group: group,
hideVoiceCallButton: false,
hideVideoCallButton: false,
)
CometChatIncomingCall
Displays when the logged-in user receives a call. Supports accept/decline with custom views.
CometChatIncomingCall(
call: call, // Required — the active Call object
user: callerUser, // Caller info for display
onAccept: (ctx, call) { },
onDecline: (ctx, call) { },
disableSoundForCalls: false,
customSoundForCalls: 'assets/ringtone.mp3',
incomingCallStyle: CometChatIncomingCallStyle(
backgroundColor: colorPalette.background3,
acceptButtonColor: colorPalette.success,
declineButtonColor: colorPalette.error,
),
// Custom view slots
titleView: (ctx, call) => Text('Custom Title'),
subTitleView: (ctx, call) => Text('Custom Subtitle'),
leadingView: (ctx, call) => Icon(Icons.call),
trailingView: (ctx, call) => CometChatAvatar(image: user.avatar),
)
CometChatOutgoingCall
Displays when the logged-in user initiates a call.
CometChatOutgoingCall(
call: call,
user: receiverUser,
outgoingCallStyle: CometChatOutgoingCallStyle(
backgroundColor: colorPalette.background1,
),
)
CometChatOngoingCall
The active call screen with WebRTC video/audio. Rendered after a call is accepted.
CometChatOngoingCall(
callSettingsBuilder: sessionSettingsBuilder,
sessionId: call.sessionId,
callWorkFlow: CallWorkFlow.directCalling,
)
CometChatCallLogs
Scrollable list of call history. Clean Architecture + BLoC with CallLogsServiceLocator.
CometChatCallLogs(
onItemClick: (callLog) { /* Navigate or initiate call */ },
callLogsStyle: CallLogsStyle(backgroundColor: colorPalette.background1),
)
CometChatCallBubble
Message bubble for call events in the message list. Automatically rendered for call-type messages.
CallingConfiguration
Top-level configuration object bundling all call component configs:
CallingConfiguration(
outgoingCallConfiguration: CometChatOutgoingCallConfiguration(...),
incomingCallConfiguration: CometChatIncomingCallConfiguration(...),
callButtonsConfiguration: CallButtonsConfiguration(...),
groupSessionSettingsBuilder: sessionSettingsBuilder,
)
CometChatUIKitCalls API
| Method | Purpose |
|---|---|
CometChatUIKitCalls.init(appId, region) | Initialize calls SDK |
CometChatUIKitCalls.initiateCall(call) | Start a call |
CometChatUIKitCalls.acceptCall(sessionId) | Accept incoming call |
CometChatUIKitCalls.rejectCall(sessionId, status) | Reject/cancel call |
CometChatUIKitCalls.generateToken(sessionId) | Generate call token |
CometChatUIKitCalls.startSession(sessionId, settings) | Start WebRTC session |
CometChatUIKitCalls.endSession() | End active call session |
Call Flow — 1:1 Direct Call
Caller Receiver
|-- CometChatCallButtons tap ------->|
|-- initiateCall(Call) ------------->|
|-- CometChatOutgoingCall shown ---->|
| |-- CometChatIncomingCall shown
| |-- acceptCall(sessionId)
|<-- onOutgoingCallAccepted ---------|
|-- generateToken(sessionId) ------->|
|-- startSession(token, settings) -->|
|-- CometChatOngoingCall shown ----->|-- CometChatOngoingCall shown
|-- endSession() ------------------>|-- endSession()
Golden Path — Messages Screen with Calls
Scaffold(
resizeToAvoidBottomInset: false,
appBar: CometChatMessageHeader(
user: user,
group: group,
onBack: () => Navigator.pop(context),
hideVoiceCallButton: false,
hideVideoCallButton: false,
),
body: Column(
children: [
Expanded(child: CometChatMessageList(user: user, group: group)),
CometChatMessageComposer(user: user, group: group),
],
),
)
BLoC Events
CallButtonsBloc
| Event | Purpose |
|---|---|
InitiateVoiceCall | Start audio call |
InitiateVideoCall | Start video call |
IncomingCallBloc
| Event | Purpose |
|---|---|
AcceptCall | Accept the incoming call |
RejectCall | Decline the incoming call |
OutgoingCallBloc
| Event | Purpose |
|---|---|
CancelCall | Cancel the outgoing call |
CallAccepted(call) | Receiver accepted |
CallRejected(call) | Receiver rejected |
OngoingCallBloc
| Event | Purpose |
|---|---|
StartSession(sessionId, settings) | Begin WebRTC session |
EndSession | End the call |
CallLogsBloc
| Event | Purpose |
|---|---|
LoadCallLogs | Initial load |
LoadMoreCallLogs | Pagination |
Gotchas
CometChatUIKitCalls.init()must happen AFTERCometChatUIKit.init()— parallel init causes "auth token null".- After logout, the calls SDK session is invalidated. Re-init required on next login.
startSessionon Android can returnnullwith a 5-second timeout and no error feedback. Known platform issue.SessionType.audiois ignored on Android in some SDK versions — always opens with video. Known external SDK bug.- Group calls use
CometChat.GroupnotCometChat.UseronCometChatCallButtons. - Incoming call handling must be global (mounted at app root level) so calls ring on every screen.
CallOperationsServiceLocatormust be initialized before using call BLoCs directly. UIKit widgets handle this automatically.- After logout, call
CallOperationsServiceLocator.instance.reset()to clean up. - On iOS, CallKit integration via
native_call_kitshows the native call UI. EnsureInfo.plisthas thevoipbackground mode. - On Android, the ongoing call foreground service shows a notification during active calls. Launched automatically by
startSession.
Anti-Patterns
// ❌ WRONG — init calls SDK before chat SDK
CometChatUIKitCalls.init(appId, region);
CometChatUIKit.init(uiKitSettings: settings);
// ✅ CORRECT — calls init in chat init's onSuccess
CometChatUIKit.init(
uiKitSettings: settings,
onSuccess: (_) {
CometChatUIKitCalls.init(appId, region);
},
);
// ❌ WRONG — not handling incoming calls globally
CometChatIncomingCall(call: call, user: user) // Only on messages screen
// ✅ CORRECT — mount incoming call overlay at app root
MaterialApp(
builder: (context, child) {
return Stack(children: [child!, /* Global incoming call listener */]);
},
)
Checklist
-
CometChatUIKitCalls.init()called afterCometChatUIKit.init()completes - Incoming call handling is global (app root level), not per-screen
- Camera + microphone permissions handled (automatic via
CallPermissions) -
resizeToAvoidBottomInset: falseon any Scaffold with call UI - Call buttons visible in
CometChatMessageHeader(default) or standalone - After logout, calls SDK re-initialized on next login
- Android:
minSdk = 26, ProGuard rules forcom.cometchat.** - iOS:
voipbackground mode inInfo.plistfor CallKit - Theme cached in
didChangeDependencies(), notbuild() - SDK listeners cleaned up in
dispose()