Device Token — это уникальный идентификатор, который APNS присваивает каждому устройству iOS для маршрутизации push-уведомлений. Токен генерируется системой при регистрации приложения на получение уведомлений и должен быть передан на сервер для отправки push именно на это устройство. По данным Apple Developer Documentation, 2026, Device Token может изменяться при переустановке приложения, восстановлении устройства с бэкапа или обновлении iOS, поэтому сервер должен регулярно обновлять токены для обеспечения доставки.
Главное
Device Token (токен устройства) — это уникальный идентификатор в виде hex-строки, который APNS (Apple Push Notification Service) генерирует для каждого приложения на устройстве iOS. Токен является ключом, по которому сервер отправляет push-уведомления на конкретное устройство. Без корректного Device Token сервер не может доставить push — APNS отклоняет запрос с ошибкой 400 BadRequest.
Device Token создаётся системой iOS при первом обращении приложения к APNS после установки. Процесс генерации включает криптографическую привязку к идентификатору приложения (bundle ID) и уникальному идентификатору устройства (UID), после чего APNS возвращает приложению 32-байтовый токен в hex-формате (64 символа). Токен не является постоянным — система может сгенерировать новый при определённых условиях.
Когда сервер отправляет push-уведомление, он включает Device Token в HTTP/2 запрос к APNS. APNS проверяет валидность токена: если токен относится к другому окружению (sandbox вместо production), истёк или отозван, сервер Apple возвращает ошибку 410 Gone или 400 BadRequest. Только после успешной валидации токена APNS начинает доставку уведомления на устройство.
Device Token не следует путать с IDFA (Identifier for Advertisers), IDFV (Identifier for Vendor) или UID (Unique Device Identifier). IDFA и IDFV используются для рекламы и аналитики, UID — аппаратный серийный номер. Device Token существует исключительно для push-уведомлений и не раскрывает информацию о пользователе или устройстве за пределами APNS.
| Идентификатор | Назначение | Постоянство |
|---|---|---|
| Device Token | Маршрутизация push-уведомлений APNS | Может измениться |
| IDFA | Реклама и трекинг | Сбрасывается пользователем |
| IDFV | Идентификация вендора (аналитика) | Постоянен для приложений одного разработчика |
| Bundle ID | Уникальный идентификатор приложения | Постоянен |
Процесс получения Device Token состоит из нескольких обязательных шагов, начиная от запроса разрешения у пользователя и заканчивая передачей токена на сервер. Каждый шаг критически важен — пропуск любого из них приводит к невозможности отправки push-уведомлений на устройство.
Первым шагом приложение запрашивает у пользователя разрешение на отправку уведомлений через UNUserNotificationCenter.current().requestAuthorization. Пользователь может согласиться, запретить или выбрать опциональные опции (alert, badge, sound). Без явного согласия пользователя система не выдаст Device Token, даже если приложение вызовет registerForRemoteNotifications. После получения разрешения приложение вызывает UIApplication.shared.registerForRemoteNotifications(), что инициирует процесс регистрации в APNS.
После регистрации APNS возвращает токен через делегат AppDelegate: application(_:didRegisterForRemoteNotificationsWithDeviceToken:). Успешный вызов содержит объект Data с токеном, который необходимо конвертировать в hex-строку для передачи на сервер. В случае ошибки система вызывает application(_:didFailToRegisterForRemoteNotificationsWithError:) с описанием проблемы: неверная настройка сертификатов, отсутствие network или некорректная конфигурация проекта.
После получения токена приложение должно немедленно передать его на свой сервер для сохранения в базе данных. 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()
}
}
}
// Получение Device Token от APNS
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")
}
}
}
Серверная часть push-системы должна хранить Device Token в базе данных, ассоциированный с пользователем и окружением. При отправке уведомления сервер формирует запрос к APNS, включая токен в URL и JWT-токен (или сертификат) для авторизации. Корректное управление токенами критически влияет на процент доставки push-уведомлений.
Таблица токенов на сервере должна содержать как минимум: Device Token (уникальный), идентификатор пользователя, окружение (sandbox/production), дату последнего обновления и статус (активен/неактивен). Рекомендуется добавлять индекс по токену для быстрого поиска при отправке и по пользователю для получения списка всех устройств пользователя. Многие приложения позволяют одному пользователю иметь несколько устройств — каждое со своим токеном.
Для отправки push-уведомления сервер должен авторизовать запрос к APNS двумя способами. Certificate-based использует SSL-сертификат, сгенерированный в Apple Developer Console. Token-based использует JWT (JSON Web Token) с ключом .p8, который действует до 30 дней без необходимости обновления сертификата. Токен-базированная авторизация считается более современной и рекомендуется Apple для новых проектов.
Запрос к APNS включает HTTP/2 метод POST, URL с путём /3/device/{device_token}, заголовки авторизации и JSON-тело с пейлоудом. Заголовок apns-topic обязательно содержит bundle ID приложения. apns-priority указывает приоритет доставки (5 — немедленно, 10 — с экономией батареи). apns-expiration задаёт время в секундах от эпохи, до которого APNS будет пытаться доставить уведомление.
// Пример отправки push на Node.js через APNS HTTP/2
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('response', (headers) => {
if (headers[':status'] === '200') {
console.log('Push sent successfully');
}
});
При отправке push-уведомлений на большое количество устройств используйте пакетную отправку с контролем скорости. APNS рекомендует не превышать 1500 запросов в секунду на одно соединение. При превышении лимита сервер Apple возвращает ошибку 429 Too Many Requests. Для масштабных рассылок используйте несколько соединений и распределяйте нагрузку по устройствам равномерно.
Device Token не является постоянным и может измениться в нескольких сценариях, что требует от сервера механизма обновления. Если сервер продолжает отправлять push на устаревший токен, APNS возвращает ошибку 410 Gone, указывая, что токен больше недействителен для данного окружения.
Apple документирует несколько сценариев, при которых Device Token меняется: пользователь переустанавливает приложение, восстанавливает устройство из iCloud бэкапа, устанавливает новую версию iOS, а также при сбросе настроек сети или конфиденциальности. В каждом случае приложение при следующем запуске получит новый токен от APNS. Сервер должен обновить токен в базе данных, удалив старый и сохранив новый.
Когда сервер отправляет push на устаревший токен, APNS возвращает HTTP 410 с заголовком apns-unless-timestamp. Этот заголовок указывает время, после которого токен стал недействительным. Сервер должен немедленно удалить или деактивировать этот токен в базе данных, чтобы не отправлять на него повторно. Игнорирование ошибки 410 приводит к пустой трате ресурсов и снижению deliverability rate.
Для поддержания базы токенов в актуальном состоянии рекомендуется запускать периодическую очистку. Скрипт очистки анализирует логи APNS за последние N дней, находит все токены, на которые была получена ошибка 410, и деактивирует их в базе данных. Дополнительно можно удалять токены, по которым не было активности пользователя более 90 дней — это бесполезные записи, которые только увеличивают размер базы данных.
Перед массовой отправкой push-уведомлений (рассылка, промо-кампания) рекомендуется предварительно проверить актуальность токенов. APNS не предоставляет прямого API для batch-валидации токенов, поэтому используется стратегия отправки тестового push с низким приоритетом и анализ ошибок. Токены, вернувшие ошибку 410, исключаются из основной рассылки.
Рассмотрим полный цикл получения Device Token в Swift, включая обработку ошибок и передачу на сервер. Код охватывает запрос разрешения, регистрацию в 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)")
// Retry после задержки при сетевых ошибках
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 (например, отключён capability Push Notifications), использование симулятора (который не поддерживает push) или неправильное provisioning profile. В production важно логировать ошибки и, при возможности, повторять регистрацию при следующем запуске приложения.
iOS Simulator не поддерживает получение реального Device Token. Для тестирования регистрации на симуляторе используйте i386-архитектурные проверки: в debug-сборке можно симулировать получение токена или использовать UI-тесты с mock объектами. Реальное тестирование push-уведомлений всегда выполняется на физическом устройстве, подключённом к Xcode.
Часто задаваемые вопросы
Да, Device Token может измениться при переустановке приложения, восстановлении устройства из бэкапа или обновлении iOS. Сервер должен обрабатывать обновления токенов: при получении нового токена от известного устройства — заменять старый, при ошибке 410 — удалять токен из базы.
Device Token — это 32-байтовая hex-строка из 64 символов в нижнем регистре (0–9, a–f). Пример: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2". Токен передаётся как Data из APNS и конвертируется в строку на стороне приложения.
Sandbox-токен выдаётся для приложений, собранных с разработческим provisioning profile, и работает только с api.sandbox.push.apple.com. Production-токен — для App Store и TestFlight, работает с api.push.apple.com. Сервер должен различать окружения и отправлять push на соответствующий APNS endpoint.
Ошибка 410 Gone означает, что Device Token недействителен. Сервер должен немедленно удалить этот токен из базы данных и прекратить попытки отправки на него. Заголовок apns-unless-timestamp в ответе указывает, с какого времени токен перестал работать.
Проверьте вызов делегата application(_:didRegisterForRemoteNotificationsWithDeviceToken:) в AppDelegate. Если метод вызывается — токен получен. Используйте debugging-логи или OSLog для вывода токена в консоль Xcode. На физическом устройстве проверьте, что токен отправляется на сервер через Network Link Conditioner.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также