Bonjour, also known as zero-configuration networking, enables automatic discovery of devices and services on a local network using industry standard.

Pinned Posts

Posts under Bonjour tag

50 Posts
Sort by:
Post not yet marked as solved
26 Replies
9.0k Views
Hi, I am facing a strange issue in my app with iOS14 there is a intermittent crash, i am using NetServiceBrowser for MDNS discovery not sure if that is causing the problem crash log has below information: Crashed: com.apple.main-thread 0 CoreFoundation 0x1a906c4c4 CFAssertMismatchedTypeID + 108 1 CoreFoundation 0x1a8f7db0c CFRunLoopSourceRemoveFromRunLoop + 298 2 CFNetwork 0x1a96255b0 CFNetServiceBrowserStopSearch + 460 3 CoreFoundation 0x1a8f81240 CFRUNLOOPISCALLINGOUTTOASOURCE0PERFORMFUNCTION + 24 4 CoreFoundation 0x1a8f81140 CFRunLoopDoSource0 + 204 5 CoreFoundation 0x1a8f80488 CFRunLoopDoSources0 + 256 6 CoreFoundation 0x1a8f7aa40 CFRunLoopRun + 776 7 CoreFoundation 0x1a8f7a200 CFRunLoopRunSpecific + 572 8 GraphicsServices 0x1bf075598 GSEventRunModal + 160 9 UIKitCore 0x1ab840004 -[UIApplication run] + 1052 10 UIKitCore 0x1ab8455d8 UIApplicationMain + 164
Posted
by
Post not yet marked as solved
0 Replies
14k Views
I regularly get asked questions about local network privacy. This is my attempt to collect together the answers for the benefit of all. Before you delve into the details, familiarise yourself with the basics by watching WWDC 2020 Session 10110 Support local network privacy in your app. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Local Network Privacy FAQ With local network privacy, any app that wants to interact with devices on your network must ask for permission the first time that it attempts that access. Local network privacy is implemented on iOS, iPadOS, and the current visionOS beta. It’s not implemented on other platforms, including macOS and tvOS. Some common questions about local network privacy are: FAQ-1 What is a local network? FAQ-2 What operations require local network access? FAQ-3 What operations require the multicast entitlement? FAQ-4 Do I need the multicast entitlement? FAQ-5 I’ve been granted the multicast entitlement; how do I enable it? FAQ-6 Can App Clips access the local network? FAQ-7 How does local network privacy work with app extensions? FAQ-8 How do I explicitly trigger the local network privacy alert? FAQ-9 How do I tell whether I’ve been granted local network access? FAQ-10 How do I use the unsatisfied reason property? FAQ-11 Do I need a local network usage description property? FAQ-12 Can I test on the simulator? FAQ-13 Once my app has displayed the local network privacy alert, how can I reset its state so that it shows again? FAQ-14 How do I map my Multipeer Connectivity service type to an entry in the Bonjour services property? FAQ-15 My app presents the local network privacy alert unexpectedly. Is there a way to track down the cause? FAQ-16 On a small fraction of devices my app fails to present the local network privacy alert. What’s going on? FAQ-17 Why does local network privacy get confused when I install two variants of my app? FAQ-18 Can my app trigger the local network privacy alert when the device is on WWAN? Revision History 2023-10-31 Fixed a bug in the top-level FAQ that mistakenly removed some recent changes. Added FAQ-18. 2023-10-19 Added a preamble to clarify that local network privacy is only relevant on specific platforms. 2023-09-14 Added FAQ-17. 2023-08-29 Added FAQ-16. 2023-03-13 Added connecting a UDP socket to FAQ-2. 2022-10-04 Added screen shots to FAQ-11. 2022-09-22 Fixed the pointer from FAQ-9 to FAQ-10. 2022-09-19 Updated FAQ-3 to cover iOS 16 changes. Made other minor editorial changes. 2020-11-12 Made a minor tweak to FAQ-9. 2020-10-17 Added FAQ-15. Added a second suggestion to FAQ-13. 2020-10-16 First posted.
Posted
by
Post marked as solved
25 Replies
10k Views
Hi, I'm new to swift programming and right now writing an app for esp8266-controlled lamp device. My lamp is broadcasting it's own IP through bonjour. So all I want is to discover any lamps in my network (http.tcp) and to read name and value. Is there any example of such implementation? All I found so far is old or a lit bit complicated for such simple question. Thanks in advance!
Posted
by
Post not yet marked as solved
1 Replies
507 Views
In this thread, eskimo posted code containing the line: listener.service = .init(type: "_ssh._tcp") I see in this document the type parameter is a service string, where its first substring identifies the application protocol, and its second identifies the transport protocol. Where is it documented what the valid NWListener.listener.service string options are for these application, and transport, protocols?
Posted
by
Post not yet marked as solved
2 Replies
551 Views
In the example code in this thread: https://stackoverflow.com/questions/61235935/understanding-some-nwbrowser-i-managed-to-get-working there is this line: print("result ", result ) The second argument in the print statement, the "result" variable, is not a String type. It is instead a struct whose definition begins in line 10731 in the "Network" import file. Somehow the print function knows how to convert this into a string for printing to the terminal. I conclude, with some uncertainty, that the instructions for doing this conversion have to be defined in this struct. Where in this struct is the conversion defined? If not defined there, how is the conversion done?
Posted
by
Post not yet marked as solved
3 Replies
764 Views
The function: browseResultsChangedHandler: ((_ newResults: Set<NWBrowser.Result>, _ changes: Set<NWBrowser.Result.Change>) -> Void)? returns two Set type parameters. There is data in each element of these sets I need to display in a view. What is the best way to convert these sets to an array that can be iterated in a "ForEach" statement so they can be displayed in a View? When I attempt to do it on a set directly I get the error: Cannot convert value of type 'Set<NWBrowser.Result>' to expected argument type 'Range<Int>'
Posted
by
Post not yet marked as solved
0 Replies
531 Views
These are download links to zip files that contain Xcode 14.3 project files which are my attempt to establish USB communications with an iPhone 14 connected by lightning cable to a MacStudio: https://www.mediafire.com/file/k3my6y94iyjobeq/Bonjour-Trial-iPhone.zip/file https://www.mediafire.com/file/cof3b3w9tru1jd0/Bonjour-Trial-Mac-Enumeration.zip/file I could not attach them here. This web interface's file browser had these files grayed out, so it was necessary to make them available on a file sharing site. The Bonjour-Trial-iPhone.zip project files run on the iPhone 14. The Bonjour-Trial-Mac-Enumeration.zip run on the MacStudio. I have the iPhone 14 project code working on the iPhone. I expect it should be advertising its presence. MacStudio project runs, but does not find the iPhone 14. When I trace execution in file Bonjour-Trial-Mac-Enumeration.swift the "results" array is empty on line 65. What is going wrong here? Is a type "_ssh._tcp" connection possible between a MacStudio, and an iPhone, over the lightning cable?
Posted
by
Post not yet marked as solved
3 Replies
613 Views
On the 4th question of: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/NetServices/Articles/faq.html I see: "you can ask the Bonjour to reconfirm the record" I am basing my code on the TicTacToe example at: https://developer.apple.com/videos/play/wwdc2022/110339/ I believe the DNS records which remains after the device that put them there shuts down is causing problems for me when again. Using the DeviceDiscoveryUI as in that TicTacToe example how are these records "reconfirmed" ?
Posted
by
Post marked as solved
5 Replies
1.3k Views
I'm using the following: mDNSResponder 1790.80.10 Bonjour Conformance Test (BCT) 1.5.2 Linux 6.1.y kernel I'm testing an Airplay 2 speaker as part of our self certification. When BCT gets into the mDNS tests mDNSResponder fails the subsequent conflict test with this message: ERROR 2023-06-12 10:37:29.398711-0500 _sub_conflict 03570: Device did not complete its probing sequence for a new name after a subsequent conflict arose for its previously acquired name. BCT then retries three times with each retry failing with the same message. Am I missing something from my software that interacts with the mdns daemon? Is this a known issue with the posix build for mDNSResponder? What can I do to get this test to pass? Any help would be appreciated. Ethan
Posted
by
Post not yet marked as solved
0 Replies
535 Views
I am trying to use BCT to test my iPhone. However, it just stuck in the initial probe stage though the BCT indeed outputs the mDNS packets. Most weird thing is that the target IP of packets BCT outputs is gateway instead of 224.0.0.251. Could somebody help me figure out? Thank you very much.
Posted
by
Post not yet marked as solved
5 Replies
945 Views
NWTXTRecord dictionary keys are lowercased in iOS 17, on iOS Simulator and the device. Records returned by NWBrowser in the listener block: browser.browseResultsChangedHandler = { result, changes in metadata : ["dvty": “AppName”, "txtvers": "1", "dbid": "50BFB79F"] But the actual keys are: "DvTy", "DbId". So, in iOS 17 all keys were lowercased, but not in any previous versions. And if in the app we were looking for “DvTy” key, nil is returned. The existing app simply stopped working properly in the first iOS 17 betas. Is it a bug or the app should be updated now to check for lowercased keys always? FB12309561
Posted
by
Post not yet marked as solved
1 Replies
429 Views
My app uses NWBrowser and NWListener to advertise a service and to discover other peer instances on the local network. It regenerates a serial number with each fresh launch. This serial number is included in TXTRecord. I can see that the serial number correctly changes after every restart. The problem that is bugging me right now is as follows. If I run the app with the lightning cable connected to my Macbook and then disconnect the cable, the app running on my IPhone would retain the information about my Macbook no matter how many times I restart the app or restart the other peer. It doesn't matter if I close the app before disconnecting the cable or the other way around. Restarting the app on my Macbook while in this state doesn't refresh the record on my IPhone. The app is supposed to replace the found instances for new and change cases but the old instance always prevails. I even went into airplane mode and turned off everything wireless on both my IPhone and my macbook. Nothing but services previously advertised by my Macbook still show up, which includes _airplay._tcp A third-party app for Bonjour discovery also confirms the phantom instances but it was of course unable to resolve these instances. It always takes tens of minutes for the phantom instances to be removed short of a reboot. I then discovered that if I start the app without the lightening cable connected, this issue wouldn't happen anymore. This suggests to me that this may have to do with the lightning port's network. The same app (via Mac Catalyst) running on the Macbook does not have this issue. Has anyone experienced anything similar?
Posted
by
YFQ
Post not yet marked as solved
3 Replies
787 Views
DNSServiceNATPortMappingCreate returns external port 0 since macOS 13 b3 build 23A5286i. This was the case in macOS 12 as well (see FB9137313 and FB9139688). Hopefully this won't take months after macOS is released before it is fixed like last time. Latest radar: FB12579235 Also, see https://developer.apple.com/forums/thread/681836
Posted
by
Post not yet marked as solved
1 Replies
716 Views
I am developing an app that is to be runnable on both Mac Studio, and iPhone 14. The app instance on the Mac communicates with the app's other instance in the iPhone 14. To debug the Bonjour communications I need to run this source code in the debugger in both the Mac Studio simulator, and at the iPhone, simultaneously. The ideal would be to able to step through source code, and set break points, in each app instance simultaneously. Is that possible? If so how?
Posted
by
Post marked as solved
8 Replies
1.1k Views
Is it possible to disable Local network option from xcode, so that do not popup notification to user about turn off /on and user could not disable or enable it
Posted
by
Post marked as solved
9 Replies
1.9k Views
I have iPhone named myphone. To get its IP address on local network, I used to do do host myphone.local in Terminal, or just checking if it is alive by ping myphone.local. This basic mDNS function worked every time, but with iOS 17 betas it is not working anymore. Is this intended functionality cut or just a bug?
Posted
by
Post not yet marked as solved
0 Replies
1.5k Views
Every now and then I talk to someone who’s trying to use Bonjour and just can’t get over the first hurdle. That happened today, and so I decided to share my write-up for the benefit of others. Questions or comments? Put them in a new thread here on DevForums, tagging it with Bonjour so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Getting Started with Bonjour Bonjour is an Apple term for a variety of Internet standards [1]. Bonjour allows your app to browse for and connect to services on the network without infrastructure support. For example, Bonjour lets you find and connect to a printer even if the network has no DHCP server to hand out IP addresses. If you’re new to Bonjour, a good place to start is the Bonjour Overview. It’s in the documentation archive, so it hasn’t been updated in a while, but the fundamentals haven’t changed. There are, however, two things that have changed: Network framework has new Bonjour APIs, and the old ones are now deprecated. iOS 14 introduced local network privacy. This post shows how to get started with Bonjour, taking into account these new developments. [1] Specifically: RFC 3927 Dynamic Configuration of IPv4 Link-Local Addresses RFC 6762 Multicast DNS RFC 6763 DNS-Based Service Discovery Start Browsing Let’s start by implementing a service browser. To simplify things, this browses for SSH services. That way you can get started with the browser without first having to implement a server to register your service. If you don’t already have an SSH service registered on your network, start one by enabling System Settings > General > Sharing > Remote Login on your Mac. The SSH service type is, unsurprisingly, _ssh._tcp. First, on your Mac, run the dns-sd tool to confirm that you have an SSH service visible on your network: % dns-sd -B "_ssh._tcp" "local." % dns-sd -B "_ssh._tcp" "local." … Timestamp A-R Flags if Domain Service Type Instance Name … 11:54:43.315 Add 2 6 local. _ssh._tcp. Fluffy … 11:54:43.725 Add 2 6 local. _ssh._tcp. SAM the Robot 12 ^C This shows that I have two services, one called Fluffy and the other called SAM the Robot 12. Let’s write some iOS code to browse for those. To start, create an app from the iOS > App template and connect a button to the startStop() method of a class like this: import Foundation import Network class AppModel { var browserQ: NWBrowser? = nil func start() -> NWBrowser { print("browser will start") let descriptor = NWBrowser.Descriptor.bonjour(type: "_ssh._tcp", domain: "local.") let browser = NWBrowser(for: descriptor, using: .tcp) browser.stateUpdateHandler = { newState in print("browser did change state, new: \(newState)") } browser.browseResultsChangedHandler = { updated, changes in print("browser results did change:") for change in changes { switch change { case .added(let result): print("+ \(result.endpoint)") case .removed(let result): print("- \(result.endpoint)") case .changed(old: let old, new: let new, flags: _): print("± \(old.endpoint) \(new.endpoint)") case .identical: fallthrough @unknown default: print("?") } } } browser.start(queue: .main) return browser } func stop(browser: NWBrowser) { print("browser will stop") browser.stateUpdateHandler = nil browser.cancel() } func startStop() { if let browser = self.browserQ { self.browserQ = nil self.stop(browser: browser) } else { self.browserQ = self.start() } } } Note I’m using SwiftUI, but if you chose to use UIKit you could add this code directly to your view controller. Of course, whether you want to add networking code to your view controller is another question. The answer is, natch, “No”, except when creating a tiny test project like this one (-: Now build and run in the simulator and click your buton. It’ll print something like this: browser will start browser did change state, new: ready browser results did change: + SAM the Robot 12._ssh._tcp.local. + Fluffy._ssh._tcp.local. As you can see, it’s found our two SSH services. Yay! Run on the Device Now stop the app and run it on a real device. This time the Test button results in: browser will start … browser did change state, new: failed(-65555: NoAuth) This is local network privacy kicking in. There are two things you need to do: Add a NSBonjourServices property to your Info.plist to declare what service types you’re using. Add a NSLocalNetworkUsageDescription property to your Info.plist to explain what you’re doing with the local network. Do that and run your app again. On tapping the Test button you’ll see an alert asking you to grant your app access to the local network. Tap Allow and the browser will start generating results as before. Respond to Updates When working with Bonjour it’s important to keep your browser running to update your app’s state. To test this, start a Remote Login on a different machine and look for a new result being printed: browser results did change: + Slimey._ssh._tcplocal. And then turn it off: browser results did change: - Slimey._ssh._tcplocal. If you don’t have another Mac to test this with, start a dummy service using dns-sd: % dns-sd -R "Guy Smiley" "_ssh._tcp" "local." 12345 Registering Service Test._ssh._tcp.local. port 12345 … Press control-C to stop the dns-sd tool, which unregisters the service. Connect When the user choose a service, it’s time to connect. There are two ways to do this, depending on the networking API you use to run your connection. NWConnection can connect directly to a Bonjour service endpoint. For example, you might have code that connects to a DNS name and port: func makeConnection(host: String, port: UInt16) -> NWConnection { let host = NWEndpoint.Host(host) let port = NWEndpoint.Port(rawValue: port)! let endpoint = NWEndpoint.hostPort(host: host, port: port) return NWConnection(to: endpoint, using: .tcp) } Replace that with code that takes the endpoint you get back from the browser: func makeConnection(endpoint: NWEndpoint) -> NWConnection { return NWConnection(to: endpoint, using: .tcp) } If you’re using a legacy API, like BSD Sockets, you’ll need to resolve the Bonjour service endpoint to a DNS name and then pass that DNS name into your connection code. Network framework does not support resolving Bonjour service endpoints out of the box, so you’ll have to do that yourself. For an example of how you might do this, see this post. IMPORTANT For this to work reliably, your BSD Sockets code must support Happy Eyeballs. See TN3151 Choosing the right networking API for specific advice on that front. Register a Service Now let’s look at the server side. To listen for connections with Network framework, you might write code like this: import Foundation import Network class AppModel { var listenerQ: NWListener? = nil func start() -> NWListener? { print("listener will start") guard let listener = try? NWListener(using: .tcp) else { return nil } listener.stateUpdateHandler = { newState in print("listener did change state, new: \(newState)") } listener.newConnectionHandler = { connection in connection.cancel() } listener.start(queue: .main) return listener } func stop(listener: NWListener) { print("listener will stop") listener.stateUpdateHandler = nil listener.cancel() } func startStop() { if let listener = self.listenerQ { self.listenerQ = nil self.stop(listener: listener) } else { self.listenerQ = self.start() } } } To register your service with Bonjour, add these lines before the call to start(queue:): listener.service = .init(type: "_ssh._tcp") listener.serviceRegistrationUpdateHandler = { change in print(change) } The listener calls your service registration update handler to tell you the name of the service. Typically you display this value somewhere in your UI. For more about this, see Showing Connection Information in an iOS Server. To confirm that your service is running, open Terminal and choose Shell > New Remote Command. Your service should show up in the Secure Shell (ssh) list. Alternatively, browse for SSH services using the dns-sd tool, as illustrated in the Start Browsing section above.
Posted
by
Post not yet marked as solved
1 Replies
694 Views
Unable to launch this sample project. Xcode says it cannot open the file. Building a custom peer-to-peer protocol I'm trying to build iPhone as a mouse. I am not planning on releasing it but more like a practice for myself. I have one other question, how to use a mac app to receive mouse data while it's in background as it's required by my app. Is Background Tasks the right way ? I am planning to use Network framework for networking but there is not much documentation available. Pardon me if it's a basic question.
Posted
by
Post not yet marked as solved
3 Replies
671 Views
I have an system that is designed around a collection of devices (iPhones or iPads) discovered via bonjour and connected with a NWConnection over TCP. Commands issued from one of the devices are sent to each of the peers and should be executed as soon as they are received. The problem I am encountering is a high variability in transit time device to device that I am having a hard time accounting for. By 'high' I am noting anywhere from 20-80ms of latency device to device. CPU utilization on each iPhone is essentially 0. Keepalives are enabled and firing off every 2 seconds. Additionally, the physical devices all have bluetooth off (as recommended in other posts) The interesting part is when I add into the connection mix an iPhone simulator (running on either a M1 MacBook Air, or my M1U Studio). When a command is issued from the simulator instance, all connected devices report back anywhere within ~0-3ms of deviation from the initiator, which is more what I expect from the network. Thinking that it's perhaps the M1 series of chips being far and away more competent than the A15's in the iPhone 13's and 14 that are in my testbed, I added my M1 iPad to the mix. Invoking a command from the iPad has similar variability as invoking it from one of the iPhones. The code is stupid simple and I'm posting here prior to opening up a DTS case in the hope that there's a magic "shouldUseSpeedholes=true" flag I can set. I have gone through several variations: using UDP instead of TCP (worse variations), changing from a listener/browser on each device to a single browser, multiple listener (no difference), changing from keeping things on the main queue (as in the docs) to a separate concurrent high priority dispatch queue (no difference). There is no TLS in the mix. I have tried both allowing peer-to-peer as well as not (no difference). I'm even using a single purpose project instead of my main codebase to isolate everything else that could be messing with scheduling with communications. I've tried each band of my WIFI (2.4 and 2x5ghz SSIDs) - no change. Sending func send(option: AppFramingOptions, withData data: Data?) { let message = NWProtocolFramer.Message(appFramingOption: option) let context = NWConnection.ContentContext(identifier: "\(option.rawValue)", metadata: [message]) for (uniqueKey, connection) in connections { if uniqueKey.contains(serviceName) { connection.send(content: data, contentContext: context, isComplete: true, completion: .idempotent) } } } In the above function, I am looking for the serviceName because I want to use connections connected via the browser as opposed to the listener (which isn't tagged with service name info in the endpoint). The check avoids a device receiving the command twice. Receiving connection.receiveMessage { content, contentContext, isComplete, error in guard error == nil else { connection.cancel() return } if let msg = contentContext?.protocolMetadata(definition: AppFraming.definition) as? NWProtocolFramer.Message { switch msg.appFramingOption { default: self.messageReceivedHandler?(content, msg.appFramingOption, Date().timeIntervalSince1970, withUniqueKey) } } receiveMessage() } } It's very much patterned off the TicTacToe example code (with a mechanism for multiple connections). My next step is embedding a web server in each device and making REST calls rather than commands over a TCP stream (which is CRAZY INSANE I KNOW). I also do not want to have to have a Macintosh dependency for this system because I cannot get predictable(ish) transit times. Any help is appreciated!
Posted
by