CallKitはAppleのフレームワークで、VoIPアプリケーションがiOSのシステム電話インターフェースに着信および発信通話を表示できるようにします。ロック画面も含まれます。開発者は独自のUIを作成する必要なく、標準の制御(応答、拒否、保留)を取得できます。Apple Developer Documentation、2026によると、このフレームワークは単一のシステムインターフェースを介して最大98%のVoIP通話を処理し、異なるメッセンジャーや通信アプリ間でのユーザーエクスペリエンスの断片化を排除します。
重要なポイント
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はPushKitと組み合わせることで、この経路をゼロに短縮します:アプリが実行されていなくても通話が即座に表示され、システムインターフェースはミリ秒単位で応答準備が整います。
CallKitのアーキテクチャは、2つの主要クラス — 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は、アプリが通話に対するアクション(開始、終了、保留、切り替え)をリクエストするためのクライアントオブジェクトです。リクエストはCXTransactionを介してCallKitに送信され、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に配信するための必須コンポーネントです。通常のプッシュ通知(APNs)は予測不可能な遅延があり、アプリがバックグラウンドにある場合の配信を保証しません。PushKitはAppleサーバーとの永続的なTCP接続を使用してVoIP通知を即座に配信します。これはリアルタイム通話にとって重要です。
ワークフロー:サーバーがPushKitを介してVoIP通知を送信 → アプリがpushRegistry:didReceiveIncomingPushWithPayloadで受信 → アプリがCXProviderを介して直ちに着信通話を表示 → CallKitがシステム通話画面を表示。すべてが一瞬で行われ、ユーザーはサーバーに到着するのと同時に通話を確認できます。
iOS 13以降、Appleは制限を導入しました:VoIP通知は着信通話の示唆のみに使用する必要があります。バックグラウンドデータのロードやコンテンツ更新にPushKitを使用することは禁止されており、そのようなアプリは審査で拒否される可能性があります。この変更により、すべてのPushKit通知が通話に関連することが保証され、VoIPエコシステムがより予測可能になりました。
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はシステムへの不要な負荷を避けるため、1時間に1回以上のデータ更新を推奨していません。
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統合には3つのコンポーネントの設定が必要です:プロバイダー構成、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以降で利用可能ですが、CatalystでビルドされたかAppKitを直接使用するMacアプリに限られます。
主な制限 — CallKitはwatchOSではサポートされていません。Apple Watchの開発者は、時計のシステムインターフェースを介してVoIP通話を表示できません。代わりに、watchOSアプリはWCSessionを介して通話通知を受け取り、独自の通話画面を実装する必要があります。また、CallKitはシミュレーターでは動作しません — VoIP機能のテストは物理デバイスでのみ可能です。
| 機能 | iOS | iPadOS | macOS |
|---|---|---|---|
| システム通話画面 | 全画面 | バナー | バナー |
| ロック画面 | あり | なし | なし |
| CarPlay | あり | なし | なし |
| 通話ディレクトリ | あり | あり | なし |
| 最近の履歴 | あり | あり | あり |
よくある質問
はい、着信通話にはPushKitが必須です。PushKitのみがスリープ中または閉じられたアプリへのVoIP通知の即時配信を保証し、CallKitを介したタイムリーな通話表示に重要です。
はい、CallKitは音声とビデオをサポートしています。CXProviderを構成する際にsupportsVideo = trueを設定し、CXStartCallActionでisVideo = trueを設定します。システムは通話インターフェースにビデオカメラアイコンを正しく表示します。
できません — CallKitはシミュレーターでは動作しません。テストには物理的なiOSまたはiPadOSデバイスを使用してください。macOSでは、マイク付きの実際のMacでテストできます。
はい、各アプリは独自のCXProviderを登録します。システムは異なるアプリからの通話を正しく処理し、最近の通話に個別の通話として表示します。ユーザーはどのアプリから通話が来たかを確認できます。
アプリが制限時間内にオーディオセッションをアクティブにしない場合、CallKitは自動的に通話を終了します。実際のオーディオストリームなしでシステムが通話状態のままにならないようにタイマーが作動します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。