Skill v1.0.1
currentAutomated scan100/100+3 new
version: "1.0.1" name: "add-expo-notifications-fcm" description: "Set up Firebase Cloud Messaging (FCM) push notifications via expo-notifications for Android. Use when the user says 'add fcm', 'push notifications android', 'expo notifications android', 'firebase push'."
Add FCM Push (expo-notifications)
Firebase Cloud Messaging — free, unlimited push for Android.
Install
npm exec --no -- expo install expo-notifications expo-device
Firebase project setup
Run set-up-firebase-cli skill first. Result: google-services.json in android/app/.
app.json:
{"expo": {"android": { "googleServicesFile": "./google-services.json" },"notification": {"icon": "./assets/notification-icon.png","color": "#ffffff","androidMode": "default"}}}
Request permission (Android 13+ runtime)
import * as Notifications from 'expo-notifications';import * as Device from 'expo-device';async function registerForPush() {if (!Device.isDevice) return;let { status } = await Notifications.getPermissionsAsync();if (status !== 'granted') {const r = await Notifications.requestPermissionsAsync();if (r.status !== 'granted') return null;}const token = (await Notifications.getDevicePushTokenAsync()).data;// FCM token — save to backendreturn token;}
Custom pre-prompt (boost permission opt-in)
Before calling requestPermissionsAsync, show your own screen:
"Get a daily reminder. We promise no spam."[Sure] [Later]
If "Sure" → trigger system dialog. If "Later" → don't ask again this session.
Notification channels (Android 8+)
import * as Notifications from 'expo-notifications';Notifications.setNotificationChannelAsync('daily-reminders', {name: 'Daily Reminders',importance: Notifications.AndroidImportance.HIGH,sound: 'default',vibrationPattern: [0, 250, 250, 250],lightColor: '#FF231F7C',});
Channels are user-controllable in Settings. Group related notifs.
Foreground handler
Notifications.setNotificationHandler({handleNotification: async () => ({shouldShowAlert: true,shouldPlaySound: false,shouldSetBadge: true,}),});
Send from backend
Use Firebase Admin SDK or Expo Push API:
fetch('https://exp.host/--/api/v2/push/send', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({to: deviceToken,title: 'Reminder',body: 'Time to log today',channelId: 'daily-reminders',}),});
Deep link on tap
const notificationRoutes = new Set(['/today', '/library']);Notifications.addNotificationResponseReceivedListener((response) => {const screen = response.notification.request.content.data.screen;if (typeof screen === 'string' && notificationRoutes.has(screen)) {router.push(screen);}});
Manufacturer battery optimization (CRITICAL)
Xiaomi (MIUI), Oppo (ColorOS), OnePlus, Samsung kill background apps aggressively. Push works most of the time but for ENGAGEMENT push (reminders), users must:
- Settings → Battery → [Your app] → "Don't optimize"
- Some need: Settings → Apps → [Your app] → Battery saver → "No restriction"
Document this in onboarding for power users.
Pair with
add-onesignal-pushfor advanced campaigns (RC for transactional, OS for marketing)add-deep-linksto handle taps