NWBrowser + NWListener + NWConnection

I am seeking assistance with how to properly handle / save / reuse NWConnections when it comes to the NWBrowser vs NWListener.

Let me give some context surrounding why I am trying to do what I am.

I am building an iOS app that has peer to peer functionality. The design is for a user (for our example the user is Bob) to have N number of devices that have my app installed on it. All these devices are near each other or on the same wifi network. As such I want all the devices to be able to discover each other and automatically connect to each other. For example if Bob had three devices (A, B, C) then A discovers B and C and has a connection to each, B discovers B and C and has a connection to each and finally C discovers A and B and has a connection to each.

In the app there is a concept of a leader and a follower. A leader device issues commands to the follower devices. A follower device just waits for commands. For our example device A is the leader and devices B and C are followers. Any follower device can opt to become a leader. So if Bob taps the “become leader” button on device B - device B sends out a message to all the devices it’s connected to telling them it is becoming the new leader. Device B doesn’t need to do anything but device A needs to set itself as a follower. This detail is to show my need to have everyone connected to everyone.

Please note that I am using .includePeerToPeer = true in my NWParameters. I am using http/3 and QUIC. I am using P12 identity for TLS1.3. I am successfully able to verify certs in sec_protocal_options_set_verify_block. I am able to establish connections - both from the NWBrowser and from NWListener. My issue is that it’s flaky. I found that I have to put a 3 second delay prior to establishing a connection to a peer found by the NWBrowser. I also opted to not save the incoming connection from NWListener. I only save the connection I created from the peer I found in NWBrowser. For this example there is Device X and Device Y. Device X discovers device Y and connects to it and saves the connection. Device Y discovers device X and connects to it and saves the connection. When things work they work great - I am able to send messages back and forth. Device X uses the saved connection to send a message to device Y and device Y uses the saved connection to send a message to device X.

Now here come the questions.

Do I save the connection I create from the peer I discovered from the NWBrowser?

Do I save the connection I get from my NWListener via newConnectionHandler?

And when I save a connection (be it from NWBrowser or NWListener) am I able to reuse it to send data over (ie “i am the new leader command”)?

When my NWBrowser discovers a peer, should I be able to build a connection and connect to it immediately? I know if I save the connection I create from the peer I discover I am able to send messages with it. I know if I save the connection from NWListener - I am NOT able to send messages with it — but should I be able to?

I have a deterministic algorithm for who makes a connection to who. Each device has an ID - it is a UUID I generate when the app loads - I store it in UserDefaults and the next time I try and fetch it so I’m not generating new UUIDs all the time. I set this deviceID as the name of the NWListener.Service I create. As a result the peer a NWBrowser discovers has the deviceID set as its name. Due to this the NWBrowser is able to determine if it should try and connect to the peer or if it should not because the discovered peer is going to try and connect to it.

So the algorithm above would be great if I could save and use the connection from NWListener to send messages over.

Answered by DTS Engineer in 834389022

I cover much of this ground in Moving from Multipeer Connectivity to Network Framework. I’m gonna recommend that you read that and then come back here with your follow-up questions. That way I can help you out and getting a better handle on what that post is missing [1].

Share and Enjoy

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

[1] It’s hard to know what you don’t know, you know? (-:

@DTS Engineer im going to continue forward with Bonjour as it's important things work automatically and dont need user interaction.

Is there any hints / fears that bonjour would be deprecated?

Is there any hints / fears that bonjour would be deprecated?

We’ve not published any official guidance on that subject.


When someone responds with “No comment”, as I’ve done here, there’s a temptation to infer that they actually have a plan but they can’t talk about it. I recommend against such inference. Rather, it’s simply that I get in trouble if I try to speculate about The Future™.

Share and Enjoy

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

@DTS Engineer I have searched here on the forums for "WiFi Aware" and have read through just about every post. In a lot of them the person says they were able to get the example app (https://developer.apple.com/documentation/wifiaware/building-peer-to-peer-apps) working with their iOS devices. I, for some reason, am not able to get the example app to fully work. I am able to build the app and load the app onto two physical iPhone 12 minis. I follow the steps shown here https://developer.apple.com/documentation/wifiaware/building-peer-to-peer-apps but I get stuck because I can't get past the "enter this pin code to connect" step. I make one device be a host of a simulation and the other to view a simulation. On each device I tap the "+" button. On the viewer device I tap the discovered device. On the host device I then see the pin. I then enter the pin on the viewer device. After this step nothing happens. My only choice on the viewer device is to tap "cancel" and exit the "enter the pin step". If I go into the actual device settings I see that the devices are "paired" but the app doesn't seem to think so.

Are there some special settings I need to turn on for the app to work properly?


I have a second question that pertains to the new iOS 26 Networking stuff (NetworkBrowser, NetworkListener, NetworkConnection). So as you know I'm currently using NWBrowser, NWListener, NWConnection with Bonjour and QUIC. All it is working as expected. I wanted to try and migrate all my code to use the the new APIs (still use bonjour and NOT use wifi aware) but hit some issues. I was following how the example app was receiving messages like this

for try await messageData in connection.messages {

but got these errors

Requirement from conditional conformance of '(content: QUIC.ContentType, metadata: QUIC.Metadata)' to 'Copyable'

Requirement from conditional conformance of '(content: QUIC.ContentType, metadata: QUIC.Metadata)' to 'Escapable'

Requirement from conditional conformance of '(content: QUIC.ContentType, metadata: QUIC.Metadata)' to 'Copyable'

Requirement from conditional conformance of '(content: QUIC.ContentType, metadata: QUIC.Metadata)' to 'Escapable'

When I ask Cursor about this its response was as follows: "The connection.messages stream changed in the new Network APIs: it now yields typed (content, metadata) tuples. Iterating with for try await incoming in connection.messages asks the compiler to conform that tuple to Copyable/Escapable; for QUIC the tuple isn’t copyable, so you hit the conditional-conformance error."

I am curious if you've been able to use the new iOS 26 network APIs with QUIC?

Note that both iPhone 12 minis are on iOS 26.0.1, both have the wifi toggle ON.

I took the example app and paired it down to just send back simple messages based on user button taps.

These are my logs from when i start up the app and start on device as the hoster and one as the viewer.

Selected Mode: Hoster
Start NetworkListener
[L1 ready, local endpoint: <NULL>, parameters: udp, traffic class: 700, interface: nan0, local: ::.0, definite, attribution: developer, server, port: 62182, path satisfied (Path is satisfied), interface: nan0[802.11], ipv4, uses wifi, LQM: unknown, service: com.example.apple-samplecode.Wi-FiAwareSample8B4DX93M9J._sat-simulation._udp scope:0 route:0 custom:107]: waiting(POSIXErrorCode(rawValue: 50): Network is down)
[L1 ready, local endpoint: <NULL>, parameters: udp, traffic class: 700, interface: nan0, local: ::.0, definite, attribution: developer, server, port: 62182, path satisfied (Path is satisfied), interface: nan0[802.11], ipv4, uses wifi, LQM: unknown, service: com.example.apple-samplecode.Wi-FiAwareSample8B4DX93M9J._sat-simulation._udp scope:0 route:0 custom:107]: ready
[L1 failed, local endpoint: <NULL>, parameters: udp, traffic class: 700, interface: nan0, local: ::.0, definite, attribution: developer, server, port: 62182, path satisfied (Path is satisfied), interface: nan0[802.11], ipv4, uses wifi, LQM: unknown, service: com.example.apple-samplecode.Wi-FiAwareSample8B4DX93M9J._sat-simulation._udp scope:0 route:0 custom:107]: failed(-11992: Wi-Fi Aware)
nw_listener_cancel_block_invoke [L1] Listener is already cancelled, ignoring cancel
nw_listener_cancel_block_invoke [L1] Listener is already cancelled, ignoring cancel
nw_listener_cancel_block_invoke [L1] Listener is already cancelled, ignoring cancel
Networking failed: -11992: Wi-Fi Aware
Error acquiring assertion: <Error Domain=RBSAssertionErrorDomain Code=2 "Could not find attribute name in domain plist" UserInfo={NSLocalizedFailureReason=Could not find attribute name in domain plist}>
<0x105e35400> Gesture: System gesture gate timed out.
Selected Mode: Viewer
Start NetworkBrowser
[B1 <nw_browse_descriptor application_service _sat-simulation._udp bundle_id=com.example.apple-samplecode.Wi-FiAwareSample8B4DX93M9J device_types=7f device_scope=ff custom:109>, generic, interface: nan0, attribution: developer]: ready
nw_browser_update_path_browser_locked Received browser Wi-Fi Aware
nw_browser_cancel [B1] The browser has already been cancelled, ignoring nw_browser_cancel().
[B1 <nw_browse_descriptor application_service _sat-simulation._udp bundle_id=com.example.apple-samplecode.Wi-FiAwareSample8B4DX93M9J device_types=7f device_scope=ff custom:109>, generic, interface: nan0, attribution: developer]: failed(-11992: Wi-Fi Aware)
nw_browser_cancel [B1] The browser has already been cancelled, ignoring nw_browser_cancel().
Networking failed: -11992: Wi-Fi Aware
Error acquiring assertion: <Error Domain=RBSAssertionErrorDomain Code=2 "Could not find attribute name in domain plist" UserInfo={NSLocalizedFailureReason=Could not find attribute name in domain plist}>

This guy stands out to me Networking failed: -11992: Wi-Fi Aware but I cant find any info on what it means.

Share and Enjoy

I figured out how to respond with a quote! I remember reading a different post about how this is your preferred way for us to respond because it will alert you.

I remember reading a different post about how this is your preferred way for us to respond

A quote isn’t necessary. What matters is that you reply in the reply rather than in the comments. See Quinn’s Top Ten DevForums Tips for this and other tips.

Coming back to your technical issue, you seem to be trying to debug two problems at once:

  • Using QUIC with the latest Network framework API.
  • Getting the Wi-Fi Aware sample working.

I recommend that you focus on one or the other.

And it would make sense for you to start a new thread for that. This thread is already 3 pages long, and the forums experience degrades as the thread length increases.

Or, if you decide you want to deal with both simultaneously, start two new threads.

If you use the App & System Services > Networking, I’ll be sure to notice them go by.

Share and Enjoy

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

NWBrowser &#43; NWListener &#43; NWConnection
 
 
Q