CallKit é um framework da Apple que permite que aplicativos VoIP exibam chamadas recebidas e realizadas na interface do telefone do sistema iOS, incluindo a tela de bloqueio. O desenvolvedor obtém controles padrão — aceitar, rejeitar, colocar em espera — sem a necessidade de criar sua própria interface do usuário. De acordo com Apple Developer Documentation, 2026, o framework processa até 98% das chamadas VoIP através de uma única interface do sistema, eliminando a fragmentação da experiência do usuário entre diferentes mensageiros e aplicativos de comunicação.
Pontos principais
CallKit é um framework da Apple apresentado no iOS 10 que fornece uma interface de programação para integrar aplicativos VoIP com o aplicativo Telefone do sistema. Antes do CallKit, cada aplicativo VoIP exibia chamadas recebidas em sua própria interface do usuário — o usuário via uma notificação do aplicativo, mas não podia atender de forma sistêmica. O CallKit unifica essa experiência: uma chamada VoIP recebida aparece como uma chamada telefônica normal com os mesmos controles.
O objetivo principal do CallKit é eliminar a fragmentação da experiência do usuário. Quando um aplicativo usa o CallKit, a chamada aparece na tela de bloqueio, no histórico de chamadas e na lista de chamadas recentes do aplicativo Telefone do sistema. O usuário pode atender, rejeitar ou enviar uma chamada para o correio de voz com gestos familiares — sem pensar em qual aplicativo está processando a chamada.
De acordo com a sessão da Apple WWDC 2023 “What’s new in CallKit”, mais de 85% dos usuários preferem aplicativos com integração CallKit àqueles que usam sua própria interface do usuário para chamadas. A razão é a uniformidade e previsibilidade dos controles do sistema que não exigem aprendizado.
Sem o CallKit, uma chamada VoIP recebida é entregue através de uma notificação push padrão. O usuário vê um banner, toca nele, espera o aplicativo abrir e só então vê a tela de chamada. CallKit junto com o PushKit reduz esse caminho a zero: a chamada aparece instantaneamente, mesmo que o aplicativo não esteja em execução, e a interface do sistema está pronta para responder em milissegundos.
A arquitetura do CallKit é construída em torno de duas classes principais — CXProvider e CXCallController, que implementam o padrão provedor-cliente. O provedor gerencia a chamada no lado do sistema, enquanto o cliente inicia ações em nome do usuário ou do aplicativo. Essa separação garante que a interface do sistema permaneça sempre consistente, mesmo que o aplicativo esteja temporariamente indisponível.
CXProvider é o objeto central que registra o aplicativo no CallKit como provedor de chamadas. Ele é configurado através do CXProviderConfiguration, onde são especificados o ícone do aplicativo, os tipos de chamada suportados (áudio, vídeo) e o número máximo de grupos simultâneos. O provedor recebe solicitações de ação do sistema e as transmite ao aplicativo através do 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 é o objeto cliente através do qual o aplicativo solicita ações em chamadas: iniciar, finalizar, colocar em espera, alternar. As solicitações são enviadas ao CallKit através do CXTransaction, que contém um array de objetos CXAction. O CallKit valida cada ação e a executa se for permitida no estado atual.
let controller = CXCallController()
let startCallAction = CXStartCallAction(
callUUID: UUID(),
handle: CXHandle(type: .phoneNumber, value: "+15551234567")
)
startCallAction.isVideo = true
controller.request(CXTransaction(action: startCallAction))
O delegado do provedor recebe todos os eventos do CallKit. O método crítico é providerDidBegin, que sinaliza que uma chamada foi iniciada. Em provider:performAnswerCallAction, o aplicativo deve iniciar uma sessão de áudio: ativar o AVAudioSession e começar a transmissão de mídia. Se o aplicativo não ativar a sessão de áudio dentro de um tempo limitado, o CallKit encerrará a chamada.
PushKit é um componente obrigatório para entregar chamadas VoIP recebidas ao CallKit. As notificações push comuns (APNs) têm latência imprevisível e não garantem a entrega se o aplicativo estiver em segundo plano. O PushKit usa uma conexão TCP persistente com os servidores da Apple para entrega instantânea de notificações VoIP, o que é crítico para chamadas em tempo real.
Fluxo de trabalho: o servidor envia uma notificação VoIP via PushKit → o aplicativo a recebe em pushRegistry:didReceiveIncomingPushWithPayload → o aplicativo exibe imediatamente a chamada recebida através do CXProvider → o CallKit mostra a tela de chamada do sistema. Tudo acontece em frações de segundo, e o usuário vê a chamada ao mesmo tempo em que ela chega ao servidor.
A partir do iOS 13, a Apple introduziu uma restrição: as notificações VoIP devem ser usadas apenas para indicar chamadas recebidas. O uso do PushKit para carregamento de dados em segundo plano ou atualização de conteúdo é proibido — esses aplicativos podem ser rejeitados durante a moderação. Essa mudança tornou o ecossistema VoIP mais previsível, pois todas as notificações PushKit agora estão garantidamente relacionadas a chamadas.
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 é uma extensão de aplicativo que permite ao aplicativo fornecer ao sistema listas de números para identificação (exibir o nome do chamador) e bloqueio. A extensão funciona independentemente do aplicativo principal: o sistema carrega os dados da extensão ao ser ativada, e todas as operações subsequentes são realizadas sem a participação do aplicativo, economizando recursos e aumentando a segurança.
A extensão usa CXCallDirectoryManager para gerenciar os dados. O aplicativo através do processo principal adiciona números ao banco de dados da extensão e, em seguida, chama reloadExtension para atualizar o cache do sistema. A Apple recomenda atualizar os dados não mais do que uma vez por hora para evitar carga desnecessária no sistema.
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()
}
}
| Método do CXCallDirectoryManager | Propósito |
|---|---|
| reloadExtension | Atualização forçada do cache do sistema |
| getEnabledStatus | Verificar se a extensão está habilitada pelo usuário |
| openSettings | Ir para a tela de configurações da extensão |
A integração completa do CallKit requer a configuração de três componentes: configuração do provedor, manipulação de chamadas recebidas via PushKit e gerenciamento da sessão de áudio. Abaixo está um exemplo funcional mínimo que processa uma chamada VoIP recebida, a exibe através do CallKit e ativa o áudio.
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()
}
}
O CallKit está disponível no iOS, macOS e iPadOS, mas o comportamento do framework difere entre as plataformas. No iOS, o CallKit funciona completamente: tela de chamada do sistema, tela de bloqueio, integração com CarPlay. No iPadOS, a chamada é exibida como um banner do sistema em vez de uma interface de tela cheia. No macOS, o CallKit está disponível desde o macOS 10.14 Mojave, mas apenas para aplicativos Mac compilados com Catalyst ou que usam AppKit diretamente.
A principal limitação é que o CallKit não é suportado no watchOS. Os desenvolvedores do Apple Watch não podem exibir chamadas VoIP através da interface do sistema no relógio. Em vez disso, o aplicativo watchOS recebe uma notificação de chamada através do WCSession e deve implementar sua própria tela de chamada. Além disso, o CallKit não funciona no simulador — testar recursos VoIP só é possível em um dispositivo físico.
| Funcionalidade | iOS | iPadOS | macOS |
|---|---|---|---|
| Tela de chamada do sistema | Tela cheia | Banner | Banner |
| Tela de bloqueio | Sim | Não | Não |
| CarPlay | Sim | Não | Não |
| Diretório de chamadas | Sim | Sim | Não |
| Histórico de Recentes | Sim | Sim | Sim |
Perguntas frequentes
Sim, para chamadas recebidas o PushKit é obrigatório. Apenas o PushKit garante a entrega instantânea de notificações VoIP a um aplicativo adormecido ou fechado, o que é crítico para a exibição oportuna da chamada através do CallKit.
Sim, o CallKit suporta áudio e vídeo. Ao configurar o CXProvider, defina supportsVideo = true e, no CXStartCallAction, defina isVideo = true. O sistema exibirá corretamente o ícone da câmera de vídeo na interface da chamada.
De jeito nenhum — o CallKit não funciona no simulador. Para testes, use um dispositivo físico iOS ou iPadOS. No macOS, você pode testar em um Mac real com microfone.
Sim, cada aplicativo registra seu próprio CXProvider. O sistema lida corretamente com chamadas de diferentes aplicativos e as exibe como chamadas separadas em Recentes. O usuário pode ver de qual aplicativo a chamada veio.
O CallKit encerrará a chamada automaticamente após um tempo limitado se o aplicativo não ativar a sessão de áudio. O temporizador é acionado para que o sistema não permaneça em um estado de chamada sem um fluxo de áudio real.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também