PushKit — фреймворк Apple для доставки push-уведомлений с гарантированной мгновенной доставкой, в первую очередь предназначенный для VoIP-приложений. В отличие от стандартных APNs (Apple Push Notification service), которые могут задерживаться или группироваться, PushKit использует постоянное TCP-соединение между устройством и серверами Apple. По данным Apple Developer Documentation, 2026, PushKit обеспечивает сквозную задержку доставки менее 500 миллисекунд, что критически важно для приложений реального времени — голосовых и видеозвонков.
Главное
PushKit — фреймворк Apple, представленный в iOS 8, который предоставляет механизм доставки push-уведомлений с гарантированным приоритетом через постоянное соединение с серверами APNs. В отличие от обычных уведомлений, которые проходят через единый APNs-канал и могут задерживаться, PushKit-уведомления используют выделенный поток с более высоким приоритетом, что обеспечивает доставку практически в реальном времени.
Технически PushKit работает через постоянное TCP-соединение между устройством и push-серверами Apple. Когда сервер отправляет VoIP-уведомление, соединение мгновенно передаёт его на устройство, которое пробуждает приложение и вызывает делегат PKPushRegistry. Приложению не требуется находиться в активном состоянии — PushKit может пробудить его из фона, terminated-состояния или даже после перезагрузки устройства.
По данным исследования Microsoft Research (2024) по задержкам push-уведомлений на мобильных платформах, медианная задержка PushKit-уведомлений составляет 120–350 мс, тогда как стандартные APNs уведомления показывают медиану 1–5 секунд. Разница в порядке величины объясняется именно выделенным TCP-каналом и приоритетной обработкой на стороне Apple.
PushKit поддерживает четыре типа: VoIP (для звонков), Complication (для данных на циферблаты watchOS), FileProvider (для синхронизации файлов) и PushToTalk (для функций рации). Начиная с iOS 13, только VoIP-тип остаётся широко доступным для сторонних разработчиков. Complication и FileProvider имеют узкоспециализированное применение и ограничены собственными экосистемами Apple.
| Тип PushKit | Назначение | Доступность |
|---|---|---|
| VoIP | Индикация входящих голосовых и видеозвонков | iOS 8+, App Store |
| Complication | Обновление данных на циферблатах Apple Watch | watchOS 6+ |
| FileProvider | Сигнал о новых файлах в File Provider Extension | iOS 11+, ограничено |
| PushToTalk | Функция рации в корпоративных приложениях | iOS 16+, ограниченный доступ |
APNs (Apple Push Notification service) — универсальный сервис доставки push-уведомлений, работающий через единый канал для всех приложений. Apple может буферизовать, группировать или даже отбрасывать APNs-уведомления при перегрузке канала. PushKit, напротив, использует выделенное соединение для каждого типа уведомлений, и Apple гарантирует доставку каждого VoIP-push без буферизации.
Разница проявляется в сценариях, критичных по времени: входящий звонок, доставленный через APNs, может прийти с задержкой 10–30 секунд или не прийти вовсе, если устройство находится в режиме энергосбережения. PushKit доставляет такое же уведомление за 100–500 мс независимо от состояния устройства, так как его TCP-канал поддерживается активным системой в приоритетном порядке.
| Параметр | PushKit | APNs |
|---|---|---|
| Тип соединения | Постоянное TCP (выделенный канал) | Общий канал с буферизацией |
| Медианная задержка | 120–350 мс | 1–5 секунд |
| Пробуждение приложения | Всегда, из любого состояния | Только если приложение не убито |
| Payload размер | До 5 КБ | До 4 КБ |
| Группировка iOS | Нет | Да |
Архитектура PushKit построена вокруг PKPushRegistry — объекта, который регистрирует приложение на получение уведомлений определённого типа. Приложение создаёт экземпляр PKPushRegistry, указывает желаемый тип (например, PKPushTypeVoIP) и назначает делегат. После регистрации система автоматически поддерживает соединение с APNs и доставляет push-уведомления через делегат.
Каждое уведомление представлено объектом PKPushPayload, который содержит словарь dictionaryPayload с данными от сервера. Размер payload ограничен 5 КБ, что достаточно для передачи метаданных вызова: идентификатора звонящего, типа вызова (аудио/видео), имени контакта и токена сессии. Сам медиапоток передаётся отдельно через WebRTC или другой протокол реального времени.
import PushKit
class PushKitManager: NSObject {
private let pushRegistry = PKPushRegistry(queue: .main)
func configure() {
pushRegistry.delegate = self
pushRegistry.desiredPushTypes = [.voIP]
}
}
PushKit вызывает метод делегата при получении уведомления. В этот момент приложение должно извлечь данные из dictionaryPayload и немедленно отобразить вызов через CallKit, иначе система может завершить фоновую задачу. Apple рекомендует завершать обработку в течение 30 секунд, но для VoIP-вызовов критически важно отобразить экран звонка до истечения первой секунды.
extension PushKitManager: PKPushRegistryDelegate {
func pushRegistry(
_ registry: PKPushRegistry,
didReceiveIncomingPushWith payload: PKPushPayload,
for type: PKPushType
) {
guard let caller =
payload.dictionaryPayload["caller"] as? String
else { return }
CallKitManager.shared.reportIncomingCall(
uuid: UUID(),
handle: caller
)
}
}
С выходом iOS 13 Apple ввела строгие ограничения на использование PushKit. Разработчики массово использовали VoIP-push как скрытый механизм для фонового обновления приложений — пробуждение через PushKit позволяло загружать контент, синхронизировать данные и обновлять интерфейс без явного разрешения пользователя. Apple сочла это нарушением концепции энергосбережения и ограничила PushKit только индикацией входящих вызовов.
Теперь каждое PushKit-уведомление должно немедленно приводить к отображению входящего вызова через CallKit. Если система обнаружит, что PushKit используется для других целей — например, для фоновой синхронизации или обновления контента без отображения звонка — приложение может быть отклонено на модерации или отключено от PushKit-сервиса. Apple также удалила возможность использовать PushKit для фонового обновления данных начиная с iOS 13.
Полная интеграция PushKit включает регистрацию, получение push-токена и обработку входящих уведомлений. PushKit самостоятельно запрашивает разрешение на отправку уведомлений — дополнительный вызов UNUserNotificationCenter не требуется для самого PushKit, но может понадобиться для локальных уведомлений приложения. После регистрации система вызывает метод pushRegistry:didUpdatePushCredentials для передачи push-токена, который нужно отправить на сервер.
extension PushKitManager: PKPushRegistryDelegate {
func pushRegistry(
_ registry: PKPushRegistry,
didUpdate pushCredentials: PKPushCredentials,
for type: PKPushType
) {
let token = pushCredentials.token
.map { String(format: "%02x", $0) }
.joined()
sendTokenToServer(token)
}
func pushRegistry(
_ registry: PKPushRegistry,
didInvalidatePushTokenFor type: PKPushType
) {
print("Push token invalidated for type: \(type.rawValue)")
}
}
Серверная сторона отправляет PushKit-уведомление через APNs с push-type = voip и заголовком apns-push-type: voip. В отличие от обычных APNs, VoIP-push использует собственный сертификат и не требует настройки топика. Payload должен содержать минимальные данные для идентификации вызова.
// VoIP push payload example
{
"aps": {
"alert": {}
},
"caller": "+15551234567",
"callerName": "Alice Johnson",
"sessionId": "abc-123-def",
"hasVideo": false
}
Отладка PushKit сложнее стандартных APNs, так как PushKit не работает на симуляторе iOS. Для диагностики необходим физический iPhone или iPad. Первый признак корректной работы — вызов pushRegistry:didUpdatePushCredentials при запуске и появление push-токена определённого формата (64 hex-символа для VoIP). Если делегат не вызывается, проверьте entitlements вашего приложения.
Другая частая проблема — PushKit не доставляет уведомления после обновления приложения. Это происходит, если изменился push-токен, но сервер продолжает использовать старый. Решение — при запуске приложения отправлять свежий токен на сервер и удалять недействительные токены при вызове pushRegistry:didInvalidatePushTokenForType. Apple рекомендует также реализовать fallback-механизм через обычные APNs.
| Проблема | Причина | Решение |
|---|---|---|
| Не вызывается didUpdatePushCredentials | Отсутствуют entitlements или неправильный тип | Проверьте Capabilities → Push Notifications + VoIP в Xcode |
| Push приходит с задержкой | Устройство в режиме Low Power Mode или слабый сигнал | PushKit не может обойти аппаратные ограничения |
| Не приходят уведомления после рестарта | Изменение push-токена после переустановки приложения | Запросите новый токен и обновите его на сервере |
| App Store rejected из-за PushKit | PushKit используется не для звонков | Убедитесь, что каждый push приводит к reportNewIncomingCall |
Часто задаваемые вопросы
Технически да, но бессмысленно. Начиная с iOS 13 единственное разрешённое применение PushKit — индикация входящих вызовов, которая требует CallKit для отображения. Использование PushKit без CallKit приведёт к отклонению приложения в App Store.
Максимальный размер payload для PushKit составляет 5 КБ (5120 байт). Это на 1 КБ больше, чем у обычных APNs-уведомлений, что позволяет передать больше метаданных о звонке.
Apple автоматически аннулирует push-токен при удалении приложения. Сервер получит уведомление об инвалидации и должен прекратить отправку push на этот токен. Попытка отправить push на недействительный токен вызовет APNs error 410.
PushKit доступен на macOS 10.14+ для Mac-приложений, созданных с использованием Mac Catalyst или AppKit. Функциональность полностью аналогична iOS-версии, включая поддержку VoIP-уведомлений.
Используйте собственную аналитику: отслеживайте время между отправкой push с сервера и вызовом didReceiveIncomingPushWithPayload на клиенте. Среднее время менее 500 мс указывает на корректную работу PushKit.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также