13 KiB
13 KiB
Push Notifications Setup Guide (FCM & APNs)
Overview
This guide covers setting up Firebase Cloud Messaging (FCM) for Android and Apple Push Notification service (APNs) for iOS push notifications in the ShieldAI mobile app.
Architecture
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Mobile │────▶│ API Gateway │────▶│ Notification │
│ App │ │ /devices/* │ │ Service │
└─────────────┘ └──────────────────┘ └────────┬────────┘
│
┌──────────────────────────────┼──────────────────────┐
│ │ │
▼ ▼ ▼
┌────────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ Firebase │ │ Apple Push │ │ Redis (Rate │
│ Cloud │ │ Notification │ │ Limiting) │
│ Messaging │ │ Service │ │ │
│ (Android) │ │ (iOS) │ │ │
└────────────────┘ └─────────────────┘ └──────────────────┘
Environment Variables
Add the following to your .env file:
# Firebase Cloud Messaging (FCM)
FCM_PROJECT_ID=your-firebase-project-id
FCM_CLIENT_EMAIL=service-account@your-project.iam.gserviceaccount.com
FCM_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
# Apple Push Notification (APNs)
APNS_KEY_ID=your-key-id
APNS_TEAM_ID=your-team-id
APNS_BUNDLE_ID=com.yourcompany.shieldai
APNS_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
# Redis (for rate limiting)
REDIS_URL=redis://localhost:6379
# Rate Limits
PUSH_RATE_LIMIT=100
RATE_LIMIT_WINDOW_SECONDS=60
Firebase Cloud Messaging (FCM) Setup
1. Create Firebase Project
- Go to Firebase Console
- Click Add project
- Enter project name:
shieldai-production(or your preferred name) - Disable Google Analytics (optional)
- Click Create project
2. Enable Cloud Messaging
- In Firebase Console, go to Project settings
- Scroll down to Your apps section
- Click the Web icon
</>to add a web app - Register app nickname:
ShieldAI API - Do not check "Also set up for Firebase Hosting"
- Click Register app
- Copy the
firebaseConfigfor later use in mobile app
3. Generate Service Account Key
- Go to Project settings → Service accounts
- Click Generate new private key
- Save the downloaded JSON file securely
- Extract the following values:
project_idclient_emailprivate_key
4. Configure FCM in ShieldAI
Create a file packages/shared-notifications/.fcm-config.json (gitignored):
{
"projectId": "your-firebase-project-id",
"clientEmail": "service-account@your-project.iam.gserviceaccount.com",
"privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
}
Set environment variables:
export FCM_PROJECT_ID="your-firebase-project-id"
export FCM_CLIENT_EMAIL="service-account@your-project.iam.gserviceaccount.com"
export FCM_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
5. Install Firebase Admin SDK
cd packages/shared-notifications
npm install firebase-admin
Apple Push Notification (APNs) Setup
1. Create App ID
- Go to Apple Developer Portal
- Click + to create new identifier
- Select App IDs → App
- Enter description:
ShieldAI Mobile - Enter Bundle ID:
com.yourcompany.shieldai - Enable Push Notifications capability
- Click Continue → Register
2. Create APNs Key
- Go to Certificates, IDs & Profiles → Keys
- Click + to create new key
- Enter key name:
ShieldAI APNs Key - Enable Apple Push Notification service (APNs)
- Click Continue → Register
- Download the key (
.p8file) - you can only download once! - Note the Key ID displayed
3. Configure APNs in ShieldAI
Convert the .p8 file to PEM format:
# Convert .p8 to PEM
openssl pkcs8 -topk8 -nocrypt -in AuthKey_XXXXXX.p8 -out apns_key.pem
# Copy the PEM content
cat apns_key.pem
Set environment variables:
export APNS_KEY_ID="XXXXXX"
export APNS_TEAM_ID="YYYYYY"
export APNS_BUNDLE_ID="com.yourcompany.shieldai"
export APNS_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
4. Configure in Xcode
In your iOS app's Info.plist:
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
Enable capabilities in Xcode:
- Push Notifications
- Background Modes → Remote notifications
API Endpoints
Device Registration
Register Device
POST /api/v1/devices/register
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
{
"platform": "android",
"fcmToken": "eXwR9...",
"appVersion": "1.0.0",
"osVersion": "Android 13"
}
Response:
{
"success": true,
"device": {
"deviceId": "dev_1234567890_abc123",
"platform": "android",
"registeredAt": "2026-05-14T13:00:00.000Z"
},
"message": "Device registered successfully"
}
Update Device Tokens
PUT /api/v1/devices/:deviceId/tokens
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
{
"fcmToken": "new-token-here",
"apnsToken": "new-token-here"
}
Get Registered Devices
GET /api/v1/devices
Authorization: Bearer <JWT_TOKEN>
Deregister Device
DELETE /api/v1/devices/:deviceId
Authorization: Bearer <JWT_TOKEN>
Mobile App Integration
Android (React Native)
import messaging from '@react-native-firebase/messaging';
import { API } from '@shieldai/api-client';
// Request permission
async function requestPushPermission() {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Push permission granted:', authStatus);
}
}
// Get FCM token
async function getFCMToken() {
const token = await messaging().getToken();
return token;
}
// Register device with API
async function registerDevice() {
try {
const fcmToken = await getFCMToken();
const response = await API.post('/devices/register', {
platform: 'android',
fcmToken,
appVersion: '1.0.0',
osVersion: Platform.OS + ' ' + Platform.Version,
});
console.log('Device registered:', response.data);
} catch (error) {
console.error('Failed to register device:', error);
}
}
// Listen for token refresh
messaging().onTokenRefresh(async (newToken) => {
await API.put('/devices/tokens', {
fcmToken: newToken,
});
});
// Handle foreground messages
messaging().onMessage(async (remoteMessage) => {
console.log('Foreground message received:', remoteMessage);
// Show local notification
});
// Handle background messages
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Background message received:', remoteMessage);
});
iOS (React Native)
import messaging from '@react-native-firebase/messaging';
import { API } from '@shieldai/api-client';
// Request permission
async function requestPushPermission() {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Push permission granted:', authStatus);
}
}
// Get APNs token
async function getAPNSToken() {
const token = await messaging().getToken();
return token;
}
// Register device with API
async function registerDevice() {
try {
const apnsToken = await getAPNSToken();
const response = await API.post('/devices/register', {
platform: 'ios',
apnsToken,
appVersion: '1.0.0',
osVersion: Platform.OS + ' ' + Platform.Version,
});
console.log('Device registered:', response.data);
} catch (error) {
console.error('Failed to register device:', error);
}
}
// Handle foreground messages
messaging().onMessage(async (remoteMessage => {
console.log('Foreground message received:', remoteMessage);
// Show local notification
}));
Testing Push Notifications
Test with Firebase Console
- Go to Firebase Console → Cloud Messaging
- Click Send your first message
- Enter notification title and body
- Choose test device or all users
- Click Send test message
Test with API
# Send test push notification
curl -X POST https://your-api.com/api/v1/notifications/send \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-123",
"channel": "push",
"title": "Test Notification",
"body": "This is a test push notification",
"data": {
"type": "test",
"action": "open_app"
}
}'
Test with cURL (Direct FCM)
curl -X POST https://fcm.googleapis.com/v1/projects/your-project-id/messages:send \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "Content-Type: application/json" \
-d '{
"message": {
"token": "FCM_TOKEN_HERE",
"notification": {
"title": "Test Title",
"body": "Test Body"
},
"data": {
"type": "test"
}
}
}'
Production Checklist
FCM Configuration
- Firebase project created
- Service account key generated and stored securely
- FCM environment variables configured
- Firebase Admin SDK initialized
- Test notifications sent successfully
APNs Configuration
- App ID created with push capability
- APNs key generated and downloaded
- Key converted to PEM format
- APNs environment variables configured
- Xcode capabilities enabled
- Test notifications sent from simulator
API Configuration
- Device registration endpoints working
- Token update endpoints working
- Rate limiting configured
- Error handling implemented
- Logging for push notifications
Mobile App Configuration
- Push permissions requested
- Token retrieval implemented
- Device registration on app start
- Token refresh handling
- Foreground message handling
- Background message handling
- Notification display implemented
Troubleshooting
FCM Token Not Received
- Check Firebase configuration in mobile app
- Verify Google Services (Android) / GoogleService-Info.plist (iOS)
- Ensure push permissions granted
APNs Token Not Received
- Verify App ID configuration in Apple Developer
- Check APNs key configuration
- Ensure background modes enabled in Xcode
- Test on actual device (not simulator)
Notifications Not Delivering
- Check device registration status
- Verify tokens are valid
- Check rate limiting status
- Review server logs for errors
Token Refresh Issues
- Listen for
onTokenRefreshevents - Update tokens via API immediately
- Handle network errors gracefully
Security Considerations
- Never expose service account keys in client-side code
- Always validate device ownership on server
- Use HTTPS for all API calls
- Implement rate limiting to prevent abuse
- Store tokens securely using secure storage libraries
- Deregister devices on user logout
Monitoring
Monitor the following metrics:
- Push notification delivery rate
- Token refresh frequency
- Device registration failures
- Rate limit hits
- Notification open rate
Support
- Firebase Support: https://firebase.google.com/support
- Apple Developer Support: https://developer.apple.com/contact/
- FCM Documentation: https://firebase.google.com/docs/cloud-messaging
- APNs Documentation: https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server