Reference implementation
Browse the full push-notification sample (Flutter + native iOS glue) to diff or copy files.
What this guide covers
- CometChat dashboard setup (enable push, create APNs + optional VoIP/FCM providers) with screenshots.
- Apple + Firebase setup (entitlements, APNs key,
GoogleService-Info.plist). - Copying the sample notification stack and aligning package IDs/provider IDs.
- Native iOS glue (PushKit, CallKit, MethodChannel) plus Flutter wiring.
- Token registration, navigation from pushes, testing, and troubleshooting.
What you need first
- Apple Developer account with Push Notifications, Background Modes, and VoIP entitlements for your bundle ID.
- Firebase project with an iOS app configured (
GoogleService-Info.plistinside the Runner target) and Cloud Messaging enabled. - CometChat app credentials (App ID, Region, Auth Key) plus Push Notification extension enabled with at least an APNs provider (add VoIP and FCM providers if you use them).
- Flutter 3.24+ / Dart 3+, the latest CometChat UI Kit (
cometchat_chat_uikit) and Calls UI Kit (cometchat_calls_uikit) packages. - Physical iPhone or iPad for testing—simulators cannot receive VoIP pushes or present CallKit UI.
1. Enable push and add providers (CometChat Dashboard)
- Go to Notifications → Settings and enable Push Notifications.

- Click Add Credentials, choose APNs (and APNs VoIP if you want in-call pushes), upload your
.p8key or certificate, and copy each Provider ID.

- (Optional) Add an FCM provider if you plan to register FCM tokens on iOS.

CometChatConfig.
2. Prepare Apple + Firebase credentials
2.1 Apple Developer portal
- Generate an APNs Auth Key (
.p8) and note the Key ID and Team ID. - Enable Push Notifications plus Background Modes → Remote notifications and Voice over IP on the bundle ID.
- Create a VoIP Services certificate/key if you want separate credentials.
2.2 Firebase Console
- Register the same bundle ID and download
GoogleService-Info.plistintoios/Runner. - Enable Cloud Messaging and upload the APNs key under Project Settings → Cloud Messaging.

3. Local configuration file
Updatelib/cometchat_config.dart (or your own config file) so it exposes:
4. Bring the notification stack into Flutter
4.1 Copy lib/notifications
- Clone or download the sample once.
- Copy the entire
lib/notificationsdirectory (models, Android/iOS services, helpers) into your app. - Update the import prefixes (for example replace
package:flutter_application_demo/...with your own package name). Keeping the same folder names avoids manual refactors later.
4.2 Wire the entry points
lib/main.dart
- Initialize
SharedPreferencesClass, Firebase, andFlutterLocalNotificationsPluginbefore callingrunApp. - Store
NotificationLaunchHandler.pendingNotificationResponsewhen the app is opened by tapping a notification while terminated. - On iOS, call
APNSService.setupNativeCallListener(context)frominitStateso Flutter reacts when the native CallKit UI changes state.
lib/guard_screen.dart / lib/dashboard.dart (or your first screen after login)
- Ensure
CometChatUIKit.init()andCometChatUIKit.login()finish before rendering the dashboard. - Instantiate
APNSService(iOS only) and callapnsService.init(context)insideinitState. - Register CometChat UI + Calls listeners (
CometChatUIEventListener,CometChatCallEventListener, andCallListener) exactly once per session; the sample stores the listener IDs insideAPNSService. - Replay
NotificationLaunchHandler.pendingNotificationResponseafter the widget tree builds so taps from a killed app still navigate toMessagesScreen. - Forward lifecycle changes to
IncomingCallOverlay/BoolSingletonto hide stale overlays when the app resumes.
4.3 Align dependencies and configuration
Mirror the samplepubspec.yaml versions (update as needed when newer releases ship):
flutter pub get, then flutterfire configure if you still need to generate firebase_options.dart.
5. Configure the native iOS layer
5.1 Capabilities and Info.plist
- Open
ios/Runner.xcworkspacein Xcode. - Under Signing & Capabilities, enable Push Notifications and Background Modes (Remote notifications + Voice over IP).
- Add microphone, camera, bluetooth, and notification permission strings to
Info.plist. - Set the development team that has access to the APNs/VoIP keys you generated earlier.
5.2 AppDelegate.swift bridge
Start from the sample ios/Runner/AppDelegate.swift and keep these pieces intact:
- MethodChannel handshake – create a channel that both Flutter and Swift know:
getAppInfo, endCall, onCallAcceptedFromNative, and onCallEndedFromNative, mirroring the Dart side (APNSService.setupNativeCallListener).
- Firebase + plugin registration – call
FirebaseApp.configure()beforeGeneratedPluginRegistrant.register(with: self). - PushKit – instantiate
PKPushRegistry, setdesiredPushTypes = [.voIP], and forward the token insidepushRegistry(_:didUpdate:for:)viaSwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP(tokenHex). - CallKit – configure
CXProviderConfiguration, keep aCXCallController, and implementprovider(_:perform: CXAnswerCallAction)/provider(_:perform: CXEndCallAction)so native actions propagate to Flutter. - Incoming push handler – inside
pushRegistry(_:didReceiveIncomingPushWith:), convert the CometChat payload intoflutter_callkit_incoming.Data, setextrawith the raw payload, and callshowCallkitIncoming(..., fromPushKit: true). - UUID helper – reuse
createUUID(sessionid:)to produce validUUIDs from long CometChat session IDs; this lets CallKit correlate calls even if the payload string exceeds 32 characters.
APNSService.platform in Dart to match.
6. Token registration and runtime events
6.1 Standard APNs tokens
APNSService hooks into FirebaseMessaging.instance.getAPNSToken() (and onTokenRefresh) before calling:
CometChatConfig.apnProviderId.
6.2 VoIP tokens
- Capture the PushKit token in
AppDelegate.pushRegistry(_:didUpdate:for:). - Forward it to Flutter via the MethodChannel or register it directly from Swift by invoking
CometChatPushRegistrythroughSwiftFlutterCallkitIncomingPlugin. - If you keep the Dart implementation, emit a MethodChannel call named
onVoipTokenand handle it inAPNSServiceby callingCometChatPushRegistry.register(token: token, isFcm: false, isVoip: true);.
6.3 Local notifications and navigation
APNSService._showNotificationdisplays a local notification when the incoming CometChat message does not belong to the currently open conversation.LocalNotificationService.handleNotificationTapparses the payload, fetches the relevant user/group, and pushesMessagesScreen.NotificationLaunchHandler.pendingNotificationResponsecaches taps triggered while the app is terminated; replay it on the dashboard once the UI is ready.
6.4 Call events
FlutterCallkitIncoming.onEventis already wired insideAPNSServiceto accept or end calls initiated by CallKit.- When native CallKit UI accepts/ends a call, Swift invokes
onCallAcceptedFromNative/onCallEndedFromNativeon the MethodChannel;APNSServicethen callsFlutterCallkitIncoming.setCallConnectedorCometChat.endCall()to keep both stacks synchronized.
7. Testing checklist
- Run the app on a physical device in debug first. Grant notification, microphone, camera, and Bluetooth permissions when prompted.
- Send a message from another user:
- Foreground: a local notification banner shows (unless you are in that chat).
- Background: APNs notification appears, tapping opens the right conversation.
- Force-quit the app, send another message push, tap it, and confirm
NotificationLaunchHandlerlaunchesMessagesScreen. - Trigger an incoming CometChat call. Ensure:
- CallKit UI shows contact name, call type, and Accept/Decline.
- Accepting on the lock screen notifies Flutter (
setupNativeCallListener), starts the call session, and dismisses the native UI when the call ends.
- Decline the call and confirm both CallKit and Flutter clean up (
BoolSingletonresets, overlays dismissed). - Rotate through Wi-Fi/cellular and reinstall the app to confirm token registration works after refresh events.
8. Troubleshooting tips
| Symptom | Quick checks |
|---|---|
| No VoIP pushes | Entitlements missing? Ensure Push Notifications + Background Modes (VoIP) are enabled and the bundle ID matches the CometChat provider. |
| CallKit UI never dismisses | Make sure endCall(callUUID:) reports to CXProvider, runs a CXEndCallAction, and calls SwiftFlutterCallkitIncomingPlugin.sharedInstance?.endCall. |
| Flutter never receives native call events | Confirm the MethodChannel names match between Swift and Dart, and APNSService.setupNativeCallListener runs inside initState. |
| Token registration errors | Double-check CometChatConfig provider IDs, and verify you call registerPushToken after CometChatUIKit.login succeeds. |
| Notification taps ignored | Ensure you replay NotificationLaunchHandler.pendingNotificationResponse after the navigator key is ready (typically WidgetsBinding.instance.addPostFrameCallback). |