CallKit:概要、VoIPフレームワーク、システム電話との統合

著者: IT Sectr 公開日: 2026-06-16 読了時間: 9 分

CallKitはAppleのフレームワークで、VoIPアプリケーションがiOSのシステム電話インターフェースに着信および発信通話を表示できるようにします。ロック画面も含まれます。開発者は独自のUIを作成する必要なく、標準の制御(応答、拒否、保留)を取得できます。Apple Developer Documentation、2026によると、このフレームワークは単一のシステムインターフェースを介して最大98%のVoIP通話を処理し、異なるメッセンジャーや通信アプリ間でのユーザーエクスペリエンスの断片化を排除します。

重要なポイント

  • CallKit — iOS、macOS、iPadOSのシステム電話アプリにVoIP通話を統合するためのフレームワーク。
  • CXProvider — 通話管理のためのメインクラス:開始、終了、保留、通話の切り替え。
  • CXCallController — 発信通話を行い、現在の通話に対するアクションをリクエストするためのクライアントインターフェース。
  • Call Directory Extension — システムレベルで着信番号を識別およびブロックする拡張機能。
  • PushKit — CallKitの必須コンパニオン:遅延なく着信VoIP通知を配信し、即時に通話を表示。

CallKitとは何か、なぜ必要なのか

CallKitはiOS 10で導入されたAppleのフレームワークで、VoIPアプリケーションをシステム電話アプリと統合するためのプログラミングインターフェースを提供します。CallKit以前は、各VoIPアプリは独自のUIで着信通話を表示していました。ユーザーはアプリからの通知を見ましたが、システム的な方法で応答できませんでした。CallKitはこのエクスペリエンスを統一します:着信VoIP通話が同じコントロールを持つ通常の電話通話として表示されます。

CallKitの主な目的は、ユーザーエクスペリエンスの断片化を排除することです。アプリがCallKitを使用すると、通話がロック画面、通話履歴、システム電話アプリの最近の通話リストに表示されます。ユーザーは使い慣れたジェスチャーで通話に応答、拒否、またはボイスメールに送信できます。どのアプリが通話を処理しているかを意識する必要はありません。

Apple WWDC 2023セッション「What’s new in CallKit」によると、85%以上のユーザーが通話に独自のUIを使用するアプリよりもCallKit統合アプリを好みます。その理由は、学習を必要としないシステムコントロールの一貫性と予測可能性です。

CallKitがVoIPユーザーエクスペリエンスをどう変えるか

CallKitがない場合、着信VoIP通話は標準のプッシュ通知で配信されます。ユーザーはバナーを見て、タップし、アプリが開くのを待ち、その後ようやく通話画面を見ます。CallKitはPushKitと組み合わせることで、この経路をゼロに短縮します:アプリが実行されていなくても通話が即座に表示され、システムインターフェースはミリ秒単位で応答準備が整います。

  • 通話がロック画面に表示され、他のアプリの上に常に表示される
  • 標準アクションをサポート:応答、拒否、リマインダー、メッセージで返信
  • CarPlay統合 — 通話が車の画面に表示される
  • 最近の通話とシステム通話履歴への自動記録

CallKitのアーキテクチャ:CXProviderとCXCallController

CallKitのアーキテクチャは、2つの主要クラス — CXProviderCXCallController — を中心に構築されており、プロバイダー・クライアントパターンを実装しています。プロバイダーはシステム側で通話を管理し、クライアントはユーザーまたはアプリに代わってアクションを開始します。この分離により、アプリが一時的に利用できなくても、システムインターフェースは常に一貫性を保ちます。

CXProvider — 通話プロバイダー

CXProviderは、CallKitにアプリを通話プロバイダーとして登録する中心的なオブジェクトです。CXProviderConfigurationを介して構成され、アプリアイコン、サポートされる通話タイプ(音声、ビデオ)、最大同時グループ数が指定されます。プロバイダーはシステムからアクションリクエストを受け取り、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 — 通話管理

CXCallControllerは、アプリが通話に対するアクション(開始、終了、保留、切り替え)をリクエストするためのクライアントオブジェクトです。リクエストはCXTransactionを介してCallKitに送信され、CXActionオブジェクトの配列が含まれます。CallKitは各アクションを検証し、現在の状態で許可されている場合に実行します。

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

CXProviderDelegate — イベント処理

プロバイダーデリゲートはCallKitからすべてのイベントを受け取ります。重要なメソッドはproviderDidBeginで、通話が開始されたことを示します。provider:performAnswerCallActionでは、アプリはオーディオセッションを開始する必要があります:AVAudioSessionをアクティブにし、メディア送信を開始します。アプリが制限時間内にオーディオセッションをアクティブにしない場合、CallKitは通話を終了します。

  • providerDidBegin — 通話開始、オーディオ準備
  • provider:performAnswerCallAction — ユーザー応答、AVAudioSessionのアクティブ化が必要
  • provider:performEndCallAction — 通話終了、メディア停止
  • provider:performSetMutedCallAction — マイク切り替え

着信通話のためのPushKitとCallKitの統合

PushKitは、着信VoIP通話をCallKitに配信するための必須コンポーネントです。通常のプッシュ通知(APNs)は予測不可能な遅延があり、アプリがバックグラウンドにある場合の配信を保証しません。PushKitはAppleサーバーとの永続的なTCP接続を使用してVoIP通知を即座に配信します。これはリアルタイム通話にとって重要です。

ワークフロー:サーバーがPushKitを介してVoIP通知を送信 → アプリがpushRegistry:didReceiveIncomingPushWithPayloadで受信 → アプリがCXProviderを介して直ちに着信通話を表示 → CallKitがシステム通話画面を表示。すべてが一瞬で行われ、ユーザーはサーバーに到着するのと同時に通話を確認できます。

iOS 13以降、Appleは制限を導入しました:VoIP通知は着信通話の示唆のみに使用する必要があります。バックグラウンドデータのロードやコンテンツ更新にPushKitを使用することは禁止されており、そのようなアプリは審査で拒否される可能性があります。この変更により、すべてのPushKit通知が通話に関連することが保証され、VoIPエコシステムがより予測可能になりました。

着信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:番号のブロックと識別

Call Directory Extensionは、アプリがシステムに識別(発信者名の表示)とブロックのための番号リストを提供できるようにするアプリ拡張機能です。拡張機能はメインアプリから独立して動作します:システムはアクティベーション時に拡張機能からデータをロードし、以降のすべての操作はアプリの関与なしに実行されるため、リソースを節約しセキュリティを向上させます。

拡張機能はCXCallDirectoryManagerを使用してデータを管理します。アプリはメインプロセスを介して拡張機能のデータベースに番号を追加し、reloadExtensionを呼び出してシステムキャッシュを更新します。Appleはシステムへの不要な負荷を避けるため、1時間に1回以上のデータ更新を推奨していません。

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()
    }
}
CXCallDirectoryManagerのメソッド目的
reloadExtensionシステムキャッシュの強制更新
getEnabledStatus拡張機能がユーザーによって有効化されているか確認
openSettings拡張機能の設定画面に移動

SwiftでのCallKit統合の例

完全なCallKit統合には3つのコンポーネントの設定が必要です:プロバイダー構成、PushKitを介した着信通話の処理、オーディオセッション管理。以下は、着信VoIP通話を処理し、CallKitを介して表示し、オーディオをアクティブにする最小限の実用的な例です。

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

異なるプラットフォームでのCallKitの制限と機能

CallKitはiOS、macOS、iPadOSで利用可能ですが、フレームワークの動作はプラットフォーム間で異なります。iOSではCallKitが完全に機能します:システム通話画面、ロック画面、CarPlay統合。iPadOSでは、通話は全画面インターフェースではなくシステムバナーとして表示されます。macOSでは、CallKitはmacOS 10.14 Mojave以降で利用可能ですが、CatalystでビルドされたかAppKitを直接使用するMacアプリに限られます。

主な制限 — CallKitはwatchOSではサポートされていません。Apple Watchの開発者は、時計のシステムインターフェースを介してVoIP通話を表示できません。代わりに、watchOSアプリはWCSessionを介して通話通知を受け取り、独自の通話画面を実装する必要があります。また、CallKitはシミュレーターでは動作しません — VoIP機能のテストは物理デバイスでのみ可能です。

iOS、iPadOS、macOSでのCallKit比較

機能iOSiPadOSmacOS
システム通話画面全画面バナーバナー
ロック画面ありなしなし
CarPlayありなしなし
通話ディレクトリありありなし
最近の履歴ありありあり

よくある質問

CallKitと一緒にPushKitを使用する必要がありますか?

はい、着信通話にはPushKitが必須です。PushKitのみがスリープ中または閉じられたアプリへのVoIP通知の即時配信を保証し、CallKitを介したタイムリーな通話表示に重要です。

CallKitをビデオ通話に使用できますか?

はい、CallKitは音声とビデオをサポートしています。CXProviderを構成する際にsupportsVideo = trueを設定し、CXStartCallActionでisVideo = trueを設定します。システムは通話インターフェースにビデオカメラアイコンを正しく表示します。

物理デバイスなしでCallKitをテストする方法は?

できません — CallKitはシミュレーターでは動作しません。テストには物理的なiOSまたはiPadOSデバイスを使用してください。macOSでは、マイク付きの実際のMacでテストできます。

2つのアプリが同時にCallKitを使用できますか?

はい、各アプリは独自のCXProviderを登録します。システムは異なるアプリからの通話を正しく処理し、最近の通話に個別の通話として表示します。ユーザーはどのアプリから通話が来たかを確認できます。

通話に応答した後にAVAudioSessionをアクティブにしないとどうなりますか?

アプリが制限時間内にオーディオセッションをアクティブにしない場合、CallKitは自動的に通話を終了します。実際のオーディオストリームなしでシステムが通話状態のままにならないようにタイマーが作動します。

まとめ

  • CallKit — iOS 10以降で利用可能な、iOS、iPadOS、macOSのシステム電話アプリにVoIP通話を統合するためのAppleフレームワーク。
  • CXProviderCXCallController — CallKitアーキテクチャの主要クラスで、通話管理のためのプロバイダー・クライアントパターンを実装。
  • PushKit — 永続的なTCP接続を介して動作する、着信VoIP通知の即時配信のためのCallKitの必須コンパニオン。
  • Call Directory Extensionはシステムレベルで番号をブロックおよび識別でき、スパム対策アプリに有用。
  • CallKitはwatchOSでサポートされておらず、シミュレーターでは動作しない — VoIP機能のテストには物理デバイスが必要。
  • CallKitの動作はプラットフォーム間で異なる:iOSでは全画面インターフェース、iPadOSとmacOSではシステムバナー。
  • 通話応答後のAVAudioSessionのアクティブ化は必須 — ない場合、CallKitはタイムアウトで通話を終了。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください