How to listen for UDP packets in the background?

I have an app that is listening to incoming UDP packets with NWListener.

I instantiate the listener:

Code Block
var listener: NWListener?
do {
listener = try NWListener(using: .udp, on: port)
} catch {
print("exception upon creating listener")
}


I implement the stateUpdateHandler:

Code Block
listener?.stateUpdateHandler = {(newState) in
switch newState {
case .ready:
print("ready")
default:
break
}
}


And of course the handler for new connection where I also start the connection:

Code Block
listener?.newConnectionHandler = {(newConnection) in
newConnection.stateUpdateHandler = {newState in
switch newState {
case .ready:
print("ready")
default:
break
}
}
newConnection.start(queue: DispatchQueue(label: "newconn"))
}

Finally I receive the message with

Code Block
connection.receiveMessage { (data, context, isComplete, error) in
// Decode and continue processing data
}


The code works perfectly when the app is actively in the foreground.

What is the recommended approach to keep listening in the background when the user switches to another phone or presses the power button?

I was looking at the "Background Modes"-Capability and first thought about getting this to work with "Background processing", but after some research this does not seem suitable.

Is there any other suitable way to get the UDP listening to work in the background?

The app is also supposed to track the users location as well, also in the background. This would work with "Location updates" I suppose. Correct?

I have written a location tracker test app already and trying to get the location tracking working in the background. I need to test a little more.

In case I get location tracking in the background to work, will then the UDP listener also work in the background?

Any insights highly appreciated!

What is the recommended approach to keep listening in the background
when the user switches to another phone or presses the power button?

Networking in the background works just fine as long as your app remains running. Things go south when your app gets suspended. For some general background on this, see Technote 2277 Networking and Multitasking (some of the details have drifted since I wrote that but the basic ideas still apply).

You have two choices here:
  • You can move to a networking API that works even if your app is suspended (A).

  • You can prevent your app from being suspended (B).

I don’t think you’ll make much headway with A. The only API for this, NSURLSession background sessions, is limited to outgoing HTTP\[S\] requests, and you’re looking for incoming UDP support.

With regards B, there’s no general-purpose approach to keep your app running in the background indefinitely. Rather, each approach is tied to a specific user scenario. Apropos that you wrote:

The app is also supposed to track the users location as well, also in
the background. This would work with "Location updates" I suppose.
Correct?

Possibly. Most location tracking — region monitor, significant location changes, and so on — does not keep your app running indefinitely in the background. The only one that does is navigation. It’s hard to say whether that’s appropriate for your app based on the info you’ve posted so far.

So, what does your app do? And is it aimed as general users? Or targeted at specific users in a managed environment?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Thank you, Quinn!

The app shall record telemetry data from a device in a vehicle. The device continuously sends out the UDP packets over WiFi.

It is a specific user in a managed environment. Nothing the general public would use or come in contact with.

The user enters the vehicle and ideally, the app shall already start recording or the user presses a "Start Recording" button after entering the vehicle, doesn't matter, as long as the user does not have to necessarily keep the app active all the time. There might be other apps the user might need in that situation. So there is always the danger the app might get suspended.

Navigation could be an option and if its the only viable option there might be a use case that could involve navigation.

Reading the documents you have provided me made be thinking about background tasks again.

Might it be possible to start a background task, e.g. every X seconds that captures a few UDP packets and then finishes until the next X seconds have passed?

Naively thinking, I somehow would have to put

Code Block
connection.receiveMessage { (data, context, isComplete, error) in
// Decode and continue processing data
}

into a background process.

Is it doable in some way?

Might it be possible to start a background task, e.g. every X seconds
that captures a few UDP packets and then finishes until the next X
seconds have passed?

No. That would be a trivial way to get unlimited amounts of background execution time, which is something that iOS deliberately prevents you from doing.

In this setup is the device guaranteed to be connected to the vehicle’s power?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Some vehicles do have a power supply, but some do not have one.

How about those that have one?

Some vehicles do have a power supply, but some do not have one.

Yeah, this is getting increasingly unlikely to be practical. Running continuously in the background chews through a lot of energy (which is why iOS is so strict about allowing it) and that makes any solution impractical unless you have a power source.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
What would you recommend for those devices connected to power all the time?

Use navigation to prevent the app from being suspended?
The only solid recommendation I have is that you restructure your system so that you don’t need to continuously receive network data in this way. It’s not a good fit for iOS’s multitasking capabilities.

All the possibilities beyond that are far from ideal.



You could use the location background mode to keep your app running in the background, but there’s a bunch of issues with that:
  • It’s only really feasible if you have external power.

  • It’s not what this mode was designed for. It was specifically designed for folks implementing turn-by-turn navigation apps. That mismatch will cause both business and technical complications.

  • At a technical level, it’s not like this mode prevents your app from being suspended completely. Rather, the app must start an active navigation session while it’s in the foreground and it prevents your app from being suspended while that navigation session is running.

  • Use of ‘super powered’ background modes is always carefully scrutinised by App Review.

IMPORTANT I don’t work for App Review and can’t give definitive answers about their policy.



The audio background mode has many of the same issues as the location one.



You could use the Local Push Connectivity API. The tricky part here is that this is gated by an additional capability that must be granted by Apple. I’m not involved in that approval process, so I can’t say whether your usage is aligned with their policy.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thank you, Quinn!

I am going to use the location background mode because I actually have a use case for that. Capturing the UDP packets is essential and being able to correlate them with the users location is even better.

Even ran a test already by combining the code base with the UDP listener and the code responsible for tracking the users location. Did start the app yesterday morning and put it in the background. Then I have send UDP packets throughout the day, the last time this morning. My app successfully captured all packets but one. All in all, I have received around 60k location updates as well.

Now, I am just unsure about what activityType I need to set and in how far this variable changes the behaviour.

What I have found through my research is, that activityType determines when no location updates will be send any longer when the position does not change anymore.

Am struggling to understand what this means in case of otherNavigation, other, automotiveNavigation and airborne.

My assumption is, the faster you move in your activity type, the sooner it will pause updating locations.

Is my assumption correct?

There are a bunch of activityType properties but I presume you’re reference to this one. If so, that’s not something I can help you with. I know just enough about Core Location to get into trouble (-:

My advice is that you put this question into a new thread, tagging it with Core Location so that interested folks see it [1].

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] And, yes, this thread is also tagged with Core Location but it’s likely that all this networking guff has scared away any CL experts (-:

How to listen for UDP packets in the background?
 
 
Q