Skip to content

Native API ​

Latest package release: 3.0.0

Audio routes, DTMF, caller name updates and system call requests are documented in phone features. They use contract 0.3.0 and are published on npm and pub.dev.

The native API is the same in both framework packages; only the module name and the framework entry point differ.

FlutterReact Native
Android entry pointdev.callx.flutter.CallxPlugindev.callx.reactnative.CallxModule
iOS moduleimport callximport callx_react_native
iOS entry pointCallxPluginCallxReactNativeHost

Kotlin types live in dev.callx.core and dev.callx.telecom.

Bootstrap ​

KotlinSwiftDescription
CallxPlugin.bootstrap(context, config) / CallxModule.bootstrap(context, config)CallxPlugin.bootstrap(config) / CallxReactNativeHost.bootstrap(config)Builds and installs the whole pipeline
CallxBootstrapConfigCallxBootstrapConfigOptions; see native host integration
CallxBootstrap.startedThe running pipeline after bootstrap (Android)
Started.runtime, .ingress, .media, .recoveredCallCallxBootstrap.runtime, .ingress, .provider, .media, .readyWhat the bootstrap built. On iOS, ready completes with the recovered call after recovery
CallxMediaStatusCallxMediaStatusAdapter(source), host-controlled, or none
CallxBootstrapConfig.donateCallsDonate each answered call to Siri suggestions (default true)

Push tokens ​

KotlinSwiftDescription
CallxPushTokens.updateFcm(token)Records the FCM token for getPushToken()
CallxPushTokens.currentCallxPushTokens.currentThe recorded token
CallxPushTokens.updateVoIP(token)Records a VoIP token (the bootstrap does this)

On iOS the bootstrap records the VoIP token itself.

Ingress ​

TelecomIngress (Android) and CallKitIngress (iOS).

MemberDescription
handlePush(data, priority, originalPriority) (Android)Rings or rejects a forwarded FCM message; false if it is not a Callx invitation
handleInvitation(invitation)An invitation that arrived over signaling
remoteAnswered(callId)The remote side answered an outgoing call; returns whether the call changed (3.0.1)
remoteEnded(callId, reason)The remote side ended or cancelled; recorded even before the invitation; returns whether a live call ended (3.0.1)
handleSignal(signal) (Android, 3.0.1)A call.ended or call.accepted that arrived by push; handlePush calls it
silenceIncoming(callId) (Android)Stops the ringtone
requestAudioEndpoint(callId, endpoint) (Android)Switches audio route through Telecom; Dart/JS use setAudioRoute
supportsVideo, supportsDtmf (Android)Whether the installed media adapter carries video or keypad tones
cameraChanged(callID:on:), rename(callID:displayName:) (iOS)Update CallKit's video flag and caller name; the bootstrap calls them
recoverAfterProcessDeath()Cleanup after a previous process died; the bootstrap calls it
startPushRegistry() (iOS)Registers for VoIP pushes; the bootstrap calls it
TelecomIngress.EXTRA_CALL_IDIntent extra with the answered call's ID

Runtime ​

BridgeRuntime

MemberDescription
mediaConnected(callId)Media flows (first time or after an interruption)
mediaInterrupted(callId)Connected media dropped
videoObserved(callId, localVideo, remoteVideo)Video state a media adapter observed
audioRoutesObserved(callId, current, routes)Audio outputs the platform reports; the bootstrap calls it on both platforms
executeNative(type, callId, value)A command started from native UI, such as a notification button
reportIncoming(…), platformAnswered(callId), platformEnded(callId, reason), remoteEnded(callId, reason)Provider-managed mode only

Listeners ​

TelecomIngressListener (Android) ​

CallbackWhen
onPushReceived(callId?, priority?, originalPriority?)A Callx message arrived
onInvitationAccepted(invitation)The call rings
onInvitationRejected(invitation?, outcome?)It does not ring: Duplicate, Busy, Expired, Ended(reason)
onUserAnswered(callId) / onUserEnded(callId)The user acted from the notification
onCallAnswered(callId)Answered, from any surface. Start media
onCallEnded(callId)Ended, for any reason. Stop media
onRingTimedOut(callId)The ring deadline passed
onAudioEndpointsChanged(callId, current, available)Audio routes changed

CallKitIngressListener (iOS) ​

CallbackWhen
pushTokenUpdated(_:) / pushTokenInvalidated()VoIP token changes
invitationAccepted(_:)The call rings
invitationRejected(_:outcome:)It does not ring
callAnswered(callID:)Answered, from any surface. Prepare media
callEnded(callID:)Ended, for any reason. Stop media
ringTimedOut(callID:)The ring deadline passed

Android presentation ​

TypeDescription
CallStylePresenter(context, channelId, smallIcon, fullScreenIntent, contentIntent, labels, lockedAnswer, missedCalls)The default notification presenter. missedCalls = false turns off the missed-call notification
CallNotificationLabelsanswer, decline, hangUp, openApp, incomingChannel, ongoingChannel, mute, unmute, hold, resume, audio, missedCall, missedVideoCall, callBack, missedChannel
LockedAnswerRequireUnlock, ShowOverLockScreen
CallxLockScreen.onIntent(activity, intent)Needed with ShowOverLockScreen
CallxFullScreenIntent.isAllowed(context) / .settingsIntent(context)Android 14+ full-screen intent permission
CallxTelecomAvailability.requireSupported(context)Throws when the device has no Telecom
IncomingCallPresenterImplement for full control of the notification; optional rename(callId, displayName) and showMissed(MissedCall)
MissedCallcallId, displayName, handle, video, endedAtMs: an incoming call that stopped ringing unanswered
CallxCallBackActivityDeclared by the library; the missed-call Call back button records a call request and opens the app
TelecomSystemActionHandlerBackend work for actions from watches and cars

iOS actions and audio ​

TypeDescription
CallKitActionPerformingBackend work per CallKit action; return false to fail it
CallKitAudioSessionHandlingdidActivate(_:), didDeactivate(_:)
MediaRoutingPerformerWraps a performer so mute and CallKit keypad actions reach the media adapter
CallxAudioRoutesLists and switches outputs while CallKit's audio session is active; the bootstrap installs it
CallxCallFeatureExecutorPerforms setAudioRoute, sendDtmf and setDisplayName; the bootstrap installs it

Call requests ​

The user asked the system to call someone through the app (ADR-0013). Not a command: the host looks up the handle and decides whether to call startCall.

KotlinSwiftDescription
CallxCallRequest(handle, displayName, video, requestedAtMs)CallxCallRequestOne request
CallxCallRequests.take()CallxCallRequests.take()The pending request, delivered once; held for 60 seconds
CallxCallRequests.setListener(listener)CallxCallRequests.setListener(_:)One consumer (the framework plugin) is told when a request arrives
CallxCallRequests.offer(request)CallxCallRequests.offer(_:)Records a request from another source
CallxCallRequests.handle(_ activity:)Forward an NSUserActivity from Recents, contacts or Siri; true when it was a call request
CallxStartCallIntentHandlerReturn it from application(_:handlerFor:) for Siri voice requests (unverified on a physical iPhone)

See phone features for host setup.

Media adapters ​

KotlinSwift
CallxMediaAdapter (apiVersion, start, stop, setMuted)CallxMediaAdapter (same, plus audio session callbacks)
CallxMediaSink (connected, interrupted, videoChanged)CallxMediaSink
CallxVideoAdapter (setCamera, attach, detach; adapter API 2)CallxVideoAdapter
CallxDtmfAdapter.sendDtmf(callId, digits) (optional)CallxDTMFAdapter.sendDTMF(callID:digits:) (optional)
CallxMediaAdapterFactory.create(context)CallxMediaAdapterFactory.makeAdapter(context:)
CallxAdapterContext(context, scope, log)CallxAdapterContext(log:)
Manifest dev.callx.media.<provider>Info.plist CallxMediaAdapterFactories

See write a media adapter.

LiveKit adapter (native) ​

KotlinSwift
CallxLiveKit.configure(context, tokenUrl, headers)CallxLiveKit.configure(tokenURL:headers:)
CallxLiveKit.setCredentialProvider { callId -> LiveKitCredentials(url, token) }CallxLiveKit.setCredentialProvider { callID in … }
CallxLiveKit.reset(context)CallxLiveKit.reset()

Released under the MIT License. No telemetry, in the library or on this site.