How to use multicast networking in your app
June 22, 2020
Apps use multicast networking to see and talk to other devices on their local networks. For example, an app might discover smart lightbulbs connected to a person’s Wi-Fi network and send them messages to turn on or off the lights. While the ability to discover and communicate with all devices on a local network is a powerful tool, those devices may carry sensitive personal information that could be used to build a marketing profile or to predict when people might be at home.
iOS 14 brings transparency and control over these behaviors by informing people when an app would like to access their local network — and allows them to block or revoke this access at any time.
Note: This privacy control applies only to accessing devices on an immediate network, and it doesn’t restrict an app from talking to the Internet.
If you need to interact with devices and protocols that require the use of multicast or broadcast networking, make sure to update your app to support the latest privacy protections added to iOS and iPadOS.
Multicast networking 101
Multicast networking is commonly used for discovery protocols, allowing you to identify other devices on the network, or for bulk delivery of data to many hosts on the same network. Due to the way Wi-Fi networks operate, bulk data transfer with multicast can be inefficient, so multicast should be used for short, limited transactions.
Apple platforms provide built in support for a cross-platform discovery protocol, Bonjour, which is also referred to as “multicast DNS”, “mDNS”, or “DNS service discovery” on other platforms. Bonjour is built into every major platform.
Use Bonjour whenever you need to discover or connect to other devices on your network. NWBrowser in Network.framework makes it easy to discover other Bonjour services on your network and establish NWConnection objects for communication with them, as well as to advertise Bonjour services using NWListener when you want others to find and connect to you.
Building a custom peer-to-peer protocol
Protect privacy during device discovery
If your app currently uses Bonjour to discover devices on a local network, it’s easy to integrate iOS 14’s privacy controls.
Make your declaration
If you’re using Bonjour, declare the services that you use in your app’s Info.plist
.
Provide context After declaring these services, you also need to provide a reason string, which provides context to someone when your app attempts to access a local network. Make sure this text clearly explains what your app is doing with the information it discovers from the local network and how receiving this data enables a necessary experience in your app.
Do you need to support legacy devices?
Maintaining compatibility with some legacy devices and software might require the use of custom multicast and broadcast protocols. Since these capabilities give your app complete access to the user’s local network, such access requires the com.apple.developer.networking.multicast
restricted entitlement.
Note: You can test your app using the iOS and iPadOS simulators without an active entitlement, but using multicast and broadcast networking on physical hardware requires the entitlement.
Request the com.apple.developer.networking.multicast entitlement
Send and receive multicast packets with NWConnectionGroup
If your app has the com.apple.developer.networking.multicast
entitlement, it can use NWConnectionGroup
to cleanly send and receive multicast packets in Swift using Network.framework.
To do this, first create a NWMulticastGroup
to describe the multicast group you’d like to join.
guard let multicast = try? NWMulticastGroup(for:
[ .hostPort(host: "224.0.0.251", port: 5353) ])
else { fatalError(...) }
Next, create a NWConnectionGroup
to handle incoming messages to that group and to use for sending messages to that group.
let group = NWConnectionGroup(from: multicast, using: .udp)
Set the newMessageHandler
to receive incoming packets sent to the multicast group and optionally send a message in reply.
group.setReceiveHandler(maximumMessageSize: 16384, rejectOversizedMessages: true) { (message, content, isComplete) in
print("Received message from \(String(describing: message.remoteEndpoint))")
let sendContent = Data("ack".utf8)
message.reply(content: sendContent)
}
Just like the other Network.framework objects, NWConnectionGroup
has a state update handler, which will be called on the DispatchQueue
you pass to start()
.
group.stateUpdateHandler = { (newState) in
print("Group entered state \(String(describing: newState))")
}
group.start(queue: .main)
When you want to send messages to the group, use send()
. To keep from overwhelming the network, schedule subsequent sends in the completion handler from the previous send.
let groupSendContent = Data("helloAll".utf8)
group.send(content: groupSendContent) { (error)
print("Send complete with error \(String(describing: error))")
}
And when you’re done with the NWConnectionGroup
, cancel it to clean up any associated state.
group.cancel()
Security and privacy for all
Local networking privacy is yet another way you can make your app safer and more secure for people who use it. Together with the other privacy controls in Apple platforms, local network protections help people have more control and context over what they’re sharing and when. You can help protect your users’ privacy by using Bonjour to discover devices on the network, listing the services you use in your Info.plist
and by providing a reason string to help them understand what you’re doing on their network.