推送渠道 - iOS 与安卓的推送差异

第一个真正的问题

入职第二周,老王找到我:“iOS 用户投诉说收不到推送,特别是晚上发的消息。”

我查了一下推送日志:

2026-03-31 22:30:15 [ERROR] APNs push failed: Invalid token
2026-03-31 22:30:16 [ERROR] APNs push failed: Invalid token
2026-03-31 22:30:17 [ERROR] APNs push failed: Invalid token
...

“Invalid token?” 我问老王。

“可能是用户卸载了 App,或者 token 过期了。”

“我们用的什么推送服务?”

“极光推送,统一封装了 iOS 和安卓。”

我打开极光的文档,发现一个问题:

极光推送的工作原理

┌──────────┐     ┌──────────┐     ┌──────────┐
│ 我们的    │────▶│ 极光推送 │────▶│  APNs    │
│ 服务器    │     │  服务器  │     │ (Apple)  │
└──────────┘     └──────────┘     └──────────┘


                 ┌──────────┐
                 │ 安卓厂商 │
                 │ 推送服务 │
                 └──────────┘

极光推送作为中间层,帮我们对接了各家推送服务。但这也意味着:

  • 我们无法直接控制推送参数
  • 推送失败时,只能看到极光返回的错误,看不到真正的原因
  • 调试困难

iOS 推送:APNs

我决定深入了解一下 APNs。

Apple Push Notification service(APNs)是苹果官方的推送服务。所有 iOS App 的推送,都必须经过 APNs。

APNs 的工作流程

┌────────────┐     ┌────────────┐     ┌────────────┐     ┌────────────┐
│ iOS App    │────▶│ APNs       │────▶│ iOS 设备   │────▶│ 用户       │
│ (我们的)   │     │ (Apple)    │     │            │     │            │
└────────────┘     └────────────┘     └────────────┘     └────────────┘
      │                  ▲
      │                  │
      ▼                  │
┌────────────┐     ┌────────────┐
│ 我们的     │────▶│ APNs       │
│ 服务器     │     │            │
└────────────┘     └────────────┘
  1. App 在用户设备上注册推送
  2. APNs 返回一个 device token
  3. App 把 token 发给我们的服务器
  4. 我们的服务器用 token 通过 APNs 发送推送

关键概念:Device Token

Device token 是 APNs 分配给每个设备的唯一标识。它不是设备 ID,也不是用户 ID,而是 APNs 内部使用的标识。

Device token 可能变化:

  • 用户卸载重装 App
  • 用户恢复设备
  • 用户升级系统
  • Apple 定期更新 token

所以,我们需要定期更新 token,并在推送失败时检测 token 是否失效。

Token 失效处理

我查看了当前的 token 存储方式:

数据设计要点

  • 核心是在 user_devices 里保存业务事实,而不是把规则散落在应用逻辑里。
  • 索引服务于高频查询,重点是缩小扫描范围,而不是堆更多字段。

“这张表有个问题,” 我告诉老王,“同一个用户可能有多台设备,但我们没有处理 token 失效的情况。“

APNs 的反馈服务

APNs 提供了一个反馈服务(Feedback Service),会告诉我们哪些 token 已经失效。

我写了一个脚本,定期查询失效 token:

部署后,失效 token 问题减少了 80%。

安卓推送:更复杂的世界

iOS 只有一个 APNs,但安卓呢?

由于国内无法使用 Google 服务(包括 FCM - Firebase Cloud Messaging),各家手机厂商都有自己的推送服务:

厂商推送服务特点
小米Mi Push系统级推送,到达率高
华为HMS Push需要华为开发者账号
OPPOOPPO Push需要认证
vivovivo Push较新的服务
其他无系统推送需要自建推送通道

问题:我们需要对接多家推送服务!

我调研了一下,发现有两种方案:

方案 A:统一推送平台

使用极光、个推等第三方服务,他们封装了各家厂商推送:

┌──────────┐     ┌──────────┐     ┌──────────┐
│ 我们的    │────▶│ 统一推送 │────▶│ 各厂商   │
│ 服务器    │     │ 平台     │     │ 推送     │
└──────────┘     └──────────┘     └──────────┘

优点:

  • 一套 API,接入简单
  • 维护成本低

缺点:

  • 推送到达率受平台影响
  • 成本较高(按推送量收费)
  • 无法精细控制

方案 B:自建推送系统

直接对接各家厂商推送:

┌──────────┐     ┌──────────┐
│ 我们的    │────▶│ Mi Push  │
│ 服务器    │     └──────────┘
└──────────┘     ┌──────────┐
                 │ HMS Push │
                 └──────────┘
                 ┌──────────┐
                 │ OPPO Push│
                 └──────────┘

优点:

  • 完全控制,可优化到达率
  • 成本可控

缺点:

  • 开发和维护成本高
  • 需要对接多家 API

我权衡了一下,决定先用统一推送平台(极光),再逐步自建。

推送到达率

老王问我:“我们的推送到达率是多少?”

我查了一下极光的统计:

上周推送统计:
- 发送总数:10 万条
- 到达数:8.5 万条
- 到达率:85%

按平台分析:
- iOS:92%
- 安卓(小米):88%
- 安卓(华为):90%
- 安卓(其他):65%

“安卓’其他’到达率只有 65%?”

“那些是没有系统推送的机型,” 老王说,“比如 Google Pixel、一加等,需要 App 在前台才能收到推送。”

我分析了一下原因:

到达率影响因素

  1. 系统级推送:系统内置推送服务,App 不运行也能收到

    • iOS:APNs(100% 系统级)
    • 小米、华为、OPPO、vivo:厂商推送(系统级)
  2. 应用级推送:需要 App 在前台运行

    • 其他机型:无系统推送,到达率低
  3. 用户设置:用户可能关闭了通知权限

    • 需要在 App 内引导用户开启
  4. 网络因素:推送通道不稳定

    • 需要重试机制

提高到达率

我决定采取几个措施:

1. 针对不同机型选择不同策略

2. 引导用户开启通知权限

我在 App 启动时检测通知权限:

3. 推送失败自动降级

推送内容设计

产品经理小李找到我:“推送文案要怎么设计?”

我给她展示了几个例子:

不好的推送

用户 A 评论了你的动态
  • 太模糊,用户不知道哪个动态
  • 没有吸引力,用户可能不点击

好的推送

用户 A:你的文章写得真好,特别是第三段关于...
  • 包含具体内容
  • 吸引用户点击查看完整评论

推送内容限制

不同渠道对推送内容有限制:

渠道标题长度内容长度其他限制
APNs最多 178 字符最多 1024 字符不支持自定义声音
Mi Push最多 50 字符最多 128 字符需要审核
HMS Push最多 40 字符最多 180 字符不支持自定义图标

我写了一个内容适配函数:

推送时机选择

老王问:“半夜推送打扰用户的问题,怎么解决?”

我调研了一下用户活跃时间:

用户活跃时间分布(24 小时):
- 0:00-6:00:5%(深夜)
- 6:00-9:00:15%(早晨)
- 9:00-12:00:25%(上午)
- 12:00-14:00:20%(午休)
- 14:00-18:00:25%(下午)
- 18:00-22:00:30%(晚上)
- 22:00-24:00:10%(睡前)

深夜(0:00-6:00)用户活跃率只有 5%,这时候推送不仅打扰用户,还浪费资源。

我设计了一个推送时段控制:

小结

这周我学到了:

  1. iOS 推送:APNs 是唯一通道,需要处理 token 失效
  2. 安卓推送:国内多家厂商推送,需要选择合适的策略
  3. 到达率优化:区分系统级和应用级推送,引导用户开启权限
  4. 推送内容:不同渠道有限制,需要适配
  5. 推送时机:避免深夜打扰,支持用户自定义免打扰时段

下周,我要处理站内信的设计了。