CallKit — рамка на Apple, която позволява на VoIP приложенията да показват входящи и изходящи повиквания в системния интерфейс на телефона iOS, включително на заключения екран. Разработчикът получава стандартни контроли — приемане, отказване, задържане на повикване — без необходимост от създаване на собствен UI. Според Apple Developer Documentation, 2026, рамката обработва до 98% от VoIP повикванията чрез единен системен интерфейс, което елиминира фрагментирането на потребителското изживяване между различни месинджъри и комуникационни приложения.
Основни точки
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 повикване се доставя чрез стандартно push известие. Потребителят вижда банер, докосва го, чака отварянето на приложението и едва тогава вижда екрана на повикването. CallKit заедно с PushKit съкращава този път до нула: повикването се появява незабавно, дори ако приложението не е стартирано, а системният интерфейс е готов за отговор за милисекунди.
Архитектурата на CallKit е изградена около два ключови класа — CXProvider и CXCallController, които реализират модела доставчик-клиент. Доставчикът управлява повикването от страна на системата, клиентът инициира действия от името на потребителя или приложението. Това разделение гарантира, че системният интерфейс винаги остава последователен, дори ако приложението е временно недостъпно.
CXProvider — централният обект, който регистрира приложението в CallKit като доставчик на повиквания. Конфигурира се чрез CXProviderConfiguration, където се посочват иконата на приложението, поддържаните типове повиквания (аудио, видео) и максималният брой едновременни групи. Доставчикът получава от системата заявки за действия и ги предава на приложението чрез делегата CXProviderDelegate.
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 — клиентският обект, чрез който приложението заявява действия върху повиквания: начало, край, задържане, превключване. Заявките се изпращат до CallKit чрез CXTransaction, който съдържа масив от CXAction обекти. CallKit валидира всяко действие и го изпълнява, ако е позволено в текущото състояние.
let controller = CXCallController()
let startCallAction = CXStartCallAction(
callUUID: UUID(),
handle: CXHandle(type: .phoneNumber, value: "+15551234567")
)
startCallAction.isVideo = true
controller.request(CXTransaction(action: startCallAction))
Делегатът на доставчика получава всички събития от CallKit. Критичният метод е providerDidBegin, сигнализиращ, че повикването е започнало. В provider:performAnswerCallAction приложението трябва да стартира аудио сесия: да активира AVAudioSession и да започне предаване на медия. Ако приложението не активира аудио сесията в ограничено време, CallKit ще прекрати повикването.
PushKit — задължителен компонент за доставяне на входящи VoIP повиквания до CallKit. Обикновените push известия (APNs) имат непредвидимо закъснение и не гарантират доставка, ако приложението е на заден план. PushKit използва постоянна TCP връзка със сървърите на Apple за незабавна доставка на VoIP известия, което е критично за разговори в реално време.
Схема на работа: сървърът изпраща VoIP известие чрез PushKit → приложението го получава в pushRegistry:didReceiveIncomingPushWithPayload → приложението незабавно показва входящото повикване чрез CXProvider → CallKit показва системния екран на повикването. Всичко се случва за части от секундата и потребителят вижда повикването едновременно с пристигането му на сървъра.
От iOS 13 нататък Apple въведе ограничение: VoIP известията трябва да се използват само за индикация на входящи повиквания. Използването на PushKit за зареждане на данни на заден план или актуализиране на съдържание е забранено — такива приложения могат да бъдат отхвърлени при модериране. Тази промяна направи VoIP екосистемата по-предвидима, тъй като всички PushKit известия вече са гарантирано свързани с повиквания.
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 — разширение на приложението, което позволява на приложението да предоставя на системата списъци с номера за идентификация (показване на името на обаждащия се) и блокиране. Разширението работи независимо от основното приложение: системата зарежда данни от разширението при активиране и всички последващи операции се извършват без участие на приложението, което спестява ресурси и повишава сигурността.
Разширението използва CXCallDirectoryManager за управление на данни. Приложението чрез основния процес добавя номера в базата данни на разширението, след което извиква reloadExtension за актуализиране на системния кеш. Apple препоръчва актуализиране на данните не по-често от веднъж на час, за да се избегне ненужно натоварване на системата.
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 изисква конфигуриране на три компонента: конфигурация на доставчика, обработка на входящи повиквания чрез PushKit и управление на аудио сесията. По-долу е минимален работещ пример, който обработва входящо VoIP повикване, показва го чрез CallKit и активира аудио.
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 е достъпен на 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 функции е възможно само на физическо устройство.
| Функция | iOS | iPadOS | macOS |
|---|---|---|---|
| Системен екран на повикване | Цял екран | Банер | Банер |
| Заключен екран | Да | Не | Не |
| CarPlay | Да | Не | Не |
| Call Directory | Да | Да | Не |
| История Recents | Да | Да | Да |
Често задавани въпроси
Да, за входящи повиквания PushKit е задължителен. Само PushKit гарантира незабавна доставка на VoIP известието до заспало или затворено приложение, което е критично за навременното показване на повикването чрез CallKit.
Да, CallKit поддържа аудио и видео. При конфигуриране на CXProvider задайте supportsVideo = true, а в CXStartCallAction задайте isVideo = true. Системата ще покаже правилно иконата на камерата в интерфейса на повикването.
По никакъв начин — CallKit не работи на симулатор. За тестване използвайте физическо iOS или iPadOS устройство. На macOS можете да тествате на реален Mac с микрофон.
Да, всяко приложение регистрира свой собствен CXProvider. Системата обработва правилно повиквания от различни приложения и ги показва като отделни повиквания в Recents. Потребителят вижда от кое приложение е дошло повикването.
CallKit автоматично ще прекрати повикването след ограничено време, ако приложението не активира аудио сесията. Таймерът се задейства, за да не остане системата в състояние на повикване без реален аудио поток.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също