From 1b03099a1edac87c5544e6d78402ab81db036058 Mon Sep 17 00:00:00 2001 From: Marat Alekperov Date: Fri, 27 Feb 2026 00:29:33 +0100 Subject: [PATCH] feat: React Native push getting started guide. --- src/data/nav/pubsub.ts | 4 + ...eact-native-push-getting-started-guide.png | Bin 0 -> 65252 bytes .../push/getting-started/react-native.mdx | 520 ++++++++++++++++++ 3 files changed, 524 insertions(+) create mode 100644 src/images/content/screenshots/getting-started/react-native-push-getting-started-guide.png create mode 100644 src/pages/docs/push/getting-started/react-native.mdx diff --git a/src/data/nav/pubsub.ts b/src/data/nav/pubsub.ts index 72f4e39228..61d952a2ef 100644 --- a/src/data/nav/pubsub.ts +++ b/src/data/nav/pubsub.ts @@ -272,6 +272,10 @@ export default { name: 'FCM', link: '/docs/push/getting-started/fcm', }, + { + name: 'React Native', + link: '/docs/push/getting-started/react-native', + }, ], }, { diff --git a/src/images/content/screenshots/getting-started/react-native-push-getting-started-guide.png b/src/images/content/screenshots/getting-started/react-native-push-getting-started-guide.png new file mode 100644 index 0000000000000000000000000000000000000000..a1bb2188e65b7707cc75160a453dcac279c65c12 GIT binary patch literal 65252 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 + +### Handle push notifications + +The FCM SDK handles background push notifications automatically and displays them as system notifications. For foreground handling, use `@notifee/react-native` to display notifications while the app is open. + +Add the following inside `PushScreen`: + + +```react +useEffect(() => { + // Create a default Android notification channel + if (Platform.OS === 'android') { + notifee.createChannel({id: 'default', name: 'Default Channel'}); + } + + // Handle foreground push messages + const unsubscribe = messaging().onMessage(async remoteMessage => { + const title = remoteMessage.notification?.title ?? 'Push Notification'; + const body = remoteMessage.notification?.body ?? ''; + addLog(`Push received: ${title} — ${body}`); + await notifee.displayNotification({ + title, + body, + android: {channelId: 'default'}, + }); + }); + + return () => { + unsubscribe(); + }; +}, []); +``` + + +## Step 3: Subscribe and test push notifications + +### Subscribe to channel push notifications + +To subscribe your device to a channel so it can receive channel-based push notifications, add the following functions inside `PushScreen`, after the functions from Step 2: + + +```react +async function subscribeToChannel() { + try { + await client.push.admin.channelSubscriptions.save({ + deviceId, + channel: CHANNEL_NAME, + }); + showStatus(`Subscribed to push on channel: ${CHANNEL_NAME}`); + } catch (error) { + showStatus(`Failed to subscribe: ${(error as Ably.ErrorInfo).message}`); + } +} + +async function unsubscribeFromChannel() { + try { + await client.push.admin.channelSubscriptions.remove({ + deviceId, + channel: CHANNEL_NAME, + }); + showStatus(`Unsubscribed from push on channel: ${CHANNEL_NAME}`); + } catch (error) { + showStatus(`Failed to unsubscribe: ${(error as Ably.ErrorInfo).message}`); + } +} +``` + + +### Build the UI + +Update the `return` statement in `PushScreen` to add buttons that call all the push functions: + + +```react +return ( + + + Ably Push Tutorial + + {status} + + + + Activate Push + + + Deactivate Push + + + Subscribe to Channel + + + Unsubscribe from Channel + + + + {log.map((entry, i) => ( + {entry} + ))} + + setLog([])}> + Clear Log + + + +); +``` + + +Add the button styles to the `StyleSheet.create` call: + + +```react +buttons: {gap: 8, marginBottom: 12}, +btn: {padding: 14, borderRadius: 6, alignItems: 'center'}, +btnText: {color: '#fff', fontWeight: '600'}, +btnGreen: {backgroundColor: '#28a745'}, +btnRed: {backgroundColor: '#dc3545'}, +btnPurple: {backgroundColor: '#6f42c1'}, +btnOrange: {backgroundColor: '#fd7e14'}, +btnGray: {backgroundColor: '#6c757d', marginTop: 8}, + +``` + + +Build and run your app on a physical device: + + +```shell +# Android +npx react-native run-android + +# iOS +npx react-native run-ios --device +``` + + +You can also open each platform project in their respective IDEs and run from there. + +### Publish a push notification + +In the app tap **Activate Push** and wait until the status message displays your device ID. + +#### Direct push notification + +Publish a push notification directly to your client ID (or device ID using `--device-id` instead of `--client-id`) via the Ably CLI: + + +```shell +ably push publish --client-id push-tutorial-client \ + --title "Hello" \ + --body "World!" \ + --data '{"foo":"bar"}' +``` + + +#### Channel push notification + +Tap **Subscribe to Channel** in the app, then publish a push notification to your channel using the Ably CLI: + + +```shell +ably push publish --channel my-first-push-channel \ + --title "Hello" \ + --body "World!" \ + --message '{"name":"greeting","data":"Hello World!"}' +``` + + +If you tap **Unsubscribe from Channel**, the device no longer receives push notifications for that channel. Send the same command again and verify that no notification is received. + +To see the full list of options for sending push notifications with the Ably CLI, run `ably push publish --help` or see the [Ably CLI push documentation](/docs/cli/push). To send push notifications from your own server code instead of the CLI, see [Push notification publishing](https://ably.com/docs/push/publish). + +![Screenshot of the React Native push tutorial application](../../../../images/content/screenshots/getting-started/react-native-push-getting-started-guide.png) + +## Next steps + +* Understand [token authentication](/docs/auth/token) before going to production. +* Explore [push notification administration](/docs/push#push-admin) for managing devices and subscriptions. +* Learn about [channel rules](/docs/channels#rules) for channel-based push notifications. +* Read more about the [Push Admin API](/docs/api/realtime-sdk/push-admin). + +You can also explore the [Ably JavaScript SDK](https://github.com/ably/ably-js) on GitHub, or visit the [API references](/docs/api/realtime-sdk?lang=javascript) for additional functionality.

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 literal 0 HcmV?d00001 diff --git a/src/pages/docs/push/getting-started/react-native.mdx b/src/pages/docs/push/getting-started/react-native.mdx new file mode 100644 index 0000000000..378540d316 --- /dev/null +++ b/src/pages/docs/push/getting-started/react-native.mdx @@ -0,0 +1,520 @@ +--- +title: "Getting started: Push Notifications in React Native" +meta_description: "Get started with Ably Push Notifications in React Native. Learn how to register for push notifications with Firebase Cloud Messaging (FCM), activate push on your client, handle incoming notifications, and send push messages on iOS and Android." +meta_keywords: "Push Notifications React Native, Ably Push, FCM, Android Push, iOS Push, React Native push notifications, Firebase Cloud Messaging, Ably Push Notifications guide, realtime push React Native, push notification example, Ably tutorial React Native, device registration, push messaging" +--- + +This guide will get you started with Ably Push Notifications in a new React Native application. + +You'll learn how to set up your application with Firebase Cloud Messaging (FCM), register devices with Ably, send push notifications, subscribe to channel-based push, and handle incoming notifications on both iOS and Android. + +## Prerequisites + +1. [Sign up](https://ably.com/signup) for an Ably account. +2. Create a [new app](https://ably.com/accounts/any/apps/new), and create your first API key in the **API Keys** tab of the dashboard. + * Your API key needs the `publish`, `subscribe` capabilities. + * Also add the `push-admin` capability if you're using the same API key to send a push notification. In production this would more likely be a server using a different API key. +3. Add a rule to a channel so you can test sending push notification via a channel. Select [**Rules**](https://ably.com/accounts/any/apps/any/app_namespaces) in the Ably dashboard, add a new rule and enable the **Push notifications** option. +4. Install [Node.js](https://nodejs.org/) 18 or higher. +5. Set up your React Native development environment following the [React Native CLI Quickstart](https://reactnative.dev/docs/set-up-your-environment). +6. For iOS: Install [Xcode](https://developer.apple.com/xcode/). Push notifications require a physical iOS device (simulators do not support push). +7. For Android: Install [Android Studio](https://developer.android.com/studio). Use a physical device or an emulator with Google Play Services installed. + +### (Optional) Install Ably CLI + +Use the [Ably CLI](https://github.com/ably/cli) as an additional client to quickly test Pub/Sub features and push notifications. + +1. Install the Ably CLI: + + +```shell +npm install -g @ably/cli +``` + + +2. Run the following to log in to your Ably account and set the default app and API key: + + +```shell +ably login +``` + + +### Set up Firebase Cloud Messaging + +Firebase Cloud Messaging delivers push notifications for both Android and iOS. To enable FCM: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) and create a new project (or use an existing one). +2. Register your Android app using your package name. Download `google-services.json` and place it in `android/app/`. +3. Download your Firebase service account JSON file from your Firebase console: **Project configuration** → **Service Accounts** → **Generate new private key**. +4. In the Ably dashboard left sidebar, navigate to your app's **Push Notifications**. +5. Scroll to the **Configure push service for devices** section and press **Configure Push**. +6. Upload your Firebase service account JSON file in **Setting up Firebase Cloud Messaging** section. +7. In the [Apple Developer portal](https://developer.apple.com), go to **Certificates, Identifiers & Profiles** → **Keys**. +8. Add a new key and check **Apple Push Notifications service (APNs)**, click **Register**. +9. Download the `.p8` file — you can only download it once. Note your **Key ID** and **Team ID**. +10. In the Firebase Console, go to **Project configuration** → **Cloud Messaging** → **Apple App Setup** → **APNS authentication key** to upload your `.p8` file. +11. Register an iOS app in your Firebase project using your bundle identifier. Download `GoogleService-Info.plist` and add it to your Xcode project's root target. + +### Create a React Native project + +Create a new React Native project and install the required dependencies: + + +```shell +npx react-native@latest init PushTutorial +cd PushTutorial +npm install ably @react-native-firebase/app @react-native-firebase/messaging @notifee/react-native +``` + + +#### Configure Android project + +Apply the Google Services plugin in `android/build.gradle`: + + +```text +// android/build.gradle +buildscript { + dependencies { + classpath('com.google.gms:google-services:4.4.2') + } +} +``` + + +Then apply it in `android/app/build.gradle`: + + +```text +// android/app/build.gradle +apply plugin: 'com.google.gms.google-services' +``` + + +Also declare the `POST_NOTIFICATIONS` permission in `android/app/src/main/AndroidManifest.xml`: + + +```xml + + + + ... + +``` + + +#### Configure iOS project + +Open `ios/PushTutorial.xcworkspace` in Xcode and add the `Push Notifications` capability: select your target, go to **Signing & Capabilities**, and click **+ Capability**. + +Add `use_modular_headers!` to `ios/Podfile` after `prepare_react_native_project!`: + + +```text +prepare_react_native_project! +use_modular_headers! +``` + + +This is required for Firebase Swift pods (`FirebaseCoreInternal`, `GoogleUtilities`) to be integrated as static libraries. Then install the native pods: + + +```shell +cd ios && pod install && cd .. +``` + + +Then add `FirebaseApp.configure()` to `AppDelegate.swift` before React Native starts: + + +```text +import Firebase + +func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil +) -> Bool { + FirebaseApp.configure() + // ... rest of existing setup +} +``` + + +Add all further code to `App.tsx`. + +## Step 1: Set up Ably + +Replace the contents of `App.tsx` with the following to initialize the Ably Pub/Sub client, wrap the app in `AblyProvider` and `ChannelProvider`, and subscribe to realtime messages on the channel with `useChannel`: + + +```react +import React, {useRef, useState} from 'react'; +import { + Platform, + ScrollView, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native'; +import {SafeAreaView} from 'react-native-safe-area-context'; +import * as Ably from 'ably'; +import {AblyProvider, ChannelProvider, useAbly, useChannel} from 'ably/react'; +import messaging from '@react-native-firebase/messaging'; +import notifee, {AuthorizationStatus} from '@notifee/react-native'; + +const CHANNEL_NAME = 'my-first-push-channel'; + +// Use token authentication in production +const client = new Ably.Realtime({ + key: '{{API_KEY}}', + clientId: 'push-tutorial-client', +}); + +function PushScreen() { + const [status, setStatus] = useState('Ready to start'); + const [log, setLog] = useState([]); + + function addLog(message: string) { + setLog(prev => [...prev, message]); + } + + function showStatus(message: string) { + setStatus(message); + console.log(message); + } + + useChannel(CHANNEL_NAME, message => { + addLog(`Received: ${message.name} - ${JSON.stringify(message.data)}`); + }); + + return ( + + + Ably Push Tutorial + + {status} + + + {log.map((entry, i) => ( + {entry} + ))} + + + + ); +} + +export default function App() { + return ( + + + + + + ); +} + +const styles = StyleSheet.create({ + safeArea: {flex: 1, backgroundColor: '#fff'}, + container: {flex: 1, padding: 16}, + title: {fontSize: 22, fontWeight: 'bold', textAlign: 'center', marginBottom: 12}, + statusBox: {backgroundColor: '#f0f0f0', padding: 12, borderRadius: 6, marginBottom: 12}, + statusText: {fontSize: 14}, + logBox: {flex: 1, backgroundColor: '#fff', borderWidth: 1, borderColor: '#ddd', borderRadius: 6, padding: 8}, + logEntry: {fontFamily: Platform.OS === 'ios' ? 'Courier' : 'monospace', fontSize: 12, marginBottom: 4}, +}); +``` + + +Key configuration options: + +- `key`: Your Ably API key. +- `clientId`: A unique identifier for this client. + +`AblyProvider` makes the Ably client available to all child components via React context. `ChannelProvider` scopes child components to `my-first-push-channel`. `useChannel` subscribes to realtime messages published on the channel. + +## Step 2: Set up push notifications + +Push notification activation in React Native requires obtaining an FCM registration token and registering the device with Ably. Add the following inside `PushScreen`: + + +```react +// Inside PushScreen: +const client = useAbly(); + +// Randomly generated on each app start for simplicity — in production, persist this (e.g. using AsyncStorage) to reuse the same device registration across restarts +const [deviceId] = useState( + `push-tutorial-${Platform.OS}-${Math.random().toString(36).slice(2, 9)}`, +); +const tokenRefreshUnsubscribeRef = useRef<(() => void) | null>(null); // To store the FCM token refresh listener unsubscribe function + +async function requestPermission(): Promise { + if (Platform.OS === 'android') { + // Use notifee for consistent POST_NOTIFICATIONS permission behavior across Android API levels + const settings = await notifee.requestPermission(); + return settings.authorizationStatus >= AuthorizationStatus.AUTHORIZED; + } + // On iOS, request permission using Firebase Messaging which will trigger the native iOS permission dialog + const authStatus = await messaging().requestPermission(); + return ( + authStatus === messaging.AuthorizationStatus.AUTHORIZED || + authStatus === messaging.AuthorizationStatus.PROVISIONAL + ); +} + +// Save the device registration with Ably using the FCM token +async function saveDeviceRegistration(token: string) { + await client.push.admin.deviceRegistrations.save({ + id: deviceId, + clientId: 'push-tutorial-client', + platform: Platform.OS === 'ios' ? 'ios' : 'android', + formFactor: 'phone', + push: { + recipient: { + transportType: 'fcm', // FCM on both platforms — messaging().getToken() returns an FCM token even on iOS + registrationToken: token, + }, + }, + }); +} + +async function activatePush() { + try { + showStatus('Activating push notifications...'); + const granted = await requestPermission(); + if (!granted) { + showStatus('Notification permission denied.'); + return; + } + + await messaging().registerDeviceForRemoteMessages(); // Required to receive push notifications on iOS, no-op on Android + const fcmToken = await messaging().getToken(); + await saveDeviceRegistration(fcmToken); + + tokenRefreshUnsubscribeRef.current?.(); + tokenRefreshUnsubscribeRef.current = messaging().onTokenRefresh(async newToken => { + try { + await saveDeviceRegistration(newToken); + } catch (error) { + console.error('Failed to update FCM token:', (error as Ably.ErrorInfo).message); + } + }); + + showStatus(`Push activated. Device ID: ${deviceId}`); + addLog(`Push activated. Device ID: ${deviceId}`); + } catch (error) { + showStatus(`Failed to activate push: ${(error as Ably.ErrorInfo).message}`); + } +} + +async function deactivatePush() { + try { + showStatus('Deactivating push notifications...'); + await client.push.admin.deviceRegistrations.remove(deviceId); + tokenRefreshUnsubscribeRef.current?.(); + tokenRefreshUnsubscribeRef.current = null; + showStatus('Push notifications deactivated.'); + } catch (error) { + showStatus(`Failed to deactivate push: ${(error as Ably.ErrorInfo).message}`); + } +} +``` + + +`activatePush()` does the following: + +1. Requests notification permission from the user. +2. Obtains the FCM registration token from Firebase. +3. Registers the device with Ably's push notification service using the token. +4. Sets up a listener for FCM token refresh events to update the registration with Ably if the token changes. + +After successful activation, `deviceId` can be used to send push notifications to this device. + +