cometchat-flutter-v6-troubleshooting
$
npx mdskill add cometchat/cometchat-skills/cometchat-flutter-v6-troubleshootingDiagnose and fix CometChat Flutter UIKit v6 integration issues.
- Resolves init failures, login errors, UI rendering, and call problems.
- Depends on cometchat_chat_uikit ^6.0.1 and official CometChat docs.
- Uses a decision tree to route to the correct troubleshooting section.
- Provides step-by-step fixes for crashes, layout bugs, and build errors.
SKILL.md
.github/skills/cometchat-flutter-v6-troubleshootingView on GitHub ↗
---
name: cometchat-flutter-v6-troubleshooting
description: >
Diagnose and fix CometChat Flutter UIKit v6 integration problems. Covers init
failures, login errors, UI rendering issues, keyboard problems, call failures,
listener leaks, theme jank, and platform-specific build errors. Use when seeing
errors, crashes, or unexpected behavior with CometChat components.
license: "MIT"
compatibility: "cometchat_chat_uikit ^6.0.1"
metadata:
author: "CometChat"
version: "3.0.0"
tags: "cometchat flutter troubleshooting errors debugging crashes fixes"
---
> **Ground truth:** `cometchat_chat_uikit: ^6.0` — pub-cache source + `ui-kit/flutter`. **Official docs:** https://www.cometchat.com/docs/ui-kit/flutter/overview · **Docs MCP:** `claude mcp add --transport http cometchat-docs https://www.cometchat.com/docs/mcp` (or fetch the URL directly without MCP). Verify symbols against the installed package/source before relying on them.
# CometChat Flutter UIKit v6 — Troubleshooting Guide
Comprehensive guide for diagnosing and fixing CometChat Flutter UIKit v6 integration problems.
---
## 1. Quick Diagnosis Flow
Use this decision tree to jump to the right section:
```
What's happening?
│
├─ App crashes or errors on startup
│ └─ Go to → Section 2: Init & Login Errors
│
├─ UI looks wrong, layout broken, keyboard issues
│ └─ Go to → Section 3: UI Rendering Issues
│
├─ Calls not working, call screen blank or stuck
│ ├─ Outgoing screen NEVER renders (peer rings, caller shows nothing) → Section 4.7 (V6 navigatorKey trap)
│ ├─ Stuck on "Calling…" after peer accepts → Section 4.8 (upgrade to 6.0.1)
│ └─ Otherwise → Section 4: Call Issues
│
├─ Events not firing, duplicate events, memory leaks
│ └─ Go to → Section 5: Listener Issues
│
├─ Build fails on Android or iOS
│ └─ Go to → Section 6: Build Errors
│
├─ App is slow, janky scrolling, laggy keyboard
│ └─ Go to → Section 7: Performance Issues
│
└─ Platform-specific weirdness (Android/iOS/Web)
└─ Go to → Section 8: Platform-Specific Issues
```
---
## 2. Init & Login Errors
### 2.1 "Authentication null"
- **Symptom**: Error message `Authentication null` or `Please log in to CometChat before calling this method` when using any CometChat component or SDK call.
- **Cause**: `CometChatUIKit.init()` was not called, or was called but not awaited before using components or calling login.
- **Fix**: Ensure `init()` completes before any other CometChat usage:
```dart
// ✅ CORRECT — await init before anything else
final settings = (UIKitSettingsBuilder()
..appId = 'APP_ID'
..region = 'us'
..authKey = 'AUTH_KEY'
..subscriptionType = CometChatSubscriptionType.allUsers)
.build();
await CometChatUIKit.init(
uiKitSettings: settings,
onSuccess: (_) => debugPrint('Init done'),
onError: (e) => debugPrint('Init failed: ${e.message}'),
);
// ❌ WRONG — login before init completes (race condition)
CometChatUIKit.init(uiKitSettings: settings);
CometChatUIKit.login('uid');
```
### 2.2 "APP ID null"
- **Symptom**: Error `APP ID null` or `appId is required` during init.
- **Cause**: `appId` not set in `UIKitSettingsBuilder`.
- **Fix**: Set `appId` before calling `.build()`:
```dart
final settings = (UIKitSettingsBuilder()
..appId = 'YOUR_APP_ID' // ← Must be set
..region = 'us'
..authKey = 'YOUR_AUTH_KEY')
.build();
```
### 2.3 ERR_ALREADY_LOGGED_IN
- **Symptom**: Error `ERR_ALREADY_LOGGED_IN` when calling `CometChatUIKit.login()`.
- **Cause**: Calling login when a session already exists. After `init()`, the SDK restores cached sessions automatically.
- **Fix**: Check `CometChatUIKit.loggedInUser` after init before calling login:
```dart
CometChatUIKit.init(
uiKitSettings: settings,
onSuccess: (_) {
if (CometChatUIKit.loggedInUser != null) {
// Already logged in — skip login, go to home
navigateToHome();
} else {
// No session — show login screen
navigateToLogin();
}
},
);
```
### 2.4 "Android internal error" on login
- **Symptom**: Login fails with a vague `Android internal error` message.
- **Cause**: Multiple possible causes — incorrect auth key, UID doesn't exist in CometChat dashboard, beta SDK bug, or network issue.
- **Fix**:
1. Verify credentials are correct in the CometChat dashboard
2. Verify the UID exists in the dashboard
3. Try calling `CometChat.login(uid, authKey)` directly to isolate UIKit vs SDK issue
4. If using beta SDK, try the stable release
5. Check network connectivity and firewall rules
### 2.5 Guard screen stuck on spinner
- **Symptom**: App shows a loading spinner forever after init. The auth guard never resolves.
- **Cause**: Using the callback-based `CometChat.getLoggedInUser()` after init instead of the synchronous `CometChatUIKit.loggedInUser`. The callback API silently fails when no session exists — neither `onSuccess` nor `onError` fires.
- **Fix**: Use the synchronous check after init:
```dart
// ✅ CORRECT — synchronous check, always resolves
CometChatUIKit.init(
uiKitSettings: settings,
onSuccess: (_) {
final hasUser = CometChatUIKit.loggedInUser != null;
setState(() {
_loggedIn = hasUser;
_initializing = false;
});
},
);
// ❌ WRONG — callback may never fire when no session exists
CometChatUIKit.init(
uiKitSettings: settings,
onSuccess: (_) {
CometChat.getLoggedInUser(
onSuccess: (user) { /* may never fire */ },
onError: (e) { /* may never fire */ },
);
},
);
// ❌ ALSO WRONG — redundant native bridge round-trip
CometChatUIKit.init(
uiKitSettings: settings,
onSuccess: (_) async {
final user = await CometChatUIKit.getLoggedInUser(); // Unnecessary!
},
);
```
### 2.6 Region error (ERR_INVALID_REGION)
- **Symptom**: Init fails with `ERR_INVALID_REGION`.
- **Cause**: Region string is uppercase or not one of the valid values.
- **Fix**: Use lowercase region string — valid values are `'us'`, `'eu'`, `'in'`:
```dart
// ✅ CORRECT
..region = 'us'
// ❌ WRONG
..region = 'US'
..region = 'United States'
```
### 2.7 StateError from uninitialized ServiceLocator
- **Symptom**: `StateError: not initialized` when creating a BLoC manually.
- **Cause**: Component's `ServiceLocator.instance.setup()` was not called before creating the BLoC. UIKit widgets do this automatically, but manual BLoC creation requires it.
- **Fix**: Call setup before creating the BLoC:
```dart
// ✅ CORRECT
ConversationsServiceLocator.instance.setup();
final bloc = ConversationsBloc(
getLoggedInUserUseCase: ConversationsServiceLocator.instance.getLoggedInUserUseCase,
);
// ❌ WRONG — setup not called
final bloc = ConversationsBloc(
getLoggedInUserUseCase: ConversationsServiceLocator.instance.getLoggedInUserUseCase,
);
```
---
## 3. UI Rendering Issues
### 3.1 Double keyboard compensation (layout jumps) — PRE-6.0.1 symptom
- **Symptom**: When the keyboard opens, the message list jumps or there's extra white space. Content shifts twice — once from Flutter's Scaffold resize, once from the composer's internal keyboard handling.
- **Cause**: A **pre-6.0.1** kit. Before kit fix **ENG-34434**, the composer did not clamp its keyboard spacing to Flutter's `viewInsets`, so a Scaffold with `resizeToAvoidBottomInset: true` (the default) double-compensated. On `^6.0.1` the composer clamps to `viewInsets`, so `true` is correct and does NOT double-compensate.
- **Fix**: **Upgrade `cometchat_chat_uikit` to `^6.0.1`** and keep `resizeToAvoidBottomInset: true` (or omit it — `true` is the default). Setting `false` is only a stopgap on old kits you can't upgrade.
```dart
// ✅ CORRECT on ^6.0.1 — true (or omit; true is the default). Composer clamps
// to viewInsets (ENG-34434), so no double-compensation.
Scaffold(
resizeToAvoidBottomInset: true,
body: Column(
children: [
Expanded(child: CometChatMessageList(user: user)),
CometChatMessageComposer(user: user),
],
),
)
// ⚠ PRE-6.0.1 STOPGAP ONLY — false suppresses the double gap on kits that
// predate the ENG-34434 clamp. Prefer upgrading the kit.
Scaffold(
resizeToAvoidBottomInset: false,
body: Column(
children: [
Expanded(child: CometChatMessageList(user: user)),
CometChatMessageComposer(user: user),
],
),
)
```
This applies everywhere the composer is used: messages screen, thread screen, or any custom screen.
### 3.2 Stale user/group data
- **Symptom**: User name, avatar, or group info doesn't update in real-time. Old data persists even after changes.
- **Cause**: Passing `widget.user` or `widget.group` directly to UIKit components instead of maintaining mutable state that updates from listeners.
- **Fix**: Keep mutable `_user`/`_group` in your State class and update from SDK listeners:
```dart
class _MessagesScreenState extends State<MessagesScreen> {
late User? _user;
late Group? _group;
@override
void initState() {
super.initState();
_user = widget.user;
_group = widget.group;
// Register listeners to update _user/_group on changes
}
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true, // ^6.0.1: composer clamps to viewInsets (ENG-34434)
body: Column(
children: [
Expanded(child: CometChatMessageList(user: _user, group: _group)),
CometChatMessageComposer(user: _user, group: _group),
],
),
);
}
}
```
### 3.3 No typing indicators / presence events
- **Symptom**: Online/offline status never updates. Typing indicators don't appear. No presence events fire. No error is thrown.
- **Cause**: `subscriptionType` was not set in `UIKitSettingsBuilder`. Omitting it silently disables all presence events.
- **Fix**: Always set `subscriptionType`:
```dart
// ✅ CORRECT
UIKitSettingsBuilder()
..appId = 'APP_ID'
..region = 'us'
..authKey = 'AUTH_KEY'
..subscriptionType = CometChatSubscriptionType.allUsers
// ❌ WRONG — no error, but presence events never fire
UIKitSettingsBuilder()
..appId = 'APP_ID'
..region = 'us'
..authKey = 'AUTH_KEY'
// subscriptionType missing!
```
### 3.4 Messages not updating in real-time
- **Symptom**: New messages don't appear until the screen is refreshed or re-opened.
- **Cause**: Multiple possible causes:
1. SDK message listener not registered (BLoC handles this automatically — check component is mounted)
2. `subscriptionType` not set (see 3.3)
3. Component was disposed and listener removed
- **Fix**:
1. Ensure `subscriptionType` is set in UIKitSettings
2. Verify the `CometChatMessageList` widget is mounted and not disposed
3. If using custom BLoC, ensure it registers `CometChat.addMessageListener()` in its constructor and removes it in `close()`
### 3.5 Theme jank during keyboard animation
- **Symptom**: Visible jank (stuttering, dropped frames) when the keyboard opens or closes, especially on message screens.
- **Cause**: Theme values (`CometChatThemeHelper.getColorPalette(context)`, etc.) are being looked up inside `build()`. During keyboard animation, `MediaQuery` changes trigger rebuilds, and each lookup does expensive InheritedWidget traversal (44–95ms instead of <16ms).
- **Fix**: Cache theme values in `didChangeDependencies()` with a `_themeInitialized` flag:
```dart
// ✅ CORRECT — cache once, reuse on every build
class _MyWidgetState extends State<MyWidget> {
late CometChatColorPalette _colorPalette;
late CometChatSpacing _spacing;
late CometChatTypography _typography;
bool _themeInitialized = false;
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (!_themeInitialized) {
_colorPalette = CometChatThemeHelper.getColorPalette(context);
_spacing = CometChatThemeHelper.getSpacing(context);
_typography = CometChatThemeHelper.getTypography(context);
_themeInitialized = true;
}
}
@override
Widget build(BuildContext context) {
// Use _colorPalette, _spacing, _typography — no lookups here
return Container(color: _colorPalette.primary);
}
}
// ❌ WRONG — lookup in build causes jank during keyboard animation
@override
Widget build(BuildContext context) {
final colors = CometChatThemeHelper.getColorPalette(context); // Expensive!
return Container(color: colors.primary);
}
```
### 3.6 Extra white space between composer and keyboard
- **Symptom**: Visible gap between the message composer and the keyboard when it opens.
- **Cause**: Safe area bottom padding being applied when the keyboard is open. The keyboard already covers the safe area, so adding safe area padding on top creates extra space.
- **Fix**: Cache `MediaQuery.paddingOf(context).bottom` once in `didChangeDependencies()`. Never wrap the composer in an extra `SafeArea` widget — `CometChatMessageComposer` already handles bottom inset internally via `SliverSpacing`:
```dart
// ✅ CORRECT — cache safe area once, no extra SafeArea wrapper
class _MessagesScreenState extends State<MessagesScreen> {
double _bottomSafeArea = 0;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_bottomSafeArea = MediaQuery.paddingOf(context).bottom;
}
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true, // ^6.0.1: composer clamps to viewInsets (ENG-34434)
body: Column(
children: [
Expanded(child: CometChatMessageList(user: widget.user)),
CometChatMessageComposer(user: widget.user), // No SafeArea wrapper!
],
),
);
}
}
// ❌ WRONG — SafeArea wrapper adds bottom padding the composer already handles
Scaffold(
resizeToAvoidBottomInset: true,
body: Column(
children: [
Expanded(child: CometChatMessageList(user: widget.user)),
SafeArea( // ← Causes extra white gap when keyboard opens
child: CometChatMessageComposer(user: widget.user),
),
],
),
)
```
---
## 4. Call Issues
### 4.1 "auth token null" on call init
- **Symptom**: Calls SDK fails with `auth token null` or similar authentication error when trying to start a call.
- **Cause**: The Calls SDK was initialized before the Chat SDK completed init and login. The Calls SDK needs the auth token from a successful chat login (rule **CALLS_INIT_AFTER_CHAT_INIT** — see `cometchat-flutter-v6-calls` §1.0).
- **Fix**: When `..enableCalls = true` is set on `UIKitSettingsBuilder`, `CallEventService` handles both `CometChatUIKitCalls.init()` and `CometChatUIKitCalls.loginWithAuthToken()` internally — chat init must complete first. For manual integrations, gate calls init on chat init success:
```dart
// ✅ CORRECT — chat init first, calls init in onSuccess
await CometChatUIKit.init(
uiKitSettings: settings,
onSuccess: (_) async {
// For manual calls integration (no ..enableCalls = true):
// CometChatUIKitCalls.init takes raw appId + region STRINGS (not a settings
// builder) and reports via callbacks — verified vs cometchat_uikit_calls.dart:9.
CometChatUIKitCalls.init(
'APP_ID',
'us',
onSuccess: (_) {},
onError: (e) => debugPrint('Calls init failed: $e'),
);
},
onError: (e) => debugPrint('Chat init failed: ${e.message}'),
);
// ❌ WRONG — calls init runs before chat init completes
CometChatUIKit.init(uiKitSettings: settings); // not awaited
await CometChatUIKitCalls.init(callAppSettings); // auth token null
```
### 4.2 "session already started"
- **Symptom**: Error `session already started` when trying to join or start a call.
- **Cause**: Two distinct causes — diagnose both:
1. **Duplicate `CometChatUIKitCalls.init()` within one app lifecycle.** The Calls SDK is single-init (rule **CALL_INIT_ONCE** — see `cometchat-flutter-v6-calls`). Calling init more than once (e.g., from multiple bootstrap paths, hot-restart with stale state) emits this error.
2. **Stale call session from a prior call** that was not ended cleanly — user navigated away without hanging up, or the app was killed mid-call.
- **Fix**:
```dart
// ✅ CAUSE (a) — single-init guard at app boot
bool _callsInitDone = false;
Future<void> initCallsOnce(CallAppSettings settings) async {
if (_callsInitDone) return;
await CometChatUIKitCalls.init(settings);
_callsInitDone = true;
}
// ✅ CAUSE (b) — clean up the stale session via the UIKit-namespaced API.
// The method is endSession (NOT endCall) and takes named callbacks, no sessionId
// — verified vs cometchat_uikit_calls.dart:236.
await CometChatUIKitCalls.endSession(
onSuccess: (_) {},
onError: (e) => debugPrint('endSession failed: $e'),
);
// ❌ WRONG — bare CometChat.endCall is the Chat SDK API, not the calls cleanup
CometChat.endCall(sessionId, onSuccess: ..., onError: ...);
```
### 4.3 "CallManager not found" / "Calling module not found"
- **Symptom**: Android native error `CallManager not found` or `CometChat Calling module not found`.
- **Cause**: The CometChat Calling native module is not properly linked on Android. This can happen with ProGuard stripping, missing dependencies, or build configuration issues.
- **Fix**:
1. Ensure ProGuard keep rules are in place (see Section 6.1)
2. Verify `cometchat_chat_uikit` is properly added to `pubspec.yaml`
3. Run `flutter clean` and rebuild
4. Check that `android.enableJetifier=true` is in `gradle.properties`
### 4.4 "startSession null" on Android
- **Symptom**: `startSession` returns null on Android with no error feedback. The call screen may appear blank or stuck.
- **Cause**: Known Android SDK issue where `startSession` silently fails. A 5-second timeout workaround exists but provides no error feedback.
- **Fix**: This is a known SDK-level issue. Workarounds:
1. Implement a timeout wrapper around `startSession` calls
2. Show a retry option to the user if the call screen doesn't load within 5 seconds
3. Check for updates to `cometchat_calls_sdk` that may fix this
### 4.5 Incoming call not received
- **Symptom**: Incoming calls are not shown to the receiver. The caller sees the outgoing call screen but the receiver gets nothing.
- **Cause**: Multiple possible causes:
1. `subscriptionType` not set (presence/events disabled)
2. Push notification / VoIP setup incomplete
3. Call listeners not registered
4. App is in background without proper background handling
- **Fix**:
1. Ensure `subscriptionType` is set to `CometChatSubscriptionType.allUsers`
2. Verify FCM/APNs push notification setup for background calls
3. Check that call event listeners are registered
4. For cross-platform issues (Android↔iOS↔React), verify all platforms are on compatible SDK versions
### 4.6 Calls SDK not re-initialized after logout
- **Symptom**: After logout and re-login, calls don't work. Call screens may be blank or throw errors.
- **Cause**: The Calls SDK maintains its own session state. After `CometChatUIKit.logout()`, the Calls SDK session is invalidated but may not be properly re-initialized on the next login.
- **Fix**: Ensure the Calls SDK is re-initialized after login. The UIKit handles this internally — if you're managing calls manually, call the Calls SDK init after each successful login.
### 4.7 Outgoing call screen never renders / app shows nothing after tapping call (V6 navigatorKey trap)
- **Symptom**: Caller taps the call button. The peer rings (server received the call). The caller's Flutter app shows **nothing** — no outgoing-call screen, no error in `onSuccess`/`onError`. `CometChat.initiateCall` returns successfully with a valid `sessionId`, but no UI ever appears.
- **Cause**: `MaterialApp` is missing `navigatorKey: CallNavigationContext.navigatorKey`. The kit's `CometChatCallButtons` and outgoing-call flow navigate via `CallNavigationContext.navigatorKey.currentContext` — which is `null` until the app's `MaterialApp` is wired to that key. The failure is silent because `initiateCall` itself succeeds; only the *navigation* to the outgoing-call screen fails. **Important**: the vendor's own 6.0.1 sample app is missing this line, so customers who copied `main.dart` verbatim will hit this bug. This is the single most common customer-blocking V6 calls trap.
- **Fix**: Wire `CallNavigationContext.navigatorKey` on the root `MaterialApp`:
```dart
// ✅ CORRECT — navigatorKey wired on MaterialApp
import 'package:flutter/material.dart';
import 'package:cometchat_chat_uikit/cometchat_calls_uikit.dart'
show CallNavigationContext; // calls is a sub-library of cometchat_chat_uikit — there is NO separate cometchat_calls_uikit package in v6
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: CallNavigationContext.navigatorKey, // REQUIRED for V6 calls
home: const HomeScreen(),
);
}
}
// ❌ WRONG — no navigatorKey; outgoing-call screen never appears
return MaterialApp(
home: const HomeScreen(),
);
```
See `cometchat-flutter-v6-calls` §1.7 for the canonical wiring rule.
### 4.8 Stuck on "Calling…" after peer accepts (v6.0.0-beta2 BLoC bug — fixed in 6.0.1)
- **Symptom**: Outgoing call screen displays correctly, peer accepts the call, but the caller's screen stays stuck on "Calling…" and never transitions to the in-call surface. Audio/video may already be flowing in the background; only the UI state is wrong.
- **Cause**: A known BLoC transition bug in `cometchat_chat_uikit ^6.0.0-beta2` where the outgoing → in-call state never fires. **This is FIXED in 6.0.1 GA.**
- **Fix**: Upgrade to `cometchat_chat_uikit ^6.0.1` (or the latest 6.x):
```yaml
# pubspec.yaml
dependencies:
cometchat_chat_uikit: ^6.0.1 # was ^6.0.0-beta2
```
Then run:
```bash
flutter pub get
flutter clean
flutter run
```
If the bug persists after upgrade, verify Section 4.7 (`navigatorKey` is still required on 6.0.1).
---
## 5. Listener Issues
### 5.1 Duplicate events (hardcoded listener IDs)
- **Symptom**: Event handlers fire multiple times for a single event. Messages appear twice, typing indicators flicker.
- **Cause**: Listener registered with a hardcoded ID. When the widget is recreated (e.g., navigation), the new listener overwrites the old one but the old widget's handler may still be referenced, or multiple instances collide.
- **Fix**: Use a unique listener ID per widget instance:
```dart
// ✅ CORRECT — unique ID per instance
class _MyScreenState extends State<MyScreen> with MessageListener {
late final String _listenerId;
@override
void initState() {
super.initState();
_listenerId = 'my_screen_${DateTime.now().millisecondsSinceEpoch}';
CometChat.addMessageListener(_listenerId, this);
}
@override
void dispose() {
CometChat.removeMessageListener(_listenerId);
super.dispose();
}
}
// ❌ WRONG — hardcoded ID causes collisions across instances
CometChat.addMessageListener('messages', this); // Collision!
```
### 5.2 Listener leaks (missing dispose)
- **Symptom**: Memory usage grows over time. Events fire on screens that are no longer visible. App becomes sluggish.
- **Cause**: SDK listeners registered in `initState()` but not removed in `dispose()`.
- **Fix**: Always remove listeners with the same ID used to register:
```dart
@override
void dispose() {
CometChat.removeMessageListener(_listenerId);
CometChat.removeUserListener(_listenerId);
CometChat.removeGroupListener(_listenerId);
CometChat.removeCallListener(_listenerId);
super.dispose();
}
```
### 5.3 No events firing (subscriptionType not set)
- **Symptom**: All listeners are properly registered and removed, but no events ever fire. No errors in console.
- **Cause**: `subscriptionType` not set in `UIKitSettingsBuilder`. This silently disables all real-time events.
- **Fix**: Set `subscriptionType` during init:
```dart
UIKitSettingsBuilder()
..subscriptionType = CometChatSubscriptionType.allUsers
```
---
## 6. Build Errors
### 6.0 `pub get` can't resolve `cometchat_chat_uikit` ^6.x / resolves a beta
- **Symptom**: `flutter pub get` fails to find `cometchat_chat_uikit ^6.0.x`, or pulls a `6.0.0-beta` instead of the GA.
- **Cause**: Wrong package source. **The v6 GA is on pub.dev**; Cloudsmith hosts only the beta + legacy V5.
- **Fix**: Use the default pub.dev source — `dependencies: cometchat_chat_uikit: ^6.0.2` (no `hosted:` block). Only add the Cloudsmith `hosted:` URL if you are intentionally on a beta/V5. (V6 calls fold into this one package — there is no separate `cometchat_calls_uikit` package on v6; calls types come from the `package:cometchat_chat_uikit/cometchat_calls_uikit.dart` sub-library.)
### 6.05 Push token never registers / looking for `PNRegistry`
- **Symptom**: Push notifications never arrive; code references a `PNRegistry` class that won't import.
- **Cause**: `PNRegistry` is **not** a kit/SDK symbol — it's a copy-in **V5 sample-app extension** (`extension PNRegistry on CometChatService`), not exported by any `cometchat_*` package.
- **Fix**: The real push API is `CometChatNotifications.registerPushToken(PushPlatforms.FCM_FLUTTER_ANDROID, fcmToken: token, providerId: ...)` (+ `FCM_FLUTTER_IOS` / `APNS_FLUTTER_DEVICE` / `APNS_FLUTTER_VOIP`) — call it AFTER login, and `unregisterPushToken(...)` on logout. See `cometchat-flutter-v6-push`.
### 6.1 Android: ClassNotFoundException (missing ProGuard rules)
- **Symptom**: Release build crashes with `ClassNotFoundException` for CometChat classes. Debug builds work fine.
- **Cause**: R8/ProGuard strips CometChat SDK classes during release minification.
- **Fix**: Create `android/app/proguard-rules.pro` with:
```
# CometChat — prevent R8 from stripping SDK classes
-keep class com.cometchat.** { *; }
-keep interface com.cometchat.** { *; }
# Suppress warnings for Calls SDK classes referenced cross-module
-dontwarn com.cometchat.calls.CometChatRTCView$CometChatRTCViewBuilder
-dontwarn com.cometchat.calls.CometChatRTCView
-dontwarn com.cometchat.calls.CometChatRTCViewListener
-dontwarn com.cometchat.calls.model.AnalyticsSettings
-dontwarn com.cometchat.calls.model.RTCCallback
-dontwarn com.cometchat.calls.model.RTCReceiver
```
Reference it in `android/app/build.gradle`:
```kotlin
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
```
### 6.2 Android: minSdk too low
- **Symptom**: Build fails with error about minimum SDK version. Error mentions `minSdkVersion` incompatibility.
- **Cause**: `minSdk` is set below 26. The `cometchat_calls_sdk` requires minSdk 26.
- **Fix**: In `android/app/build.gradle` (or `.kts`):
```kotlin
defaultConfig {
minSdk = 26 // Required by cometchat_calls_sdk
}
```
### 6.3 Android: Jetifier missing
- **Symptom**: Build fails with errors about Android Support Library classes not found, or `androidx` conflicts.
- **Cause**: `android.enableJetifier=true` not set. Transitive dependencies from the CometChat SDK use old Android Support Library references.
- **Fix**: In `android/gradle.properties`:
```properties
android.useAndroidX=true
android.enableJetifier=true
```
### 6.4 iOS: pod install failures
- **Symptom**: `pod install` fails with dependency resolution errors, version conflicts, or missing pods.
- **Cause**: Cocoapods cache is stale, or the Podfile needs updating.
- **Fix**:
```bash
cd ios
rm -rf Pods Podfile.lock
pod repo update
pod install --repo-update
cd ..
flutter clean
flutter pub get
```
If still failing, check that the iOS deployment target in `ios/Podfile` is high enough:
```ruby
platform :ios, '13.0' # Minimum for CometChat
```
### 6.5 iOS: missing permissions
- **Symptom**: App crashes or shows blank screen when trying to access camera, microphone, or photo library on iOS.
- **Cause**: Required permission descriptions missing from `Info.plist`.
- **Fix**: Add to `ios/Runner/Info.plist`:
```xml
<key>NSCameraUsageDescription</key>
<string>Camera access is needed for video calls and sending photos</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is needed for voice and video calls</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Photo library access is needed for sending images</string>
```
For VoIP calls, also add:
```xml
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
<string>remote-notification</string>
</array>
```
### 6.6 Android: KGP "legacy plugin application" warning (benign)
- **Symptom**: `flutter build apk` / `flutter run` prints a warning that the CometChat plugins apply the Kotlin Gradle Plugin the legacy way (e.g. *"The Kotlin Gradle plugin was loaded multiple times…"* / legacy-plugin-application deprecation from both `cometchat_chat_uikit` and `cometchat_calls_sdk`).
- **Cause**: kit-side — the plugins haven't migrated to the declarative `plugins {}` KGP application. It's emitted by the kit, not your project.
- **Fix**: **None needed — this is a warning, not an error.** The build still succeeds (verified — real `flutter build apk --debug`). Don't try to "fix" it in your app; it clears when the kit updates its Gradle plugin wiring.
---
## 7. Performance Issues
### 7.1 Theme lookup in build() causing jank
- **Symptom**: Dropped frames during scrolling or keyboard animation. Flutter DevTools shows long build times (44–95ms).
- **Cause**: `CometChatThemeHelper.getColorPalette(context)` and similar calls in `build()` do expensive InheritedWidget traversal on every rebuild.
- **Fix**: Cache theme values in `didChangeDependencies()` — see Section 3.5 for the full pattern. For child widgets, pass pre-cached theme values from the parent:
```dart
// Parent passes cached values to children
CometChatImageBubble(
imageUrl: message.attachment?.fileUrl,
colorPalette: _colorPalette, // Pre-cached from parent
spacing: _spacing, // Pre-cached from parent
);
```
### 7.2 Missing buildWhen optimization
- **Symptom**: Entire widget tree rebuilds on every BLoC state change, even when only a small part of the state changed.
- **Cause**: `BlocConsumer` or `BlocBuilder` without `buildWhen` — rebuilds on every state emission.
- **Fix**: Add `buildWhen` to limit rebuilds to relevant state changes:
```dart
BlocConsumer<MessageComposerBloc, MessageComposerState>(
buildWhen: (previous, current) =>
previous.isEditMode != current.isEditMode ||
previous.isReplyMode != current.isReplyMode ||
previous.isRecordingMode != current.isRecordingMode ||
previous.editMessage != current.editMessage ||
previous.replyMessage != current.replyMessage,
listener: (context, state) { /* still receives ALL state changes */ },
builder: (context, state) { /* only rebuilds when buildWhen is true */ },
)
```
### 7.3 O(n) lookups instead of O(1)
- **Symptom**: Slow scrolling in long message lists. `findChildIndexCallback` takes too long.
- **Cause**: Using `list.indexWhere()` (O(n)) to find messages instead of a Map-based O(1) lookup.
- **Fix**: Maintain a `Map<int, int>` alongside the message list for O(1) index lookups:
```dart
// In BLoC — maintain O(1) lookup map
final Map<int, int> _messageIndexMap = {};
int? findMessageIndex(int messageId) => _messageIndexMap[messageId];
// In SliverAnimatedList
SliverAnimatedList(
findChildIndexCallback: (Key key) {
if (key is ValueKey<int>) {
final index = widget.findMessageIndex?.call(key.value) ??
_messages.indexWhere((m) => m.id == key.value);
if (index != -1) return visualPosition(index);
}
return null;
},
)
```
---
## 8. Platform-Specific Issues
### 8.1 Android-specific
| Symptom | Cause | Fix |
|---------|-------|-----|
| Release crash `ClassNotFoundException` | Missing ProGuard rules | Add `-keep class com.cometchat.** { *; }` — see Section 6.1 |
| Build fail `minSdk` | minSdk < 26 | Set `minSdk = 26` in `build.gradle` |
| Build fail support library | Missing Jetifier | Add `android.enableJetifier=true` to `gradle.properties` |
| `startSession` returns null | Known Calls SDK issue | Implement timeout + retry — see Section 4.4 |
| `CallManager not found` | Native module not linked | Clean build + verify ProGuard + Jetifier — see Section 4.3 |
| Audio recording stuck after permission | Permission callback race | Ensure permission is granted before starting recording; handle the permission result callback properly |
### 8.2 iOS-specific
| Symptom | Cause | Fix |
|---------|-------|-----|
| Pod install fails | Stale cache or version conflict | `rm -rf Pods Podfile.lock && pod install --repo-update` |
| Camera/mic crash | Missing `Info.plist` permissions | Add `NSCameraUsageDescription`, `NSMicrophoneUsageDescription` — see Section 6.5 |
| Media not sending | File access or permission issue | Verify `NSPhotoLibraryUsageDescription` in Info.plist; check file picker permissions |
| App crash on iPhone 11 | Device-specific compatibility | Check iOS deployment target ≥ 13.0; verify no 32-bit dependencies |
| VoIP calls not received in background | Missing background modes | Add `voip` and `remote-notification` to `UIBackgroundModes` in Info.plist |
### 8.3 Web-specific
| Symptom | Cause | Fix |
|---------|-------|-----|
| Runtime error on web | Platform-specific code without `kIsWeb` guard | Wrap platform-specific code with `if (!kIsWeb)` checks |
| Native plugins crash on web | Plugin not available on web | Use conditional imports or `kIsWeb` guards before calling native APIs |
| CORS errors | API calls blocked by browser | Ensure CometChat API endpoints are accessible; check proxy configuration |
```dart
// ✅ CORRECT — guard platform-specific code
import 'package:flutter/foundation.dart' show kIsWeb;
if (!kIsWeb) {
// Native-only code (e.g., push notifications, file system access)
setupPushNotifications();
}
// For conditional imports:
// lib/platform/native_service.dart — native implementation
// lib/platform/web_service.dart — web implementation
```
---
## Quick Reference: Error → Fix Table
| Error / Symptom | Section | One-Line Fix |
|----------------|---------|-------------|
| "Authentication null" | 2.1 | Call `CometChatUIKit.init()` before any usage |
| "APP ID null" | 2.2 | Set `..appId = 'YOUR_APP_ID'` in UIKitSettingsBuilder |
| ERR_ALREADY_LOGGED_IN | 2.3 | Check `CometChatUIKit.loggedInUser` before calling login |
| "Android internal error" | 2.4 | Verify credentials, UID existence, try stable SDK |
| Guard screen stuck on spinner | 2.5 | Use `CometChatUIKit.loggedInUser` synchronously after init |
| ERR_INVALID_REGION | 2.6 | Use lowercase: `'us'`, `'eu'`, `'in'` |
| StateError: not initialized | 2.7 | Call `ServiceLocator.instance.setup()` before creating BLoC |
| Double keyboard compensation (pre-6.0.1) | 3.1 | Upgrade kit to `^6.0.1` (composer clamps to `viewInsets`, ENG-34434); keep `resizeToAvoidBottomInset: true`. `false` is only an old-kit stopgap |
| No typing indicators / presence | 3.3 | Set `..subscriptionType = CometChatSubscriptionType.allUsers` |
| Theme jank during keyboard | 3.5 | Cache theme in `didChangeDependencies()`, not `build()` |
| Outgoing call screen never appears | 4.7 | Wire `navigatorKey: CallNavigationContext.navigatorKey` on `MaterialApp` |
| Stuck on "Calling…" after peer accepts | 4.8 | Upgrade `cometchat_chat_uikit` from `^6.0.0-beta2` to `^6.0.1` |
| Duplicate events | 5.1 | Use unique listener ID per widget instance |
| Listener leak | 5.2 | Remove listener in `dispose()` with same ID |
| ClassNotFoundException (release) | 6.1 | Add ProGuard keep rules for `com.cometchat.**` |
| minSdk too low | 6.2 | Set `minSdk = 26` |
| Jetifier missing | 6.3 | Add `android.enableJetifier=true` |
| Pod install failure | 6.4 | Delete Pods + Podfile.lock, `pod install --repo-update` |
| Missing iOS permissions | 6.5 | Add camera/mic/photo descriptions to Info.plist |
---
## Checklist — Every CometChat Integration
Use this checklist to verify your integration is correct:
- [ ] `CometChatUIKit.init()` called and awaited before any usage
- [ ] Auth check uses `CometChatUIKit.loggedInUser` after init (not `CometChat.getLoggedInUser()`)
- [ ] `subscriptionType` set in UIKitSettingsBuilder
- [ ] `region` is lowercase (`'us'`, `'eu'`, `'in'`)
- [ ] Scaffold hosting `CometChatMessageComposer` uses `resizeToAvoidBottomInset: true` (or omits it) on `^6.0.1` — composer clamps to `viewInsets` (ENG-34434); `false` is only the pre-6.0.1 stopgap
- [ ] Theme cached in `didChangeDependencies()`, not `build()`
- [ ] SDK listeners registered with unique ID, removed in `dispose()`
- [ ] Colors from `CometChatThemeHelper`, never hardcoded
- [ ] Strings from `Translations.of(context)`, never hardcoded
- [ ] If using calls: `MaterialApp` wires `navigatorKey: CallNavigationContext.navigatorKey` (required for V6 calls, including 6.0.1)
- [ ] If using calls on 6.0.0-beta2: upgrade to `cometchat_chat_uikit ^6.0.1` (fixes outgoing → in-call BLoC transition)
- [ ] Android: minSdk ≥ 26, Jetifier enabled, ProGuard rules added
- [ ] iOS: permissions in Info.plist, deployment target ≥ 13.0
- [ ] Web: `kIsWeb` guards on platform-specific code