Enable push notifications in an Expo app (Android)

This guide walks you through enabling push notifications in your Expo app on Android using the Acoustic Connect SDK and Firebase Cloud Messaging (FCM).

Language: TypeScript and JavaScript

Availability: Pro, Premium, and Ultimate

Scope: Test setup — building, running on a connected device or emulator, and verifying push delivery. For bare React Native, see Enable push notifications in a React Native app (Android). For production setup, see Move your React Native integration to production.

Sample app: See our GitHub repository for a reference implementation to compare your configuration against.


Prerequisites

  • A Firebase project with your Android app registered. If you do not have one, create it at console.firebase.google.com.
  • Connect app key that supports push notifications. Push requires an app key from a Mobile app integration created after April 2026. If your integration is older, ask your Connect administrator to create a new one and provide you with the new app key. For instructions, see Connect mobile apps in the Connect user guide.
  • Connect React Native SDK version 19.0.9 integrated in your Expo project. If you have not yet integrated the SDK, follow Integrate the Connect SDK into an Expo app first.

Overview

  1. Get your Firebase service account key.
  2. Share your Firebase credentials with your Connect administrator.
  3. Add google-services.json to your Expo project.
  4. Configure push notifications in your development project.
  5. Add a notification icon.
  6. Add code to request notification permission from your users.

Step 1: Generate a Firebase service account key

  1. In the Firebase console, open your project.
  2. Go to Project settings > Service accounts.
  3. Click Generate new private key and confirm. Firebase downloads a .json file to your computer.

Connect uses this file to authenticate with FCM on your behalf when sending push notifications. For more information, see Initialize the SDK in non-Google environments in the Firebase documentation.


Step 2: Share Firebase credentials with your Connect administrator

Share the following with your Connect administrator so they can enable push on your Mobile app integration.

CredentialWhere to find it
Service account keyThe .json file downloaded in Step 1
Package nameapp.jsonexpo.android.package

See Connect mobile apps in the Connect user guide.


Step 3: Add Firebase to your Expo project

  1. In the Firebase console, go to Project settings > General.
  2. Under Your apps, select your Android app. Confirm it's registered with the same package name as expo.android.package in app.json — FCM matches its client by package name, and a mismatch fails the build later at :app:processDebugGoogleServices.
  3. Download google-services.json and place it in the root of your project (alongside app.json).
  4. Reference the file in app.json:
{
  "expo": {
    "android": {
      "googleServicesFile": "./google-services.json"
    }
  }
}
📘

Note

You don't need to apply the Google Services Gradle plugin or add the Firebase Messaging dependency yourself — Expo and the Connect SDK handle both automatically. For manual mode, where your app manages its own FirebaseMessagingService and forwards messages to the SDK, contact Acoustic support — manual mode is not covered in this guide.


Step 4: Configure push notifications in your development project

  1. Open ConnectConfig.json in the root of your project and add the following keys inside the Connect object:

    {
      "Connect": {
        "AppKey": "YOUR_PUSH_ENABLED_APP_KEY",
        "PostMessageUrl": "YOUR_COLLECTOR_URL",
        "PushEnabled": true,
        "AndroidNotificationIconResName": "ic_notification"
      }
    }
    KeyValue
    PushEnabledtrue — enables push support in the SDK.
    AndroidNotificationIconResNameThe name of your notification icon drawable resource, without the file extension or folder path.
  2. Run npx expo prebuild to apply your configuration to the native project.

    npx expo prebuild
  3. Validate your configuration:

    npx acoustic-connect doctor --require-push
    What the Doctor does

    --require-push treats the push-required values — AppKey, the collector URLs, and AndroidNotificationIconResName — as hard failures rather than warnings, so a typo or leftover placeholder is caught here instead of failing later in Gradle or on-device. It's safe to re-run any time you change ConnectConfig.json.


Step 5: Add a notification icon

Android requires a small monochrome icon for the notification drawer. The system applies a color tint at display time; design it as a white icon on a transparent background.

Because expo prebuild regenerates the android/ directory and it is not committed to your repository, repeat these steps after every prebuild:

  1. In Android Studio, right-click android/app/src/main/res and select New > Image Asset.
  2. Set Icon type to Notification Icons, enter ic_notification as the name, and import your source image.
  3. Click Next > Finish. Android Studio generates the icon at the required densities under res/drawable-*.

The name you give the icon must match AndroidNotificationIconResName in ConnectConfig.json exactly.

⚠️

Warning

If AndroidNotificationIconResName is set but the drawable is missing from your project, the SDK falls back to the app launcher icon. The launcher icon is typically not optimized for the notification drawer and may appear incorrectly tinted.


Step 6: Request notification permission

On Android 13 (API 33) and later, your app must request notification permission at runtime. Call pushRequestPermission() at an appropriate moment in your app's UX — for example, after an onboarding screen that explains the value of notifications.

import AcousticConnectRN from 'react-native-acoustic-connect'

const result = await AcousticConnectRN.pushRequestPermission()

if (result.granted) {
  console.log('Notification permission granted')
} else {
  console.log('Notification permission denied:', result.error)
}

pushRequestPermission() presents the system permission dialog on Android 13+ when the state is undetermined. On Android 12 and earlier, notifications are granted by default and the method resolves immediately with { granted: true }. It always resolves and never rejects.

You can also check the current permission state without prompting:

const granted = await AcousticConnectRN.pushGetPermissionState()
// true = granted, false = denied, null = not yet determined

Testing

Testing push notifications requires a physical device or an emulator with Google Play Services — FCM does not work on AOSP emulators.

  1. Connect your device via USB and build with:

    npx expo run:android
  2. Grant notification permission when prompted. A new mobile contact is created in Connect and your device becomes eligible to receive pushes.

  3. Coordinate with your marketing team to send a test push to your device, or do it yourself — see Test your push notification setup.

  4. Verify the notification appears, and push signals appear in the contact's activity feed in Connect.

Enabling SDK debug logging

Inspect Logcat in Android Studio using a filter like package:<your.app.package> | tag:AndroidRuntime | tag:Tealeaf | tag:EOCore | tag:Connect. When reporting an issue to support, attach your Logcat output.


Message structure

After you complete the setup, your marketing team creates message content in Message composer in Connect. The following elements make up a push message, and each has its own source and constraints.

  • Notification icon — shown alongside every notification. Unlike the other elements below, it's not set in Message composer; it's always taken from the development project. See Add a notification icon above. If the drawable is missing, notifications fall back to the app launcher icon instead of your branding.
  • Title and body — authored per message; no SDK-imposed character limit, though Android may truncate long text in the notification shade depending on device and OS version.
  • Thumbnail image — shown in the collapsed notification, useful for branding. Accepted formats: .jpg, .jpeg, .png. Minimum dimensions: 64 × 64 px. Maximum size: 5 MB.
  • Expandable content — additional text or a full image shown when the user expands the notification. This is rich media delivered through FCM's data payload and is fully customizable per message, independent of the notification icon.
  • Actionable notifications — a built-in action that fires when the user taps the notification: open the app, call a number, or open a URL.

Troubleshooting

Push notifications not received

  • Confirm PushEnabled is true in ConnectConfig.json and that you re-ran npx expo prebuild after the change.
  • Confirm google-services.json exists at the path set in app.jsonexpo.android.googleServicesFile and matches your Firebase project and package name.
  • On API 33+, confirm the user granted notification permission. Call pushGetPermissionState() to check.
  • Test on a physical device or an emulator with Google Play Services — FCM does not work on AOSP emulators.

Push signals not appearing in Connect

  • Confirm AppKey and PostMessageUrl in ConnectConfig.json match your Mobile app integration in Connect.
  • Confirm your Connect administrator has uploaded your Firebase service account key to the Mobile app integration.

Notification icon not showing correctly

  • Confirm AndroidNotificationIconResName in ConnectConfig.json matches the drawable resource name exactly (no extension, no folder path).
  • Confirm the icon is a white monochrome design on a transparent background. Colorful icons are flattened to grey by the Android system.
  • Confirm the drawable exists under res/drawable-* after your most recent prebuild. Since expo prebuild regenerates android/, re-run the Image Asset step in Step 5 if you generated the icon before your last prebuild.

Config changes don't take effect

ConnectConfig.json is baked in at build time, not read at runtime. Rebuild with npx expo prebuild --clean — a Metro reload is not enough.


Next step: Identify app users

Push setup is now complete. To make the most of push notifications, identify the people receiving them — see User identification signals in a React Native app.