Add native incoming and outgoing call screens to an Expo app on both iOS and Android.
Wake an app from a terminated state via VoIP push to display an incoming call.
Route audio through Bluetooth or AirPlay using the cross-platform audio port API.
Bridge CallKit and Core-Telecom events to a separate media library like LiveKit or WebRTC.
Requires native iOS and Android configuration, PushKit and FCM credentials, and a separate media library for actual audio or video.
When a mobile app makes a voice or video call, users expect the same native screens that the operating system shows for a normal phone call: a ringing screen, an incoming banner, audio routing controls, and mute and speaker buttons. On iOS that system is called CallKit, and on Android the matching framework is Jetpack Core-Telecom. This Expo module wraps both with one API so a React Native or Expo app can show the native call UI on both platforms. It is written in Swift on iOS and Kotlin on Android. The module is opinionated about system integration and unopinionated about media. It owns the system call UI, the audio session, and the handling of VoIP push notifications. It does not provide the actual audio or video stream itself: you plug in a separate library such as LiveKit or plain WebRTC and connect it to the events the module emits. Incoming VoIP pushes are parsed in native code before any JavaScript is running, so an incoming call can be shown even when the app is in a terminated state. iOS uses Apple's PushKit transport and Android uses FCM data messages, but both wrap the same incomingCall payload shape, with an event ID for deduplication, a server-assigned call ID, a video flag, a caller block, and an opaque metadata block that is forwarded to your JavaScript handler unchanged. The README also lists system ringtones, a looped dialtone with fade-in for outgoing calls, mute, hold, video toggle, DTMF, native call-end and answer buttons, a cross-platform set of audio port types like Bluetooth and AirPlay, and Siri voice command support on iOS. The install command is bun add expo-callkit-telecom, after which you add a config plugin to your app.json. The plugin can take custom ringtone and dialtone sound files, ring timeouts, and a microphone permission string. The TypeScript API groups calls into three verbs: Request, where the app asks the system to do something like start or end a call, Report, where the app tells the system about a state change such as a call being connected, and Fulfill, where the app acknowledges a system request. A single CallSession object tracks the lifecycle of one call, and events flowing from the system back into the app arrive through listener registrations such as addCallAnsweredListener.
Generated 2026-05-22 · Model: sonnet-4-6 · Verify against the repo before relying on details.