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

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Реализация CallKit для iOS (интеграция с системными звонками)
Сложная
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1054
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    445

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

CallKit позволяет приложению отображать входящие звонки так же, как системные вызовы оператора: на весь экран, с именем контакта, кнопками ответа и отклонения, интеграцией с историей звонков в «Телефоне» и блокировкой через «Заблокированные контакты». Без CallKit входящий звонок выглядит как push-уведомление — и пользователь нажимает «Позже», не понимая, что это звонок.

Как это работает изнутри

Центральный класс — 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 проверяет это и может завершить приложение.

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

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

Сроки

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