---
source_url: https://www.pubnub.com/docs/integrations/mobile-push-notifications/send-push-notifications-android
title: Send push notifications on Android
updated_at: 2026-09-30T07:20:08.000Z
---

# Send push notifications on Android

## Documentation index

To discover more PubNub resources:

1. Fetch [PubNub's llms.txt](https://www.pubnub.com/llms-full.txt) for a list of available pages in Markdown format.
2. Identify relevant URLs from that index.
3. Fetch the target pages.

Do not assume a path exists, always check the index first.

In this tutorial, we make a PubNub message arrive on an Android device as a system notification. We get a Firebase Cloud Messaging (FCM) registration token from the device, then register that token on one PubNub channel with [Mobile Push Notifications](https://www.pubnub.com/docs/integrations/mobile-push-notifications/overview.md). We publish a message carrying an FCM push payload to the same channel, and watch the notification appear in the status bar. Every step needs a device or emulator that has Google Play services, because FCM won't issue a registration token without it.

## Before you begin

You need:

* An Android Studio project with the PubNub Kotlin or Java SDK already added. If you haven't added it yet, follow [Quickstart](https://www.pubnub.com/docs/getting-started/quickstart.md) first, in Kotlin or Java, and come back here.
* A PubNub keyset. A keyset is the set of publish, subscribe, and secret keys that identifies your application to the PubNub network. You'll need its publish key and subscribe key. If you don't have a keyset yet, follow [Set up your account](https://www.pubnub.com/docs/architecture/authentication/set-up-your-account.md) to create one.
* A Firebase project. Create one in the [Firebase console](https://console.firebase.google.com) with **Create a project**, then add your Android app to it so Firebase knows its package name.
* An Android device, or an emulator image that includes Google Play services. Emulator images without the Play Store can't run FCM.

We'll use one channel throughout, called `push-tutorial`, and one device.

## Give PubNub your Firebase credentials

PubNub sends the notification to FCM on your behalf, so it needs credentials for your Firebase project. Those credentials are a service-account private key file that you generate in Firebase and upload to your keyset. This is a one-time setup task per keyset.

First, create the service account and download its key:

1. In the [Firebase console](https://console.firebase.google.com), open your project.
2. Click the settings icon next to **Project Overview** and select **Project settings**.
3. Open the **Service accounts** tab.
4. Under **All service accounts**, click the link that opens the Google Cloud Platform IAM page for the project. The default Firebase service account has near-admin privileges over the whole project, and PubNub only needs to send messages, so create a dedicated account instead.
5. Create a new service account, and give it the [Firebase Cloud Messaging API Admin](https://cloud.google.com/iam/docs/roles-permissions/firebasecloudmessaging) role. Click **Done**.
6. Back in the Firebase console **Service accounts** tab, open the new service account and click **Generate new private key**. Firebase downloads a JSON private key file. Keep it somewhere you can find it again.

Now hand that key to PubNub:

1. Open the [Admin Portal](https://admin.pubnub.com) and select the app and keyset you'll use for this tutorial.
2. Find the **Mobile Push Notifications** section and enable it.
3. In the **Firebase Cloud Messaging** part of that section, use **Private key file** to upload the JSON file you just downloaded.
4. Save the keyset.

Notice that this configuration lives on the keyset, not on a channel. Every channel on this keyset now pushes through this one Firebase project.

## Connect the app to Firebase

Your app needs the Firebase configuration file and the FCM library.

1. In the Firebase console, go to **Project settings** > **Your apps**, select your Android app, and download `google-services.json`.
2. In Android Studio, switch the **Project** window to the **Project** view, and drop `google-services.json` into your app module's root directory, next to the module's `build.gradle.kts` file.
3. Add the `google-services` Gradle plugin and the Firebase Cloud Messaging dependency. The Gradle mechanics aren't PubNub-specific, so follow Firebase's own [Add Firebase to your Android project](https://firebase.google.com/docs/android/setup#add-config-file) and add the `firebase-messaging` library.
4. Sync the project.

If the sync fails complaining that `google-services.json` is missing, the file is in the wrong directory. It belongs in the app module, not the project root.

## Get the device's FCM registration token

FCM identifies a single installation of your app on a single device by a registration token. That token is what you register with PubNub, so this is the first thing your app needs.

Declare two things in `AndroidManifest.xml`: permission to post notifications, which Android 13 and later require, and the service that receives token updates.

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    <application>

        <service
            android:name=".MyFirebaseMessagingService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

    </application>
</manifest>
```

Now ask for the token in your activity. We do this in `onCreate` so it runs every time the app starts, and we ask for the notification permission in the same place. The code blocks in this tutorial show class members rather than whole files, so let Android Studio add the missing imports as you paste them. The [complete files](#complete-files) are at the end of this page.

### Java

```java
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "PushTutorial";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            ActivityCompat.requestPermissions(
                    this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, 1);
        }

        FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> {
            if (!task.isSuccessful()) {
                Log.w(TAG, "Fetching FCM registration token failed", task.getException());
                return;
            }
            String token = task.getResult();
            Log.d(TAG, "FCM registration token: " + token);
        });
    }
}
```

### Kotlin

```kotlin
class MainActivity : AppCompatActivity() {
    private val tag = "PushTutorial"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            ActivityCompat.requestPermissions(
                this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 1
            )
        }

        FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
            if (!task.isSuccessful) {
                Log.w(tag, "Fetching FCM registration token failed", task.exception)
                return@addOnCompleteListener
            }
            Log.d(tag, "FCM registration token: ${task.result}")
        }
    }
}
```

FCM can also replace a token later, for example after the user reinstalls or clears the app's data. When that happens, FCM calls `onNewToken` on the service you declared in the manifest. Create that class now:

### Java

```java
public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private static final String TAG = "PushTutorial";

    @Override
    public void onNewToken(@NonNull String token) {
        Log.d(TAG, "FCM issued a new registration token: " + token);
    }
}
```

### Kotlin

```kotlin
class MyFirebaseMessagingService : FirebaseMessagingService() {
    private val tag = "PushTutorial"

    override fun onNewToken(token: String) {
        Log.d(tag, "FCM issued a new registration token: $token")
    }
}
```

A replaced token invalidates the registration you made with the old one. A production app registers the new token here the same way you're about to register the first one, and removes the old registration. See [Available SDKs](https://www.pubnub.com/docs/getting-started/available-sdks.md) for the mobile push API reference for your platform.

Run the app now. In **Logcat**, filter on `PushTutorial`, and you should see a line like:

```text
FCM registration token: dK3f9...:APA91bH...
```

That long string is the token. If you see `Fetching FCM registration token failed` instead, the device has no Google Play services.

## Register the token on a PubNub channel

PubNub keeps a list of device tokens per channel name. Registering the token on `push-tutorial` is what tells PubNub to forward pushes from that channel to this device. Registration is per channel, so one call covers one channel.

Create the PubNub client and register the token you just received:

### Java

```java
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "PushTutorial";
    private static final String CHANNEL = "push-tutorial";

    private PubNub pubnub;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            PNConfiguration config = PNConfiguration
                    .builder(new UserId("push-tutorial-user"), "YOUR_SUBSCRIBE_KEY")
                    .publishKey("YOUR_PUBLISH_KEY")
                    .build();
            pubnub = PubNub.create(config);
        } catch (PubNubException exception) {
            Log.e(TAG, "PubNub initialization failed", exception);
            return;
        }

        // ... permission request and getToken() from step 3 ...
    }

    private void registerForPush(String token) {
        pubnub.addPushNotificationsOnChannels()
                .pushType(PNPushType.FCM)
                .deviceId(token)
                .channels(Collections.singletonList(CHANNEL))
                .async(result -> result
                        .onSuccess(value -> Log.d(TAG, "Registered for push on " + CHANNEL))
                        .onFailure(exception ->
                                Log.w(TAG, "Push registration failed", exception)));
    }
}
```

Call `registerForPush(token)` from the `getToken()` callback in step 3, right after the line that logs the token.

### Kotlin

```kotlin
class MainActivity : AppCompatActivity() {
    private val tag = "PushTutorial"
    private val channel = "push-tutorial"

    private lateinit var pubnub: PubNub

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val config = PNConfiguration
            .builder(UserId("push-tutorial-user"), "YOUR_SUBSCRIBE_KEY").apply {
                publishKey = "YOUR_PUBLISH_KEY"
            }.build()

        pubnub = PubNub.create(config)

        // ... permission request and token request from step 3 ...
    }

    private fun registerForPush(token: String) {
        pubnub.addPushNotificationsOnChannels(
            pushType = PNPushType.FCM,
            deviceId = token,
            channels = listOf(channel)
        ).async { result ->
            result
                .onSuccess { Log.d(tag, "Registered for push on $channel") }
                .onFailure { exception -> Log.w(tag, "Push registration failed", exception) }
        }
    }
}
```

Call `registerForPush(token)` from the token callback in step 3, right after the line that logs the token.

Replace `YOUR_PUBLISH_KEY` and `YOUR_SUBSCRIBE_KEY` with the keys from the keyset you configured in step 1. Push works only for the keyset that holds the Firebase private key, so keys from a different keyset produce a registration that never delivers anything.

`PNPushType.FCM` is what selects Firebase. The `deviceId` is the FCM registration token, not the Android device ID.

Run the app again. Logcat should now show, after the token line:

```text
Registered for push on push-tutorial
```

## Publish a message with an FCM push payload

A publish becomes a push notification when its payload contains a `pn_fcm` key. PubNub's push gateway reads that key, looks up the tokens registered on the channel, and forwards the request to FCM. Anything else in the message travels over pub/sub as usual.

This is the payload we're going to send, on the wire:

```json
{
  "pn_fcm": {
    "notification": {
      "title": "Chat Invitation",
      "body": "John invited you to chat"
    }
  }
}
```

The `title` and `body` are what the device displays. Keep the whole payload within the limit.

| Item | Limit |
| --- | --- |
| Push credentials per keyset | 1 APNs certificate and 1 FCM key |
| Push notification payload size | 2 KB for APNs, 4 KB for FCM |

The Kotlin and Java SDKs build that shape for you with `PushPayloadHelper`, so you don't assemble the JSON by hand. Add a method that builds the payload and publishes it:

### Java

```java
    private void publishPushMessage() {
        PushPayloadHelper.FCMPayloadV2.Notification notification =
                new PushPayloadHelper.FCMPayloadV2.Notification();
        notification.setTitle("Chat Invitation");
        notification.setBody("John invited you to chat");

        PushPayloadHelper.FCMPayloadV2 fcmPayload = new PushPayloadHelper.FCMPayloadV2();
        fcmPayload.setNotification(notification);

        PushPayloadHelper payloadHelper = new PushPayloadHelper();
        payloadHelper.setFcmPayloadV2(fcmPayload);

        Map<String, Object> payload = payloadHelper.build();

        pubnub.channel(CHANNEL).publish(payload)
                .async(result -> result
                        .onSuccess(value -> Log.d(TAG, "Published with push payload"))
                        .onFailure(exception -> Log.w(TAG, "Publish failed", exception)));
    }
```

### Kotlin

```kotlin
    private fun publishPushMessage() {
        val fcmPayload = PushPayloadHelper.FCMPayloadV2().apply {
            notification = PushPayloadHelper.FCMPayloadV2.Notification().apply {
                title = "Chat Invitation"
                body = "John invited you to chat"
            }
        }

        val payloadHelper = PushPayloadHelper().apply {
            fcmPayloadV2 = fcmPayload
        }

        val payload = payloadHelper.build()

        pubnub.channel(channel).publish(payload).async { result ->
            result
                .onSuccess { Log.d(tag, "Published with push payload") }
                .onFailure { exception -> Log.w(tag, "Publish failed", exception) }
        }
    }
```

`payloadHelper.build()` returns the map that matches the JSON above, with `pn_fcm` at the top level.

We need this publish to happen while the app is in the background. FCM [only puts a notification in the status bar](https://firebase.google.com/docs/cloud-messaging/android/receive) when the app isn't in the foreground, so call `publishPushMessage()` from `onStop()`, which Android runs as the activity leaves the screen:

### Java

```java
    @Override
    protected void onStop() {
        super.onStop();
        publishPushMessage();
    }
```

### Kotlin

```kotlin
    override fun onStop() {
        super.onStop()
        publishPushMessage()
    }
```

The device that publishes is also registered on `push-tutorial`, so it receives the push it just triggered. That's exactly what we want here. One device does everything, and you see the result.

## See the notification

1. Run the app on your physical device, or on an emulator image with Google Play services.
2. Tap **Allow** when Android asks whether the app may send notifications.
3. Watch Logcat and wait for `Registered for push on push-tutorial`. Don't skip this. If you background the app before registration finishes, there's no token on the channel yet and nothing to push to.
4. Press the device's Home button.

Within a second or two, a notification appears in the status bar:

```text
Chat Invitation
John invited you to chat
```

Pull down the notification shade to see it in full. Logcat also shows `Published with push payload`, which confirms the publish itself succeeded.

Try it again: open the app and press Home once more. The same notification arrives every time, because `onStop()` publishes again and the registration is still in place.

## What happened

Your device and your keyset played different parts in the same round trip:

1. Firebase gave the app a registration token that identifies this installation on this device.
2. Your app sent that token to PubNub with `addPushNotificationsOnChannels`, which associated the token with the channel `push-tutorial`.
3. Your app published a message to `push-tutorial` containing a `pn_fcm` key.
4. PubNub's push gateway spotted `pn_fcm`, looked up the tokens registered on `push-tutorial`, and found yours.
5. PubNub authenticated to FCM with the private key you uploaded in step 1 and forwarded the notification.
6. FCM delivered it to your device, and because the app was in the background, Android displayed it in the status bar.

Notice that nothing subscribed to `push-tutorial` in this tutorial. Push doesn't need an open connection, and that's the point of it. The notification reaches a device whose app isn't running in the foreground. For the full model, including what happens when a device is both subscribed and push-registered, see [Mobile push notifications](https://www.pubnub.com/docs/integrations/mobile-push-notifications/overview.md).

## Complete files

Both classes, with the imports they need.

### Java

`MainActivity.java`:

```java
import android.Manifest;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import com.google.firebase.messaging.FirebaseMessaging;
import com.pubnub.api.PubNubException;
import com.pubnub.api.UserId;
import com.pubnub.api.enums.PNPushType;
import com.pubnub.api.java.PubNub;
import com.pubnub.api.java.v2.PNConfiguration;
import com.pubnub.api.models.consumer.push.payload.PushPayloadHelper;

import java.util.Collections;
import java.util.Map;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "PushTutorial";
    private static final String CHANNEL = "push-tutorial";

    private PubNub pubnub;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            ActivityCompat.requestPermissions(
                    this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, 1);
        }

        try {
            PNConfiguration config = PNConfiguration
                    .builder(new UserId("push-tutorial-user"), "YOUR_SUBSCRIBE_KEY")
                    .publishKey("YOUR_PUBLISH_KEY")
                    .build();
            pubnub = PubNub.create(config);
        } catch (PubNubException exception) {
            Log.e(TAG, "PubNub initialization failed", exception);
            return;
        }

        FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> {
            if (!task.isSuccessful()) {
                Log.w(TAG, "Fetching FCM registration token failed", task.getException());
                return;
            }
            String token = task.getResult();
            Log.d(TAG, "FCM registration token: " + token);
            registerForPush(token);
        });
    }

    private void registerForPush(String token) {
        pubnub.addPushNotificationsOnChannels()
                .pushType(PNPushType.FCM)
                .deviceId(token)
                .channels(Collections.singletonList(CHANNEL))
                .async(result -> result
                        .onSuccess(value -> Log.d(TAG, "Registered for push on " + CHANNEL))
                        .onFailure(exception ->
                                Log.w(TAG, "Push registration failed", exception)));
    }

    private void publishPushMessage() {
        PushPayloadHelper.FCMPayloadV2.Notification notification =
                new PushPayloadHelper.FCMPayloadV2.Notification();
        notification.setTitle("Chat Invitation");
        notification.setBody("John invited you to chat");

        PushPayloadHelper.FCMPayloadV2 fcmPayload = new PushPayloadHelper.FCMPayloadV2();
        fcmPayload.setNotification(notification);

        PushPayloadHelper payloadHelper = new PushPayloadHelper();
        payloadHelper.setFcmPayloadV2(fcmPayload);

        Map<String, Object> payload = payloadHelper.build();

        pubnub.channel(CHANNEL).publish(payload)
                .async(result -> result
                        .onSuccess(value -> Log.d(TAG, "Published with push payload"))
                        .onFailure(exception -> Log.w(TAG, "Publish failed", exception)));
    }

    @Override
    protected void onStop() {
        super.onStop();
        publishPushMessage();
    }
}
```

`MyFirebaseMessagingService.java`:

```java
import android.util.Log;

import androidx.annotation.NonNull;

import com.google.firebase.messaging.FirebaseMessagingService;

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private static final String TAG = "PushTutorial";

    @Override
    public void onNewToken(@NonNull String token) {
        Log.d(TAG, "FCM issued a new registration token: " + token);
    }
}
```

### Kotlin

`MainActivity.kt`:

```kotlin
import android.Manifest
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import com.google.firebase.messaging.FirebaseMessaging
import com.pubnub.api.PubNub
import com.pubnub.api.UserId
import com.pubnub.api.enums.PNPushType
import com.pubnub.api.models.consumer.push.payload.PushPayloadHelper
import com.pubnub.api.v2.PNConfiguration

class MainActivity : AppCompatActivity() {
    private val tag = "PushTutorial"
    private val channel = "push-tutorial"

    private lateinit var pubnub: PubNub

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            ActivityCompat.requestPermissions(
                this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 1
            )
        }

        val config = PNConfiguration
            .builder(UserId("push-tutorial-user"), "YOUR_SUBSCRIBE_KEY").apply {
                publishKey = "YOUR_PUBLISH_KEY"
            }.build()

        pubnub = PubNub.create(config)

        FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
            if (!task.isSuccessful) {
                Log.w(tag, "Fetching FCM registration token failed", task.exception)
                return@addOnCompleteListener
            }
            val token = task.result
            Log.d(tag, "FCM registration token: $token")
            registerForPush(token)
        }
    }

    private fun registerForPush(token: String) {
        pubnub.addPushNotificationsOnChannels(
            pushType = PNPushType.FCM,
            deviceId = token,
            channels = listOf(channel)
        ).async { result ->
            result
                .onSuccess { Log.d(tag, "Registered for push on $channel") }
                .onFailure { exception -> Log.w(tag, "Push registration failed", exception) }
        }
    }

    private fun publishPushMessage() {
        val fcmPayload = PushPayloadHelper.FCMPayloadV2().apply {
            notification = PushPayloadHelper.FCMPayloadV2.Notification().apply {
                title = "Chat Invitation"
                body = "John invited you to chat"
            }
        }

        val payloadHelper = PushPayloadHelper().apply {
            fcmPayloadV2 = fcmPayload
        }

        val payload = payloadHelper.build()

        pubnub.channel(channel).publish(payload).async { result ->
            result
                .onSuccess { Log.d(tag, "Published with push payload") }
                .onFailure { exception -> Log.w(tag, "Publish failed", exception) }
        }
    }

    override fun onStop() {
        super.onStop()
        publishPushMessage()
    }
}
```

`MyFirebaseMessagingService.kt`:

```kotlin
import android.util.Log
import com.google.firebase.messaging.FirebaseMessagingService

class MyFirebaseMessagingService : FirebaseMessagingService() {
    private val tag = "PushTutorial"

    override fun onNewToken(token: String) {
        Log.d(tag, "FCM issued a new registration token: $token")
    }
}
```

## Troubleshooting

If no notification arrives:

* **The device or emulator has no Google Play services.** FCM depends on it. Logcat shows `Fetching FCM registration token failed` and there's no token to register. Use a physical device, or an emulator image listed with the Play Store.
* **You backgrounded the app before the registration succeeded.** Reopen the app, wait for `Registered for push on push-tutorial` in Logcat, then press Home. To confirm which channels a token is currently registered on, see [Check push device registration](https://www.pubnub.com/docs/integrations/mobile-push-notifications/check-push-device-registration.md).
* **FCM replaced the token.** If `onNewToken` logged a token that differs from the one you registered, the old registration is stale and PubNub is pushing to a token FCM no longer routes. Register the new token.
* **The keys and the Firebase credentials don't match.** The private key you uploaded in step 1 must come from the same Firebase project as the `google-services.json` in your app. The publish and subscribe keys in your code must also belong to the keyset you uploaded it to. A mismatch produces a successful publish and no notification.
* **You denied the notification permission.** On Android 13 and later, a denied `POST_NOTIFICATIONS` permission means the push arrives but nothing is displayed. Grant it in the app's system settings.
* **The app was in the foreground.** FCM hands a notification to your app instead of the status bar when the app is in the foreground. Press Home first.

If the publish succeeds and you still see nothing, ask PubNub what FCM said. [Debug push notification messages](https://www.pubnub.com/docs/integrations/mobile-push-notifications/debug-push-notification-messages.md) shows how to read the errors FCM returns to the push gateway.

## Next steps

You've delivered a PubNub message to an Android device as a push notification. From here:

* [Send push notifications on iOS](https://www.pubnub.com/docs/integrations/mobile-push-notifications/send-push-notifications-ios.md). Do the same thing for an iOS device through APNs.
* [Available SDKs](https://www.pubnub.com/docs/getting-started/available-sdks.md). Find the mobile push API reference for your platform.
* [Mobile push notifications](https://www.pubnub.com/docs/integrations/mobile-push-notifications/overview.md). The conceptual model behind the push gateway, including duplicate delivery, self-notification, and what can't trigger a push.
* [Check the FCM payload](https://www.pubnub.com/docs/integrations/mobile-push-notifications/check-fcm-payload.md). Shape `pn_fcm` for the behavior you want once a plain title and body isn't enough.
* [Debug push notification messages](https://www.pubnub.com/docs/integrations/mobile-push-notifications/debug-push-notification-messages.md). Read the `-pndebug` channel to see why a push failed.
* [Forward push errors and device removals to your endpoint](https://www.pubnub.com/docs/integrations/mobile-push-notifications/set-up-push-webhooks.md). Send push errors and device-removal events to your endpoint.
* [Check push device registration](https://www.pubnub.com/docs/integrations/mobile-push-notifications/check-push-device-registration.md). Confirm which channels a device token is registered on.
* [Test mobile push notifications externally](https://www.pubnub.com/docs/integrations/mobile-push-notifications/test-mobile-push-notifications-externally.md). Send a push straight through FCM to rule PubNub out of a delivery problem.

Last updated at: 2026-09-30T07:20:08.000Z
