Background UDP receive for lighting control (Art-Net/sACN)

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

  1. 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.)
  2. Is the silent audio workaround considered acceptable for App Store distribution in a professional tools context, or will it be rejected?
  3. 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):

  1. Select the UDPBackgroundTest target → Signing & Capabilities → set your Team
  2. Plug in your iPhone → select it as the run destination
  3. Build & run — confirm packets appear on screen when you run 'send_test_udp.py'
  4. Lock the phone and observe the dropout

Test:

  1. Open the app and run 'python3 send_test_udp.py 192.168.0.XXX'
  2. The app counts up the packages, they match the python output. 1 packet per second.
  3. lock screen & and wait 10 seconds
  4. unlock phone an see the numbers are 10 packets off
Background UDP receive for lighting control (Art-Net/sACN)
 
 
Q