Post

Replies

Boosts

Views

Activity

Reply to iOS 26 Network Framework AWDL not working
[quote='867952022, DTS Engineer, /thread/808917?answerId=867952022#867952022'] Did you opt in to peer-to-peer on both the listener and the browser? [/quote] I did do that. Please see my code snippets below. private func startBrowser() async throws { let parameters = NWParameters() parameters.includePeerToPeer = true // parameters.requiredInterfaceType = .wifi // parameters.prohibitedInterfaceTypes = [.cellular] try await NetworkBrowser( for: .bonjour(serviceName, domain: nil, includeTxtRecord: false), using: parameters ) .onStateUpdate { _, state in switch state { case let .failed(error): logger.error("[startBrowser]:browser failed: -> \(error)") case .ready: logger.info("[startBrowser]: browser is ready") case .cancelled: logger.error("[startBrowser]: browser cancelled") case .setup: logger.info("[startBrowser]: browser in setup") case let .waiting(error): logger.error("[startBrowser]: browser is waiting: \(error)") @unknown default: break } } .run { endpoints in self.handleBrowserEndpoints(endpoints) } } private func startListener() async throws { guard let identity = Utils.importIdentityFromPKCS12() else { logger.error("could not get identity") return } guard let certificateData = Utils.getCertificateData(from: identity) else { logger.error("could not read certificate data") return } let builder = try makeQUICParametersBuilder(identity: identity, certificateData: certificateData) @SharedReader(.thisDeviceID) var thisDeviceID let listener = try NetworkListener(for: .bonjour(name: nil, type: serviceName), using: builder) listener.service = NWListener.Service(name: thisDeviceID, type: serviceName) try await listener.onServiceRegistrationUpdate { _, change in switch change { case let .add(endpoint): logger.info("onServiceRegistrationUpdate: added \(endpoint.debugDescription)") case let .remove(endpoint): logger.info("onServiceRegistrationUpdate: removed \(endpoint.debugDescription)") @unknown default: return } } .onStateUpdate { lst, state in logger.info("\(String(describing: lst)): \(String(describing: state))") switch state { case let .failed(error): logger.error("Listener failed: \(error)") case .ready: logger.info("Listener ready") case .cancelled: logger.info("listener cancelled") case let .waiting(error): logger.error("listener is waiting: \(error)") case .setup: logger.info("listener setup") @unknown default: break } } .run { connection in logger.info("listener run callback received connection") await self.handleInboundConnection(connection) } } private func makeQUICParametersBuilder(identity: SecIdentity, certificateData: Data) throws -> NWParametersBuilder<QUIC> { guard let nwIdentity = sec_identity_create(identity) else { throw NetworkingError.failedToCreateIdentity } var quic = QUIC(alpn: ["captadoh"]) quic = quic.idleTimeout(0) quic = quic.tls.localIdentity(nwIdentity) quic = quic.tls.certificateValidator { _, secTrust async -> Bool in let trust = sec_trust_copy_ref(secTrust).takeRetainedValue() guard let certificates = SecTrustCopyCertificateChain(trust) as? [SecCertificate], let peerCertificate = certificates.first else { logger.error("Failed to get peer certificate") return false } let peerCertificateData = SecCertificateCopyData(peerCertificate) as Data logger.info("Peer cert SHA256: \(SHA256.hash(data: peerCertificateData).map { String(format: "%02x", $0) }.joined())") logger.info("Local cert SHA256: \(SHA256.hash(data: certificateData).map { String(format: "%02x", $0) }.joined())") return peerCertificateData == certificateData } quic = quic.tls.peerAuthentication(.required) var builder = NWParametersBuilder<QUIC>.parameters { quic } builder = builder.peerToPeerIncluded(true) // builder = builder.requiredInterfaceType(.wifi) // builder = builder.prohibitedInterfaceTypes([.cellular]) return builder }
2w
Reply to NWBrowser + NWListener + NWConnection
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.
Nov ’25
Reply to NWBrowser + NWListener + NWConnection
@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?
Nov ’25
Reply to NWBrowser + NWListener + NWConnection
@DTS Engineer Thank you for sharing. From all my reading I didn't see a way to specify using QUIC with Wi-Fi Aware. I did see the use of _example_service._tcp and _hello._udp My assumption is if I use _hello._udp it would be a true UDP connection and not QUC Side note - I cant figure out how to quote your comment
Oct ’25
Reply to NWBrowser + NWListener + NWConnection
@DTS Engineer is Wifi Aware a better solution than using Network Framework with Bonjour? In my situation if I have device A and device B and they are both running my app and Bob is signed in on both devices - if he toggles on "device discovery" I want each devices to automatically discover and connect to each other. Currently I have this functionality using Network Framework with QUIC with a P12 based Sec Identity and Im curious if WiFi Aware is a more forward thinking solution. On the same note I saw that DeviceDiscoveryUI is the only way I would be able to use WiFi Aware in my app. Is there a programmatic way to use WiFi Aware and not make the user select from a UI?
Oct ’25
Reply to NWBrowser + NWListener + NWConnection
Hello, I'm back revisiting this and have some findings to report. When I tried to create a group as seen below let descriptor = NWMultiplexGroup(to: endpoint) guard let identity = networkingService.importIdentityFromPKCS12() else { print("[browseResultsChangedHandler] could not import identity") continue } do { let parameters = try NWParameters(identity: identity) let group = NWConnectionGroup(with: descriptor, using: parameters) group.stateUpdateHandler = { _ in } group.newConnectionHandler = { _ in } group.start(queue: .global()) networkingService.addGroup(deviceID, group) } catch { } Note that endpoint comes from browser's browseResultsChangedHandler Identity comes from me importing a SecIdentity from the user's p12 Parameters has the identity in it so that QUIC works. My app crashes when it tries to create the group and I see the following error nw_group_descriptor_allows_endpoint Endpoint 1B1654DF-62B5-4B29-9495-C4965E8E99FF._captadoh._udp.local. is of invalid type for multiplex group -[NWConcrete_nw_group_descriptor initWithType:member:groupID:] Invalid endpoint type specified for group descriptor of type multiplex Does this mean that a peer to peer endpoint not work with the multiplex group?
Aug ’25
Reply to NWBrowser + NWListener + NWConnection
And just like how we determined for the non NWConnectionGroup setup.... We don't want Device A discovering and connecting to Device B and also Device B discovering and connecting to Device A. We want to have one side (via the comparison of device IDs) discover and connect to the other so we wont have multiple connection groups. I think for me this is the final detail that a tad fuzzy. Could you walk through an example of three devices, Device A, B and C? Sharing what you would save[1] on each device? [1] saving things like the connection group, each connection or endpoints?
Apr ’25
Reply to NWBrowser + NWListener + NWConnection
Thank you for the reply. Now for my sanity check... Client -> NWBrowser Server -> NWListener Connection -> NWConnection In the NWBrowser I discover NWEndpoints With a discovered endpoint I can create a connection group (ie if I discovered 5 endpoints, excluding my own, I would then create 5 connection groups) From a single connection group I can create many connections to the endpoint that was used to create the connection group. When I create the connection group in the client I need to set newConnectionHandler to handle new incoming connections. In NWListener I listen for new connection groups. I do this by setting newConnectionGroupHandler. For each group on the server i setup newConnectionHandler to handle new connections. When everything is said and done and properly setup: a device will have a list of groups (a group for each device it has discovered) a device can have a list of connections that came from a group In my head I see: Client client discovers endpoints client creates connection groups client setup connection group to listen for new connections client can create new connections from a connection group client is saving the connection group and the many connections Server server listens for new connection groups server handles new incoming connection groups server setup connection group to listen for new connections service is saving the connection group and the many connections Questions: What am I gaining from using a connection group vs how I was doing things before with just NWConnections? Is the benefit of using a connection group is that both sides (the server and the client) have a connection group so either one could simply create a new connection(ie let connection = NWConnection(from: group)) from the group and send data? See below for design plan / question Design Use comparison of peer IDs to determine who initiates connection to who. So if this device's ID (this device will be an iPhone) is greater than the device of the discovered peer ID (the discovered device will be an iPad) then the iPhone will: create a connection group from iPad endpoint create a connection from the group to connect to the discovered peer iPad the discovered peer iPad will then receive a new group connection the discovered peer iPad will setup the group connection the discovered peer iPad will receive a new connection on the connection group In the end the iPhone will have a connection group and a single connection and the iPad will have a connection group and a single connection. Either side (iPhone or iPad) can easily create a new connection from their group connection. If they did, in our example, both sides would still have a single connection group but two connections now. Is my thinking correct?
Apr ’25
Reply to NWBrowser + NWListener + NWConnection
Hello - I've been thinking... should I even be using QUIC? If I need to use UDP to live stream video then why not use TCP for sending simple messages (ie "stop video recording", "take photo", "send me your latest media") and downloading files from devices? If I went to TCP I would be able to use PSK and it would allow me to get rid of a whole piece of my backend (generating the identity). You've been on this journey with me for a while (my first post - https://developer.apple.com/forums/thread/768961). I do value your expertise. I remember you sharing QUIC would be the route to go but i think you shared that before you found the bug that restricted QUIC from being used in a best effort way. I do appreciate you taking the time to work through this with me.
Apr ’25