Skip to main content
Ringing on Android from a killed app crosses four layers, each of which an OEM can break independently. This is what breaks, how RingKit mitigates it, and what you still have to do.

The four layers

The silent Telecom failure

The nastiest OEM bug: handing the call to the system returns success, no error callback fires, and no call UI appears. A naive hybrid assumes success and never falls back → no ring at all. RingKit doesn’t trust “accepted.” After the system takes a call, it arms a watchdog; if the real call screen hasn’t materialized shortly after and the call is still live, RingKit claims the call for its full-screen fallback and rings there. A late system screen for a claimed call is turned away, so the OEM can’t pop a second, empty call window.

Per-OEM expectations

Prefer the behavioural watchdog over manufacturer sniffing — skins and versions drift, the watchdog does not.

Config recipes

What your app still does

RingKit ships the plumbing; a couple of levers are the user’s to pull and can’t be toggled in code:
  • Request POST_NOTIFICATIONS (Android 13+) — the fallback is a notification.
  • Prompt for battery-optimization exemption — Google allows this for calling apps; it materially improves push delivery.
  • Guide users to OEM autostart settings on MIUI/EMUI/ColorOS. RingKit gives you getReliabilityInfo() (manufacturer + battery-exemption + whether an autostart screen is likely) and the actions openBatteryOptimizationSettings() / openAutoStartSettings() to take the user straight there. Show a one-time hint when !ignoringBatteryOptimizations || autoStartAvailable.

Honest limits

  • A device with FCM fully starved (aggressive OEM killer + user never opened the app) can still miss a call — no library beats an OS that refuses to deliver the push. Battery-exemption and autostart guidance is the real lever.
  • The full-screen fallback is a very good call screen, but it isn’t the system call UI: it doesn’t appear in the OS call log or integrate with car kits the way a Telecom call does. That’s the trade-off for ringing everywhere.

Non-GMS (Huawei) via HMS Push

RingKit is push-transport-agnostic, so HMS plugs into the same native entry point — no RingKit changes, and the Huawei SDK never touches your GMS builds. Add HMS to your app, then hand the wake message to RingKit:
Send an HMS Push data message carrying the same call fields as FCM (callId, handle, hasVideo, chatId). Everything downstream — Telecom, the fallback, the watchdog, answer routing — is identical to the GMS path. The plugin’s docs/HMS.md has the full Gradle wiring.