Skip to content

Create hook and native methods to handle incoming voip calls#59

Merged
Magmusacy merged 28 commits into
masterfrom
FCE-3438
Jun 29, 2026
Merged

Create hook and native methods to handle incoming voip calls#59
Magmusacy merged 28 commits into
masterfrom
FCE-3438

Conversation

@Magmusacy

Copy link
Copy Markdown

Summary

Adds VoIP calling support (iOS) to @fishjam-cloud/react-native-webrtc: incoming calls now show the native CallKit UI, and the SDK receives VoIP pushes via PushKit so calls ring even when the app is backgrounded or killed. Everything is surfaced to JS through a single useVoIPEvents hook.

What changed

  • CallKit incoming calls (native): CallKitManager is now a shared singleton with reportIncomingCall…, which calls reportNewIncomingCall to show the system call UI, and emits an answer event when the user accepts.
  • PushKit (native): new FishjamVoIPPush owns the PKPushRegistry / delegate on a dedicated serial queue — handles the VoIP token, and on didReceiveIncomingPush reports the call to CallKit (with an always-report safety net so iOS never throttles us). Registered at launch from the AppDelegate.
  • Events bridged to JS: CallKit actions (answer/ended) ride the existing callKitActionPerformed channel; PushKit events (registered/incoming) ride a new voipPushEvent channel. Added a synchronous getVoipToken getter.
  • JS API: new PushKit.ts (getVoipToken) and an updated useVoIPEvents({ onIncoming, onAnswered, onEnded, onRegistered }) hook that listens on both channels and seeds the current token on mount (covers the token-issued-before-subscribe race).
  • Example (voip-call): wires useVoIPEvents, plus AppDelegate registration, aps-environment entitlement, and the voip background mode.

Notes

  • AppDelegate registration is currently a manual edit

@linear

linear Bot commented Jun 23, 2026

Copy link
Copy Markdown

FCE-3438

@Magmusacy Magmusacy marked this pull request as ready for review June 23, 2026 08:35
Copilot AI review requested due to automatic review settings June 23, 2026 08:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds iOS VoIP call support to the library by integrating PushKit + CallKit on the native side and exposing the resulting events to JS via a new useVoIPEvents hook plus a getVoipToken() accessor.

Changes:

  • Added native PushKit support (FishjamVoIPPush) and bridged voipPushEvent + synchronous getVoipToken to JS.
  • Extended CallKit handling to emit an answer action and to initialize PushKit observing when the native event emitter starts observing.
  • Added JS-facing APIs: useVoIPEvents hook and getVoipToken export; wired new native event name into the JS event pipeline.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/useVoIPEvents.ts New hook listening to CallKit + PushKit event channels and seeding the current VoIP token on mount.
src/PushKit.ts Adds JS getVoipToken() wrapper for the native synchronous getter.
src/index.ts Exports new VoIP APIs (getVoipToken, useVoIPEvents, related types).
src/EventEmitter.ts Registers voipPushEvent as a supported native event on the JS side.
src/CallKit.ts Adds answer action type and a JS wrapper for reportIncomingCall.
src/useCallKit.ts Minor formatting change in imports.
ios/RCTWebRTC/WebRTCModule+PushKit.{h,m} Bridges PushKit token/incoming events to JS and exports getVoipToken.
ios/RCTWebRTC/FishjamVoIPPush.{h,m} Implements PushKit registry/delegate, token tracking, and reporting incoming calls to CallKit.
ios/RCTWebRTC/CallKitManager.{h,m} Makes manager a singleton, adds reportIncomingCall..., and emits answer callback.
ios/RCTWebRTC/WebRTCModule+CallKit.m Uses singleton CallKitManager, emits answer, and starts/stops PushKit observing with event observing lifecycle.
ios/RCTWebRTC/WebRTCModule.{h,m} Adds voipPushEvent constant and includes it in supportedEvents.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ios/RCTWebRTC/WebRTCModule+CallKit.m
Comment thread ios/RCTWebRTC/CallKitManager.m
Comment thread ios/RCTWebRTC/CallKitManager.m
Comment thread ios/RCTWebRTC/FishjamVoIPPush.m Outdated
Comment thread ios/RCTWebRTC/FishjamVoIPPush.m Outdated
Comment thread ios/RCTWebRTC/WebRTCModule+PushKit.m
dict[@"displayName"] = displayName;
}

[[CallKitManager shared] reportIncomingCallWithDisplayName:displayName isVideo:isVideo];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: What's going to happen if this is called before JS is ready? Will the hook be retried? The native method can be called before the js loads.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, right now the incoming payload doesn't show up when the app is not even in background. I'll add retries to deliver the payload to js side

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd rather make the JS pull/check if there is any payload waiting. Should be much simpler.

@Magmusacy Magmusacy Jun 26, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that's what I've done, changes will be ready in a minute, I also did the same for accepting the call because it was also prone to race condition if the user accepted the call but JS hasn't lodaded yet

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

src/CallKit.ts:17

  • CallKitAction models started/answer/ended as undefined, but the native side emits these keys with NSNull (which becomes null in JS). Updating the types to null better reflects the runtime payload and avoids misleading callback typings for consumers of useCallKitEvent.
export type CallKitAction = {
    started?: undefined;
    answer?: undefined;
    ended?: undefined;
    failed?: string;
    muted?: boolean;
    held?: boolean;
};

Comment thread src/useVoIPEvents.ts
Comment thread src/useVoIPEvents.ts
Comment thread src/useVoIPEvents.ts
Magmusacy and others added 2 commits June 26, 2026 15:21
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Comment thread ios/RCTWebRTC/CallKitManager.m Outdated
@Magmusacy Magmusacy merged commit 84c9dbb into master Jun 29, 2026
8 checks passed
@Magmusacy Magmusacy deleted the FCE-3438 branch June 29, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants