push-notification-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePush Notification Best Practices
推送通知最佳实践
Overview
概述
Comprehensive guide for implementing and troubleshooting push notifications in mobile applications. Covers iOS (APNS), Android (FCM), React Native, Expo, and Flutter platforms with platform-specific configurations, token management, message handling, and deep linking patterns.
移动端应用推送通知的实现与排查全面指南,涵盖iOS(APNS)、Android(FCM)、React Native、Expo及Flutter平台,包含平台专属配置、令牌管理、消息处理与深度链接模式。
Platform Support Matrix
平台支持矩阵
| Platform | Offline Push | Notification Bar | Click Navigation | In-App Toast | Background Handler |
|---|---|---|---|---|---|
| iOS | APNS | System | Deep Link | Custom | data-only payload |
| Android | FCM | System | Intent | Custom | data-only payload |
| React Native | APNS/FCM | System | React Navigation | Custom | setBackgroundMessageHandler |
| Expo | Expo Push | System | Linking | Custom | TaskManager |
| Flutter | APNS/FCM | System | Navigator | Custom | onBackgroundMessage |
| 平台 | 离线推送 | 通知栏 | 点击导航 | 应用内提示框 | 后台处理器 |
|---|---|---|---|---|---|
| iOS | APNS | 系统级 | 深度链接 | 自定义 | 仅数据负载 |
| Android | FCM | 系统级 | Intent | 自定义 | 仅数据负载 |
| React Native | APNS/FCM | 系统级 | React Navigation | 自定义 | setBackgroundMessageHandler |
| Expo | Expo Push | 系统级 | Linking | 自定义 | TaskManager |
| Flutter | APNS/FCM | 系统级 | Navigator | 自定义 | onBackgroundMessage |
Decision Trees
决策树
Permission Request Timing
权限申请时机
When to request notification permission?
User installing app
|
v
[First launch?] ──Yes──> [Show value proposition first]
| |
No v
| [User action triggers need?]
v |
[Already granted?] Yes
| |
Yes v
| [Request permission] ──> 70-80% acceptance rate
v
[Notifications ready]| Timing | Acceptance Rate | Use Case |
|---|---|---|
| Immediate (app launch) | 15-20% | Low engagement apps |
| After onboarding | 40-50% | Standard apps |
| User-initiated action | 70-80% | High engagement apps |
Recommendation: Request after explaining value or when user enables a related feature.
何时申请通知权限?
用户安装应用
|
v
[首次启动?] ──是──> [先展示价值主张]
| |
否 v
| [用户操作触发需求?]
v |
[已授权?] 是
| |
是 v
| [申请权限] ──> 70-80%接受率
v
[通知功能就绪]| 时机 | 接受率 | 使用场景 |
|---|---|---|
| 立即申请(应用启动时) | 15-20% | 低活跃度应用 |
| 引导流程后申请 | 40-50% | 标准应用 |
| 用户主动操作后申请 | 70-80% | 高活跃度应用 |
推荐方案: 先解释通知功能价值,或在用户启用相关功能后再申请权限。
Silent vs Visible Notification
静默通知 vs 可见通知
Which payload type should I use?
[What's the purpose?]
|
+──> Time-sensitive user alert ──> Visible (notification payload)
|
+──> Background data sync ──> Silent (data-only payload)
|
+──> Custom UI required ──> Silent (data-only payload)
|
+──> Need background processing ──> Silent (data-only payload)| Scenario | Payload Type | Reason |
|---|---|---|
| New message alert | Visible | User needs immediate attention |
| Order status update | Visible | Time-sensitive information |
| Background sync | Silent | No user interruption needed |
| Custom notification UI | Silent | Full control over display |
| Update badge count | Silent | Background processing needed |
应使用哪种负载类型?
[使用目的是什么?]
|
+──> 时间敏感型用户提醒 ──> 可见通知(通知负载)
|
+──> 后台数据同步 ──> 静默通知(仅数据负载)
|
+──> 需要自定义UI ──> 静默通知(仅数据负载)
|
+──> 需要后台处理 ──> 静默通知(仅数据负载)| 场景 | 负载类型 | 原因 |
|---|---|---|
| 新消息提醒 | 可见通知 | 用户需要立即关注 |
| 订单状态更新 | 可见通知 | 时间敏感型信息 |
| 后台同步 | 静默通知 | 无需打扰用户 |
| 自定义通知UI | 静默通知 | 完全控制显示样式 |
| 更新角标计数 | 静默通知 | 需要后台处理 |
Extension Strategy (iOS)
扩展策略(iOS)
When to use Notification Service Extension?
- Need to modify notification content before display
- Need to download and attach media (images, videos)
- Need to decrypt end-to-end encrypted payloads
- Need to add action buttons dynamically
When to use Notification Content Extension?
- Need custom notification UI beyond system template
- Need interactive elements in expanded view
何时使用Notification Service Extension?
- 需要在通知显示前修改内容
- 需要下载并附加媒体(图片、视频)
- 需要解密端到端加密的负载
- 需要动态添加操作按钮
何时使用Notification Content Extension?
- 需要超出系统模板的自定义通知UI
- 需要在展开视图中添加交互元素
Anti-patterns (NEVER Do)
反模式(绝对不要做)
Permission Handling
权限处理
| NEVER | Why | Instead |
|---|---|---|
| Request permission on first launch without context | 15-20% acceptance rate | Explain value first, then request |
| Re-ask after user denies | System ignores repeated requests | Show settings redirect |
| Ignore provisional authorization | Misses iOS 12+ quiet delivery | Use |
| 绝对不要 | 原因 | 替代方案 |
|---|---|---|
| 首次启动无上下文就申请权限 | 接受率仅15-20% | 先解释价值,再申请权限 |
| 用户拒绝后重复申请 | 系统会忽略重复请求 | 引导用户前往设置开启 |
| 忽略临时授权 | 错过iOS 12+的静默推送功能 | 使用 |
Token Management
令牌管理
| NEVER | Why | Instead |
|---|---|---|
| Cache tokens long-term | Tokens can change on reinstall/restore | Always use fresh token from callback |
| Assume token format | Format varies by platform/SDK | Treat as opaque string |
| Send token without user association | Can't target notifications | Associate with userId on backend |
| Store tokens without device ID | Duplicate tokens per user | Use deviceId as unique key |
| 绝对不要 | 原因 | 替代方案 |
|---|---|---|
| 长期缓存令牌 | 重装/恢复设备后令牌会变更 | 始终使用回调返回的新鲜令牌 |
| 假设令牌格式固定 | 格式因平台/SDK而异 | 将其视为不透明字符串 |
| 发送未关联用户的令牌 | 无法精准推送通知 | 在后端将令牌与userId关联 |
| 存储令牌时不关联设备ID | 同一用户可能有重复令牌 | 使用deviceId作为唯一标识 |
Message Handling
消息处理
| NEVER | Why | Instead |
|---|---|---|
Use | onMessageReceived not called in background | Use data-only payload |
| Rely on silent notifications for time-critical delivery | Delivery not guaranteed | Use visible notifications |
| Execute heavy operations in background handler | System kills app after ~30 seconds | Queue work, process quickly |
| Forget to handle both payload types | Missing notifications | Handle notification + data payloads |
| 绝对不要 | 原因 | 替代方案 |
|---|---|---|
使用 | 后台不会触发onMessageReceived | 使用仅数据负载 |
| 依赖静默通知实现时间敏感型推送 | 送达无法保证 | 使用可见通知 |
| 在后台处理器中执行重操作 | 系统会在约30秒后杀死应用 | 任务入队,快速处理 |
| 忘记同时处理两种负载类型 | 会遗漏通知 | 同时处理通知负载与数据负载 |
iOS Specific
iOS专属
| NEVER | Why | Instead |
|---|---|---|
| Register for notifications before delegate setup | Delegate methods not called | Set delegate before |
Skip | Content modification fails | Always implement fallback |
| Use .p12 certificates | Expires yearly, deprecated | Use .p8 authentication key |
| 绝对不要 | 原因 | 替代方案 |
|---|---|---|
| 未设置代理就注册通知 | 代理方法不会被调用 | 在 |
不实现 | 内容修改会失败 | 始终实现降级方案 |
| 使用.p12证书 | 每年过期且已被弃用 | 使用.p8认证密钥 |
Android Specific
Android专属
| NEVER | Why | Instead |
|---|---|---|
| Skip NotificationChannel creation | Notifications don't appear on Android 8.0+ | Create channel at app start |
Use priority | Doze mode blocks delivery | Use priority |
| Use colored notification icons | Android ignores colors, shows white square | Use white-on-transparent icons |
| 绝对不要 | 原因 | 替代方案 |
|---|---|---|
| 不创建NotificationChannel | Android 8.0+上通知不会显示 | 应用启动时创建渠道 |
后台处理器使用 | 休眠模式会阻止送达 | 使用 |
| 使用彩色通知图标 | Android会忽略颜色,显示白色方块 | 使用白底透明图标 |
Skill Format
规则格式
Each rule file follows a hybrid format for fast lookup and deep understanding:
- Quick Pattern: Incorrect/Correct code snippets for immediate pattern matching
- When to Apply: Situations where this rule is relevant
- Deep Dive: Full context with step-by-step guides and platform-specific details
- Common Pitfalls: Common mistakes and how to avoid them
- Related Rules: Cross-references to related patterns
Impact ratings: CRITICAL (fix immediately), HIGH (significant improvement), MEDIUM (worthwhile optimization)
每个规则文件采用混合格式,兼顾快速查询与深度理解:
- 快速模式:错误/正确代码片段,用于即时匹配模式
- 适用场景:该规则的适用情况
- 深度解析:完整上下文,含分步指南与平台专属细节
- 常见陷阱:常见错误及规避方法
- 相关规则:关联模式的交叉引用
影响等级:CRITICAL(立即修复)、HIGH(显著改进)、MEDIUM(值得优化)
When to Apply
适用场景
Reference these guidelines when:
- Setting up push notifications in a mobile app
- Debugging push notification delivery issues
- Implementing background notification handlers
- Integrating deep linking with push notifications
- Managing push tokens and device registration
- Troubleshooting platform-specific push issues
- Reviewing push notification code for reliability
以下场景可参考本指南:
- 移动端应用推送通知搭建
- 推送通知送达问题调试
- 后台通知处理器实现
- 推送通知与深度链接集成
- 推送令牌与设备注册管理
- 平台专属推送问题排查
- 推送通知代码可靠性评审
Priority-Ordered Guidelines
优先级排序指南
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | iOS Setup | CRITICAL | |
| 2 | Android Setup | CRITICAL | |
| 3 | Token Management | HIGH | |
| 4 | Message Handling | HIGH | |
| 5 | Deep Linking | MEDIUM | |
| 6 | Infrastructure | MEDIUM | |
| 优先级 | 分类 | 影响等级 | 前缀 |
|---|---|---|---|
| 1 | iOS配置 | CRITICAL | |
| 2 | Android配置 | CRITICAL | |
| 3 | 令牌管理 | HIGH | |
| 4 | 消息处理 | HIGH | |
| 5 | 深度链接 | MEDIUM | |
| 6 | 基础设施 | MEDIUM | |
Quick Reference
快速参考
Critical: iOS Setup
关键:iOS配置
Setup checklist:
- Generate APNs authentication key (.p8) from Apple Developer
- Upload to Firebase Console with Key ID and Team ID
- Enable Push Notifications capability in Xcode
- Set UNUserNotificationCenter delegate in didFinishLaunchingWithOptions
- Request notification authorization before registering
- Implement foreground presentation options
配置清单:
- 从Apple Developer生成APNs认证密钥(.p8)
- 上传至Firebase控制台,填写Key ID与Team ID
- 在Xcode中启用Push Notifications能力
- 在didFinishLaunchingWithOptions中设置UNUserNotificationCenter代理
- 注册前申请通知授权
- 实现前台展示选项
Critical: Android Setup
关键:Android配置
Setup checklist:
- Add google-services.json to app/ directory
- Apply google-services Gradle plugin
- Create NotificationChannel (Android 8.0+)
- Request POST_NOTIFICATIONS permission (Android 13+)
- Implement FirebaseMessagingService
- Set notification icon (transparent background + white)
- Use priority 'high' for Doze mode compatibility
配置清单:
- 将google-services.json添加至app/目录
- 应用google-services Gradle插件
- 创建NotificationChannel(Android 8.0+)
- 申请POST_NOTIFICATIONS权限(Android 13+)
- 实现FirebaseMessagingService
- 设置通知图标(透明背景+白色)
- 使用'high'优先级以兼容休眠模式
High: Token Management
重要:令牌管理
Token lifecycle:
javascript
// 1. Register token with server
const token = await getToken();
await registerToken(token, userId);
// 2. Handle token refresh
onTokenRefresh((newToken) => {
updateTokenOnServer(newToken, userId);
});
// 3. Handle invalidation
if (error.code === 'DeviceNotRegistered') {
deleteTokenFromDatabase(token);
}令牌生命周期:
javascript
// 1. 向服务器注册令牌
const token = await getToken();
await registerToken(token, userId);
// 2. 处理令牌刷新
onTokenRefresh((newToken) => {
updateTokenOnServer(newToken, userId);
});
// 3. 处理令牌失效
if (error.code === 'DeviceNotRegistered') {
deleteTokenFromDatabase(token);
}High: Message Handling
重要:消息处理
Payload types:
- data-only: Background handler runs on both platforms
- notification + data: iOS/Android behavior differs
- iOS: Always shows notification
- Android: Background = system tray, Foreground = onMessageReceived
Priority settings:
- Use for time-sensitive notifications
priority: 'high' - Required for Android Doze mode background handlers
负载类型:
- 仅数据负载:前后台处理器在双平台均会运行
- 通知+数据负载:iOS/Android行为不同
- iOS:始终显示通知
- Android:后台=系统托盘,前台=触发onMessageReceived
优先级设置:
- 时间敏感型通知使用
priority: 'high' - Android休眠模式下的后台处理器必须设置该优先级
Rules
规则
Full documentation with code examples in :
rules/含代码示例的完整文档位于目录:
rules/iOS Setup (ios-*
)
ios-*iOS配置 (ios-*
)
ios-*| File | Impact | Description |
|---|---|---|
| CRITICAL | APNs authentication key setup |
| CRITICAL | UNUserNotificationCenter delegate configuration |
| CRITICAL | Notification permission request flow |
| HIGH | APNS token registration and handling |
| HIGH | Display notifications in foreground |
| MEDIUM | Method Swizzling management |
| MEDIUM | Notification Service Extension setup |
| 文件 | 影响等级 | 描述 |
|---|---|---|
| CRITICAL | APNs认证密钥配置 |
| CRITICAL | UNUserNotificationCenter代理配置 |
| CRITICAL | 通知权限申请流程 |
| HIGH | APNS令牌注册与处理 |
| HIGH | 前台通知展示 |
| MEDIUM | 方法混写管理 |
| MEDIUM | Notification Service Extension配置 |
Android Setup (android-*
)
android-*Android配置 (android-*
)
android-*| File | Impact | Description |
|---|---|---|
| CRITICAL | Notification channel creation (Android 8.0+) |
| CRITICAL | POST_NOTIFICATIONS runtime permission (Android 13+) |
| CRITICAL | Firebase project configuration |
| HIGH | FirebaseMessagingService implementation |
| MEDIUM | Notification icon asset requirements |
| HIGH | Priority 'high' for Doze mode |
| 文件 | 影响等级 | 描述 |
|---|---|---|
| CRITICAL | NotificationChannel创建(Android 8.0+) |
| CRITICAL | POST_NOTIFICATIONS运行时权限(Android 13+) |
| CRITICAL | Firebase项目配置 |
| HIGH | FirebaseMessagingService实现 |
| MEDIUM | 通知图标资源要求 |
| HIGH | 高优先级配置以兼容休眠模式 |
Token Management (token-*
)
token-*令牌管理 (token-*
)
token-*| File | Impact | Description |
|---|---|---|
| HIGH | Token registration with backend |
| HIGH | Token refresh handling |
| MEDIUM | DeviceNotRegistered error handling |
| 文件 | 影响等级 | 描述 |
|---|---|---|
| HIGH | 令牌与后端注册 |
| HIGH | 令牌刷新处理 |
| MEDIUM | DeviceNotRegistered错误处理 |
Message Handling (message-*
)
message-*消息处理 (message-*
)
message-*| File | Impact | Description |
|---|---|---|
| CRITICAL | data vs notification payload differences |
| HIGH | Background message processing |
| HIGH | Foreground notification display |
| 文件 | 影响等级 | 描述 |
|---|---|---|
| CRITICAL | 数据负载与通知负载的差异 |
| HIGH | 后台消息处理 |
| HIGH | 前台通知展示 |
Deep Linking (deeplink-*
)
deeplink-*深度链接 (deeplink-*
)
deeplink-*| File | Impact | Description |
|---|---|---|
| MEDIUM | React Navigation conflict resolution |
| MEDIUM | Deep link handling when app is terminated |
| 文件 | 影响等级 | 描述 |
|---|---|---|
| MEDIUM | React Navigation冲突解决 |
| MEDIUM | 应用终止状态下的深度链接处理 |
Infrastructure (infra-*
)
infra-*基础设施 (infra-*
)
infra-*| File | Impact | Description |
|---|---|---|
| MEDIUM | Network firewall configuration |
| MEDIUM | Firebase Installation ID backup exclusion |
| MEDIUM | Push notification rate limiting |
| 文件 | 影响等级 | 描述 |
|---|---|---|
| MEDIUM | 网络防火墙配置 |
| MEDIUM | Firebase安装ID备份排除 |
| MEDIUM | 推送通知频率限制 |
Best Practices
最佳实践
| File | Impact | Description |
|---|---|---|
| HIGH | Permission request timing optimization (70-80% acceptance) |
| HIGH | Testing tools, debugging techniques, payload validation |
| 文件 | 影响等级 | 描述 |
|---|---|---|
| HIGH | 权限申请时机优化(70-80%接受率) |
| HIGH | 测试工具、调试技巧、负载验证 |
Searching Rules
规则搜索
bash
undefinedbash
undefinedFind rules by keyword
按关键词查找规则
grep -l "apns" rules/
grep -l "fcm" rules/
grep -l "token" rules/
grep -l "background" rules/
grep -l "permission" rules/
grep -l "deeplink" rules/
undefinedgrep -l "apns" rules/
grep -l "fcm" rules/
grep -l "token" rules/
grep -l "background" rules/
grep -l "permission" rules/
grep -l "deeplink" rules/
undefinedProblem → Rule Mapping
问题→规则映射
| Problem | Start With |
|---|---|
| iOS not receiving push | |
| Android not receiving push | |
| Push not working in background | |
| Push not visible in foreground | |
| Token missing/expired | |
| Deep link conflict error | |
| Notification icon broken (Android) | |
| Failed on corporate network | |
| Background handler not called (Android) | |
| userNotificationCenter not called (iOS) | |
| 404 error after backup restore | |
| Send failed (429 error) | |
| Low permission acceptance rate | |
| How to debug/test push | |
| Cannot test locally | |
| 问题 | 从以下规则开始排查 |
|---|---|
| iOS无法接收推送 | |
| Android无法接收推送 | |
| 后台推送不生效 | |
| 前台推送不可见 | |
| 令牌丢失/过期 | |
| 深度链接冲突错误 | |
| Android通知图标损坏 | |
| 企业网络下推送失败 | |
| Android后台处理器未触发 | |
| iOS的userNotificationCenter未触发 | |
| 备份恢复后出现404错误 | |
| 发送失败(429错误) | |
| 权限接受率低 | |
| 如何调试/测试推送 | |
| 无法本地测试 | |
Platform-Specific Notes
平台专属说明
iOS (APNS)
iOS (APNS)
- Requires Apple Developer account and APNs authentication key (.p8)
- Different behavior for Development vs Production builds
- Delegate must be set before other SDK initialization
- Method Swizzling can interfere with delegate calls
- 需要Apple开发者账号与APNs认证密钥(.p8)
- 开发版与生产版构建的行为不同
- 必须在其他SDK初始化前设置代理
- 方法混写可能干扰代理调用
Android (FCM)
Android (FCM)
- Requires google-services.json from Firebase Console
- NotificationChannel required for Android 8.0+
- Runtime permission required for Android 13+
- Doze mode requires for background handlers
priority: 'high' - Notification icons must be monochrome (white on transparent)
- 需要从Firebase控制台获取google-services.json
- Android 8.0+必须创建NotificationChannel
- Android 13+需要运行时权限
- 休眠模式下后台处理器需要设置
priority: 'high' - 通知图标必须为单色(白底透明)
React Native
React Native
- Common issue: required for foreground notifications
gcm.message_id - Deep linking conflicts with React Navigation
- Terminated state requires native → JS bridge pattern
- 常见问题:前台通知需要
gcm.message_id - 深度链接与React Navigation存在冲突
- 应用终止状态下需要原生→JS桥接模式
Expo
Expo
- ExpoPushToken format:
ExponentPushToken[...] - Rate limit: 600 push notifications per second per project
- Development builds required for SDK 53+
- Use for APNs key management
eas credentials
- ExpoPushToken格式:
ExponentPushToken[...] - 频率限制:每个项目每秒最多600条推送通知
- SDK 53+需要使用开发构建版本
- 使用管理APNs密钥
eas credentials
Full Compiled Document
完整编译文档
For the complete guide with all rules expanded:
AGENTS.md包含所有规则详情的完整指南:
AGENTS.mdAttribution
参考来源
Based on push notification troubleshooting guides and Firebase Cloud Messaging official documentation.
基于推送通知排查指南与Firebase Cloud Messaging官方文档整理。