Loading...
Loading...
Compare original and translation side by side
| 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 |
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 |
用户安装应用
|
v
[首次启动?] ──是──> [先展示价值主张]
| |
否 v
| [用户操作触发需求?]
v |
[已授权?] 是
| |
是 v
| [申请权限] ──> 70-80%接受率
v
[通知功能就绪]| 时机 | 接受率 | 使用场景 |
|---|---|---|
| 立即申请(应用启动时) | 15-20% | 低活跃度应用 |
| 引导流程后申请 | 40-50% | 标准应用 |
| 用户主动操作后申请 | 70-80% | 高活跃度应用 |
[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 | 静默通知 | 完全控制显示样式 |
| 更新角标计数 | 静默通知 | 需要后台处理 |
| 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+的静默推送功能 | 使用 |
| 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作为唯一标识 |
| 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秒后杀死应用 | 任务入队,快速处理 |
| 忘记同时处理两种负载类型 | 会遗漏通知 | 同时处理通知负载与数据负载 |
| 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认证密钥 |
| 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会忽略颜色,显示白色方块 | 使用白底透明图标 |
| 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 | |
// 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);
}// 1. 向服务器注册令牌
const token = await getToken();
await registerToken(token, userId);
// 2. 处理令牌刷新
onTokenRefresh((newToken) => {
updateTokenOnServer(newToken, userId);
});
// 3. 处理令牌失效
if (error.code === 'DeviceNotRegistered') {
deleteTokenFromDatabase(token);
}priority: 'high'priority: 'high'rules/rules/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-*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-*token-*| File | Impact | Description |
|---|---|---|
| HIGH | Token registration with backend |
| HIGH | Token refresh handling |
| MEDIUM | DeviceNotRegistered error handling |
| 文件 | 影响等级 | 描述 |
|---|---|---|
| HIGH | 令牌与后端注册 |
| HIGH | 令牌刷新处理 |
| MEDIUM | DeviceNotRegistered错误处理 |
message-*message-*| File | Impact | Description |
|---|---|---|
| CRITICAL | data vs notification payload differences |
| HIGH | Background message processing |
| HIGH | Foreground notification display |
| 文件 | 影响等级 | 描述 |
|---|---|---|
| CRITICAL | 数据负载与通知负载的差异 |
| HIGH | 后台消息处理 |
| HIGH | 前台通知展示 |
deeplink-*deeplink-*| File | Impact | Description |
|---|---|---|
| MEDIUM | React Navigation conflict resolution |
| MEDIUM | Deep link handling when app is terminated |
| 文件 | 影响等级 | 描述 |
|---|---|---|
| MEDIUM | React Navigation冲突解决 |
| MEDIUM | 应用终止状态下的深度链接处理 |
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 | 推送通知频率限制 |
| File | Impact | Description |
|---|---|---|
| HIGH | Permission request timing optimization (70-80% acceptance) |
| HIGH | Testing tools, debugging techniques, payload validation |
| 文件 | 影响等级 | 描述 |
|---|---|---|
| HIGH | 权限申请时机优化(70-80%接受率) |
| HIGH | 测试工具、调试技巧、负载验证 |
undefinedundefinedundefinedundefined| 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错误) | |
| 权限接受率低 | |
| 如何调试/测试推送 | |
| 无法本地测试 | |
priority: 'high'priority: 'high'gcm.message_idgcm.message_idExponentPushToken[...]eas credentialsExponentPushToken[...]eas credentialsAGENTS.mdAGENTS.md