Реализация CallKit для iOS (интеграция с системными звонками)

Реализация CallKit для iOS (интеграция с системными звонками) Мы сталкивались с ситуацией, когда VoIP-приложение получало входящий звонок, но пользователь его пропускал, потому что системное уведомление ничем не отличалось от обычного баннера. Результат — потерянные звонки и недовольные клиенты.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Реализация CallKit для iOS (интеграция с системными звонками)
Сложный
~2-3 дня

Наши компетенции:

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

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    597

Реализация CallKit для iOS (интеграция с системными звонками)

Мы сталкивались с ситуацией, когда VoIP-приложение получало входящий звонок, но пользователь его пропускал, потому что системное уведомление ничем не отличалось от обычного баннера. Результат — потерянные звонки и недовольные клиенты. CallKit решает эту проблему, превращая звонок приложения в полноценный системный вызов с большим экраном, кнопками и записью в историю. В этой статье расскажем, как настроить CallKit с нуля, избежать типичных ошибок и увеличить процент принятых звонков.

Как CallKit меняет взаимодействие пользователя с входящим звонком?

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

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

Центральный класс — CXProvider. Он является точкой коммуникации между приложением и системой: через него сообщаем о входящем звонке, обновляем информацию, завершаем вызов. Второй класс — CXCallController, через который приложение инициирует исходящие звонки и управляет ими.

let providerConfiguration = CXProviderConfiguration() providerConfiguration.supportsVideo = true providerConfiguration.maximumCallsPerCallGroup = 1 providerConfiguration.supportedHandleTypes = [.phoneNumber, .emailAddress, .generic] provider = CXProvider(configuration: providerConfiguration) provider.setDelegate(self, queue: nil) 

Входящий звонок. Приходит через VoIP push (PushKit, не APNs). Это важно: обычный APNs push не поддерживает CallKit-звонки с iOS 13 — Apple требует использовать PKPushType.voIP и в делегате PKPushRegistryDelegate.pushRegistry(_:didReceiveIncomingPushWith:) немедленно вызывать reportNewIncomingCall. Задержка между push и вызовом reportNewIncomingCall — приложение завершается системой.

func reportIncomingCall(uuid: UUID, handle: String, hasVideo: Bool) { let update = CXCallUpdate() update.remoteHandle = CXHandle(type: .generic, value: handle) update.hasVideo = hasVideo provider.reportNewIncomingCall(with: uuid, update: update) { error in // если error != nil — система отклонила звонок (например, DND) } } 

Ответ/отклонение.

Система вызывает CXProviderDelegate методы: provider(_:perform:) с CXAnswerCallAction или CXEndCallAction. В ответ на AnswerAction нужно подключить аудио — запустить WebRTC сессию, подключить VoIP SDK (Twilio Voice, Agora, Daily).

WebRTC и аудио сессия

CallKit управляет аудио сессией системы. Нельзя настраивать AVAudioSession самостоятельно — это обязанность CallKit. При ответе на звонок система активирует аудио сессию и вызывает provider(_:didActivate:). В этот момент подключаем аудио-поток WebRTC к AVAudioSession. При завершении — provider(_:didDeactivate:), отключаем.

Если вызвать AVAudioSession.setActive(true) раньше этого момента — звонок может прерваться или аудио не появится. Типичный баг при первой интеграции.

Twilio Voice SDK: TwilioVoice.handleNotificationcall.accept(with: delegate) → в callDidConnect активируем аудио через CallKit. SDK инкапсулирует часть этой логики, но CXProvider всё равно нужен свой.

История звонков и Siri

После завершения звонка вызываем provider.reportCall(with: uuid, endedAt: Date(), reason: .remoteEnded). iOS автоматически добавляет запись в историю звонков «Телефона» с именем и длительностью. Пользователь может перезвонить через «Телефон» — это вызов через приложение, если CXHandle типа .generic совпадает с идентификатором.

Siri Shortcuts для звонков: через INStartCallIntent (iOS 13+) приложение регистрирует намерение. «Позвони Ивану через MyApp» — Siri запускает звонок через CallKit.

Типичные проблемы

Дублирующиеся звонки.

UUID должен быть уникальным для каждого вызова и не меняться между push и ответом. Если push пришёл дважды (retry), проверяем UUID — не создаём второй CXCallUpdate для того же UUID.

Зависший звонок в истории. Если приложение крашнуло не вызвав reportCall(endedAt:), звонок остаётся как «активный» в истории. Решение: при следующем запуске приложения проверяем CXCallObserver.calls — если есть незавершённые, завершаем их.

VoIP Push на iOS 13+.

PKPushRegistry должен быть инициализирован в application(_:didFinishLaunchingWithOptions:), не лениво. Apple проверяет это и может завершить приложение.

Сравнение: CallKit vs обычный push

Параметр Без CallKit С CallKit
Отображение звонка Баннер push-уведомления Полноэкранный интерфейс с именем и фото
Кнопки действий Нет (только "Позже") Ответить, Отклонить, Напоминание
Запись в историю Нет Автоматическая запись в "Телефон"
Процент ответов ~20-30% ~70-80% (по данным клиентов)

Статистика основана на Apple CallKit Documentation и реальных кейсах.

Как долго занимает интеграция CallKit?

Базовая реализация входящего/исходящего звонка с одним VoIP SDK: 2-3 дня. С групповыми звонками, видео, Siri Shortcuts и custom UI: 4-5 дней. Стоимость рассчитывается после анализа VoIP-инфраструктуры и требований. Свяжитесь с нами — оценим ваш проект и предложим оптимальное решение.

Что входит в работу

  • Настройка CXProvider и CXCallController с конфигурацией под требования приложения
  • Интеграция PushKit для VoIP push
  • Обработчики ответа, отклонения, завершения, hold, mute
  • Подключение к WebRTC/VoIP SDK (Twilio Voice, Agora, Daily, Vonage)
  • Аудио сессия через CallKit lifecycle
  • Запись в историю звонков
  • Обработка краш-сценариев и незавершённых звонков

Мы гарантируем корректную работу CallKit в соответствии с документацией Apple. За 5+ лет мы реализовали более 30 проектов с VoIP и CallKit, поэтому знаем все подводные камни.