Mobile SIP Apps & the Background-Running Challenge
Running a SIP softphone on a phone (iOS or Android) sounds simple but is fundamentally hard. Mobile OSes aggressively suspend background apps to save battery, which kills SIP REGISTER refreshes and inbound INVITE delivery. Modern mobile SIP apps work around this with push notifications and OS-specific wake-up paths — not by keeping the SIP socket alive.
Why a 'normal' SIP softphone fails on mobile
- iOS suspends apps within seconds of going to background. The SIP TCP/UDP socket dies.
- The app cannot send REGISTER refreshes — binding expires, calls stop ringing.
- Even if the binding is alive, an inbound INVITE arriving over UDP is dropped because the OS has unmounted the app's network stack.
- Android has slightly more leeway (foreground services, JobScheduler) but battery optimizers from OEMs (Xiaomi, Huawei, Samsung) kill background SIP aggressively.
The fix is not 'fight harder to stay alive'. The fix is 'don't try to stay connected; use OS push to wake up only when there's a call'.
The push-based architecture (the way it actually works)
- App registers with the SIP server using SIP outbound (RFC 5626) and a
Path:header containing a push-token reference. - SIP server stores: extension ↔ push token mapping.
- Inbound call arrives. Server tries normal SIP delivery first.
- If the app's TCP socket is dead, server sends a push notification (APNs on iOS, FCM on Android) carrying the call info.
- OS wakes the app. App restores SIP socket and replies to the INVITE within the push timeout (~30s).
- Call rings.
iOS-specific: PushKit + CallKit
iOS has a special class of high-priority pushes called VoIP pushes (PushKit). They wake the app silently, with no user-visible notification, specifically for incoming calls. Apple gates this by requiring you to use CallKit — the system call UI — for every push received, otherwise the app is permanently revoked from VoIP push.
This means iOS SIP apps must:
- Register a PushKit token with the SIP server.
- On every PushKit notification, immediately call CallKit's
reportNewIncomingCall(). - Connect/answer the actual SIP call after CallKit shows its UI.
Apple monitors compliance — an app that receives a VoIP push and doesn't show CallKit gets its push entitlement revoked.
Android-specific: FCM + ConnectionService
Android uses FCM (Firebase Cloud Messaging) for push. High-priority pushes wake the app with ~10s of network access — usually enough to receive an INVITE and answer.
The system call UI equivalent of CallKit is ConnectionService (since Android 6) and Telecom framework. Required for showing native call UI, integrating with bluetooth headsets, and being treated as a real call (do-not-disturb, etc.).
Android pitfalls:
- OEM battery optimizers (Xiaomi MIUI, Huawei EMUI, Samsung) often ignore high-priority FCM and force-stop the app after a few hours of inactivity. Users must manually whitelist the app.
- Doze mode delays low-priority FCM up to 15 minutes — high-priority is required for SIP wake-up.
- Some carriers (Reliance Jio, China Mobile) block FCM entirely — you need a fallback like Huawei Push Kit or self-hosted MQTT.
Server-side support
For push wake-up to work, your SIP server must:
- Accept SIP REGISTER with push-token Contact parameters (
;pn-prid=<token>;pn-provider=apns, etc.). - Store the push token alongside the extension.
- On inbound INVITE, attempt normal delivery; on timeout, send a push.
- Optionally suppress repeated REGISTER probes from the client to save battery.
Most modern SIP stacks support this:
- Asterisk pjsip 18+: via
res_pjsip_outbound_publish+ custom AMI scripts, or via Sangoma's mobile push module. - FreeSWITCH: via mod_sofia push extension or external push gateway.
- Kamailio:
mod_outbound+mod_xhttp+ custom Lua/JS pushes. - Hosted PBXs (3CX, FreePBX with EndPoint Connector, RingCentral): handle this transparently.
Why some 'free SIP apps' don't ring reliably
Apps like Zoiper free, Linphone, and Bria (without push module) keep the SIP socket alive only while in foreground. As soon as the app backgrounds, calls stop ringing. They work fine for placing outbound, but inbound is unreliable. For dependable inbound on mobile, use:
- An app with built-in push (Acrobits Groundwire, Bria Mobile + push subscription, Zoiper Premium).
- A hosted PBX with its own mobile app (RingCentral, 3CX, Zoom).
- Microsoft Teams (uses Microsoft's push infrastructure end-to-end).
End-to-end architecture (recommended)
[Mobile app] <==FCM/APNs==> [Push gateway] <==SIP==> [SIP server / PBX] <==SIP==> [DIDHub trunk] <== PSTN == Idle state: Mobile app NOT connected to SIP server. Push gateway holds the push token. Inbound call: PSTN -> DIDHub -> PBX -> "extension is registered with push token X" PBX -> push gateway -> APNs/FCM -> phone OS -> wakes app App reconnects SIP, answers INVITE, audio flows.
Battery cost
A push-only architecture uses ~<1% battery per day for SIP. A keep-socket-alive architecture uses 5-15% per day and frequently fails. Push wins on every axis.
Related terms
SIP REGISTER
SIP over WebSocket (WSS)
Desk Phones vs Softphones
WebRTC (Web Real-Time Communications)
NAT Traversal in SIP/VoIP
Ready to get a number?
Pick a DID in 130+ countries from $1.99/month. Activates instantly on most numbers.