Environment: iOS 18.7.8, CallKit + PushKit VoIP. On VoIP push we call reportNewIncomingCall and show the system CallKit UI.
Goal: When the user declines from the CallKit UI, send a single HTTPS POST to our backend in realtime, across all app states.
Problem: Foreground and backgrounded states work. When the app is terminated (system-evicted or user-force-quit), the push launches the app, CallKit shows, and we receive CXEndCallAction — but the network request doesn't reliably leave the device. The process is suspended/terminated moments after the action returns. Tried:
URLSession.shared dataTask inside CXEndCallAction — frozen with the app; resumes only on next foreground launch. beginBackgroundTask(withName:) around the request — insufficient when terminated. Background URLSession (.background, isDiscretionary = false, sessionSendsLaunchEvents = true, uploadTask(fromFile:), body staged in Caches, held briefly with a task assertion). Reliable when backgrounded; still unreliable/delayed when terminated, especially after force-quit.
Questions:
- Is reliable, near-realtime client network delivery from a terminated, PushKit-launched app possible, or is this an inherent platform constraint?
- If it's a constraint, is the recommended pattern to treat the decline as best-effort and make the server authoritative (e.g., ring timeout)? Any official references?
- Does force-quit vs. system termination change background-execution / background-URLSession guarantees, and is there a supported approach for force-quit specifically?
- Any API we missed (e.g., a sanctioned way to extend runtime during CXEndCallAction, or background-URLSession scheduling guarantees for VoIP) that makes this realtime-reliable?