新年开新坑,写一个小教程,分享一下年前尝试用过 Vercel Serverlss function 通过 APNs 发送通知的经验,虽然能找到不错的教程,但仍然要踩一些坑。希望对大家有帮助。祝大家蛇年大吉,快速成长。
先了解一下通知 Notification
手机 App 可以跟用户联系的更加紧密,通知(Notification)在其中起到很重要的作用。通知可以很方便的把用户邀回应用,让用户体验到未曾体验过的功能,对留住用户很有帮助。
通知分为两种:普通通知和推送通知。
普通通知比较简单,最直观的例子就是定时器和闹钟。我们设置定时器的长度,或者闹钟的时间,然后应用计算出通知触发的时机,调用系统 API 设置单次通知或者重复通知。到了时间,用户就会看到通知。因为简单,本文不关注普通通知的实现。
推送通知(Push Notification)就复杂很多,最常见的例子是聊天软件,比如微信,当有人给我们发消息的时候,我们就会收到通知,点击之后进入微信与好友开始聊天。很明显,推送通知的时机是不固定的,当我们的产品服务认为应该给用户推送通知时,就推送。这个时机无法预判,所以就需要在用户的设备和推送通知服务器之间维持一个长期的通信连接,这样,才能做到实时推送实时显示。
为满足这个需求,iOS 和 Android 有不同的实施策略。Android 是开源系统,其服务组件也由系统提供商自选,没有统一的推送服务,往往是应用开发者自己实现自己的。所以 Android 手机常常会在后台维持一大堆连接,很占资源也很费电。(当然,这也倒逼 Android 手机更早发展出快充和大电池。)iOS 则必须接入 Apple Push Notification service (APNs),开发者将推送信息发给 APNs,由后者负责下发到用户的设备。
本文就关注与在 Vercel Serverless function 上部署代码,实现推送消息的功能。
代码架构
其实这套东西并不复杂,主要难点在于不便调试,很多时候必须线上打 log。简单说一下架构:
- 确定推送的时机。在我们的产品中,推送用来提醒用户做计划和做总结,用户可以自己设定推送时间。所以推送任务由 cronjob 负责,5 分钟一次,读取数据库并发送推送信息。
- 程序部署在 Vercel 上,所以由 Vercel cron + Serverless function 组成。
- Serverless function 会读取最近 5 分钟需要发送的通知,生成推送信息,然后发给 APNs。这里的难点主要有两个:
- 需要使用 http2 发送
- 需要使用 JWT 生成密钥
准备工作
服务器端
先说 iOS 开发方面。APNs 倒是没什么使用门槛,只要注册苹果开发者账号并且缴付年费即可。
接下来,在 Xcode > App 项目 > TARGETS > Signing & Capabilities 里开启 Push Notification 权限。

在苹果开发者账号后台,创建 Secret key,记得要选中 Push Notification 权限。下载 p8 文件,记录下 Key ID。
将 Bundle ID, p8 文件的内容,Key ID,Team ID(即开发者 ID)存储在环境变量里,留待后用。
在服务器端代码里安装 jsonwebtoken
库,用来生成 JWT 密钥。
App 端
接下来是 app 端。我们使用 React Native + Expo,所以只需要安装 expo- notification 库即可,方法都封装好了。
关于环境
因为我们使用 Supabase 数据库,所以我原本想使用 Deno 作为执行环境。但是最后没能搞定 Deno 下使用 p8 文件生成 JWT 密钥,所以只好退回 Node.js 运行环境。
我比较喜欢使用新版本,所以我们的 node.js 是 v22,建议大家都用新版本,能节省很多时间。
小结
一切就绪,下一篇讲解代码。
希望本系列能给大家带来帮助,最好一篇文章解决所有 iOS 推送问题。
本站目前仍在招商中,感兴趣的老板请与我联系。
【系列教程】使用 Vercel Serverless function 连接 APNs 实现 iOS 推送通知
欢迎吐槽,共同进步