1. Foreground — no push server
Run the plugin’sexample/ app and tap Simulate incoming call. It exercises
reportIncomingCall → the native call UI → callAnswered / callEnded on both platforms with no
push infrastructure. Its example/www/call-audio.js is also the reference wiring for the audio
gate and the mute / speaker / hold / end controls (see In-call audio).
2. Killed-app path — real pushes
The plugin ships two zero-dependency Node scripts (Node 18+) inexample/scripts/ that send a
real wake-up push. Read the device token from the registration event (or your logs), then:
- iOS — VoIP push
- Android — high-priority FCM
PushKit VoIP pushes do not fire on the iOS Simulator — use a real device. You need an
APNs Auth Key (It sends topic
.p8), its Key ID + your Team ID, the app bundle id, and the device’s
VoIP token. Use APNS_ENV=sandbox for a development build, prod for TestFlight /
App Store.<bundle>.voip with apns-push-type: voip and the default raw payload
(top-level callId / handle / hasVideo / chatId). Swipe the app away first — the
call screen must appear with the app terminated.3. Device matrix
Verify on at least a recent Pixel (clean Android), one Samsung, one Xiaomi / MIUI device (the strictest background limits) and an iPhone. On each, test three states — locked screen, unlocked / backgrounded, and fully killed — and confirm that answering resumes your call and declining emitscallEnded.
OEM-specific behaviour (MIUI / EMUI / ColorOS) and what to tell users is on the
Android reliability page; non-GMS Huawei devices need
HMS Push.
Automated tests (if you modify the source)
- JS — the plugin’s
npm run buildruns Vitest: the web/desktop no-op contract. - Android —
./gradlew :nickbur-ringkit:testDebugUnitTest, run from a host app that includes the plugin: payload mapping.