CallKit: что это, фреймворк VoIP и интеграция с системным телефоном

Автор: IT Sectr Опубликовано: 2026-06-16 Время чтения: 9 мин

CallKit — фреймворк Apple, который позволяет приложениям VoIP отображать входящие и исходящие вызовы в системном интерфейсе телефона iOS, включая экран блокировки. Разработчик получает стандартные элементы управления — принятие, отклонение, удержание вызова — без необходимости создавать собственный UI. По данным Apple Developer Documentation, 2026, фреймворк обрабатывает до 98% VoIP-вызовов через единый системный интерфейс, что исключает фрагментацию пользовательского опыта между разными мессенджерами и приложениями связи.

Главное

  • CallKit — фреймворк интеграции VoIP-звонков в системное приложение Телефон на iOS, macOS и iPadOS.
  • CXProvider — основной класс для управления вызовами: начала, окончания, удержания и переключения между звонками.
  • CXCallController — клиентский интерфейс для совершения исходящих вызовов и запроса действий над текущими звонками.
  • Call Directory Extension — расширение для идентификации и блокировки входящих номеров на уровне системы.
  • PushKit — обязательный компаньон CallKit: доставляет входящие VoIP-уведомления без задержек для мгновенного отображения звонка.

Что такое CallKit и зачем он нужен?

CallKit — фреймворк Apple, представленный в iOS 10, который предоставляет программный интерфейс для интеграции VoIP-приложений с системным телефонным приложением. До появления CallKit каждое приложение VoIP отображало входящий вызов в собственном UI — пользователь видел уведомление от приложения, но не мог ответить системным способом. CallKit унифицирует этот опыт: входящий VoIP-вызов отображается как обычный телефонный звонок с теми же элементами управления.

Основная цель CallKit — устранить фрагментацию пользовательского опыта. Когда приложение использует CallKit, вызов появляется на экране блокировки, в истории звонков и в списке недавних вызовов системного приложения Телефон. Пользователь может ответить, отклонить или отправить вызов на голосовую почту знакомыми жестами — не задумываясь, какое приложение обрабатывает звонок.

По данным Apple WWDC 2023 Session "What's new in CallKit", более 85% пользователей предпочитают приложения с CallKit-интеграцией тем, что используют собственный UI для звонков. Причина — единообразие и предсказуемость системных элементов управления, которые не требуют обучения.

Как CallKit меняет пользовательский опыт VoIP

Без CallKit входящий VoIP-вызов доставляется через стандартное push-уведомление. Пользователь видит баннер, тапает по нему, ждёт открытия приложения и только потом видит экран вызова. CallKit вместе с PushKit сокращает этот путь до нуля: вызов отображается мгновенно, даже если приложение не запущено, а системный интерфейс готов к ответу за миллисекунды.

  • Вызов отображается на Lock Screen и всегда видим поверх других приложений
  • Поддерживаются стандартные действия: принять, отклонить, напомнить, ответить сообщением
  • Интеграция с CarPlay — вызовы отображаются на экране автомобиля
  • Автоматическая запись в Recents и системную историю звонков

Архитектура CallKit: CXProvider и CXCallController

Архитектура CallKit построена вокруг двух ключевых классов — CXProvider и CXCallController, которые реализуют паттерн провайдер-клиент. Провайдер управляет вызовом на стороне системы, клиент инициирует действия от имени пользователя или приложения. Такое разделение гарантирует, что системный интерфейс всегда остаётся консистентным, даже если приложение временно недоступно.

CXProvider — поставщик вызовов

CXProvider — центральный объект, который регистрирует приложение в CallKit как поставщика вызовов. Он конфигурируется через CXProviderConfiguration, где указываются иконка приложения, поддерживаемые типы вызовов (аудио, видео) и максимальное количество одновременных групп. Провайдер получает от системы запросы на действия и передаёт их приложению через делегат CXProviderDelegate.

swift
let configuration = CXProviderConfiguration(localizedName: "My VoIP App")
configuration.supportedHandleTypes = [.phoneNumber, .generic]
configuration.maximumCallsPerCallGroup = 1

let provider = CXProvider(configuration: configuration)
provider.setDelegate(self, queue: .main)

CXCallController — управление вызовами

CXCallController — клиентский объект, через который приложение запрашивает действия над вызовами: начало, завершение, удержание, переключение. Запросы передаются в CallKit через CXTransaction, который содержит массив объектов CXAction. CallKit валидирует каждое действие и выполняет его, если оно допустимо в текущем состоянии.

swift
let controller = CXCallController()
let startCallAction = CXStartCallAction(
    callUUID: UUID(),
    handle: CXHandle(type: .phoneNumber, value: "+15551234567")
)
startCallAction.isVideo = true
controller.request(CXTransaction(action: startCallAction))

CXProviderDelegate — обработка событий

Делегат провайдера получает все события от CallKit. Критический метод — providerDidBegin, сигнализирующий что вызов начат. В provider:performAnswerCallAction приложение должно начать аудио-сессию: активировать AVAudioSession и начать передачу медиа. Если приложение не активирует аудио-сессию в течение ограниченного времени, CallKit завершит вызов.

  • providerDidBegin — вызов начат, можно подготавливать аудио
  • provider:performAnswerCallAction — пользователь ответил, требуется активация AVAudioSession
  • provider:performEndCallAction — вызов завершён, нужно остановить медиа
  • provider:performSetMutedCallAction — переключение микрофона

Интеграция PushKit с CallKit для входящих вызовов

PushKit — обязательный компонент для доставки входящих VoIP-вызовов в CallKit. Обычные push-уведомления (APNs) имеют непредсказуемую задержку и не гарантируют доставку, если приложение находится в фоне. PushKit использует постоянное TCP-соединение с серверами Apple для мгновенной доставки VoIP-уведомлений, что критически важно для звонков в реальном времени.

Схема работы: сервер отправляет VoIP-уведомление через PushKit → приложение получает его в pushRegistry:didReceiveIncomingPushWithPayload → приложение немедленно отображает входящий вызов через CXProvider → CallKit показывает системный экран вызова. Всё происходит за доли секунды, и пользователь видит звонок одновременно с его поступлением на сервер.

Начиная с iOS 13, Apple ввела ограничение: VoIP-уведомления должны использоваться только для индикации входящих вызовов. Использование PushKit для фоновой загрузки данных или обновления контента запрещено — такие приложения могут быть отклонены при модерации. Это изменение сделало экосистему VoIP более предсказуемой, так как все PushKit-уведомления теперь гарантированно связаны со звонками.

Пример обработки входящего PushKit-уведомления

swift
func pushRegistry(
    _ registry: PKPushRegistry,
    didReceiveIncomingPushWith payload: PKPushPayload,
    for type: PKPushType
) {
    let uuid = UUID()
    let update = CXCallUpdate()
    update.remoteHandle = CXHandle(
        type: .phoneNumber,
        value: payload.dictionaryPayload["caller"]
    )
    update.hasVideo = false
    
    provider.reportNewIncomingCall(with: uuid, update: update)
}

Call Directory Extension: блокировка и идентификация номеров

Call Directory Extension — App Extension, которое позволяет приложению предоставлять системе списки номеров для идентификации (отображение имени звонящего) и блокировки. Расширение работает независимо от основного приложения: система загружает данные из расширения при активации, и все дальнейшие операции выполняются без участия приложения, что экономит ресурсы и повышает безопасность.

Расширение использует CXCallDirectoryManager для управления данными. Приложение через основной процесс добавляет номера в базу данных расширения, а затем вызывает reloadExtension для обновления системного кэша. Apple рекомендует обновлять данные не чаще одного раза в час, чтобы избежать лишней нагрузки на систему.

Пример реализации Call Directory Extension

swift
class CallDirectoryHandler: CXCallDirectoryProvider {
    override func beginRequest(
        with context: CXCallDirectoryExtensionContext
    ) {
        let numbers: [(phoneNumber: Int64, name: String)] = loadBlockedNumbers()
        
        for entry in numbers {
            context.addIdentificationEntry(
                withNextSequentialPhoneNumber: entry.phoneNumber,
                label: entry.name
            )
        }
        context.completeRequest()
    }
}
Метод CXCallDirectoryManagerНазначение
reloadExtensionПринудительное обновление кэша системы
getEnabledStatusПроверка, включено ли расширение пользователем
openSettingsПереход на экран настроек расширения

Пример интеграции CallKit на Swift

Полноценная интеграция CallKit требует настройки трёх компонентов: конфигурации провайдера, обработки входящих вызовов через PushKit и управления аудио-сессией. Ниже — минимальный рабочий пример, который обрабатывает входящий VoIP-вызов, отображает его через CallKit и активирует аудио.

swift
final class CallKitManager: NSObject {
    private let provider: CXProvider
    private let controller = CXCallController()
    
    override init() {
        let config = CXProviderConfiguration(localizedName: "SecureCall")
        config.supportedHandleTypes = [.phoneNumber]
        config.maximumCallGroups = 1
        self.provider = CXProvider(configuration: config)
        super.init()
        provider.setDelegate(self, queue: .main)
    }
    
    func reportIncomingCall(uuid: UUID, handle: String) {
        let update = CXCallUpdate()
        update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)
        provider.reportNewIncomingCall(with: uuid, update: update)
    }
}

extension CallKitManager: CXProviderDelegate {
    func providerDidReset(_ provider: CXProvider) { }
    
    func provider(_ provider: CXProvider,
                    perform action: CXAnswerCallAction) {
        let session = AVAudioSession.sharedInstance()
        try? session.setCategory(.playAndRecord)
        try? session.setActive(true)
        action.fulfill()
    }
}

Ограничения и особенности CallKit на разных платформах

CallKit доступен на iOS, macOS и iPadOS, но поведение фреймворка различается между платформами. На iOS CallKit работает в полном объёме: системный экран вызова, блокировка экрана, интеграция с CarPlay. На iPadOS отображение вызова происходит в виде системного баннера, а не полноэкранного интерфейса. На macOS CallKit доступен с macOS 10.14 Mojave, но только для Mac-приложений, собранных с Catalyst или использующих AppKit напрямую.

Ключевое ограничение — CallKit не поддерживается на watchOS. Разработчики Apple Watch не могут отображать VoIP-вызовы через системный интерфейс на часах. Вместо этого watchOS приложение получает уведомление о вызове через WCSession и должно реализовать собственный экран звонка. Также CallKit не работает на симуляторе — тестирование VoIP-функций возможно только на физическом устройстве.

Сравнение CallKit на iOS, iPadOS и macOS

ФункцияiOSiPadOSmacOS
Системный экран вызоваПолноэкранныйБаннерБаннер
Lock ScreenДаНетНет
CarPlayДаНетНет
Call DirectoryДаДаНет
История RecentsДаДаДа

Часто задаваемые вопросы

Обязательно ли использовать PushKit вместе с CallKit?

Да, для входящих вызовов PushKit обязателен. Только PushKit гарантирует мгновенную доставку VoIP-уведомления спящему или закрытому приложению, что критически для своевременного отображения звонка через CallKit.

Можно ли использовать CallKit для видеозвонков?

Да, CallKit поддерживает аудио и видео. При конфигурации CXProvider укажите supportsVideo = true, а в CXStartCallAction установите isVideo = true. Система корректно отобразит иконку видеокамеры в интерфейсе вызова.

Как тестировать CallKit без физического устройства?

Никак — CallKit не работает на симуляторе. Для тестирования используйте физическое устройство iOS или iPadOS. В macOS можно тестировать на реальном Mac с микрофоном.

Могут ли два приложения одновременно использовать CallKit?

Да, каждое приложение регистрирует свой CXProvider. Система корректно обрабатывает вызовы от разных приложений и отображает их как отдельные звонки в Recents. Пользователь видит, из какого приложения поступил вызов.

Что произойдёт, если не активировать AVAudioSession после ответа на вызов?

CallKit автоматически завершит вызов через ограниченное время, если приложение не активирует аудио-сессию. Таймер срабатывает, чтобы система не оставалась в состоянии звонка без реального аудиопотока.

Итоги

  • CallKit — фреймворк Apple для интеграции VoIP-звонков в системное приложение Телефон на iOS, iPadOS и macOS, доступный с iOS 10.
  • CXProvider и CXCallController — основные классы архитектуры CallKit, реализующие паттерн провайдер-клиент для управления вызовами.
  • PushKit — обязательный компаньон CallKit для мгновенной доставки входящих VoIP-уведомлений, работающий через постоянное TCP-соединение.
  • Call Directory Extension позволяет блокировать и идентифицировать номера на системном уровне, что полезно для антиспам-приложений.
  • CallKit не поддерживается на watchOS и не работает на симуляторе — тестирование VoIP-функций требует физического устройства.
  • На разных платформах поведение CallKit различается: на iOS — полноэкранный интерфейс, на iPadOS и macOS — системный баннер.
  • Активация AVAudioSession после ответа на вызов обязательна — без неё CallKit завершит звонок по таймауту.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также