1. 推送不是玄学:先搞懂它到底是什么
1.1 推送的本质:一条消息如何走进用户的手机
做App开发这些年,我经常遇到产品经理跑过来问:“就给用户发个通知,怎么安卓和iOS那边的对接人说法还不一样?”这个问题背后,其实是很多人对推送的底层机制有误解。你以为推送是App自己跑在后台,然后主动弹个通知?不是的。
推送的本质是一次“服务端到客户端”的消息投递,但它走的路跟普通HTTP请求完全不同。普通请求是App主动来找服务器要数据,比如你打开淘宝刷新首页,那是“拉”的过程。而推送是服务器主动往用户手机上塞一条消息,就算App当时没打开、甚至被用户从后台划掉了,只要手机系统还允许通知权限,消息就能显示出来。
这里的关键在于:App本身在绝大多数情况下“不参与”消息的展示过程。真正把消息弹到屏幕上的,是手机系统。所以在iOS上,Apple有一套自己的推送中转站叫APNs(Apple Push Notification service);在Android上,虽然有一个Google官方的FCM(Firebase Cloud Messaging),但国内因为各种原因基本用不上,取而代之的是华为、小米、OPPO、vivo这些厂商各自的推送通道。你发的每条消息,本质上都是先跑到这些系统通道那里,再由系统决定“什么时候、以什么方式”呈现给用户。
理解了这一点,你再看“推送到达率为什么突然变低”“为什么iOS收不到但Android能收到”这些问题,思路就会清晰很多。它不是App代码的问题,而是你走的通道、配置、权限、甚至用户习惯共同作用的结果。
1.2 为什么国内Android一定要聊“厂商通道”
按照Google的设想,Android开发者只需要集成FCM,就能“一次接入、全球推送”。但在国内的实际环境里,FCM时好时坏,很多手机根本没有Google服务框架,所以FCM这条路基本是堵死的。
于是国内主流的方案变成了这样:你的App集成极光推送、个推、友盟推送或者腾讯信鸽这类第三方推送SDK,然后由这些SDK在内部“智能选择”一条可用的通道。如果App进程还活着,就用App自己建立的常连接来收发消息;如果App进程已经被系统杀掉、或者处于纯后台状态,就必须借助厂商通道——也就是华为Push Kit、小米MiPush、OPPO Push、vivo Push、荣耀Push这些系统级服务。
为什么要借厂商通道?因为手机厂商把这些通道的定义为“系统级优先级最高”,就算App被杀掉了,系统依然可以接收服务端发来的消息,然后以系统通知栏的形式展示出来。你的App进没进程、死不死亡,都不影响这条消息到达。
所以做安卓推送的第一课就是:只要能接入厂商通道,就不要只靠长连接裸奔。对于国内App来说,长连接在用户切后台、锁屏、清理内存之后会变得非常脆弱。但这也不意味着直接套一个第三方SDK就完了,你还需要去各个厂商的开放平台注册应用、申请消息服务、配置SHA256指纹、上线审核。不同厂商、不同机型、不同系统版本,规则还不太一样,这部分我后面会专门拆开讲。
1.3 iOS的APNs和Android完全不同的“游戏规则”
iOS这边相对“省心”,因为苹果把通道收得很紧。每个iOS设备在激活时会跟APNs建立一个持续的TLS连接,你的App需要从APNs拿到一个device token,然后把token传给自己的服务端。之后服务端想推消息,就打给APNs,APNs再找到对应的设备弹通知。
很多第一次做iOS推送的开发者会困惑一个问题:“为什么我服务端推送成功了,手机上就是不显示?”这种问题多半出在三个地方:证书或密钥配置错误、payload格式不正确、或者是App在前台导致通知被吞掉了。尤其是第三条,很多人不知道:iOSApp在前台运行时,默认是不会弹系统通知条幅的,你必须在AppDelegate里面实现willPresent notification这个方法,手动把内容展示出来。
Android这边的代表差异是:通知的展示方式、角标数字、通知渠道优先级、厂商通道的送达回执,都需要你自己处理。简单说,iOS把“消息能到手机”这件事做得很固定,你只需要在固定的框架里做对配置;Android则是“条条大路能通罗马”,但路况随时在变,你得自己判断哪条路最稳。
2. 从零搭一条推送链路:客户端、服务端、消息层
2.1 客户端注册Token的完整流程
先把最底层的“地基层”讲清楚。无论你用哪种推送服务,整个链路的第一步都是让设备获得一个唯一的token标识。
以iOS为例,流程是这样的:App启动后,向APNs发起注册,APNs会返回一个由设备硬件和应用BundleID共同生成的device token。App再把这个token上报给你自己的后端服务器,后端存起来,等老师要推送时拿着这个token去调用APNs接口。必须注意:这个token不是永久的,用户重装系统、从备份恢复、甚至系统更新后都可能变化,而且它在APNs沙箱环境和生产环境也是两个不同的体系。所以很多推送系统会要求服务端每次收到token都做“覆盖更新”,而不是简单去重。
Android走厂商通道时的流程也类似,但更繁琐。比如华为要求先通过HmsMessageService.onNewToken拿到token,再把token同步给推送服务端;小米那套也差不多,不同厂商还会要求不同的包名、AppID、AppSecret、证书指纹。第三方SDK一般会帮你做“聚合”,把你的token同步给所有厂商通道,你只要在后台能管理就好。
我遇到过一个特别典型的错误:测试阶段把iOS的development token传到了线上生产环境的推送接口,结果开发环境设备能收到消息、线上用户全都不行。排查了大半天,才发现是服务端把apns-topic、环境字段这些搞混了。token这个东西听着简单,真到了多平台多环境混合操作的时候,坑还不小。
2.2 服务端下发消息的两种姿势
服务端怎么把消息发出去呢?两种主流方式。
第一种,直接调用各平台或第三方SDK提供的HTTP接口。这种方式最直接,适合触发型场景。比如用户发了一条评论,另一端就要立刻收到通知,这时候你在业务代码里同步或者异步地调用一下推送接口,把参数传过去就行。
第二种,走消息队列异步推送。这个适合高并发或需要限流控制的场景。比如一场促销活动要同时给100万用户发push,你不可能在用户请求线程里直接一个循环调第三方接口,那会把上游服务和推送服务都打挂。正确做法是把“要推给谁、推什么内容”封装成一个任务,丢进RabbitMQ或者Kafka,然后由推送消费者一批一批地拉取、批量调用上游接口,并对失败任务做重试。
对于热词里提到的“sse消息推送”,它属于另一条路线:服务端主动往浏览器或App端的EventSource连接里写入事件流,常用于IM、客服对话、实时通知这类场景。它跟原生推送有一个本质区别:SSE要求App或浏览器必须保持着一个活跃连接,断开了就收不到。所以在App里面,SSE通常只作为“App在前台时”的实时补充,真正的挂后台能力还是要靠APNs或厂商通道。
2.3 消息合并、时效性与展示策略
先问自己一个问题:用户3分钟没看手机,你这期间发了5条活动通知,是让他一次看到5条好,还是合并成1条“你有5条新消息”更好?
在讲体验时,我一般主张“能合并就合并”。连续推送多条相同类型的内容,非常容易引起用户反感直接关通知权限。有些推送服务提供了collapse_id或unique_id参数,你可以在后台把同一类型消息的ID设为同一个值。这样当系统发现手机里已经有同ID的消息待显示时,新消息就会替代旧消息,而不是叠在下面。
时效性也很关键。APNs的payload里有个apns-expiration字段,代表消息的有效期,超过这个时间还没送达就不再投递。这个字段特别适合“验证码、限时秒杀提醒、直播开播提醒”这类场景。比如一个直播开播提醒,设定有效期5分钟,用户正好这5分钟没网、没开机,等他恢复时消息已经失效,那就别再弹了,再弹只会显得烦人。
展示策略上,还要考虑App处于什么状态。Android做得比较丰富,你可以定义通知渠道的重要性等级,比如分“紧急”“默认”“低优先级”。WebPush那边类似,也有urgency字段可以控制消息优先级。这些细节直接影响用户在通知栏看到的顺序和样式,但很多人忽略了它们。
3. 选型实测:自建推送还是第三方推送服务
3.1 第三方推送的优缺点
对多数中小团队来说,用市面上的第三方推送服务是性价比最高的选择。像极光推送、个推、友盟、腾讯移动推送,这些服务基本都把“聚合厂商通道”“统计报表”“标签分群”“定时推送”这些功能做成熟了,接入有现成的SDK,后台管理有可视化的界面。最早期的开发阶段,你只需要注册账号、上传证书或者配置密钥、集成SDK,一天就能让一条消息从控制台到用户手机上。
但第三方服务并不是免费的。免费版普遍限制并发、劝你展示广告,或者限制标签数量。等你用户量上来,需要更高的并发、更细的数据维度时,付费套餐不便宜。另一个问题是数据:你的用户设备信息、推送行为数据,都沉淀在第三方的服务器上,这在国内隐私合规越来越严格的背景下,需要做充分的数据合规评估。
我见过一些初创团队因为早期图方便,直接用了第三方,等做到百万日活之后才发现每条消息的费用和被绑定的数据出口都很难受。所以选型时一定不要只看“接入快不快”,要连未来两年的规模发展一起估进去。
3.2 自建推送的最佳适用场景
自建推送,听起来很硬核,但实际不是所有团队都需要。我建议至少在下面几种情况考虑自建:
一是App有极高的安全合规要求,比如金融、政企类应用,你不想让第三方拿到终端设备信息。 二是对推送链路和数据自主可控要求极高,像一些大厂在IM、社交领域,推送是产品的核心体验,自建可以针对长连接做深度调优。 三是使用量特别大,比如日均推送量超过百万甚至千万级,用第三方按量计费,成本会变得异常夸张。自建之后,运维成本会被摊薄,长期看更省钱。
自建方案的核心是自建长连接服务和消息管理后台。你自己维护一个MQTT或者自定义TCP长连接服务端,在App里维持心跳,同时配合厂商通道兜底。这套方案的难点不在“消息能发出去”,而在稳定性:海量连接下的心跳保活、弱网重连、离线消息存储、消息幂等去重、用户在线状态一致性。没做过高并发网络服务的团队,很容易在这里翻车。
3.3 我整理过的选型参照
我从成本、接入难度、到达率、可定制性四个维度做过一次对比,大致是这样:
| 方案 | 接入成本 | 加权到达率 | 定制能力 | 长期成本 |
|---|---|---|---|---|
| 第三方聚合推送 | 低 | 中高(全国产机混合) | 弱 | 随量线性上涨 |
| 第三方+FCM/APNs自管 | 中 | 中 | 中 | 中 |
| 纯自建长连接 | 高 | 中(需配厂商通道兜底) | 强 | 前期高、后期低 |
| 厂商通道直连 | 中高 | 高 | 较强 | 免费,但人力成本高 |
如果团队规模不大、又像很多互联网金融、工具类App那样特别看重送达率,我推荐“第三方推送服务为主,同时自己接好厂商通道”的混合方案。因为第三方已经帮你处理了跟多家厂商的适配,省下的时间可以拿去优化业务,而不是天天盯着安卓厂商的新规则发愁。
3.4 我踩过的选型坑:别被“到达率99%”忽悠
选型时最容易被市场宣传里的“到达率99%”忽悠。真实情况是,按通知栏显示统计的到达率,和你业务真正关心的“有效消息”到达率,完全不是一回事。有些服务商把“推送服务器收到了消息”也算作到达,那数字当然漂亮。但用户手机到底有没有显示,厂商通道在不在线,用户是不是已经关掉了通知栏权限,这些都是影响“真实到达”的因素。
我现在的习惯是:不只盯控制台的送达数,还定期抽样对比“推送消息数”和“用户点击打开数”。如果送达率高但点击率低得离谱,那大概率是消息内容或推送时机出了问题,而不是通道出了问题;如果送达率本身就低,又集中出现在某个机型或某个系统版本,那就要去查厂商通道的配置了。
另外,接入任何第三方SDK前,一定要去官网翻最新的权限文档。有些SDK默认申请了一堆跟推送无关的权限,审核的时候很容易被应用商店打回,用户看了也害怕。这块虽然不算“选型”,但算是接入的隐性成本之一。
4. 推送落地:Android项目打包、发布与更新分发
4.1 Android Studio生成APK后,凭什么还要通过Git发布到服务器
热词里有一条特别实在的诉求:“Android Studio生成的APK如何通过Git推送发布到服务器以便后续更新”。这条问得很具体,也戳中了很多独立开发者和中小团队的痛点。
很多新手开发者的做法是:用Android Studio打包生成APK,然后通过微信、QQ把文件传给同事,或者自己传到网盘,再让用户扫码下载。这种方案在开发初期确实简单,但缺点是完全没有版本管理、没有灰度策略、也没有日志排查依据。你根本不知道线上用户拿着的是哪个包、哪个版本。等用户量再大一点,你一定会需要一套“服务端存放版本信息、App启动时主动检查更新”的自动化流程。
Git在这里不是用来存大文件的,而是用来做“版本发布的触发器和审计”的。具体做法是:在你打好了新版本APK之后,打一个Git tag,比如v1.2.0,然后由一个自动化脚本检测到这个新tag,就触发打包服务器去拉源码、构建APK、并把产物同步到你自己的服务器或对象存储上。这样你的APK发布过程就跟代码版本严格绑定起来了,哪个版本对应哪段代码,一查便知。
4.2 用Git Tag触发APK发布到服务器的可落地步骤
我以一套最常用的实战流程为例,用的工具是GitLab CI、Linux服务器,以及Nginx做静态文件服务。
- 开发和测试通过了,先在本地或者CI上打一个发布tag:
git tag -a v1.2.0 -m "release: 新增活动页 + 修复登录bug" git push origin v1.2.0- 在GitLab CI的配置文件中加一条发布任务,当tag以
v开头时触发布构建:
release-apk: stage: build only: - /^v\d+\.\d+\.\d+$/ script: - ./gradlew assembleRelease - scp app/build/outputs/apk/release/app-release.apk user@your-server:/data/apk/app-v1.2.0.apk - ssh user@your-server "echo 'v1.2.0' > /data/apk/latest-version.txt"这里的关键点是:你把latest-version.txt和APK文件放到了服务器的同一个目录,Nginx把它们都暴露在同一个URL前缀下。App后续做版本更新时,只需要请求这个txt文件,就能拿到“当前服务端最新版本号”,再跟自己本地的versionCode比较,决定要不要提示升级。
- 在App里写一个简单的更新检查接口,把服务器上的版本号和本地比对,并把下载地址返回给客户端。升级弹窗一律走App内逻辑,而不是依赖应用市场。
这套流程的好处是“发布历史拉得清”:每次正式发包都有tag、有CI日志、有服务器文件记录。最重要的是,回滚的时候你在服务器上保留历史版本,出问题把txt改回上一个版本,用户端马上就能回退,不用重新打包。
4.3 版本强制升级与灰度发布的设计细节
版本更新不只是“有新版本就弹窗”那么简单。我见过不少团队因为写死了“只要服务器版本号比本地高,就弹升级窗”,结果被用户骂了几个月。原因其实很简单:要么新版本还藏着严重的崩溃bug,要么产品经理压根不想让某些用户升级。
所以更新接口最好设计成三个字段:latest_version、minimum_version、download_url。如果本地的versionCode比minimum_version低,就走强制升级逻辑,弹窗不可关闭,必须更新才能继续用App;如果只比latest_version旧但高于minimum_version,就弹一个“可选升级”,用户能点“以后再说”。
灰度发布的思路是:在服务器上维护一个“允许升级的设备列表”或“按比例放量”的规则,比如先让5%的设备收到升级提示,测试没问题再慢慢把比例调成50%、100%。很多第三方更新服务已经内置了这个能力,如果你用的是自己搭建的接口,就自己实现一个简单的白名单或按手机号尾号取模的规则。
4.4 为什么我建议把更新信息做成JSON而不是纯文本
上面写了latest-version.txt是个纯文本文件。实际上到了正式环境,我更推荐把它换成latest-version.json,因为JSON带的信息可以更多、更结构化:
{ "versionCode": 12, "versionName": "1.2.0", "downloadUrl": "https://cdn.example.com/app-v1.2.0.apk", "releaseNote": "新增活动页,修复登录偶现白屏问题", "isForce": false }App端拿到这个JSON以后,只要解析一次,就能知道要不要弹窗、弹什么文案、点了之后去哪个地址下载、下载完了用不用强制重启。整个逻辑走起来非常顺畅,也不会出现“版本号变了但下载地址还是旧包”这种低级问题。
5. 推送运营与消息设计:发得出去只是第一步
5.1 推送文案的“一眼被看到”与“一眼被关掉”
很多开发同学以为推送的难点全在技术,其实真正决定推送价值的往往是文案和策略。技术只能保证消息“到得了”,文案决定用户“点不点”,时机决定用户“想不想看”。
比如你给用户推送一条“老用户回归礼包”,文案如果写“你的优惠券即将过期”,配合一个明确的截止时间“今日24点前可用”,点击率往往会比“欢迎回来,快去看看吧”高出一截。不是说后者不行,而是推送文案在通知栏就那么一行,必须第一时间制造明确的信息增量:这件事跟我有什么关系,我为什么要现在点。
另外一个很容易踩的坑是:推送里的落地页打不开。用户点了一条“限时秒杀”通知,结果跳到一个空白页或者一个有明显bug的活动页,不但这单转化没了,用户还极有可能直接顺手把App通知权限关了。上线前,一定要把推送中的每个deeplink、每个落地页URL都自动化测试一遍。
5.2 标签、分群与个性化推送
推送对象越精准,用户的负面反馈就越少。你可以给用户打标签,比如:新用户、活跃用户、沉睡用户、未注册用户、某个城市用户、某个商品类目偏好用户。合理的标签化推送,可以让同一个活动文案在不同用户面前显示不同内容,而不是全员群发一锅端。
标签怎么来?比较常见的渠道是App埋点上报,比如用户看了哪个商品、搜索了哪个关键词、是否绑卡、是否开启会员;也可以根据用户行为自动计算,比如7天没登录自动打上“流失预警”标签。这些数据落到用户画像系统里,再由推送服务按标签圈选人群,就能实现“千人多面”的运营。
做分群推送的时候,有一个我强烈建议的原则:控制频率。单个用户一天最多收到3条左右的业务推送,超过这个阈值,次日留存大概率会跌。哪怕是再重要的活动,也要学会把不同渠道的push攒一攒再发。
5.3 推送效果的三层数据:送达、展示、点击
运营和开发经常因为“推送到底有没有效”吵架,根源是大家都只盯着一个指标看。我习惯把推送效果拆成三层来看:
第一层是“送达”:推送服务是否成功把消息交给了系统通道。这个指标主要衡量链路通不通。 第二层是“展示”:消息是否真的出现在了用户通知栏。Android上拿厂商通道的送达回执能看到,但iOS上这个数据往往不完整。 第三层才是“点击”:用户是否点进了App。这一层是最能说明内容质量的指标。
在Android的厂商通道里,消息送达和展示是可以区别统计的;在iOS这边你就得依赖自己的埋点:App在收到推送并且用户点击之后,记录一次launchOptions或userInfo的回调。第三层点击数据如果偏低,我通常先不看文案,而是先去排查用户是否长期直接划掉了通知。如果连通知都不看,那说明用户对这个品类的消息已经不感兴趣了,你需要做的是减少频次,而不是优化文案。
5.4 推送合规与用户授权,别等被下架才学
现在基本所有应用市场都要求:App在获取“通知推送”权限之前,必须先弹出自己写的引导弹窗,向用户解释为什么要推送。这里指的是“预先授权”,不能上来就直愣愣地系统弹窗,那样大多数用户会顺手选“不允许”。
正确的做法是:在合适的时机做一个自定义引导页,说明推送的用途——比如“开启通知,不会错过订单久未支付提醒和优惠动态”,用户点了同意,再调系统授权弹窗。这样把解释权提前拿到自己手里,授权率会明显提高。
另外,如果你做的是涉及金融、医疗、政务类的App,推送内容也需要注意敏感信息保护。个人隐私相关内容不要直接塞在通知里展示。比如银行交易提醒,合适的做法是通知主体只说“你的账户发生一笔交易”,具体金额跟明细放进App里,需要用户解锁后才看得见。这既是安全要求,也是很多应用市场的审核硬性标准。
6. 常见问题与排查技巧实录
6.1 用户反馈收不到推送,第一步先查什么
这是推送里最好用也最该养成的排查习惯:收不到推送,别第一时间怀疑服务端代码。先让用户去确认两件事:第一,系统设置里,App的通知权限是不是还开着;第二,用户是不是用了手机管家一类的工具,把App的自启动和锁屏权限关掉了。
国内Android手机在这块的“品牌差异”特别明显。小米、华为、vivo、OPPO这些系统,默认会对不常用App做后台冻结,就算你接了厂商通道,如果自己的App进程被清理得比较狠,某些机型上照样可能延迟或收不到。遇到用户抱怨收不到推送,你可以在后台查一下这台设备对应的厂商通道token是否还在有效期内,有没有被调成“已失效”。
如果只是某个版本更新之后突然收不到,那就要重点对比“新版本是否改了包名、签名或者重新申请了推送服务”。在Android上,包名和签名证书同时决定了厂商通道是否能正常使用,改动任何一项,推送token都会失效。
6.2 iOS推送不弹窗的5个常见原因
我在这里列一下给iOS排查时最常命中的原因:
- App正处于前台,系统默认不展示横幅,必须在代理方法里手动处理。
- token上报错误,开发环境token当成生产环境token用。
- payload里缺少
alert字段,或者Sound字段格式不对。 - 证书或者使用
p8密钥时的key_id、team_id配置有误。 - 用户在系统设置里关闭了横幅样式,现在只接收声音但不显示。
每次排查iOS推送问题,我建议你在服务端先用一段最简payload做单设备测试:
{ "aps": { "alert": { "title": "测试标题", "body": "测试内容" }, "sound": "default" } }把它发给一台已知token正确的设备,如果这台能收到,那就基本确定是业务层或者payload的问题;如果连这台都收不到,那就往证书、环境、token上查。
6.3 Android厂商通道配置的典型翻车点
厂商通道的配置文件五花八门,签名、指纹、回执、AppID、AppSecret,每一项都有反例。
先说最吓人的一个坑:消息数量限制。有些厂商对通知消息有每日推送上限,比如默认消息量级较大时会被限流。你在自测时感觉一切正常,一到正式群发就频频失败,要去后台看限流记录。
还有回执问题。厂商通道把消息送达之后,会通过你配置的回执URL来通知你的服务器。有些团队把回执地址配错了,或者服务器没做验签处理,导致统计到的送达率一直偏低。这一块要仔细看厂商文档,很多情况下不是你SDK的问题,而是回执服务没接好。
最后提醒一下:Android多个厂商通道的优先级问题。如果某个用户手机上同时装了华为移动服务和APK,但你的SDK配置了多个通道,系统可能会按照自己的调度策略,优先走某一条。万一某条通道因为包名或证书不匹配而静默失败,就会出现“手机上显示已推送,但用户没收到”的情况。排查方式是把第三方控制台的“各通道送达明细”拉出来,看每一条通道的成功率。
6.4 App内嵌H5、Web推送与deeplink的联动坑
现在很多App会用WebView内嵌H5页面来做活动运营。H5里也能通过浏览器推送或者消息事件触发App内容更新。但这里有个容易绕晕的问题:H5页面的推送权限,跟App原生的通知权限并不是一回事。H5里的Push API需要用户授权浏览器通知权限,Firebase Web Push和App原生推送是两条完全独立的消息链路。
如果你在H5页面里已经接入了Web推送,那么用户打开H5页面时,也要判断一下他是否曾经在系统层级禁用过通知,否则你的Web推送内容和原生推送内容会“叠加轰炸”,体验会很差。
deeplink的坑更多。比如推送文案写的落地页是https://m.example.com/coupon,但在App里你想唤起自己的原生页面,就得借助Universal Link或者Scheme。不少测试漏掉了iOS上“第一次点击推送时,Universal Link还没注册成功”的情况,导致用户第一次点击通知后打开的却是Safari。解决方式就是上架前把“冷启动点推送”“热启动点推送”“杀掉App再点推送”这三个场景都测一遍。
6.5 我压箱底的几个小经验
最后分享几个我这些年实际攒下来的经验,不一定写在文档里,但非常管用。
第一,推送服务端的iOS环境切换要做得足够清晰。开发、生产两套环境最好分开配置,别在同一套代码里靠一个全局布尔值硬切。我见过线上环境用了开发环境的token配置,结果整批整批推送失败,复盘时发现就是一个环境配置写错了。
第二,Android推送的“送达回调”别当作完全可靠的数据源。部分厂商在极端省电模式下并不会回传准确的送达回执,数据口径自己心里要有数。
第三,做推送服务端API调用时,设置好超时和降级。如果第三方推送接口超时了,不要让主业务流程卡住等待,而是把推送任务异步化,失败任务写进重试表,等会再补发。否则一次推送抖动,把整个用户下单流程都拖崩,那就得不偿失了。
第四,也是我自己吃过亏的地方:线上推送前一定要检查文案里的特殊字符。\u2028、emoji等字符在某些系统通知渲染时会有兼容性问题,轻则显示乱码,重则导致消息被系统直接丢弃。你可以在测试机上用不同系统版本做一轮文案渲染测试,就能提前发现这些细节。
写在最后
我在实际操盘推送系统的过程中,最大的体会是:推送从来不是“把消息发出去”这么一件简单的事,它横跨客户端、服务端、系统通道、产品运营、数据统计,还牵扯用户授权和隐私合规。想在各种机型、各种系统版本上都做到稳定送达,没有捷径,只能一层一层把细节抠清楚。刚开始做的时候,也许你会觉得厂商通道、token、证书遥遥无期,但只要你愿意按我上面梳理的链路逐层去排查和落地,大多数问题是能稳稳解决的。
最后再分享一个小技巧:推送链路一旦跑通,建议你建立一套自动化的“烟雾测试”。每天晚上自动往一批测试设备上发送一条带特殊标记的空消息,第二天早上拉一次送达数据。只要哪天这项数据掉下来了,你就知道是某个厂商通道出了问题,趁用户还没发现就提前修掉。这套机制帮我提前挡掉了好几次线上事故,是很值得投入的。