push-notification-best-practices by clix-so/skills
npx skills add https://github.com/clix-so/skills --skill push-notification-best-practices移动应用中实现和排查推送通知的综合指南。涵盖 iOS (APNS)、Android (FCM)、React Native、Expo 和 Flutter 平台,包含平台特定配置、令牌管理、消息处理和深度链接模式。
| 平台 | 离线推送 | 通知栏 | 点击导航 | 应用内弹窗 | 后台处理器 |
|---|---|---|---|---|---|
| iOS | APNS | 系统 | 深度链接 | 自定义 | 仅数据负载 |
| Android | FCM | 系统 | Intent | 自定义 | 仅数据负载 |
| React Native | APNS/FCM | 系统 | React Navigation | 自定义 | setBackgroundMessageHandler |
| Expo | Expo 推送 |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 系统 |
| 链接 |
| 自定义 |
| 任务管理器 |
| Flutter | APNS/FCM | 系统 | 导航器 | 自定义 | onBackgroundMessage |
何时请求通知权限?
用户安装应用
|
v
[首次启动?] ──是──> [先展示价值主张]
| |
否 v
| [用户操作触发需求?]
v |
[已授予?] 是
| |
是 v
| [请求权限] ──> 70-80% 接受率
v
[通知就绪]
| 时机 | 接受率 | 使用场景 |
|---|---|---|
| 立即(应用启动) | 15-20% | 低参与度应用 |
| 引导流程后 | 40-50% | 标准应用 |
| 用户主动操作后 | 70-80% | 高参与度应用 |
建议: 在解释价值后或用户启用相关功能时请求。
应使用哪种负载类型?
[目的是什么?]
|
+──> 时间敏感的用户提醒 ──> 可见(通知负载)
|
+──> 后台数据同步 ──> 静默(仅数据负载)
|
+──> 需要自定义 UI ──> 静默(仅数据负载)
|
+──> 需要后台处理 ──> 静默(仅数据负载)
| 场景 | 负载类型 | 原因 |
|---|---|---|
| 新消息提醒 | 可见 | 用户需要立即关注 |
| 订单状态更新 | 可见 | 时间敏感信息 |
| 后台同步 | 静默 | 无需打断用户 |
| 自定义通知 UI | 静默 | 完全控制显示 |
| 更新角标计数 | 静默 | 需要后台处理 |
何时使用通知服务扩展?
何时使用通知内容扩展?
| 切勿 | 原因 | 替代方案 |
|---|---|---|
| 在首次启动时无上下文请求权限 | 15-20% 接受率 | 先解释价值,再请求 |
| 用户拒绝后重复询问 | 系统忽略重复请求 | 显示设置重定向 |
| 忽略临时授权 | 错过 iOS 12+ 静默交付 | 使用 .provisional 选项 |
| 切勿 | 原因 | 替代方案 |
|---|---|---|
| 长期缓存令牌 | 重新安装/恢复时令牌可能改变 | 始终使用回调中的新令牌 |
| 假设令牌格式 | 格式因平台/SDK 而异 | 视为不透明字符串 |
| 发送未关联用户的令牌 | 无法定向通知 | 在后端与 userId 关联 |
| 存储无设备 ID 的令牌 | 每个用户有重复令牌 | 使用 deviceId 作为唯一键 |
| 切勿 | 原因 | 替代方案 |
|---|---|---|
使用 notification 负载进行后台处理 | 后台不调用 onMessageReceived | 使用仅数据负载 |
| 依赖静默通知进行时间关键交付 | 交付不保证 | 使用可见通知 |
| 在后台处理器中执行繁重操作 | 系统约 30 秒后终止应用 | 排队工作,快速处理 |
| 忘记处理两种负载类型 | 错过通知 | 处理通知 + 数据负载 |
| 切勿 | 原因 | 替代方案 |
|---|---|---|
| 在委托设置前注册通知 | 委托方法不被调用 | 在 registerForRemoteNotifications() 前设置委托 |
跳过 serviceExtensionTimeWillExpire() 实现 | 内容修改失败 | 始终实现回退 |
| 使用 .p12 证书 | 每年过期,已弃用 | 使用 .p8 认证密钥 |
| 切勿 | 原因 | 替代方案 |
|---|---|---|
| 跳过 NotificationChannel 创建 | Android 8.0+ 上通知不显示 | 在应用启动时创建通道 |
对后台处理器使用优先级 normal | Doze 模式阻止交付 | 使用优先级 high |
| 使用彩色通知图标 | Android 忽略颜色,显示白色方块 | 使用透明背景上的白色图标 |
每个规则文件采用混合格式,便于快速查找和深入理解:
影响评级 : 关键(立即修复)、高(显著改进)、中(值得优化)
在以下情况下参考这些指南:
| 优先级 | 类别 | 影响 | 前缀 |
|---|---|---|---|
| 1 | iOS 设置 | 关键 | ios- |
| 2 | Android 设置 | 关键 | android- |
| 3 | 令牌管理 | 高 | token- |
| 4 | 消息处理 | 高 | message- |
| 5 | 深度链接 | 中 | deeplink- |
| 6 | 基础设施 | 中 | infra- |
设置清单:
设置清单:
令牌生命周期:
// 1. 向服务器注册令牌
const token = await getToken();
await registerToken(token, userId);
// 2. 处理令牌刷新
onTokenRefresh((newToken) => {
updateTokenOnServer(newToken, userId);
});
// 3. 处理失效
if (error.code === 'DeviceNotRegistered') {
deleteTokenFromDatabase(token);
}
负载类型:
优先级设置:
priority: 'high'rules/ 中包含代码示例的完整文档:
ios-*)| 文件 | 影响 | 描述 |
|---|---|---|
ios-apns-auth-key.md | 关键 | APNs 认证密钥设置 |
ios-delegate-setup.md | 关键 | UNUserNotificationCenter 委托配置 |
ios-permission-request.md | 关键 | 通知权限请求流程 |
ios-token-registration.md | 高 | APNS 令牌注册和处理 |
ios-foreground-display.md | 高 | 在前台显示通知 |
ios-method-swizzling.md | 中 | 方法交换管理 |
ios-extension-build.md | 中 | 通知服务扩展设置 |
android-*)| 文件 | 影响 | 描述 |
|---|---|---|
android-notification-channel.md | 关键 | 通知通道创建 (Android 8.0+) |
android-permission.md | 关键 | POST_NOTIFICATIONS 运行时权限 (Android 13+) |
android-google-services.md | 关键 | Firebase 项目配置 |
android-messaging-service.md | 高 | FirebaseMessagingService 实现 |
android-notification-icon.md | 中 | 通知图标资源要求 |
android-priority-high.md | 高 | Doze 模式的优先级 'high' |
token-*)| 文件 | 影响 | 描述 |
|---|---|---|
token-registration.md | 高 | 向后端注册令牌 |
token-refresh.md | 高 | 令牌刷新处理 |
token-invalidation.md | 中 | DeviceNotRegistered 错误处理 |
message-*)| 文件 | 影响 | 描述 |
|---|---|---|
message-data-vs-notification.md | 关键 | 数据与通知负载差异 |
message-background-handler.md | 高 | 后台消息处理 |
message-foreground-handler.md | 高 | 前台通知显示 |
deeplink-*)| 文件 | 影响 | 描述 |
|---|---|---|
deeplink-navigation-conflict.md | 中 | React Navigation 冲突解决 |
deeplink-terminated-state.md | 中 | 应用终止时的深度链接处理 |
infra-*)| 文件 | 影响 | 描述 |
|---|---|---|
infra-firewall-ports.md | 中 | 网络防火墙配置 |
infra-backup-fid.md | 中 | Firebase 安装 ID 备份排除 |
infra-rate-limiting.md | 中 | 推送通知速率限制 |
| 文件 | 影响 | 描述 |
|---|---|---|
permission-timing.md | 高 | 权限请求时机优化 (70-80% 接受率) |
testing-debugging.md | 高 | 测试工具、调试技术、负载验证 |
# 按关键词查找规则
grep -l "apns" rules/
grep -l "fcm" rules/
grep -l "token" rules/
grep -l "background" rules/
grep -l "permission" rules/
grep -l "deeplink" rules/
| 问题 | 从以下开始 |
|---|---|
| iOS 未收到推送 | ios-apns-auth-key → ios-delegate-setup |
| Android 未收到推送 | android-google-services → android-notification-channel |
| 后台推送不工作 | android-priority-high → message-background-handler |
| 前台推送不可见 | ios-foreground-display 或 message-foreground-handler |
| 令牌缺失/过期 | token-registration → token-refresh |
| 深度链接冲突错误 | deeplink-navigation-conflict |
| 通知图标损坏 (Android) | android-notification-icon |
| 在企业网络失败 | infra-firewall-ports |
| 后台处理器未调用 (Android) | android-priority-high → message-data-vs-notification |
| userNotificationCenter 未调用 (iOS) | ios-delegate-setup |
| 备份恢复后出现 404 错误 | infra-backup-fid |
| 发送失败 (429 错误) | infra-rate-limiting |
| 权限接受率低 | permission-timing → ios-permission-request |
| 如何调试/测试推送 | testing-debugging |
| 无法本地测试 | testing-debugging → ios-apns-auth-key |
priority: 'high'gcm.message_idExponentPushToken[...]eas credentials 管理 APNs 密钥包含所有扩展规则的完整指南:AGENTS.md
基于推送通知故障排除指南和 Firebase Cloud Messaging 官方文档。
每周安装次数
60
仓库
GitHub 星标数
5
首次出现
2026年1月26日
安全审计
安装于
opencode52
codex51
gemini-cli50
cursor43
claude-code42
github-copilot41
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.
| 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 |
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.
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 |
When to use Notification Service Extension?
When to use Notification Content Extension?
| 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 .provisional option |
| 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 |
| NEVER | Why | Instead |
|---|---|---|
Use notification payload for background processing | 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 |
| NEVER | Why | Instead |
|---|---|---|
| Register for notifications before delegate setup | Delegate methods not called | Set delegate before registerForRemoteNotifications() |
Skip serviceExtensionTimeWillExpire() implementation | Content modification fails | Always implement fallback |
| Use .p12 certificates | Expires yearly, deprecated | Use .p8 authentication key |
| NEVER | Why | Instead |
|---|---|---|
| Skip NotificationChannel creation | Notifications don't appear on Android 8.0+ | Create channel at app start |
Use priority normal for background handlers | Doze mode blocks delivery | Use priority high |
| Use colored notification icons | Android ignores colors, shows white square | Use white-on-transparent icons |
Each rule file follows a hybrid format for fast lookup and deep understanding:
Impact ratings : CRITICAL (fix immediately), HIGH (significant improvement), MEDIUM (worthwhile optimization)
Reference these guidelines when:
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | iOS Setup | CRITICAL | ios- |
| 2 | Android Setup | CRITICAL | android- |
| 3 | Token Management | HIGH | token- |
| 4 | Message Handling | HIGH | message- |
| 5 | Deep Linking |
Setup checklist:
Setup checklist:
Token lifecycle:
// 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);
}
Payload types:
Priority settings:
priority: 'high' for time-sensitive notificationsFull documentation with code examples in rules/:
ios-*)| File | Impact | Description |
|---|---|---|
ios-apns-auth-key.md | CRITICAL | APNs authentication key setup |
ios-delegate-setup.md | CRITICAL | UNUserNotificationCenter delegate configuration |
ios-permission-request.md | CRITICAL | Notification permission request flow |
ios-token-registration.md | HIGH | APNS token registration and handling |
ios-foreground-display.md |
android-*)| File | Impact | Description |
|---|---|---|
android-notification-channel.md | CRITICAL | Notification channel creation (Android 8.0+) |
android-permission.md | CRITICAL | POST_NOTIFICATIONS runtime permission (Android 13+) |
android-google-services.md | CRITICAL | Firebase project configuration |
android-messaging-service.md | HIGH | FirebaseMessagingService implementation |
android-notification-icon.md |
token-*)| File | Impact | Description |
|---|---|---|
token-registration.md | HIGH | Token registration with backend |
token-refresh.md | HIGH | Token refresh handling |
token-invalidation.md | MEDIUM | DeviceNotRegistered error handling |
message-*)| File | Impact | Description |
|---|---|---|
message-data-vs-notification.md | CRITICAL | data vs notification payload differences |
message-background-handler.md | HIGH | Background message processing |
message-foreground-handler.md | HIGH | Foreground notification display |
deeplink-*)| File | Impact | Description |
|---|---|---|
deeplink-navigation-conflict.md | MEDIUM | React Navigation conflict resolution |
deeplink-terminated-state.md | MEDIUM | Deep link handling when app is terminated |
infra-*)| File | Impact | Description |
|---|---|---|
infra-firewall-ports.md | MEDIUM | Network firewall configuration |
infra-backup-fid.md | MEDIUM | Firebase Installation ID backup exclusion |
infra-rate-limiting.md | MEDIUM | Push notification rate limiting |
| File | Impact | Description |
|---|---|---|
permission-timing.md | HIGH | Permission request timing optimization (70-80% acceptance) |
testing-debugging.md | HIGH | Testing tools, debugging techniques, payload validation |
# Find 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/
| Problem | Start With |
|---|---|
| iOS not receiving push | ios-apns-auth-key → ios-delegate-setup |
| Android not receiving push | android-google-services → android-notification-channel |
| Push not working in background | android-priority-high → message-background-handler |
| Push not visible in foreground | ios-foreground-display or |
priority: 'high' for background handlersgcm.message_id required for foreground notificationsExponentPushToken[...]eas credentials for APNs key managementFor the complete guide with all rules expanded: AGENTS.md
Based on push notification troubleshooting guides and Firebase Cloud Messaging official documentation.
Weekly Installs
60
Repository
GitHub Stars
5
First Seen
Jan 26, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode52
codex51
gemini-cli50
cursor43
claude-code42
github-copilot41
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
120,000 周安装
E2E测试模式指南:Playwright实战与最佳实践,构建可靠自动化测试套件
11,600 周安装
Next.js App Router 模式指南:服务器组件、并行路由与全栈开发实战
11,900 周安装
Gmail 收件箱快速处理工具 - gws-gmail-triage 命令使用指南 | Google Workspace CLI
12,100 周安装
GWS Gmail 发送邮件命令:通过命令行快速发送Gmail邮件(支持附件、HTML、草稿)
12,100 周安装
Slack自动化指南:使用Vercel Labs Agent-Browser检查消息、提取数据与任务自动化
12,200 周安装
Tavily AI 搜索技能:为 LLM 优化的网络搜索 API,支持高级过滤与 OAuth 认证
11,900 周安装
| MEDIUM |
deeplink- |
| 6 | Infrastructure | MEDIUM | infra- |
| HIGH |
| Display notifications in foreground |
ios-method-swizzling.md | MEDIUM | Method Swizzling management |
ios-extension-build.md | MEDIUM | Notification Service Extension setup |
| MEDIUM |
| Notification icon asset requirements |
android-priority-high.md | HIGH | Priority 'high' for Doze mode |
message-foreground-handler| Token missing/expired | token-registration → token-refresh |
| Deep link conflict error | deeplink-navigation-conflict |
| Notification icon broken (Android) | android-notification-icon |
| Failed on corporate network | infra-firewall-ports |
| Background handler not called (Android) | android-priority-high → message-data-vs-notification |
| userNotificationCenter not called (iOS) | ios-delegate-setup |
| 404 error after backup restore | infra-backup-fid |
| Send failed (429 error) | infra-rate-limiting |
| Low permission acceptance rate | permission-timing → ios-permission-request |
| How to debug/test push | testing-debugging |
| Cannot test locally | testing-debugging → ios-apns-auth-key |