← 返回 Skill 列表
extension
分类: 开发与工程API Key 暂未确认

capacitor-push-notifications

使用Firebase Cloud Messaging (FCM) 和 Apple Push Notification Service (APNs) 在Capacitor应用中实现推送通知的完整指南。涵盖设置、处理以及最佳实践。当用户需要添加推送通知时,请使用此技能。

person作者: jakexiaohubgithub

Push Notifications in Capacitor

When to Use

TRIGGER when:

  • Adding remote push (FCM / APNs) to a Capacitor app
  • registration / registrationError never fire, or the token works on one platform only
  • iOS token is a 64-hex APNs token but the backend expects an FCM token
  • Notifications arrive in background but not in foreground (or vice versa)
  • Android 13+ shows no prompt and nothing is delivered
  • Upgrading to Capacitor 8.5 (UIScene) or 9 (alert presentation option removed)

Do not use:

  • Opening the app from https:// / myapp:// links: capacitor-deep-linking
  • Moving AppDelegate code to SceneDelegate: capacitor-uiscene-migration
  • Device log capture: ios-android-logs
  • Choosing other native plugins: capacitor-plugins

Choose the plugin first (ask the user if unclear)

| Need | Plugin | |------|--------| | Official plugin; APNs token on iOS, FCM token on Android | @capacitor/push-notifications | | FCM token on both platforms, topics, Firebase-first backend | @capgo/capacitor-firebase-messaging | | Capgo-managed delivery (dashboard campaigns, badges, silent live-update checks, no own push server) | @capgo/capacitor-notifications | | Local notifications only, rich layouts | @capgo/capacitor-rich-notifications or @capacitor/local-notifications |

The rest of this file covers @capacitor/push-notifications. For Capgo plugins follow https://capgo.app/docs/plugins/firebase-messaging/ or https://capgo.app/docs/plugins/notifications/getting-started/.

Workflow

  1. Inspect: package.json versions (@capacitor/core, @capacitor/push-notifications), capacitor.config.* plugins.PushNotifications, ios/App/App/AppDelegate.swift, ios/App/App/*.entitlements, android/app/google-services.json, android/variables.gradle, AndroidManifest.xml.
  2. Install: npm install @capacitor/push-notifications && npx cap sync.
  3. iOS: capability + APNs key + AppDelegate forwarding. Details: references/ios-setup.md.
  4. Android: google-services.json, channel, icon, permission. Details: references/android-setup.md.
  5. JS: listeners first, then permission, then register() (below).
  6. Backend: send a test message. Payload shapes: references/sending.md.
  7. Verify with the checklist below on physical devices.

Only load a reference when its topic is in play.

JS registration (order matters)

import { PushNotifications } from '@capacitor/push-notifications';

export async function initPush() {
  // 1. Listeners before register(), or the first token is missed
  await PushNotifications.addListener('registration', ({ value }) => sendTokenToServer(value));
  await PushNotifications.addListener('registrationError', (err) => console.error('push reg', err.error));
  await PushNotifications.addListener('pushNotificationReceived', (n) => {
    // foreground only (and Android data-only while app is alive)
  });
  await PushNotifications.addListener('pushNotificationActionPerformed', ({ notification, actionId }) => {
    routeFromNotification(notification.data); // tap handling
  });

  // 2. Permission (required on iOS and Android 13+ / targetSdk 33+)
  let perm = await PushNotifications.checkPermissions();
  if (perm.receive === 'prompt' || perm.receive === 'prompt-with-rationale') {
    perm = await PushNotifications.requestPermissions();
  }
  if (perm.receive !== 'granted') return; // explain + link to settings, do not loop prompts

  // 3. Register
  await PushNotifications.register();
}

Traps:

  • Call initPush() at bootstrap so pushNotificationActionPerformed from a cold-start tap is captured.
  • Tokens rotate. Send every registration value to the server and upsert by user + device.
  • On iOS the plugin reports the raw APNs token unless AppDelegate swaps in the FCM token (see ios-setup). Sending an APNs token to FCM fails with messaging/invalid-registration-token.
  • Ask permission after a user action that explains the value; iOS shows the system prompt only once.

Foreground presentation

// capacitor.config.ts
plugins: {
  PushNotifications: {
    presentationOptions: ['badge', 'sound', 'banner', 'list'],
  },
},
  • banner + list replace the deprecated iOS alert. Capacitor 9 removes alert on iOS; replace it when upgrading. badge is iOS only.
  • Empty array = nothing shown in foreground; handle pushNotificationReceived yourself.

Capacitor version notes

| Version | Change | |---------|--------| | 7 | firebaseMessagingVersion default 24.1.0 | | 8 | firebaseMessagingVersion default 25.0.1 | | 8.5 | UIScene lifecycle. Remote-notification callbacks (didRegisterForRemoteNotificationsWithDeviceToken, didFailToRegister...) stay in AppDelegate and keep working. Do not move them to SceneDelegate. Tap routing that used AppDelegate application(_:open:) must move (see capacitor-deep-linking). | | 9 | iOS alert presentation option removed; iOS 16 min; @main replaces @UIApplicationMain; google-services Gradle plugin 4.5.0 |

Verification

  1. iOS: codesign -d --entitlements :- path/to/App.app | grep aps-environment shows development (debug) or production (TestFlight/App Store).
  2. Android: adb shell dumpsys package com.example.app | grep POST_NOTIFICATIONS shows granted=true after accepting the prompt.
  3. App logs a registration token on a real device (iOS Simulator on Apple silicon can receive pushes via xcrun simctl push, but test real APNs on device).
  4. Send a test from Firebase Console (Messaging -> "Send test message") or your backend to that token.
  5. Check all three states: foreground (presentation + pushNotificationReceived), background (system tray), killed (tap -> pushNotificationActionPerformed routes correctly).
  6. iOS simulator smoke test without a server:
cat > /tmp/push.apns <<'EOF'
{ "Simulator Target Bundle": "com.example.app", "aps": { "alert": { "title": "Test", "body": "Hello" } }, "route": "/inbox" }
EOF
xcrun simctl push booted com.example.app /tmp/push.apns

(aps.alert in the APNs payload is the message content and is unaffected by the presentationOptions change.)

Error Handling

| Error / symptom | Cause | Fix | |-----------------|-------|-----| | no valid "aps-environment" entitlement string found for application | Push Notifications capability missing or profile not regenerated | Add capability in Xcode, re-sign, rebuild | | registration never fires on iOS, no error | AppDelegate does not post .capacitorDidRegisterForRemoteNotifications | Add forwarding methods to AppDelegate | | Default FirebaseApp is not initialized in this process (Android) | google-services.json missing/empty, so google-services plugin was not applied (google-services.json not found, google-services plugin not applied. Push Notifications won't work) | Put file in android/app/, rebuild | | messaging/registration-token-not-registered | Token stale (app reinstalled / data cleared) | Delete token server-side; rely on next registration | | messaging/invalid-registration-token / BadDeviceToken | APNs token sent to FCM, or sandbox token sent to production APNs | Use FCM token on iOS (ios-setup) or match APNs environment | | messaging/third-party-auth-error | APNs key not uploaded to Firebase, wrong Key ID / Team ID | Upload .p8 under Firebase Project Settings -> Cloud Messaging | | Android 13+: nothing shown, no prompt | requestPermissions() never called | Call it; manifest permission is added by the plugin | | Android shows white square icon | No monochrome notification icon | Set default_notification_icon meta-data | | Android notification silent / wrong importance | Channel created with low importance (importance is immutable after creation) | Create a new channel id; delete the old one | | Data-only message ignored when app killed (Android) | Plugin only delivers while app process lives | Native FirebaseMessagingService (android-setup) | | iOS silent / background push not delivered to JS | Plugin does not support iOS silent push | Native handling, or @capgo/capacitor-notifications silent update checks | | Duplicate class errors with Firebase after Capacitor 9 | Old core-ktx / Kotlin stdlib pins | See capacitor-app-upgrade-v8-to-v9 |

Resources

  • Plugin API: https://capacitorjs.com/docs/apis/push-notifications
  • Firebase guide: https://capacitorjs.com/docs/guides/push-notifications-firebase
  • Updating to 9.0: https://capacitorjs.com/docs/updating/9-0
  • Capgo Firebase Messaging: https://capgo.app/docs/plugins/firebase-messaging/
  • Capgo Notifications: https://capgo.app/docs/plugins/notifications/