> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-new-flutter-push-notifications.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Android

> Add CometChat push notifications and VoIP calls to an Android app with the drop-in cometchat push-notifications-android SDK.

## What this guide covers

* Adding the `push-notifications-android` SDK and initializing it.
* Wiring your own Firebase Messaging service to forward payloads to the SDK.
* Requesting permission and registering the FCM token after login.
* Letting the SDK render chat notifications (grouped, inline reply) and full-screen VoIP calls.
* Handling notification taps and call events, and suppressing notifications for the open chat.
* Testing and troubleshooting.

<Info>
  The `push-notifications-android` SDK replaces the previous approach of copying the UI Kit sample's `fcm/` and `voip/` packages (`FCMService`, `FCMMessageNotificationUtils`, `FCMMessageBroadcastReceiver`, `CometChatVoIP`, `CometChatVoIPConnectionService`, and related helpers). Token registration, notification channels, stacking, avatars, inline reply, delivery receipts, the VoIP ConnectionService, the incoming-call screen, ring timeout, call-collision handling, and SDK auto-init on a killed-app wake are all handled inside the SDK. Your app keeps only a \~5-line Firebase Messaging service and three facade calls.
</Info>

## How it works

* **FCM's role:** Firebase issues the registration token and delivers the CometChat payload as a **data message**. The SDK does **not** depend on `firebase-messaging` — your app owns Firebase and passes the payload as a `Map<String, String>`.
* **CometChat's role:** The FCM provider you add in the dashboard binds your registered token to the logged-in user so CometChat can route pushes on your behalf.
* **The SDK's role:** `CometChatPushNotifications` parses the payload and decides chat vs call. Chat → builds/stacks notifications. Call → drives a full-screen incoming-call experience over an Android Telecom `SELF_MANAGED` `ConnectionService` (the same approach WhatsApp/Signal use — no `READ_PHONE_STATE`/`ANSWER_PHONE_CALLS` and no phone-account toggle in Settings).
* **Killed-app wake:** When FCM starts your process, `init()` in `Application.onCreate()` runs first and stores your credentials; `handlePushNotification(...)` then auto-initializes the Chat SDK before routing, so calls connect even from a terminated state.

## Prerequisites

* The FCM provider, Firebase project, and `google-services.json` from **[Getting Started](/notifications/push-getting-started)** (this guide assumes those are done).
* The CometChat **Chat SDK / UI Kit** already integrated (you call `CometChatUIKit.init()` / `login()` yourself).
* **minSdk 24+**, **compileSdk 36**, **Java 11**, and a Gradle/AGP version matching your UI Kit project.
* A physical device — background delivery and full-screen calls are unreliable on emulators.

<Info>
  **Complete the [Getting Started](/notifications/push-getting-started) guide first** — enable Push Notifications, add your FCM provider, and configure Firebase (`google-services.json` + service account JSON). This guide covers only the Android app wiring.
</Info>

## 1. Add the dependency

Add the CometChat Maven repository (the same one that serves the Chat and Calls SDKs) in `settings.gradle.kts`:

```kotlin settings.gradle.kts theme={null}
dependencyResolutionManagement {
  repositories {
    google()
    mavenCentral()
    maven("https://dl.cloudsmith.io/public/cometchat/cometchat/maven/")
  }
}
```

Add the SDK plus your own Firebase Messaging dependency in the app module. Apply the `google-services` plugin so `google-services.json` is picked up:

```kotlin app/build.gradle.kts theme={null}
plugins {
  id("com.android.application")
  id("org.jetbrains.kotlin.android")
  id("com.google.gms.google-services")
}

dependencies {
  implementation("com.cometchat:push-notifications-android:1.0.0")

  // Your app owns Firebase — the SDK does not depend on it.
  implementation(platform("com.google.firebase:firebase-bom:34.15.0"))
  implementation("com.google.firebase:firebase-messaging")
}
```

<Note>
  You do **not** need to add notification, full-screen-intent, foreground-service, `WAKE_LOCK`, or `MANAGE_OWN_CALLS` permissions, or declare the incoming-call activity / VoIP services in your `AndroidManifest.xml`. The SDK's manifest declares everything it needs and Gradle merges it into your app automatically.
</Note>

## 2. Store your credentials

Keep the values from Getting Started where your app can read them:

```kotlin AppCredentials.kt theme={null}
object AppCredentials {
    const val APP_ID = "YOUR_APP_ID"
    const val REGION = "YOUR_REGION"
    const val AUTH_KEY = "YOUR_AUTH_KEY"
    const val FCM_PROVIDER_ID = "FCM-PROVIDER-ID"
}
```

## 3. Initialize the SDK

Initialize in `Application.onCreate()` so the SDK is ready before any push arrives (including killed-app wakes). Build the config with `PNConfiguration.Builder(appId, region)`:

```kotlin MyApplication.kt theme={null}
import android.app.Application
import com.cometchat.pushnotification.CometChatPushNotifications
import com.cometchat.pushnotification.PNConfiguration

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        // Initialize the CometChat UI Kit / Chat SDK first (your existing setup) …

        val config = PNConfiguration.Builder(AppCredentials.APP_ID, AppCredentials.REGION)
            .setNotificationSmallIcon(R.drawable.ic_notification)
            .setVoIPEnabled(true)
            .build()

        CometChatPushNotifications.init(this, config)
    }
}
```

Point `<application android:name>` at `MyApplication` in your manifest.

## 4. Forward FCM payloads to the SDK

Create your own `FirebaseMessagingService`. Forward each data message to `handlePushNotification(...)` and each token to `handleTokenRefresh(...)`:

```kotlin AppFCMService.kt theme={null}
import com.cometchat.pushnotification.CometChatPushNotifications
import com.cometchat.pushnotification.models.PushPlatform
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

class AppFCMService : FirebaseMessagingService() {
    override fun onMessageReceived(message: RemoteMessage) {
        CometChatPushNotifications.handlePushNotification(this, data = message.data)
    }

    override fun onNewToken(token: String) {
        // Re-binds a rotated token when a user is logged in; no-op otherwise.
        CometChatPushNotifications.handleTokenRefresh(
            PushPlatform.FCM_ANDROID,
            token,
            AppCredentials.FCM_PROVIDER_ID,
        )
    }
}
```

Register the service in your manifest:

```xml AndroidManifest.xml theme={null}
<service
    android:name=".AppFCMService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>
```

<Note>
  `handlePushNotification` also accepts optional `title`, `body`, `icon`, `uid`, and `guid` overrides — pass `uid`/`guid` if you want to control the notification grouping key. For the default experience, just pass `data`.
</Note>

## 5. Request permission and register the token

Request `POST_NOTIFICATIONS` (Android 13+) early using the SDK helper, and register the token **after** login so it binds to the session:

```kotlin theme={null}
import com.cometchat.pushnotification.helpers.CometChatPNHelper

// In your entry activity, before/at login:
if (!CometChatPNHelper.hasNotificationPermission(this)) {
    CometChatPNHelper.requestNotificationPermission(this, REQUEST_CODE_NOTIFICATIONS)
}
```

```kotlin theme={null}
import com.cometchat.pushnotification.CometChatPushNotifications
import com.cometchat.pushnotification.models.PushPlatform
import com.google.firebase.messaging.FirebaseMessaging

// After CometChatUIKit.login(...) succeeds:
FirebaseMessaging.getInstance().token.addOnSuccessListener { token ->
    CometChatPushNotifications.registerToken(
        PushPlatform.FCM_ANDROID,
        token,
        AppCredentials.FCM_PROVIDER_ID,
        onSuccess = { /* token registered */ },
        onError = { e -> /* log e */ },
    )
}
```

Unregister **before** logout so the device stops receiving pushes for that user:

```kotlin theme={null}
CometChatPushNotifications.unregisterToken(
    onSuccess = { /* then CometChatUIKit.logout(...) */ },
    onError = { e -> /* log e */ },
)
```

## 6. Notification taps and call events

Suppress notifications for the chat that is currently open, and set the tap listener so you can navigate when a chat notification is tapped:

```kotlin theme={null}
import com.cometchat.pushnotification.CometChatPushNotifications
import com.cometchat.pushnotification.listeners.NotificationTapListener

// When a chat screen opens (clear it on exit):
CometChatPushNotifications.setCurrentOpenChatId(conversationId)

CometChatPushNotifications.setOnNotificationTapListener(object : NotificationTapListener {
    override fun onNotificationTapped(
        context: Context,
        user: User?,
        group: Group?,
        message: BaseMessage?,
    ) {
        // Build your own Intent to open the conversation for `user` / `group`.
    }
})
```

By default the SDK shows its **built-in full-screen incoming-call screen** and launches the CometChat Calls UI on accept — you don't need to write any call UI. Optionally, observe foreground call events to drive your own in-app UI:

```kotlin theme={null}
import com.cometchat.pushnotification.listeners.CallEventListener
import com.cometchat.pushnotification.models.PNCallInfo

CometChatPushNotifications.setCallEventListener(object : CallEventListener {
    override fun onIncomingCall(callInfo: PNCallInfo) { /* callInfo.sessionId, callerName, callType … */ }
    override fun onCallCancelled(sessionId: String) { /* tear down UI */ }
})
```

<Note>
  To fully replace the built-in call screen with your own, set `setOnIncomingCallHandler(...)` (override the ringing screen) and/or `setOnCallAnsweredHandler(...)` (override the post-accept ongoing-call screen). The SDK still manages ringtone, ring timeout, and cleanup.
</Note>

## 7. Badge count

CometChat's Enhanced Push Notification payload includes an `unreadMessageCount` field (a string, total unread across all conversations). Enable it once on the dashboard: **CometChat Dashboard → Notification Engine → Settings → Preferences → Push Notification Preferences → Unread Badge Count**.

Parse it from the payload and set the app-icon badge with a launcher badge library such as `ShortcutBadger`:

```kotlin theme={null}
val count = message.data["unreadMessageCount"]?.toIntOrNull() ?: 0
ShortcutBadger.applyCount(applicationContext, count) // 0 clears the badge
```

Clear the badge when the app resumes (`onResume` of your main activity).

## 8. Testing checklist

1. Install on a physical device and grant notification + mic permissions (Android 13+ needs `POST_NOTIFICATIONS`).
2. Log in and confirm token registration succeeds (check the `registerToken` success callback / Logcat).
3. Send a message from another user:
   * App open in a different chat: notification appears (grouped, with inline reply).
   * App backgrounded/killed: notification appears; tapping opens the right conversation via `onNotificationTapped`.
   * No notification for the chat currently open (via `setCurrentOpenChatId`).
4. Trigger an incoming CometChat call and confirm the full-screen call UI shows the caller with Accept/Decline, even on the lock screen; Accept joins the call, Decline rejects it.
5. Toggle Wi-Fi/cellular and reinstall to confirm token registration survives refreshes (`onNewToken` → `handleTokenRefresh`).

## 9. Troubleshooting

| Symptom                              | Quick checks                                                                                                                                                                                                                          |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| No notifications received            | Confirm `google-services.json` is in the app module, the package name matches Firebase, `POST_NOTIFICATIONS` is granted (Android 13+), and your `FirebaseMessagingService` calls `handlePushNotification(this, data = message.data)`. |
| Token registration errors            | Verify `FCM_PROVIDER_ID` matches the dashboard exactly and that `registerToken` runs **after** `login` succeeds.                                                                                                                      |
| Nothing happens on a killed-app push | Ensure `CometChatPushNotifications.init(...)` runs in `Application.onCreate()` and `<application android:name>` points at your `Application` subclass.                                                                                |
| Full-screen call UI not showing      | Test on a physical device; on aggressive OEM skins (MIUI/Redmi/POCO), grant autostart/lock-screen/overlay permissions for the app.                                                                                                    |
| Pushes stop after some time          | Make sure `onNewToken` forwards to `handleTokenRefresh` (or re-`registerToken`) — FCM rotates tokens.                                                                                                                                 |

## Resources

<CardGroup cols={2}>
  <Card title="push-notifications-android" icon="cube" href="https://dl.cloudsmith.io/public/cometchat/cometchat/maven/">
    The drop-in push & VoIP SDK on the CometChat Maven repo.
  </Card>

  <Card title="SDK source" icon="github" href="https://github.com/cometchat/push-notifications-sdk-android">
    Source, changelog, and sample.
  </Card>
</CardGroup>
