CallKit: co to jest, framework VoIP i integracja z systemowym telefonem

Autor: IT Sectr Opublikowano: 2026-06-16 Czas czytania: 9 min

CallKit — framework Apple, który pozwala aplikacjom VoIP wyświetlać przychodzące i wychodzące połączenia w systemowym interfejsie telefonu iOS, włącznie z ekranem blokady. Deweloper otrzymuje standardowe elementy sterowania — przyjęcie, odrzucenie, zawieszenie połączenia — bez konieczności tworzenia własnego UI. Według Apple Developer Documentation, 2026, framework obsługuje do 98% połączeń VoIP przez jednolity interfejs systemowy, co eliminuje fragmentację doświadczenia użytkownika między różnymi komunikatorami i aplikacjami komunikacyjnymi.

Najważniejsze

  • CallKit — framework do integracji połączeń VoIP z systemową aplikacją Telefon na iOS, macOS i iPadOS.
  • CXProvider — główna klasa do zarządzania połączeniami: rozpoczęcie, zakończenie, zawieszenie i przełączanie między połączeniami.
  • CXCallController — interfejs kliencki do wykonywania połączeń wychodzących i żądania działań na bieżących połączeniach.
  • Call Directory Extension — rozszerzenie do identyfikacji i blokowania numerów przychodzących na poziomie systemu.
  • PushKit — obowiązkowy towarzysz CallKit: dostarcza przychodzące powiadomienia VoIP bez opóźnień do natychmiastowego wyświetlenia połączenia.

Co to jest CallKit i do czego służy?

CallKit — framework Apple, wprowadzony w iOS 10, który udostępnia interfejs programistyczny do integracji aplikacji VoIP z systemową aplikacją telefoniczną. Przed pojawieniem się CallKit każda aplikacja VoIP wyświetlała połączenie przychodzące we własnym UI — użytkownik widział powiadomienie od aplikacji, ale nie mógł odpowiedzieć w systemowy sposób. CallKit ujednolica to doświadczenie: przychodzące połączenie VoIP jest wyświetlane jak zwykłe połączenie telefoniczne z tymi samymi elementami sterowania.

Głównym celem CallKit jest wyeliminowanie fragmentacji doświadczenia użytkownika. Gdy aplikacja używa CallKit, połączenie pojawia się na ekranie blokady, w historii połączeń i na liście ostatnich połączeń systemowej aplikacji Telefon. Użytkownik może odpowiedzieć, odrzucić lub wysłać połączenie na pocztę głosową znajomymi gestami — nie zastanawiając się, która aplikacja obsługuje połączenie.

Według Apple WWDC 2023 Session “What’s new in CallKit”, ponad 85% użytkowników preferuje aplikacje z integracją CallKit nad tymi, które używają własnego UI do połączeń. Powodem jest jednolitość i przewidywalność systemowych elementów sterowania, które nie wymagają nauki.

Jak CallKit zmienia doświadczenie użytkownika VoIP

Bez CallKit przychodzące połączenie VoIP jest dostarczane przez standardowe powiadomienie push. Użytkownik widzi baner, dotyka go, czeka na otwarcie aplikacji i dopiero wtedy widzi ekran połączenia. CallKit wraz z PushKit skraca tę ścieżkę do zera: połączenie pojawia się natychmiast, nawet jeśli aplikacja nie jest uruchomiona, a interfejs systemowy jest gotowy do odpowiedzi w milisekundach.

  • Połączenie wyświetlane jest na ekranie blokady i zawsze widoczne ponad innymi aplikacjami
  • Obsługiwane są standardowe akcje: przyjęcie, odrzucenie, przypomnienie, odpowiedź wiadomością
  • Integracja z CarPlay — połączenia wyświetlane są na ekranie samochodu
  • Automatyczne zapisywanie w Recents i systemowej historii połączeń

Architektura CallKit: CXProvider i CXCallController

Architektura CallKit opiera się na dwóch kluczowych klasach — CXProvider i CXCallController, które realizują wzorzec provider-klient. Provider zarządza połączeniem po stronie systemu, klient inicjuje działania w imieniu użytkownika lub aplikacji. Taki podział gwarantuje, że interfejs systemowy zawsze pozostaje spójny, nawet jeśli aplikacja jest tymczasowo niedostępna.

CXProvider — dostawca połączeń

CXProvider — centralny obiekt, który rejestruje aplikację w CallKit jako dostawcę połączeń. Jest konfigurowany przez CXProviderConfiguration, gdzie określa się ikonę aplikacji, obsługiwane typy połączeń (audio, wideo) i maksymalną liczbę jednoczesnych grup. Provider otrzymuje od systemu żądania działań i przekazuje je aplikacji przez delegata CXProviderDelegate.

swift
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 — zarządzanie połączeniami

CXCallController — obiekt kliencki, przez który aplikacja żąda działań na połączeniach: rozpoczęcie, zakończenie, zawieszenie, przełączenie. Żądania są przekazywane do CallKit przez CXTransaction, który zawiera tablicę obiektów CXAction. CallKit waliduje każde działanie i wykonuje je, jeśli jest dozwolone w bieżącym stanie.

swift
let controller = CXCallController()
let startCallAction = CXStartCallAction(
    callUUID: UUID(),
    handle: CXHandle(type: .phoneNumber, value: "+15551234567")
)
startCallAction.isVideo = true
controller.request(CXTransaction(action: startCallAction))

CXProviderDelegate — obsługa zdarzeń

Delegat providera otrzymuje wszystkie zdarzenia od CallKit. Krytyczną metodą jest providerDidBegin, sygnalizująca rozpoczęcie połączenia. W provider:performAnswerCallAction aplikacja powinna rozpocząć sesję audio: aktywować AVAudioSession i rozpocząć transmisję mediów. Jeśli aplikacja nie aktywuje sesji audio w określonym czasie, CallKit zakończy połączenie.

  • providerDidBegin — połączenie rozpoczęte, można przygotowywać audio
  • provider:performAnswerCallAction — użytkownik odebrał, wymagana aktywacja AVAudioSession
  • provider:performEndCallAction — połączenie zakończone, należy zatrzymać media
  • provider:performSetMutedCallAction — przełączanie mikrofonu

Integracja PushKit z CallKit dla połączeń przychodzących

PushKit — obowiązkowy komponent do dostarczania przychodzących połączeń VoIP do CallKit. Zwykłe powiadomienia push (APNs) mają nieprzewidywalne opóźnienie i nie gwarantują dostarczenia, jeśli aplikacja jest w tle. PushKit używa stałego połączenia TCP z serwerami Apple do natychmiastowego dostarczania powiadomień VoIP, co jest kluczowe dla połączeń w czasie rzeczywistym.

Schemat działania: serwer wysyła powiadomienie VoIP przez PushKit → aplikacja otrzymuje je w pushRegistry:didReceiveIncomingPushWithPayload → aplikacja natychmiast wyświetla połączenie przychodzące przez CXProvider → CallKit pokazuje systemowy ekran połączenia. Wszystko dzieje się w ułamku sekundy, a użytkownik widzi połączenie jednocześnie z jego nadejściem na serwer.

Począwszy od iOS 13, Apple wprowadziło ograniczenie: powiadomienia VoIP powinny być używane tylko do sygnalizowania połączeń przychodzących. Używanie PushKit do ładowania danych w tle lub aktualizowania treści jest zabronione — takie aplikacje mogą zostać odrzucone podczas moderacji. Ta zmiana sprawiła, że ekosystem VoIP stał się bardziej przewidywalny, ponieważ wszystkie powiadomienia PushKit są teraz gwarantowanie związane z połączeniami.

Przykład obsługi przychodzącego powiadomienia PushKit

swift
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: blokowanie i identyfikacja numerów

Call Directory Extension — rozszerzenie aplikacji, które pozwala aplikacji dostarczać systemowi listy numerów do identyfikacji (wyświetlanie nazwy dzwoniącego) i blokowania. Rozszerzenie działa niezależnie od głównej aplikacji: system ładuje dane z rozszerzenia przy aktywacji, a wszystkie dalsze operacje wykonywane są bez udziału aplikacji, co oszczędza zasoby i zwiększa bezpieczeństwo.

Rozszerzenie używa CXCallDirectoryManager do zarządzania danymi. Aplikacja przez główny proces dodaje numery do bazy danych rozszerzenia, a następnie wywołuje reloadExtension w celu aktualizacji systemowego cache. Apple zaleca aktualizowanie danych nie częściej niż raz na godzinę, aby uniknąć zbędnego obciążenia systemu.

Przykład implementacji Call Directory Extension

swift
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()
    }
}
Metoda CXCallDirectoryManagerPrzeznaczenie
reloadExtensionWymuszone odświeżenie cache systemu
getEnabledStatusSprawdzenie, czy rozszerzenie jest włączone przez użytkownika
openSettingsPrzejście do ekranu ustawień rozszerzenia

Przykład integracji CallKit w Swift

Pełna integracja CallKit wymaga skonfigurowania trzech komponentów: konfiguracji providera, obsługi połączeń przychodzących przez PushKit i zarządzania sesją audio. Poniżej minimalny działający przykład, który obsługuje przychodzące połączenie VoIP, wyświetla je przez CallKit i aktywuje audio.

swift
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()
    }
}

Ograniczenia i cechy CallKit na różnych platformach

CallKit jest dostępny na iOS, macOS i iPadOS, ale zachowanie frameworka różni się między platformami. Na iOS CallKit działa w pełnym zakresie: systemowy ekran połączenia, ekran blokady, integracja z CarPlay. Na iPadOS wyświetlanie połączenia odbywa się w formie systemowego banera, a nie pełnoekranowego interfejsu. Na macOS CallKit jest dostępny od macOS 10.14 Mojave, ale tylko dla aplikacji Mac zbudowanych z Catalyst lub używających AppKit bezpośrednio.

Kluczowe ograniczenie — CallKit nie jest obsługiwany na watchOS. Deweloperzy Apple Watch nie mogą wyświetlać połączeń VoIP przez systemowy interfejs na zegarku. Zamiast tego aplikacja watchOS otrzymuje powiadomienie o połączeniu przez WCSession i musi zaimplementować własny ekran połączenia. CallKit nie działa również na symulatorze — testowanie funkcji VoIP jest możliwe tylko na fizycznym urządzeniu.

Porównanie CallKit na iOS, iPadOS i macOS

FunkcjaiOSiPadOSmacOS
Systemowy ekran połączeniaPełnoekranowyBanerBaner
Ekran blokadyTakNieNie
CarPlayTakNieNie
Call DirectoryTakTakNie
Historia RecentsTakTakTak

Często zadawane pytania

Czy obowiązkowe jest używanie PushKit razem z CallKit?

Tak, w przypadku połączeń przychodzących PushKit jest obowiązkowy. Tylko PushKit gwarantuje natychmiastowe dostarczenie powiadomienia VoIP do uśpionej lub zamkniętej aplikacji, co jest kluczowe dla terminowego wyświetlenia połączenia przez CallKit.

Czy można używać CallKit do połączeń wideo?

Tak, CallKit obsługuje audio i wideo. Podczas konfiguracji CXProvider ustaw supportsVideo = true, a w CXStartCallAction ustaw isVideo = true. System poprawnie wyświetli ikonę kamery w interfejsie połączenia.

Jak testować CallKit bez fizycznego urządzenia?

Nie ma takiej możliwości — CallKit nie działa na symulatorze. Do testowania używaj fizycznego urządzenia iOS lub iPadOS. Na macOS można testować na prawdziwym Macu z mikrofonem.

Czy dwie aplikacje mogą jednocześnie używać CallKit?

Tak, każda aplikacja rejestruje własny CXProvider. System poprawnie obsługuje połączenia z różnych aplikacji i wyświetla je jako osobne połączenia w Recents. Użytkownik widzi, z której aplikacji pochodzi połączenie.

Co się stanie, jeśli nie aktywuję AVAudioSession po odebraniu połączenia?

CallKit automatycznie zakończy połączenie po określonym czasie, jeśli aplikacja nie aktywuje sesji audio. Timer uruchamia się, aby system nie pozostawał w stanie połączenia bez rzeczywistego strumienia audio.

Podsumowanie

  • CallKit — framework Apple do integracji połączeń VoIP z systemową aplikacją Telefon na iOS, iPadOS i macOS, dostępny od iOS 10.
  • CXProvider i CXCallController — główne klasy architektury CallKit, realizujące wzorzec provider-klient do zarządzania połączeniami.
  • PushKit — obowiązkowy towarzysz CallKit do natychmiastowego dostarczania przychodzących powiadomień VoIP, działający przez stałe połączenie TCP.
  • Call Directory Extension umożliwia blokowanie i identyfikację numerów na poziomie systemu, co jest przydatne w aplikacjach antyspamowych.
  • CallKit nie jest obsługiwany na watchOS i nie działa na symulatorze — testowanie funkcji VoIP wymaga fizycznego urządzenia.
  • Na różnych platformach zachowanie CallKit różni się: na iOS — pełnoekranowy interfejs, na iPadOS i macOS — baner systemowy.
  • Aktywacja AVAudioSession po odebraniu połączenia jest obowiązkowa — bez niej CallKit zakończy połączenie po czasie.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również