Device Token是APNS分配给每个iOS设备的唯一标识符,用于路由推送通知。令牌在应用注册接收通知时由系统生成,必须发送到服务器,以便向该特定设备发送推送。根据Apple Developer Documentation, 2026,Device Token可能在应用重装、从备份恢复设备或iOS更新时发生变化,因此服务器必须定期更新令牌以确保送达。
要点
Device Token(设备令牌)是一个hex字符串形式的唯一标识符,由APNS(Apple推送通知服务)为iOS设备上的每个应用生成。令牌是服务器向特定设备发送推送通知的密钥。没有正确的Device Token,服务器无法送达推送 — APNS会返回400 BadRequest错误拒绝请求。
Device Token由iOS系统在应用安装后首次访问APNS时创建。生成过程包括对应用标识符(bundle ID)和设备唯一标识符(UID)的加密绑定,之后APNS返回32字节hex格式(64字符)的令牌。令牌不是永久的 — 系统在特定条件下可能生成新的令牌。
当服务器发送推送通知时,它将Device Token包含在对APNS的HTTP/2请求中。APNS验证令牌的有效性:如果令牌属于不同环境(sandbox而非production)、已过期或被撤销,Apple服务器返回410 Gone或400 BadRequest错误。仅在令牌验证成功后,APNS才开始向设备送达通知。
Device Token不应与IDFA(广告标识符)、IDFV(供应商标识符)或UID(唯一设备标识符)混淆。IDFA和IDFV用于广告和分析,UID是硬件序列号。Device Token仅用于推送通知,不会在APNS之外泄露用户或设备信息。
| 标识符 | 用途 | 持久性 |
|---|---|---|
| Device Token | APNS推送通知路由 | 可能变化 |
| IDFA | 广告和追踪 | 用户可重置 |
| IDFV | 供应商标识(分析) | 同一开发者应用间持久 |
| Bundle ID | 应用唯一标识符 | 持久 |
获取Device Token的过程包括几个必要步骤,从请求用户权限开始,到将令牌传输到服务器结束。每一步都至关重要 — 跳过任何一步都会导致无法向设备发送推送通知。
第一步,应用通过UNUserNotificationCenter.current().requestAuthorization向用户请求发送通知的权限。用户可以选择同意、拒绝或选择可选选项(alert、badge、sound)。未经用户明确同意,即使应用调用registerForRemoteNotifications,系统也不会颁发Device Token。获得权限后,应用调用UIApplication.shared.registerForRemoteNotifications(),启动APNS注册过程。
注册后,APNS通过AppDelegate委托返回令牌:application(_:didRegisterForRemoteNotificationsWithDeviceToken:)。成功调用包含含有令牌的Data对象,需要将其转换为hex字符串以传输到服务器。如果出错,系统调用application(_:didFailToRegisterForRemoteNotificationsWithError:)并描述问题:证书配置错误、网络不可用或项目配置不正确。
获取令牌后,应用应立即将其传输到自己的服务器以保存在数据库中。API请求包括令牌、设备标识符(用于关联)、环境(sandbox/production)以及可选的附加数据:操作系统版本、设备型号、语言。建议在每次应用启动时重新传输令牌,以便服务器始终拥有最新的令牌。
// 请求权限与APNS注册
func registerForPushNotifications() {
UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .sound, .badge]) {
[weak self] granted, error in
guard granted else {
print("未获得权限")
return
}
DispatchQueue.main.async {
UIApplication.shared
.registerForRemoteNotifications()
}
}
}
// 从APNS获取Device Token
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let tokenString = deviceToken
.map { String(format: "%02.2hhx", $0) }
.joined()
print("Device Token:\(tokenString)")
// 发送令牌到服务器
PushTokenService.shared
.sendTokenToServer(tokenString) { success in
if success {
UserDefaults.standard.set(tokenString,
forKey: "lastDeviceToken")
}
}
}
推送系统的服务器端应将Device Token存储在数据库中,与用户和环境关联。发送通知时,服务器构建对APNS的请求,将令牌包含在URL中,并使用JWT令牌(或证书)进行授权。正确的令牌管理对推送通知的送达率有重大影响。
服务器上的令牌表至少应包含:Device Token(唯一)、用户标识符、环境(sandbox/production)、最后更新日期和状态(活跃/不活跃)。建议对令牌添加索引以便发送时快速查找,对用户添加索引以获取用户所有设备的列表。许多应用允许一个用户拥有多个设备 — 每个设备都有自己的令牌。
要发送推送通知,服务器必须通过两种方式授权对APNS的请求。基于证书的方式使用在Apple Developer Console中生成的SSL证书。基于令牌的方式使用带有.p8密钥的JWT(JSON Web令牌),有效期为30天,无需更新证书。基于令牌的授权被认为更现代,Apple推荐在新项目中使用。
对APNS的请求包括HTTP/2 POST方法、路径为/3/device/{device_token}的URL、授权标头和带有payload的JSON正文。apns-topic标头必须包含应用的bundle ID。apns-priority指定送达优先级(5 — 立即,10 — 省电模式)。apns-expiration设置从纪元开始的秒数时间,APNS将在此时间之前尝试送达通知。
// 通过APNS HTTP/2在Node.js上发送推送的示例
const http2 = require('http2');
const client = http2.connect('https://api.push.apple.com');
const deviceToken = 'abcdef0123456789...';
const payload = JSON.stringify({
"aps": { "alert": "Hello!", "sound": "default" }
});
const req = client.request({
':method': 'POST',
':path': `/3/device/${deviceToken}`,
'apns-topic': 'com.example.app',
'apns-priority': '10',
'apns-expiration': '0',
'authorization': `bearer ${jwtToken}`
});
req.write(payload);
req.end();
req.on('响应', (headers) => {
if (headers[':status'] === '200') {
console.log('推送发送成功');
}
});
向大量设备发送推送通知时,请使用带速度控制的批量发送。APNS建议每个连接每秒不超过1500个请求。超过限制时,Apple服务器返回429 Too Many Requests错误。对于大规模推送,请使用多个连接并均匀分配设备负载。
Device Token不是永久的,在多种情况下可能发生变化,这要求服务器具备更新机制。如果服务器继续向过期的令牌发送推送,APNS返回410 Gone错误,指示该令牌在给定环境中不再有效。
Apple记录了Device Token变化的几种情况:用户重装应用、从iCloud备份恢复设备、安装新版iOS,以及重置网络或隐私设置。在每种情况下,应用在下次启动时会从APNS获取新令牌。服务器应更新数据库中的令牌,删除旧令牌并保存新令牌。
当服务器向过期的令牌发送推送时,APNS返回带有apns-unless-timestamp标头的HTTP 410。此标头指示令牌失效的时间。服务器应立即从数据库中删除或停用此令牌,以避免重复发送。忽略410错误会导致资源浪费和送达率降低。
为保持令牌数据库的最新状态,建议运行定期清理。清理脚本分析最近N天的APNS日志,查找所有收到410错误的令牌,并在数据库中将其停用。此外,可以删除超过90天没有用户活动的令牌 — 这些是无用记录,只会增加数据库大小。
在批量发送推送通知(新闻通讯、促销活动)之前,建议预先验证令牌的有效性。APNS不提供直接的批量令牌验证API,因此采用发送低优先级测试推送并分析错误的策略。返回410错误的令牌将从主发送中排除。
让我们来看Swift中获取Device Token的完整流程,包括错误处理和传输到服务器。代码涵盖请求权限、APNS注册、将Data转换为hex字符串、错误处理以及在失败时重试将令牌发送到自己的服务器。
import UIKit
import UserNotifications
final class PushNotificationManager: NSObject {
static let shared = PushNotificationManager()
private let apiClient = APIClient()
private var currentToken: String?
func register() {
UNUserNotificationCenter.current()
.requestAuthorization(
options: [.alert, .badge, .sound]) {
[weak self] granted, error in
guard granted else {
Analytics.log(
"Push permission denied")
return
}
DispatchQueue.main.async {
UIApplication.shared
.registerForRemoteNotifications()
}
}
}
func handleDeviceToken(_ tokenData: Data) {
let token = tokenData
.map { String(format: "%02.2hhx", $0) }
.joined()
guard token != currentToken else { return }
currentToken = token
sendTokenToServer(token)
}
func handleRegistrationError(_ error: Error) {
Analytics.log(
"Push registration failed: \(error)")
// 网络错误时延迟重试
if let urlError = error as? URLError,
urlError.code == .notConnectedToInternet {
DispatchQueue.main.asyncAfter(
deadline: .now() + 10) { [weak self] in
self?.register()
}
}
}
private func sendTokenToServer(_ token: String) {
let body = PushTokenRequest(
token: token,
environment: Environment.current == .debug
? "sandbox" : "production",
osVersion: UIDevice.current.systemVersion,
locale: Locale.current.identifier
)
apiClient.sendToken(body) { [weak self] result in
if case .success = result {
self?.currentToken = token
}
}
}
}
APNS注册错误可能由多种原因引起。最常见的原因包括:网络不可用、Xcode中证书配置错误(例如Push Notifications功能未启用)、使用模拟器(不支持推送)或配置文件不正确。在生产环境中,记录错误并在可能的情况下在下次应用启动时重试注册非常重要。
iOS模拟器不支持获取真实的Device Token。要在模拟器上测试注册,请使用i386架构检查:在debug构建中可以模拟令牌获取或使用带有mock对象的UI测试。真实的推送通知测试始终在连接到Xcode的物理设备上执行。
常见问题
是的,Device Token可能在应用重装、从备份恢复设备或iOS更新时发生变化。服务器应处理令牌更新:从已知设备收到新令牌时替换旧令牌,收到410错误时从数据库中删除令牌。
Device Token是一个64字符的32字节hex字符串,小写(0–9, a–f)。示例:“a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2”。令牌作为Data从APNS传输,在应用端转换为字符串。
沙箱令牌颁发给使用开发配置文件构建的应用,仅适用于api.sandbox.push.apple.com。生产环境令牌用于App Store和TestFlight,适用于api.push.apple.com。服务器应区分环境并将推送发送到相应的APNS端点。
410 Gone错误表示Device Token无效。服务器应立即从数据库中删除此令牌并停止尝试向其发送推送。响应中的apns-unless-timestamp标头指示令牌从何时起停止工作。
检查AppDelegate中的委托方法application(_:didRegisterForRemoteNotificationsWithDeviceToken:)是否被调用。如果方法被调用 — 令牌已获取。使用调试日志或OSLog将令牌输出到Xcode控制台。在物理设备上,通过Network Link Conditioner检查令牌是否发送到服务器。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。