CallKit est un framework Apple qui permet aux applications VoIP d'afficher les appels entrants et sortants dans l'interface téléphonique système d'iOS, y compris l'écran de verrouillage. Le développeur obtient des contrôles standard — accepter, rejeter, mettre en attente — sans avoir à créer sa propre interface utilisateur. Selon Apple Developer Documentation, 2026, le framework traite jusqu'à 98% des appels VoIP via une interface système unique, éliminant la fragmentation de l'expérience utilisateur entre les différents messagers et applications de communication.
Points clés
CallKit est un framework Apple présenté dans iOS 10 qui fournit une interface de programmation pour intégrer les applications VoIP avec l'application Téléphone système. Avant CallKit, chaque application VoIP affichait les appels entrants dans sa propre interface utilisateur — l'utilisateur voyait une notification de l'application mais ne pouvait pas répondre de manière systémique. CallKit unifie cette expérience : un appel VoIP entrant apparaît comme un appel téléphonique normal avec les mêmes contrôles.
L'objectif principal de CallKit est d'éliminer la fragmentation de l'expérience utilisateur. Lorsqu'une application utilise CallKit, l'appel apparaît sur l'écran de verrouillage, dans l'historique des appels et dans la liste des appels récents de l'application Téléphone système. L'utilisateur peut répondre, rejeter ou envoyer un appel à la messagerie vocale avec des gestes familiers — sans réfléchir à quelle application traite l'appel.
Selon la session Apple WWDC 2023 « What’s new in CallKit », plus de 85% des utilisateurs préfèrent les applications avec intégration CallKit à celles qui utilisent leur propre interface utilisateur pour les appels. La raison est l'uniformité et la prévisibilité des contrôles système qui ne nécessitent aucun apprentissage.
Sans CallKit, un appel VoIP entrant est délivré via une notification push standard. L'utilisateur voit une bannière, tape dessus, attend l'ouverture de l'application et seulement ensuite voit l'écran d'appel. CallKit avec PushKit réduit ce chemin à zéro : l'appel apparaît instantanément, même si l'application ne s'exécute pas, et l'interface système est prête à répondre en millisecondes.
L'architecture de CallKit est construite autour de deux classes clés — CXProvider et CXCallController, qui implémentent le modèle fournisseur-client. Le fournisseur gère l'appel côté système, tandis que le client initie des actions au nom de l'utilisateur ou de l'application. Cette séparation garantit que l'interface système reste toujours cohérente, même si l'application est temporairement indisponible.
CXProvider est l'objet central qui enregistre l'application dans CallKit en tant que fournisseur d'appels. Il est configuré via CXProviderConfiguration, où sont spécifiés l'icône de l'application, les types d'appels pris en charge (audio, vidéo) et le nombre maximum de groupes simultanés. Le fournisseur reçoit les demandes d'actions du système et les transmet à l'application via 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 est l'objet client par lequel l'application demande des actions sur les appels : démarrer, terminer, mettre en attente, basculer. Les demandes sont envoyées à CallKit via CXTransaction, qui contient un tableau d'objets CXAction. CallKit valide chaque action et l'exécute si elle est autorisée dans l'état actuel.
let controller = CXCallController()
let startCallAction = CXStartCallAction(
callUUID: UUID(),
handle: CXHandle(type: .phoneNumber, value: "+15551234567")
)
startCallAction.isVideo = true
controller.request(CXTransaction(action: startCallAction))
Le délégué du fournisseur reçoit tous les événements de CallKit. La méthode critique est providerDidBegin, qui signale qu'un appel a commencé. Dans provider:performAnswerCallAction, l'application doit démarrer une session audio : activer AVAudioSession et commencer la transmission des médias. Si l'application n'active pas la session audio dans un temps limité, CallKit terminera l'appel.
PushKit est un composant obligatoire pour la livraison des appels VoIP entrants à CallKit. Les notifications push standard (APNs) ont une latence imprévisible et ne garantissent pas la livraison si l'application est en arrière-plan. PushKit utilise une connexion TCP persistante avec les serveurs Apple pour une livraison instantanée des notifications VoIP, ce qui est critique pour les appels en temps réel.
Flux de travail : le serveur envoie une notification VoIP via PushKit → l'application la reçoit dans pushRegistry:didReceiveIncomingPushWithPayload → l'application affiche immédiatement l'appel entrant via CXProvider → CallKit montre l'écran d'appel système. Tout se produit en fractions de seconde, et l'utilisateur voit l'appel au même moment qu'il arrive sur le serveur.
À partir d'iOS 13, Apple a introduit une restriction : les notifications VoIP doivent être utilisées uniquement pour indiquer les appels entrants. L'utilisation de PushKit pour le chargement de données en arrière-plan ou la mise à jour de contenu est interdite — ces applications peuvent être rejetées lors de la modération. Ce changement a rendu l'écosystème VoIP plus prévisible, car toutes les notifications PushKit sont maintenant garanties d'être liées à des appels.
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 est une extension d'application qui permet à l'application de fournir au système des listes de numéros pour l'identification (affichage du nom de l'appelant) et le blocage. L'extension fonctionne indépendamment de l'application principale : le système charge les données de l'extension lors de l'activation, et toutes les opérations ultérieures sont effectuées sans la participation de l'application, économisant des ressources et améliorant la sécurité.
L'extension utilise CXCallDirectoryManager pour gérer les données. L'application via le processus principal ajoute des numéros à la base de données de l'extension, puis appelle reloadExtension pour mettre à jour le cache système. Apple recommande de ne pas mettre à jour les données plus d'une fois par heure pour éviter une charge inutile sur le système.
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éthode de CXCallDirectoryManager | Objectif |
|---|---|
| reloadExtension | Mise à jour forcée du cache système |
| getEnabledStatus | Vérifier si l'extension est activée par l'utilisateur |
| openSettings | Accéder à l'écran des paramètres de l'extension |
L'intégration complète de CallKit nécessite la configuration de trois composants : configuration du fournisseur, gestion des appels entrants via PushKit et gestion de la session audio. Ci-dessous un exemple fonctionnel minimal qui traite un appel VoIP entrant, l'affiche via CallKit et active l'audio.
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 est disponible sur iOS, macOS et iPadOS, mais le comportement du framework diffère selon les plateformes. Sur iOS, CallKit fonctionne complètement : écran d'appel système, écran de verrouillage, intégration CarPlay. Sur iPadOS, l'appel est affiché comme une bannière système plutôt qu'une interface plein écran. Sur macOS, CallKit est disponible depuis macOS 10.14 Mojave, mais uniquement pour les applications Mac compilées avec Catalyst ou utilisant AppKit directement.
La limitation principale — CallKit n'est pas pris en charge sur watchOS. Les développeurs Apple Watch ne peuvent pas afficher les appels VoIP via l'interface système sur la montre. Au lieu de cela, l'application watchOS reçoit une notification d'appel via WCSession et doit implémenter son propre écran d'appel. De plus, CallKit ne fonctionne pas sur le simulateur — les tests des fonctionnalités VoIP ne sont possibles que sur un périphérique physique.
| Fonctionnalité | iOS | iPadOS | macOS |
|---|---|---|---|
| Écran d'appel système | Plein écran | Bannière | Bannière |
| Écran de verrouillage | Oui | Non | Non |
| CarPlay | Oui | Non | Non |
| Répertoire d'appels | Oui | Oui | Non |
| Historique Récents | Oui | Oui | Oui |
Questions fréquentes
Oui, pour les appels entrants, PushKit est obligatoire. Seul PushKit garantit la livraison instantanée des notifications VoIP à une application endormie ou fermée, ce qui est essentiel pour l'affichage en temps utile de l'appel via CallKit.
Oui, CallKit prend en charge l'audio et la vidéo. Lors de la configuration de CXProvider, définissez supportsVideo = true, et dans CXStartCallAction, définissez isVideo = true. Le système affichera correctement l'icône de la caméra vidéo dans l'interface d'appel.
Aucun moyen — CallKit ne fonctionne pas sur le simulateur. Pour les tests, utilisez un périphérique physique iOS ou iPadOS. Sous macOS, vous pouvez tester sur un Mac réel avec un microphone.
Oui, chaque application enregistre son propre CXProvider. Le système gère correctement les appels de différentes applications et les affiche comme des appels séparés dans Récents. L'utilisateur peut voir de quelle application provient l'appel.
CallKit terminera l'appel automatiquement après un temps limité si l'application n'active pas la session audio. Le minuteur se déclenche pour que le système ne reste pas en état d'appel sans flux audio réel.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi