Hi,
I wanted to try using the new NWBrowser available in iOS 13 to replace my old Bonjour browsing code, problem is I'm unabe to get the IP and Port of the service I'm looking for.
My code :
let params = NWParameters() params.includePeerToPeer = true _bonjourBrowser = NWBrowser(for: .bonjour(type: "_mpd._tcp.", domain: nil), using: params) _bonjourBrowser.browseResultsChangedHandler = { results, changes in for change in changes { switch change { case .added(let browseResult): switch browseResult.endpoint { case .hostPort(let host, let port): print("added hostPort \(host) \(port)") case .service(let name, let type, let domain, let interface): print("added service \(name) \(type) \(domain) \(String(describing: interface))") default: print("fail") } case .removed(let browseResult): print("removed \(browseResult.endpoint)") case .changed(_, let browseResult, let flags): if flags.contains(.interfaceAdded) { print("\(browseResult.endpoint) added interfaces") } if flags.contains(.interfaceRemoved) { print("\(browseResult.endpoint) removed interfaces") } default: print("no change") } } } _bonjourBrowser.start(queue: DispatchQueue.global())
What I get is :
added service MPD.PI _mpd._tcp local. nil
added service MPD.MBP _mpd._tcp local. nil
How can I get an IP and Port out of this ?
AFAIK Network framework does not have an API that does the Bonjour resolve operation without also connecting. To solve this, you’ll have to go either up or down the stack:
Construct an
and then callNSNetService
on it.-resolveWithTimeout:
Use
.DNSServiceResolve
Both of these have their challenges. Specifically, in the
NSNetService
case, you have to deal with run loops.
In both cases, make sure to take the resulting DNS name and pass that to your third-party library. That allows it to connect by name, which should improve the chances of it connecting successfully [1].
Oh, before I go, I want to stress that the fact that
NWBrowser
does not resolve is a feature, not a bug. Resolving every service you encounter when browsing is a major Bonjour faux pas. The goal is to only resolve the service you’re connecting to, and then only at the point when you do the connection. Network framework does that as part of
NWConnection
, so the issue here is about whether there’s a way to do that without actually connecting.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"
[1] This assumes that it uses a system connect-by-name API, or contains all the necessary smarts to connect in a wide variety of environments. If this is a cross-platform code base it may not, in which case you may encounter connectivity problems in oddball network environments. If so, you might want to do a dummy connection yourself (using
NWConnection
), get the IP address it used, and pass that to your library.