I'm attempting to create a service that:
- Listens on iOS device A using
NWListener
- Broadcasts the
NWService
( usingNWListener(service:using:))
) on Bonjour - Allows a separate device, iOS device B, to receive information about that service via an
NWBrowser
- Connect to that service using the information contained in
NWBrowser.Result
'sNWEndpoint
I've been able to successfully do this using a SwiftNIO
service, in the following environments:
- iOS device A and iOS device B are physical iOS devices on the same WiFi network. This works.
- iOS device A and iOS device B are iOS simulators on the same machine. This works.
- iOS device A is a physical device, and iOS device B is a simulator. iOS device A is not connected to a WiFi network, iOS device B is connected to a WiFi network. This works.
However, when iOS device A and iOS device B are physical devices that are not connected to a WiFi network, I encounter the following behavior:
- The Bonjour service is correctly advertised, and iOS device A and iOS device B are able to observe the advertisement of the service.
- In both cases, iOS device A and iOS device B, while able to resolve an
NWEndpoint
for the Bonjour service, are not able to connect to each other, and the connection attempt hangs.
My setup for the listener side of things looks roughly like:
let opts: NWParameters = .tcp
opts.includePeerToPeer = true
opts.allowLocalEndpointReuse = true
let service = NWListener.Service(name: "aux", type: BONJOUR_SERVICE_TYPE, domain: "")
try bootstrap.withNWListener(NWListener(service: service, using: opts)).wait() // bootstrap is an artifact of using SwiftNIO
Similarly, my setup on the discovery side of things looks like:
let params: NWParameters = .tcp
params.includePeerToPeer = true
let browser = NWBrowser(for: .bonjour(type: BONJOUR_SERVICE_TYPE, domain: BONJOUR_SERVICE_DOMAIN), using: params)
browser.browseResultsChangedHandler = { (searchResults, changed) in
// save the result to pass on its NWEndpoint later
}
and finally, where I have an NWEndpoint
, I use SwiftNIO's NIOTSConnectionBootstrap.connect(endpoint:)
to initialize a connection to my TCP service ( a web socket server ).
The fact that I am able to get P2P networking (presumably over an awdl
interface?) between the simulator and the iOS device suggests to me that I haven't done anything obviously wrong in my setup. Similarly, the fact that it works over the same WiFi network and that, in P2P, I am able to at least observe the Bonjour advertisement, strikes me that I'm somewhere in the right neighborhood of getting this to work. I've also ensured that my Info.plist
for the app has a NSLocalNetworkUsageDescription
and NSBonjourServices
for the Bonjour service type I'm browsing for.
I've even attempted to exercise the "Local Network Permission" dialog by using a hacky attempt that sends data to a local IP in order to trigger a permissions dialog, though the hack does not appear to actually force the dialog to appear.
Is there some trick or other piece of knowledge regarding allowing the use of P2P w/ Network.framework
and TCP connections to services?
I use SwiftNIO's
NIOTSConnectionBootstrap.connect(endpoint:)
to initialize a connection to my TCP service ( a web socket server ).
Is that code setting includePeerToPeer
on the parameters use to create the underlying NWConnection
?
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"