Expo Notifications Not Working on Android in React Native App
I’m developing a React Native app using Expo GO and have implemented push notifications. While notifications are being received successfully on iOS devices, they’re not appearing on Android devices. I’m using a .NET API to send the notifications.
Could someone help me identify what might be causing this issue? Additionally, I’ve created a dev build but I’m unsure how to use it or how it differs from Expo GO when it comes to Expo notifications.
Here’s my current notification setup:
import { useState, useEffect, useRef } from 'react';
import { Text, View, Button, Platform, Alert } from 'react-native';
import * as Device from 'expo-device';
import * as Notifications from 'expo-notifications';
import Constants from 'expo-constants';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldPlaySound: true,
shouldSetBadge: true,
shouldShowBanner: true,
shouldShowList: true,
}),
});
export default function Notification() {
const [expoPushToken, setExpoPushToken] = useState(''); //ovo je jedinstveni identifikator
const [channels, setChannels] = useState([]);
const [notification, setNotification] = useState(
undefined
); //ovo je notifikacija
useEffect(() => {
registerForPushNotificationsAsync().then(token => token && setExpoPushToken(token));
if (Platform.OS === 'android') {
Notifications.getNotificationChannelsAsync().then(value => setChannels(value ?? []));
}
//prisluskivaci
const notificationListener = Notifications.addNotificationReceivedListener(notification => {
setNotification(notification);
}); //za primljene notifikacije
//OVO JE KLJUCNO
useEffect(() => {
const subscription = Notifications.addNotificationResponseReceivedListener(response => {
const { type, bunjoNovostiId } = response.notification.request.content.data;
if(type === "news" && bunjoNovostiId != null){
navigate('Akcija');
}
});
return () => {
subscription.remove();
};
}, []);
return () => {
notificationListener.remove();
responseListener.remove();
};
}, []);
}
export async function registerForPushNotificationsAsync() {
let token;
if (Platform.OS === 'android') {
await Notifications.setNotificationChannelAsync('myNotificationChannel', {
name: 'A channel is needed for the permissions prompt to appear',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#FF231F7C',
});
}
if (Device.isDevice) {
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
Alert.alert('Nećete primati obavijesti.');
return;
}
try {
const projectId =
Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId;
if (!projectId) {
throw new Error('Project ID not found');
}
token = (
await Notifications.getExpoPushTokenAsync({
projectId,
})
).data;
} catch (e) {
token = `${e}`;
}
} else {
alert('Must use physical device for Push Notifications');
}
return token;
}
What could be preventing notifications from working on Android, and how do dev builds affect notification functionality compared to Expo GO?
Push notifications not working on Android in your Expo React Native app is a common issue, primarily because Expo GO doesn’t support remote push notifications on Android devices - you must use a development build or standalone app. While your notifications work perfectly on iOS due to different implementation requirements, Android requires specific configuration and build processes that Expo GO cannot provide.
Contents
- Why Expo GO Doesn’t Support Android Push Notifications
- Development Build vs Expo GO for Notifications
- Common Android Notification Issues
- FCM Configuration Requirements
- Code Problems in Your Implementation
- Step-by-Step Solutions
- Testing and Verification
Why Expo GO Doesn’t Support Android Push Notifications
The fundamental issue you’re experiencing stems from Expo’s architecture limitations. According to Expo’s official documentation, “Push notifications (remote notifications) functionality provided by expo-notifications is unavailable in Expo Go on Android from SDK 53. A development build is required to use push notifications.”
This limitation exists because:
- Expo GO uses Expo’s shared credentials for development
- Android requires app-specific Firebase Cloud Messaging (FCM) configurations
- Google Play Store policies require proper app signing and key management
- Push notifications need deep system integration that Expo GO sandbox prevents
As noted in the Expo FAQ, “Expo Go uses Expo’s credentials, which allows working on notifications in development. When you build your app for the app stores, you need to generate and use your own…”
Development Build vs Expo GO for Notifications
The key difference between these environments for push notifications:
| Feature | Expo GO (Android) | Development Build/Standalone App |
|---|---|---|
| Push Notifications | ❌ Not supported | ✅ Fully supported |
| Local Notifications | ✅ Supported | ✅ Supported |
| FCM Integration | ❌ Not available | ✅ Required |
| Device Token | Limited functionality | Full device token access |
| Testing | Basic only | Complete testing possible |
As explained in the Expo documentation, you need to “build with EAS Build” for proper push notification functionality on Android.
Common Android Notification Issues
Several specific problems commonly affect Android notifications:
1. FCM Configuration Missing
- Problem: Missing or incorrect Firebase Cloud Messaging keys
- Symptoms: Notifications work on Expo GO but fail in standalone builds
- Evidence: A Reddit user specifically noted, “Make sure to configure the FCM keys for android. Otherwise, push notification does not work on standalone builds.”
2. Notification Channel Issues
- Problem: Android requires proper notification channel setup
- Symptoms: Notifications appear but don’t make sound or show properly
- Evidence: Some users report notifications only “show at top bar icon only” without pop-up functionality
3. Listener Implementation Problems
- Problem: Notification listeners not properly triggered on Android
- Symptoms: Clicking notifications doesn’t navigate to expected screens
- Evidence: Stack Overflow discussions mention “notification listener not working for Android in react native expo app - the listener doesn’t get trigger for Android when I click on notification”
FCM Configuration Requirements
For Android push notifications to work, you must properly configure Firebase Cloud Messaging:
-
Create Firebase Project
- Go to Firebase Console
- Create a new project for your app
-
Add Android App
- Register your Android package name
- Download
google-services.jsonfile
-
Configure EAS Build
basheas build:configure
This will set up the necessary Android configuration files
-
Set Up Environment Variables
- Add your FCM server key to EAS secrets
- Configure the project ID in your app configuration
As Expo’s FCM guide explains, “Learn how to send notifications with FCM and APNs” for proper setup.
Code Problems in Your Implementation
Looking at your notification code, several issues need addressing:
1. Undefined Response Listener
// Your code has this issue:
useEffect(() => {
const subscription = Notifications.addNotificationResponseReceivedListener(response => {
// ...
});
return () => {
subscription.remove();
};
}, []);
// But responseListener is used before being defined in cleanup:
return () => {
notificationListener.remove();
responseListener.remove(); // ❌ responseListener is undefined here
};
2. Expo Token Limitations
The getExpoPushTokenAsync() method has limitations in standalone builds. For Android, you should use the device’s FCM token instead.
3. Missing Error Handling
The code doesn’t properly handle cases where token retrieval fails in standalone builds.
Step-by-Step Solutions
Solution 1: Create Development Build
# First, configure EAS
eas build:configure
# Create development build
eas build --platform android --profile development
Solution 2: Fix Your Notification Code
import * as Notifications from 'expo-notifications';
import Constants from 'expo-constants';
export default function Notification() {
const [expoPushToken, setExpoPushToken] = useState('');
const [notification, setNotification] = useState(undefined);
useEffect(() => {
registerForPushNotificationsAsync().then(token => {
if (token) setExpoPushToken(token);
});
// Setup notification channels for Android
if (Platform.OS === 'android') {
setupNotificationChannels();
}
// Add listeners
const notificationListener = Notifications.addNotificationReceivedListener(setNotification);
const responseListener = Notifications.addNotificationResponseReceivedListener(handleNotificationResponse);
return () => {
notificationListener.remove();
responseListener.remove();
};
}, []);
const handleNotificationResponse = (response) => {
const { type, bunjoNovostiId } = response.notification.request.content.data;
if(type === "news" && bunjoNovostiId != null){
// Navigate to your screen here
console.log('Navigating to news:', bunjoNovostiId);
}
};
const setupNotificationChannels = async () => {
if (Platform.OS === 'android') {
await Notifications.setNotificationChannelAsync('myNotificationChannel', {
name: 'My Notifications',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#FF231F7C',
});
}
};
}
export async function registerForPushNotificationsAsync() {
if (!Device.isDevice) {
alert('Must use physical device for Push Notifications');
return;
}
// Request permissions
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
Alert.alert('Permission not granted for notifications');
return;
}
// Get token with proper project ID
const projectId = Constants.expoConfig.extra.eas.projectId;
if (!projectId) {
throw new Error('Project ID not found in app config');
}
return await Notifications.getExpoPushTokenAsync({
projectId,
});
}
Solution 3: Configure FCM for Production
-
Get FCM Credentials:
- In Firebase Console, go to Project Settings
- Under Cloud Messaging, find Server Key and Sender ID
-
Configure EAS Secrets:
basheas secret:create FCM_SERVER_KEY=your_server_key_here eas secret:create FCM_SENDER_ID=your_sender_id_here
-
Update app.json:
json{ "expo": { "android": { "package": "com.yourcompany.yourapp" }, "extra": { "eas": { "projectId": "your-project-id" } } } }
Testing and Verification
Testing Your Development Build
- Install the development build on your Android device
- Verify you receive the push notifications
- Test notification responses and navigation
Common Testing Issues
- Notifications appear but don’t make sound: Check notification channel importance settings
- Notifications don’t appear: Verify FCM configuration and network permissions
- Listeners don’t trigger: Ensure proper cleanup and listener setup
As Expo’s troubleshooting guide suggests, “This indicates that you have either misconfigured your credentials or didn’t configure them at all in your production app.”
Conclusion
The primary issue preventing your Android notifications from working is that Expo GO doesn’t support push notifications on Android - you must use a development build or standalone app. Key takeaways:
- Use Development Builds: Create an EAS development build for proper Android push notification support
- Configure FCM Properly: Set up Firebase Cloud Messaging with correct server keys and package names
- Fix Code Issues: Address the undefined responseListener and improve error handling
- Test on Physical Devices: Notifications won’t work properly on emulators for standalone builds
For continuous development, consider using local notifications in Expo GO for testing UI components, while using development builds for end-to-end push notification testing. The transition from Expo GO to standalone builds requires careful attention to FCM configuration and proper build setup, but once implemented, Android notifications will work as expected.