PusherHub

Docs Add PusherHub to your app

React Native push notifications: add the SDK step by step

Android and iOS, with Expo too — every step with a picture from a real React Native app: the SDK file, the packages, Gradle, the Podfile, Xcode and the code in App.tsx.

12 min read

All guides
1

Download PusherHub.js

In the dashboard, open Applications your app SDK Integration and pick React Native ①. Choose where your app runs — Android + iOS ② here — and click Download PusherHub.js ③. It goes in your src/ folder ④.

1 Pick React Native · 2 Android + iOS · 3 Download the SDK file · 4 The folder it goes in

Every step below is on this tab too, with your own keys already filled in — copy the code from there.

2

Put the three files in your project

  1. PusherHub.js ① goes in src/ (make the folder if you don't have one).
  2. Android: google-services.json ② goes in android/app/.
  3. iOS: GoogleService-Info.plist ③ goes in your app's folder under ios/, and Xcode has to know about it: open ios/MyApp.xcworkspace (your app's name), drag the file onto your app's folder and tick your app target.
1 PusherHub.js in src · 2 google-services.json in android/app · 3 GoogleService-Info.plist in ios
3

Install the packages

Run this in your project folder ③. It adds Firebase Cloud Messaging ①, plus what PusherHub uses to ask for permission and show notifications (notifee), to remember the phone (async-storage) and to show web in-app messages ② (webview — skip it if you don't use those).

npm install @react-native-firebase/app @react-native-firebase/messaging \
    @react-native-async-storage/async-storage @notifee/react-native \
    react-native-webview
1 Firebase, notifee and async-storage · 2 webview · 3 npm install · 4 pod install (after step 7)

For iOS, cd ios && pod install ④ comes after the Podfile change in step 7. Using Expo? Install with npx expo install instead of npm install.

4

Android: add the Google services plugin

Open android/build.gradle. Inside buildscript { dependencies { } }, add ①:

classpath("com.google.gms:google-services:4.4.3")
1 The classpath line
5

Android: turn the plugin on for the app

Open android/app/build.gradle and add this under the other apply plugin lines at the top ①:

apply plugin: "com.google.gms.google-services"
1 The plugin
6

Android: add to AndroidManifest.xml

Open android/app/src/main/AndroidManifest.xml and add to the manifest you already have — don't replace it:

  1. The permissions ①.
  2. A second <intent-filter> ② inside the MainActivity <activity>. Without it, tapping a notification while the app is closed doesn't open it. The name says Flutter, but every PusherHub notification uses it, React Native apps too.
1 Permissions · 2 The notification-tap intent filter
7

iOS: Podfile and pod install

Firebase for iOS needs dynamic frameworks. In ios/Podfile, inside your app's target … do block, add ①:

use_frameworks! :linkage => :dynamic
1 Dynamic frameworks

Then run cd ios && pod install. Without the line, pod install fails.

8

iOS: start Firebase in AppDelegate.swift

Open your app's AppDelegate.swift under ios/ and add the import ① and FirebaseApp.configure() as the first line of application(_:didFinishLaunchingWithOptions:) ②.

1 The import · 2 Start Firebase

An Objective-C AppDelegate.mm takes #import <Firebase.h> and [FIRApp configure]; instead.

9

iOS: turn on push notifications in Xcode

Open ios/MyApp.xcworkspace in Xcode and select your app target (called Runner in the picture). On Signing & Capabilities ①, choose your paid Apple Developer Team, then click + Capability ② and add Background Modes — tick Remote notifications ③ — and Push Notifications ④.

1 Signing & Capabilities · 2 + Capability · 3 Remote notifications · 4 Push Notifications
10

iOS with Expo: app.json instead

Expo makes the ios/ folder from app.json, so hand edits to Xcode, the Podfile or the AppDelegate would be lost. In an Expo app, do this instead of steps 7–9:

  1. In "ios": your bundle ID, the Firebase file (put GoogleService-Info.plist in the project folder) and your Apple Team ID ①.
  2. The push entitlement and background notifications ②.
  3. The plugins ③: the two Firebase ones, and expo-build-properties for dynamic frameworks.
1 Bundle ID, Firebase file, Team ID · 2 Push and background notifications · 3 Plugins

Then build a development build — Expo Go can't receive pushes:

npx expo install expo-build-properties
npx expo prebuild --platform ios
npx expo run:ios --device
11

iOS: show pictures in notifications (recommended)

An iPhone doesn't download a notification's image by itself when the app is closed — without this step it shows only the title and text. In Xcode, with your .xcworkspace open:

  1. File New Target… , pick Notification Service Extension, name it NotificationService, click Finish, then Don't Activate.
  2. Replace everything in ios/NotificationService/NotificationService.swift with the file on your SDK Integration tab.

Expo apps need a config plugin for this, so skip it there for now. The simulator can't draw notification pictures, so check this on a real iPhone.

12

Attach PusherHub in index.js

Open index.js and add the import ① and PusherHub.attachNotificationHandlers() ② — before AppRegistry.registerComponent, not inside a component, so it's ready before the app finishes opening.

1 The import · 2 Attach the notification handlers

Expo: put the same line in index.ts (or index.js), just before registerRootComponent(App).

13

Start PusherHub in App.tsx

Open App.tsx and add the code from your SDK Integration tab — your keys and server are already filled in. (In the picture they're placeholders.)

  1. The import ①.
  2. PusherHub.initialize(…) ② in a useEffect, with your App key, Public key and server.
  3. registerDevice() ③ asks the user to allow notifications, gets the push token and adds the phone to PusherHub. collectDeviceMetadata() after it is optional: it adds the phone's brand, model, language and country.
  4. <PusherHubMessageHost> ④ around your app — optional: it shows your in-app messages when the app opens. Leave it out if you only send notifications.
1 The import · 2 Your keys · 3 Register the phone · 4 In-app messages (optional)
14

Optional: log the user in

If your app has its own sign-in, tell PusherHub who's using the phone. Then you can send to one person by your own user ID. It's remembered, even after the app restarts, until logout().

// When someone signs in:
await PusherHub.login(currentUserId);

// When they sign out:
await PusherHub.logout();
15

Optional: open a screen when a notification is tapped

Put your own data in Custom Data when you create a notification — say {"campaign_id": "232"} — and your app gets it back whenever someone taps that notification, whether it was open, in the background or closed. Add onNotificationOpened to the PusherHub.initialize(…) in App.tsx from step 13:

export const navigationRef = createNavigationContainerRef(); // <NavigationContainer ref={navigationRef} onReady={openPending}>
let pendingCampaignId = null;
const openPending = () => {
  if (pendingCampaignId) navigationRef.navigate('Campaign', { id: pendingCampaignId });
  pendingCampaignId = null;
};

await PusherHub.initialize({
  appKey: 'YOUR_APP_KEY',
  publicKey: 'YOUR_PUBLIC_KEY',
  baseUrl: 'YOUR_SERVER',
  onNotificationOpened: (data) => {
    if (!data.campaign_id) return;
    pendingCampaignId = data.campaign_id;
    if (navigationRef.isReady()) openPending();
  },
});

A tap that opened a closed app can arrive before your navigation is ready — pendingCampaignId keeps it until it is. Every value arrives as text ("232"). This needs PusherHub.js from 24 October 2026 or later — download it again if yours is older.

16

Run the app on a phone

Run npx react-native run-android on an Android phone or emulator with Google Play, or npx react-native run-ios --device on a real iPhone (the iOS simulator can't get push notifications). Tap Allow when it asks about notifications. Within a few seconds the phone shows up in PusherHub under Devices.

Then send it a test notification.