I'm developing a lighting control app for iOS that receives Art-Net (UDP port 6454) and sACN (UDP port 5568) packets from a lighting console and relays commands to BLE wristbands with LEDs. This is used in live event production — the participant locks their phone while in a show and expects lighting control to continue uninterrupted.
The problem
UDP receive stops reliably ~30 seconds after the screen locks. I understand this is by design - iOS suspends apps in the background. However, I'm trying to understand if any supported path exists for this use case.
What I've already tried
- UIRequiresPersistentWiFi = true - helps with Wi-Fi association but doesn't prevent app suspension
- Silent AVAudioEngine loop with UIBackgroundModes: audio - keeps the app alive, works in testing, but risks App Store rejection and feels like an abuse of the audio background mode
- NWListener (Network framework) on the UDP port - same suspension behaviour
- Socket rebind on applicationWillEnterForeground - recovers after resume but doesn't prevent dropout
What I'm asking
- Is there any supported background mode or entitlement for sustained UDP receive in a professional/enterprise context? (Similar to how VoIP apps get the voip background mode for sustained network activity.)
- Is the silent audio workaround considered acceptable for App Store distribution in a professional tools context, or will it be rejected?
- Is NEAppProxyProvider or another Network Extension a viable path, and if so does it require a special entitlement?
Test project
I have a minimal Xcode project (~130 lines) demonstrating the issue — NWListener on port 6454, packet counter, staleness timer, and silent audio toggle. I can share the test code.
STEPS TO REPRODUCE
In Xcode (one-time setup):
- Select the UDPBackgroundTest target → Signing & Capabilities → set your Team
- Plug in your iPhone → select it as the run destination
- Build & run — confirm packets appear on screen when you run 'send_test_udp.py'
- Lock the phone and observe the dropout
Test:
- Open the app and run 'python3 send_test_udp.py 192.168.0.XXX'
- The app counts up the packages, they match the python output. 1 packet per second.
- lock screen & and wait 10 seconds
- unlock phone an see the numbers are 10 packets off