| name | capacitor-push-notifications |
| description | Complete guide to implementing push notifications in Capacitor apps using Firebase Cloud Messaging (FCM) and Apple Push Notification Service (APNs). Covers setup, handling, and best practices. Use this skill when users need to add push notifications. |
Push Notifications in Capacitor
Implement push notifications for iOS and Android using Firebase and APNs.
When to Use This Skill
- User wants push notifications
- User needs FCM setup
- User asks about APNs
- User has notification issues
- User wants rich notifications
Quick Start
Install Plugin
npm install @capacitor/push-notifications
npx cap sync
Basic Implementation
import { PushNotifications } from '@capacitor/push-notifications';
async function initPushNotifications() {
const permission = await PushNotifications.requestPermissions();
if (permission.receive === 'granted') {
await PushNotifications.register();
}
PushNotifications.addListener('registration', (token) => {
console.log('Push token:', token.value);
sendTokenToServer(token.value);
});
PushNotifications.addListener('registrationError', (error) => {
console.error('Registration error:', error);
});
PushNotifications.addListener('pushNotificationReceived', (notification) => {
console.log('Notification received:', notification);
showInAppNotification(notification);
});
PushNotifications.addListener('pushNotificationActionPerformed', (action) => {
console.log('Notification action:', action);
handleNotificationTap(action.notification);
});
}
Firebase Setup
1. Create Firebase Project
- Go to https://console.firebase.google.com
- Create new project
- Add iOS and Android apps
2. Android Configuration
Download google-services.json to android/app/
// android/build.gradle
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.4.0'
}
}
// android/app/build.gradle
apply plugin: 'com.google.gms.google-services'
dependencies {
implementation platform('com.google.firebase:firebase-bom:32.7.0')
implementation 'com.google.firebase:firebase-messaging'
}
3. iOS Configuration
Download GoogleService-Info.plist to ios/App/App/
pod 'Firebase/Messaging'
import Firebase
import FirebaseMessaging
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure()
return true
}
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
Messaging.messaging().apnsToken = deviceToken
}
}
4. iOS Capabilities
In Xcode:
- Select App target
- Signing & Capabilities
- Add "Push Notifications"
- Add "Background Modes" > "Remote notifications"
APNs Key Setup (iOS)
Create APNs Key
- Go to https://developer.apple.com/account
- Certificates, IDs & Profiles
- Keys > Create Key
- Enable Apple Push Notifications service (APNs)
- Download .p8 file
Add to Firebase
- Firebase Console > Project Settings
- Cloud Messaging tab
- iOS app configuration
- Upload APNs Authentication Key (.p8)
- Enter Key ID and Team ID
Sending Notifications
Firebase Admin SDK (Node.js)
import admin from 'firebase-admin';
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
async function sendToDevice(token: string) {
await admin.messaging().send({
token,
notification: {
title: 'Hello!',
body: 'You have a new message',
},
data: {
type: 'message',
messageId: '123',
},
android: {
priority: 'high',
notification: {
channelId: 'messages',
icon: 'ic_notification',
color: '#4285f4',
},
},
apns: {
payload: {
aps: {
badge: 1,
sound: 'default',
},
},
},
});
}
async function sendToTopic(topic: string) {
await admin.messaging().send({
topic,
notification: {
title: 'Breaking News',
body: 'Something important happened',
},
});
}
async function sendToMultiple(tokens: string[]) {
await admin.messaging().sendEachForMulticast({
tokens,
notification: {
title: 'Update',
body: 'New features available',
},
});
}
HTTP v1 API
curl -X POST \
'https://fcm.googleapis.com/v1/projects/YOUR_PROJECT/messages:send' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"message": {
"token": "DEVICE_TOKEN",
"notification": {
"title": "Hello",
"body": "World"
}
}
}'
Advanced Features
Notification Channels (Android)
import { PushNotifications } from '@capacitor/push-notifications';
await PushNotifications.createChannel({
id: 'messages',
name: 'Messages',
description: 'Message notifications',
importance: 5,
visibility: 1,
sound: 'notification.wav',
vibration: true,
lights: true,
lightColor: '#FF0000',
});
await PushNotifications.deleteChannel({ id: 'old-channel' });
const channels = await PushNotifications.listChannels();
Topic Subscription
await PushNotifications.addListener('registration', async () => {
const messaging = getMessaging();
await subscribeToTopic(messaging, 'news');
await subscribeToTopic(messaging, 'promotions');
});
Rich Notifications (iOS)
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
) {
guard let mutableContent = request.content.mutableCopy() as? UNMutableNotificationContent else {
contentHandler(request.content)
return
}
if let imageUrl = request.content.userInfo["image"] as? String,
let url = URL(string: imageUrl) {
downloadImage(url: url) { attachment in
if let attachment = attachment {
mutableContent.attachments = [attachment]
}
contentHandler(mutableContent)
}
} else {
contentHandler(mutableContent)
}
}
}
Notification Actions
PushNotifications.addListener('pushNotificationActionPerformed', (action) => {
switch (action.actionId) {
case 'reply':
const input = action.inputValue;
sendReply(input);
break;
case 'dismiss':
break;
default:
navigateToContent(action.notification.data);
}
});
Background Handling
Data-Only Notifications
{
"to": "DEVICE_TOKEN",
"data": {
"type": "sync",
"action": "refresh"
}
}
class FirebaseService : FirebaseMessagingService() {
override fun onMessageReceived(message: RemoteMessage) {
message.data["type"]?.let { type ->
when (type) {
"sync" -> performBackgroundSync()
"update" -> checkForUpdates()
}
}
}
}
Local Notifications Fallback
import { LocalNotifications } from '@capacitor/local-notifications';
PushNotifications.addListener('pushNotificationReceived', async (notification) => {
await LocalNotifications.schedule({
notifications: [
{
id: Date.now(),
title: notification.title || '',
body: notification.body || '',
extra: notification.data,
},
],
});
});
Best Practices
Permission Handling
async function requestNotificationPermission() {
const { receive } = await PushNotifications.checkPermissions();
if (receive === 'prompt') {
const shouldRequest = await showPermissionExplanation();
if (shouldRequest) {
const result = await PushNotifications.requestPermissions();
return result.receive === 'granted';
}
return false;
}
if (receive === 'denied') {
showSettingsPrompt();
return false;
}
return receive === 'granted';
}
Token Refresh
PushNotifications.addListener('registration', async (token) => {
const oldToken = await getStoredToken();
if (oldToken !== token.value) {
await updateServerToken(oldToken, token.value);
await storeToken(token.value);
}
});
Error Handling
PushNotifications.addListener('registrationError', (error) => {
console.error('Push registration failed:', error);
analytics.logEvent('push_registration_failed', {
error: error.error,
});
scheduleRetry();
});
Troubleshooting
iOS Not Receiving
- Check APNs key in Firebase
- Verify Push Notifications capability
- Check provisioning profile
- Verify device token format
- Test with Firebase Console
Android Not Receiving
- Verify google-services.json
- Check notification channel exists
- Verify FCM token
- Check battery optimization
- Test with Firebase Console
Common Issues
| Issue | Solution |
|---|
| No token | Check permissions, network |
| Foreground only | Implement background handler |
| Delayed delivery | Use high priority, data-only |
| No sound | Configure notification channel |
| Badge not updating | Set badge in payload |
Resources