Hi,
We're receiving data via centralManager.centralManager.scanForPeripherals, with no options or filtering (for now), and in the func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) callback, we get advertisementData for each bluetooth device found.
But, I know one of my BLE devices is sending an Eddystone TLM payload, which generally is received into the kCBAdvDataServiceData part of the advertisementData dictionary, but, it doesn't show up.
What is happening however (when comparing to other devices that do show that payload), is I've noticed the "isConnectable" part is false, and others have it true. Technically we're not "connecting" as such as we're simply reading passive advertisement data, but does that have any bearing on how CoreBluetooth decides to build up it's AdvertisementData response?
Example (with serviceData; and I know this has Eddystone TLM)
["kCBAdvDataLocalName": FSC-BP105N, "kCBAdvDataRxPrimaryPHY": 1, "kCBAdvDataServiceUUIDs": <__NSArrayM 0x300b71f80>(
FEAA,
FEF5
)
, "kCBAdvDataTimestamp": 773270526.26279, "kCBAdvDataServiceData": {
FFF0 = {length = 11, bytes = 0x36021892dc0d3015aeb164};
FEAA = {length = 14, bytes = 0x20000be680000339ffa229bbce8a};
}, "kCBAdvDataRxSecondaryPHY": 0, "kCBAdvDataIsConnectable": 1]
Vs
This also has Eddystone TLM configured
["kCBAdvDataLocalName": 100FA9FD-7000-1000, "kCBAdvDataIsConnectable": 0, "kCBAdvDataRxPrimaryPHY": 1, "kCBAdvDataRxSecondaryPHY": 0, "kCBAdvDataTimestamp": 773270918.97273]
Any insight would be great to understand if the presence of other flags drive the exposure of ServiceData or not...
Networking
RSS for tagExplore the networking protocols and technologies used by the device to connect to Wi-Fi networks, Bluetooth devices, and cellular data services.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hi there, I am working on an app that configures a PacketTunnelProvider to establish a VPN connection. Unfortunately, while a VPN connection is established, I am unable to update the app via testflight. Downloading other app updates works fine.
I noticed that after I receive the alert that updating failed, the vpn badge appears at the top of my screen (the same ux that occurs when the connection is first established). So it's almost like it tried to close the tunnel, and seeing that the app update failed it restablishes the tunnel.
I am unsure of why I would not be able to update my app. Maybe stopTunnel is not being called with NEProviderStopReason.appUpdate?
Starting in iOS 26, two notable changes have been made to CallKit, LiveCommunicationKit, and the PushToTalk framework:
As a diagnostic aid, we're introducing new dialogs to warn apps of voip push related issue, for example when they fail to report a call or when when voip push delivery stops. The specific details of that behavior are still being determined and are likely to change over time, however, the critical point here is that these alerts are only intended to help developers debug and improve their app. Because of that, they're specifically tied to development and TestFlight signed builds, so the alert dialogs will not appear for customers running app store builds. The existing termination/crashes will still occur, but the new warning alerts will not appear.
As PushToTalk developers have previously been warned, the last unrestricted PushKit entitlement ("com.apple.developer.pushkit.unrestricted-voip.ptt") has been disabled in the iOS 26 SDK. ALL apps that link against the iOS 26 SDK which receive a voip push through PushKit and which fail to report a call to CallKit will be now be terminated by the system, as the API contract has long specified.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware
I am trying to activate an application which sends my serial number to a server. The send is being blocked. The app is signed but not sandboxed.
I am running Sequoia on a recent iMac. My network firewall is off and I do not have any third party virus software. I have selected Allow Applications from App Store & Known Developers.
My local network is wifi using the eero product. There is no firewall or virus scanning installed with this product.
Under what circumstances will Mac OS block outgoing internet connections from a non-sandboxed app? How else could the outgoing connection be blocked?
Topic:
App & System Services
SubTopic:
Networking
Hi,
I have created an application for NFC tag scanning and read the tag data. For that,
i enabled the capability: NearField Communication Tag reading.
Then I added 2 tag formats in the entitlement
then i added info.plist:
NFCReaderUsageDescription
We need to use NFC
com.apple.developer.nfc.readersession.felica.systemcodes
8005
8008
0003
fe00
90b7
927a
12FC
86a7
com.apple.developer.nfc.readersession.iso7816.select-identifiers
D2760000850100
D2760000850101
but even though when i run the app and tap the nfc card im getting some error:
NFCTag didBecomeActive
2025-08-29 19:08:12.272278+0530 SAFRAN_NFC[894:113090] NFCTag didDetectTags
2025-08-29 19:08:12.282869+0530 SAFRAN_NFC[894:113520] [CoreNFC] -[NFCTagReaderSession _connectTag:error:]:730 Error Domain=NFCError Code=2 "Missing required entitlement" UserInfo={NSLocalizedDescription=Missing required entitlement}
2025-08-29 19:08:12.284044+0530 SAFRAN_NFC[894:113090] NFCTag restarting polling
2025-08-29 19:08:12.372116+0530 SAFRAN_NFC[894:113090] NFCTag didDetectTags
2025-08-29 19:08:12.381535+0530 SAFRAN_NFC[894:113378] [CoreNFC] -[NFCTagReaderSession _connectTag:error:]:730 Error Domain=NFCError Code=2 "Missing required entitlement" UserInfo={NSLocalizedDescription=Missing required entitlement}
2025-08-29 19:08:12.382246+0530 SAFRAN_NFC[894:113090] NFCTag restarting polling
2025-08-29 19:08:12.470667+0530 SAFRAN_NFC[894:113090] NFCTag didDetectTags
2025-08-29 19:08:12.479336+0530 SAFRAN_NFC[894:113378] [CoreNFC] -[NFCTagReaderSession _connectTag:error:]:730 Error Domain=NFCError Code=2 "Missing required entitlement" UserInfo={NSLocalizedDescription=Missing required entitlement}
2025-08-29 19:08:12.480101+0530 SAFRAN_NFC[894:113090] NFCTag restarting polling
Could you please help me wha tis the issue and give solution for that?
Hello everyone,
I'm trying to figure out how to transmit a UIImage (png or tiff) securely to an application running in my desktop browser (Mac or PC). The desktop application and iOS app would potentially be running on the same local network (iOS hotspot or something) or have no internet connection at all.
I'm trying to securely send over an image that the running desktop app could ingest. I was thinking something like a local server securely accepting image data from an iPhone.
Any suggestions ideas or where to look for more info would be greatly appreciated!
Thank you for your help.
Hi!
I'm working on a solution (iOS 18) that uses Network Extensions PacketTunnelProvider and Content Filter. Currently I'm trying to integrate it with another extension – DNSProxyProvider. My goal is to process dns queries and use resolved ips and names for additional routing inside of the packet tunnel. I'm running into a major issue: whenever both VPN and DNS proxy are active simultaneously, the device completely loses internet connectivity — no traffic goes through, and DNS resolution seems to stop working entirely.
I know about the mdm supervision requirement to use DNSProxyProvider and that's covered as I work with a managed device and install a DNS proxy profile, here's how its .mobileconfig file looks like:
The DNS proxy itself works fine when working by itself (without VPN being turned on), as I implemented it that it successfully processes DNS packets flows while collecting information about domains etc, and everything works perfectly. Problems begin when using VPN at the same time. I'm aware that tunnel settings include dns related options that can affect this, but I haven't had much luck with tweaking them. Here's how they look right now for reference:
let settings: NEPacketTunnelNetworkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "240.0.0.1")
// let dnsSettings = NEDNSSettings(servers: "8.8.8.8,8.8.4.4".components(separatedBy: ","))
// dnsSettings.matchDomains = [""]
// settings.dnsSettings = dnsSettings
settings.proxySettings = nil
/* ipv4 settings */
let ipv4Settings = NEIPv4Settings(addresses: ["240.0.0.2"], subnetMasks: ["255.255.255.0"])
ipv4Settings.includedRoutes = [NEIPv4Route.default()]
settings.ipv4Settings = ipv4Settings
/* MTU */
settings.mtu = 1500
return settings
I've tried excluding some dns related ip routes and dns settings shenanigans but nothing.
I haven't found any information that might suggest that using both of these extensions at the same time doesn't work, on the contrary, this page in the official documentation about the expected use of packet tunnel provider the expected use of packet tunnel provider, as it talks about the fact that you should not use it for interception of all of DNS traffic, as the use of DNSPRoxyProvider (or dns settings) are built for that, which in my mind, suggests that there should be no problem with using them both and just splitting the dns traffic handling to the proxy.
Will be thankful for any help!
Most apps perform ordinary network operations, like fetching an HTTP resource with URLSession and opening a TCP connection to a mail server with Network framework. These operations are not without their challenges, but they’re the well-trodden path.
If your app performs ordinary networking, see TN3151 Choosing the right networking API for recommendations as to where to start.
Some apps have extra-ordinary networking requirements. For example, apps that:
Help the user configure a Wi-Fi accessory
Require a connection to run over a specific interface
Listen for incoming connections
Building such an app is tricky because:
Networking is hard in general.
Apple devices support very dynamic networking, and your app has to work well in whatever environment it’s running in.
Documentation for the APIs you need is tucked away in man pages and doc comments.
In many cases you have to assemble these APIs in creative ways.
If you’re developing an app with extra-ordinary networking requirements, this post is for you.
Note If you have questions or comments about any of the topics discussed here, put them in a new thread here on DevForums. Make sure I see it by putting it in the App & System Services > Networking area. And feel free to add tags appropriate to the specific technology you’re using, like Foundation, CFNetwork, Network, or Network Extension.
Links, Links, and More Links
Each topic is covered in a separate post:
The iOS Wi-Fi Lifecycle describes how iOS joins and leaves Wi-Fi networks. Understanding this is especially important if you’re building an app that works with a Wi-Fi accessory.
Network Interface Concepts explains how Apple platforms manage network interfaces. If you’ve got this far, you definitely want to read this.
Network Interface Techniques offers a high-level overview of some of the more common techniques you need when working with network interfaces.
Network Interface APIs describes APIs and core techniques for working with network interfaces. It’s referenced by many other posts.
Running an HTTP Request over WWAN explains why most apps should not force an HTTP request to run over WWAN, what they should do instead, and what to do if you really need that behaviour.
If you’re building an iOS app with an embedded network server, see Showing Connection Information in an iOS Server for details on how to get the information to show to your user so they can connect to your server.
Many folks run into trouble when they try to find the device’s IP address, or other seemingly simple things, like the name of the Wi-Fi interface. Don’t Try to Get the Device’s IP Address explains why these problems are hard, and offers alternative approaches that function correctly in all network environments.
Similarly, folks also run into trouble when trying to get the host name. On Host Names explains why that’s more complex than you might think.
If you’re working with broadcasts or multicasts, see Broadcasts and Multicasts, Hints and Tips.
If you’re building an app that works with a Wi-Fi accessory, see Working with a Wi-Fi Accessory.
If you’re trying to gather network interface statistics, see Network Interface Statistics.
There are also some posts that are not part of this series but likely to be of interest if you’re working in this space:
TN3179 Understanding local network privacy discusses the local network privacy feature.
Calling BSD Sockets from Swift does what it says on the tin, that is, explains how to call BSD Sockets from Swift. When doing weird things with the network, you often find yourself having to use BSD Sockets, and that API is not easy to call from Swift. The code therein is primarily for the benefit of test projects, oh, and DevForums posts like these.
TN3111 iOS Wi-Fi API overview is a critical resource if you’re doing Wi-Fi specific stuff on iOS.
TLS For Accessory Developers tackles the tricky topic of how to communicate securely with a network-based accessory.
A Peek Behind the NECP Curtain discusses NECP, a subsystem that control which programs have access to which network interfaces.
Networking Resources has links to many other useful resources.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Revision History
2025-07-31 Added a link to A Peek Behind the NECP Curtain.
2025-03-28 Added a link to On Host Names.
2025-01-16 Added a link to Broadcasts and Multicasts, Hints and Tips. Updated the local network privacy link to point to TN3179. Made other minor editorial changes.
2024-04-30 Added a link to Network Interface Statistics.
2023-09-14 Added a link to TLS For Accessory Developers.
2023-07-23 First posted.
Hello, I have encountered an issue with an iPhone 15PM with iOS 18.5. The NSHTTPCookieStorage failed to clear cookies, but even after clearing them, I was still able to retrieve them. However, on the same system
It is normal on iPhone 14PM. I would like to know the specific reason and whether there are any adaptation related issues. Following code:
NSHTTPCookie *cookie;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [storage cookies]) {
[storage deleteCookie:cookie];
}
I'm a long-time developer, but pretty new to Swift. I'm trying to get information from a web service (and found code online that I adjusted to build the function below). (Note: AAA_Result -- referenced towards the end -- is another class in my project)
Trouble is, I'm getting the subject error on the call to session.dataTask. Any help/suggestions/doc pointers will be greatly appreciated!!!
var result: Bool = false
var cancellable: AnyCancellable?
self.name = name
let params = "json={\"\"}}" // removed json details
let base_url = URL(string: "https://aaa.yyy.com?params=\(params)&format=json")! // removed URL specifics
do {
let task = URLSession.shared.dataTask(with: base_url) { data, response, error in
if let error = error {
print("Error: \(error)")
}
guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode)
else {
print("Error \(String(describing: response))")
}
do {
let decoder = JSONDecoder()
let ar = try decoder.decode(AAA_Result.self, from: response.value)
// removed specific details...
result = true
}
catch {
print(error)
}
}
task.resume()
}
catch {
print(error)
}
return result
}
Topic:
App & System Services
SubTopic:
Networking
I'm developing a Matter-over-thread generic switch with 2 generic switch endpoints. This is configured as an Intermittently Connected Device with Long Idle Time.
I have an Apple TV serving as the thread border router.
I'm able to commission the device successfully in the Home app and assign actions to each of the buttons however when the device is rebooted the subscription doesn't appear to resume successfully and the buttons no longer work.
I've tested this on various SOC's with their respective SDKs including ESP32-C6, nrf52840 and EFR32MG24 and the behaviour was consistent across all of them.
It was working originally when I first started out on the ESP32-C6, then the issue popped up first when I was testing the nrf52840. In that SDK I set persistent subscriptions explicitly and it seemed to resolve the issue until it popped up again when I found that unplugging and restarting the Apple TV completely which appeared to fix the issue with subscriptions not resuming.
Recently I've added a Home Pod Mini Gen 2 to the matter fabric so there are now two TBR on the network and restarting both the Apple TV and the HomePod doesn't appear to resolve the issue anymore and the subscriptions are not resuming across all three SOC's on device reboot
I'm wondering if there might be something preventing the subscriptions from resuming?
Hello,
Our app uses Network Extension / Packet Tunnel Provider to establish VPN connections on macOS and iOS.
We have observed that after creating a utun device and adding any IPv4 routes (NEPacketTunnelNetworkSettings.IPv4Settings), the OS automatically adds several host routes via utun to services such as Akamai, Apple Push, etc. These routes appear to correspond to TCP flows that were active at the moment the VPN connection was established. When a particular TCP flow ends, the corresponding host route is deleted. We understand this is likely intended to avoid breaking existing TCP connections.
However, we find the behavior of migrating existing TCP flows to the new utun interface simply because any IPv4 route is added somewhat questionable. This approach would make sense in a "full-tunnel" scenario — for example, when all IPv4 traffic (e.g., 0.0.0.0/0) is routed through the tunnel — but not necessarily in a "split-tunnel" configuration where only specific IPv4 routes are added.
Is there any way to control or influence this behavior?
Would it be possible for FlowDivert to differentiate between full-tunnel and split-tunnel cases, and only preserve existing TCP flows via utun in the full-tunnel scenario?
Thank you.
I need to know the https address of a certain page within my app. This is going to be used as a redirect URL. I don't think it is a good idea to use deep links because it has to be an https address. I don't think Universal Links will work because it is not my website that I will be communicating with.
Are the network relays introduced in 2023 and
https://developer.apple.com/videos/play/wwdc2023/10002/
the same thing as the Private Relay introduced in 2021?
https://developer.apple.com/videos/play/wwdc2021/10096/
We are considering verifying the relay function, but we are not sure whether they are the same function or different functions.
https://developer.apple.com/documentation/devicemanagement/relay?language=objc
Topic:
App & System Services
SubTopic:
Networking
Every now and again folks notice that Network framework seems to create an unexpected number of connections on the wire. This post explains why that happens and what you should do about it.
If you have questions or comments, put them in a new thread here on the forums. Use the App & System Services > Networking topic area and the Network tag.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Understanding Also-Ran Connections
Network framework implements the Happy Eyeballs algorithm. That might create more on-the-wire connections than you expect. There are two common places where folks notice this:
When looking at a packet trace
When implementing a listener
Imagine that you’ve implemented a TCP server using NWListener and you connect to it from a client using NWConnection. In many situations there are multiple network paths between the client and the server. For example, on a local network there’s always at least two paths: the link-local IPv6 path and either an infrastructure IPv4 path or the link-local IPv4 path.
When you start your NWConnection, Network framework’s Happy Eyeballs algorithm might [1] start a TCP connection for each of these paths. It then races those connections. The one that connects first is the ‘winner’, and Network framework uses that connection for your traffic. Once it has a winner, the other connections, the also-ran connections, are redundant, and Network framework just closes them.
You can observe this behaviour on the client side by looking in the system log. Many Network framework log entries (subsystem com.apple.network) contain a connection identifier. For example C8 is the eighth connection started by this process. Each connection may have child connections (C8.1, C8.2, …) and grandchild connections (C8.1.1, C8.1.2, …), and so on. You’ll see state transitions for these child connections occurring in parallel. For example, the following log entries show that C8 is racing the connection of two grandchild connections, C8.1.1 and C8.1.2:
type: debug
time: 12:22:26.825331+0100
process: TestAlsoRanConnections
subsystem: com.apple.network
category: connection
message: nw_socket_connect [C8.1.1:1] Calling connectx(…)
type: debug
time: 12:22:26.964150+0100
process: TestAlsoRanConnections
subsystem: com.apple.network
category: connection
message: nw_socket_connect [C8.1.2:1] Calling connectx(…)
Note For more information about accessing the system log, see Your Friend the System Log.
You also see this on the server side, but in this case each connection is visible to your code. When you connect from the client, Network framework calls your listener’s new connection handler with multiple connections. One of those is the winning connection and you’ll receive traffic on it. The others are the also-ran connections, and they close promptly.
IMPORTANT Depending on network conditions there may be no also-ran connections. Or there may be lots of them. If you want to test the also-ran connection case, use Network Link Conditioner to add a bunch of delay to your packets.
You don’t need to write special code to handle also-ran connections. From the perspective of your listener, these are simply connections that open and then immediately close. There’s no difference between an also-ran connection and, say, a connection from a client that immediately crashes. Or a connection generated by someone doing a port scan. Your server must be resilient to such things.
However, the presence of these also-ran connections can be confusing, especially if you’re just getting started with Network framework, and hence this post.
[1] This is “might” because the exact behaviour depends on network conditions. More on that below.
I am currently developing a custom-protocol VPN application for iOS using PacketTunnelProvider. I have also integrated an HTTP proxy service, which is launched via a dylib.
The overall flow is as follows:
App -> VPN TUN -> Local HTTP Proxy -> External Network
I have a question:
I am capturing all traffic, and normally, requests sent out by the HTTP proxy are also captured again by the VPN. However, when I send requests using createUdpSession in my code, they are not being captured by the virtual interface (TUN).
What could be the reason for this?
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
let tunnelNetworkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "192.168.18.0")
tunnelNetworkSettings.mtu=1400
let ipv4Settings = NEIPv4Settings(addresses: ["192.169.10.10"], subnetMasks: ["255.255.255.0"])
ipv4Settings.includedRoutes=[NEIPv4Route.default()]
ipv4Settings.excludedRoutes = [NEIPv4Route(destinationAddress: "10.0.0.0", subnetMask: "255.0.0.0"),
NEIPv4Route(destinationAddress: "172.16.0.0", subnetMask: "255.240.0.0"),
NEIPv4Route(destinationAddress: "192.168.0.0", subnetMask: "255.255.0.0"),
NEIPv4Route(destinationAddress:"127.0.0.0", subnetMask: "255.0.0.0"),
]
tunnelNetworkSettings.ipv4Settings = ipv4Settings
// Configure proxy settings
let proxySettings = NEProxySettings()
proxySettings.httpEnabled = true
proxySettings.httpServer = NEProxyServer(address: "127.0.0.1", port: 7890)
proxySettings.httpsEnabled = true
proxySettings.httpsServer = NEProxyServer(address: "127.0.0.1", port: 7890)
proxySettings.excludeSimpleHostnames = true
proxySettings.exceptionList=["localhost","127.0.0.1"]
tunnelNetworkSettings.proxySettings = proxySettings
setTunnelNetworkSettings(tunnelNetworkSettings) { [weak self] error in
if error != nil {
completionHandler(error)
return
}
completionHandler(nil)
let stack = TUNInterface(packetFlow: self!.packetFlow)
RawScoketFactory.TunnelProvider=self
stack.register(stack: UDPDirectStack())
stack.register(stack: TCPDirectStack())
stack.start()
}
}
NWUdpSession.swift
//
// NWUDPSocket.swift
// supervpn
//
// Created by TobbyQuinn on 2025/2/3.
//
import Foundation
import NetworkExtension
import CocoaLumberjack
public protocol NWUDPSocketDelegate: AnyObject{
func didReceive(data:Data,from:NWUDPSocket)
func didCancel(socket:NWUDPSocket)
}
public class NWUDPSocket:NSObject{
private let session:NWUDPSession
private let timeout:Int
private var pendingWriteData: [Data] = []
private var writing = false
private let queue:DispatchQueue=QueueFactory.getQueue()
public weak var delegate:NWUDPSocketDelegate?
public init?(host:String,port:UInt16,timeout:Int=Opt.UDPSocketActiveTimeout){
guard let udpSession = RawScoketFactory.TunnelProvider?.createUDPSession(to: NWHostEndpoint(hostname: host, port: "\(port)"), from: nil) else{
return nil
}
session = udpSession
self.timeout=timeout
super.init()
session.addObserver(self, forKeyPath: #keyPath(NWUDPSession.state),options: [.new], context: nil)
session.setReadHandler({ dataArray, error in
self.queueCall{
guard error == nil, let dataArray = dataArray else {
print("Error when reading from remote server or connection reset")
return
}
for data in dataArray{
self.delegate?.didReceive(data: data, from: self)
}
}
}, maxDatagrams: 32)
}
/**
Send data to remote.
- parameter data: The data to send.
*/
public func write(data: Data) {
pendingWriteData.append(data)
checkWrite()
}
public func disconnect() {
session.cancel()
}
public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard keyPath == "state" else {
return
}
switch session.state {
case .cancelled:
queueCall {
self.delegate?.didCancel(socket: self)
}
case .ready:
checkWrite()
default:
break
}
}
private func checkWrite() {
guard session.state == .ready else {
return
}
guard !writing else {
return
}
guard pendingWriteData.count > 0 else {
return
}
writing = true
session.writeMultipleDatagrams(self.pendingWriteData) {_ in
self.queueCall {
self.writing = false
self.checkWrite()
}
}
self.pendingWriteData.removeAll(keepingCapacity: true)
}
private func queueCall(block:@escaping ()->Void){
queue.async {
block()
}
}
deinit{
session.removeObserver(self, forKeyPath: #keyPath(NWUDPSession.state))
}
}
Hi folks, I'm building an iOS companion app to a local hosted server app (hosted on 0.0.0.0). The MacOS app locally connects to this server hosted, and I took the approach of advertising the server using a Daemon and BonjourwithTXT(for port) and then net service to resolve a local name. Unfortunately if there's not enough time given after the iPhone/iPad is plugged in (usb or ethernet), the app will cycle through attempts and disconnects many times before connecting and I'm trying to find a way to only connect when a viable en interface is available.
I've run into a weird thing in which the en interface only becomes seen on the NWMonitor after multiple connection attempts have been made and failed. If I screen for en before connecting it simply never appears. Is there any way to handle this such that my app can intelligently wait for an en connection before trying to connect? Attaching my code although I have tried a few other setups but none has been perfect.
func startMonitoringAndBrowse() {
DebugLogger.shared.append("Starting Bonjour + Ethernet monitoring")
if !browserStarted {
let params = NWParameters.tcp
params.includePeerToPeer = false
params.requiredInterfaceType = .wiredEthernet
browser = NWBrowser(for: .bonjourWithTXTRecord(type: "_mytcpapp._tcp", domain: nil), using: params)
browser?.stateUpdateHandler = { state in
if case .ready = state {
DebugLogger.shared.append("Bonjour browser ready.")
}
}
browser?.browseResultsChangedHandler = { results, _ in
self.handleBrowseResults(results)
}
browser?.start(queue: .main)
browserStarted = true
}
// Start monitoring for wired ethernet
monitor = NWPathMonitor()
monitor?.pathUpdateHandler = { path in
let hasEthernet = path.availableInterfaces.contains { $0.type == .wiredEthernet }
let ethernetInUse = path.usesInterfaceType(.wiredEthernet)
DebugLogger.shared.append("""
NWPathMonitor:
- Status: \(path.status)
- Interfaces: \(path.availableInterfaces.map { "\($0.name)[\($0.type)]" }.joined(separator: ", "))
- Wired Ethernet: \(hasEthernet), In Use: \(ethernetInUse)
""")
self.tryToConnectIfReady()
self.stopMonitoring()
}
monitor?.start(queue: monitorQueue)
}
// MARK: - Internal Logic
private func handleBrowseResults(_ results: Set<NWBrowser.Result>) {
guard !self.isResolving, !self.hasResolvedService else { return }
for result in results {
guard case let .bonjour(txtRecord) = result.metadata,
let portString = txtRecord["actual_port"],
let actualPort = Int(portString),
case let .service(name, type, domain, _) = result.endpoint else {
continue
}
DebugLogger.shared.append("Bonjour result — port: \(actualPort)")
self.resolvedPort = actualPort
self.isResolving = true
self.resolveWithNetService(name: name, type: type, domain: domain)
break
}
}
private func resolveWithNetService(name: String, type: String, domain: String) {
let netService = NetService(domain: domain, type: type, name: name)
netService.delegate = self
netService.includesPeerToPeer = false
netService.resolve(withTimeout: 5.0)
resolvingNetService = netService
DebugLogger.shared.append("Resolving NetService: \(name).\(type)\(domain)")
}
private func tryToConnectIfReady() {
guard hasResolvedService,
let host = resolvedHost, let port = resolvedPort else { return }
DebugLogger.shared.append("Attempting to connect: \(host):\(port)")
discoveredIP = host
discoveredPort = port
connectionPublisher.send(.connecting(ip: host, port: port))
stopBrowsing()
socketManager.connectToServer(ip: host, port: port)
hasResolvedService = false
}
}
// MARK: - NetServiceDelegate
extension BonjourManager: NetServiceDelegate {
func netServiceDidResolveAddress(_ sender: NetService) {
guard let hostname = sender.hostName else {
DebugLogger.shared.append("Resolved service with no hostname")
return
}
DebugLogger.shared.append("Resolved NetService hostname: \(hostname)")
resolvedHost = hostname
isResolving = false
hasResolvedService = true
tryToConnectIfReady()
}
func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
DebugLogger.shared.append("NetService failed to resolve: \(errorDict)")
}
}
We are currently working on a zero-configuration networking compliant device thru avahi-daemon.
Our Device want to have multiple Instance name for different services.
Example
InstanceA._ipps._tcp.local.
InstanceA._ipp._tcp.local.
InstanceB._ipps._tcp.local.
InstanceB._ipp._tcp.local.
Will BCT confuse this as multiple device connected in the network and cause it to fail? Does Bonjour only allows only a Single Instance name with multiple services?
I'm using NWBrowser to search for a server that I hosted. The browser does find my service but when it tries to connect to it, it gets stuck in the preparing phase in NWConnection.stateUpdateHandler. When I hardcode the local IP address of my computer (where the server is hosted) into NWConnection it works perfectly fine and is able to connect.
When it gets stuck in the preparing phase, it gives me the warnings and error messages in the image below. You can also see that the service name is correct and it is found.
I have tried _http._tcp and _ssh._tcp types and neither work.
This is what my code looks like:
func findServerAndConnect(port: UInt16) {
print("Searching for server...")
let browser = NWBrowser(for: .bonjour(type: "_ssh._tcp", domain: "local."), using: .tcp)
browser.browseResultsChangedHandler = { results, _ in
print("Found results: \(results)")
for result in results {
if case let NWEndpoint.service(name, type_, domain, interface) = result.endpoint {
if name == "PocketPadServer" {
print("Found service: \(name) of type \(type_) in domain \(domain) on interface \(interface)")
// Construct the full service name, including type and domain
let fullServiceName = "\(name).\(type_).\(domain)"
print("Full service name: \(fullServiceName), \(result.endpoint)")
self.connect(to: result.endpoint, port: port)
browser.cancel()
break
}
}
}
}
browser.start(queue: .main)
}
func connect(to endpoint: NWEndpoint, port: UInt16) {
print("Connecting to \(endpoint) on port \(port)...")
// endpoint = NWEndpoint(
let tcpParams = NWProtocolTCP.Options()
tcpParams.enableFastOpen = true
tcpParams.keepaliveIdle = 2
let params = NWParameters(tls: nil, tcp: tcpParams)
params.includePeerToPeer = true
// connection = NWConnection(host: NWEndpoint.Host("xx.xxx.xxx.xxx"), port: NWEndpoint.Port(3000), using: params)
connection = NWConnection(to: endpoint, using: params)
connection?.pathUpdateHandler = { path in
print("Connection path update: \(path)")
if path.status == .satisfied {
print("Connection path is satisfied")
} else {
print("Connection path is not satisfied: \(path.status)")
}
}
connection?.stateUpdateHandler = { newState in
DispatchQueue.main.async {
switch newState {
case .ready:
print("Connected to server")
self.pairing = true
self.receiveMessage()
case .failed(let error):
print("Connection failed: \(error)")
self.isConnected = false
case .waiting(let error):
print("Waiting for connection... \(error)")
self.isConnected = false
case .cancelled:
print("Connection cancelled")
self.isConnected = false
case .preparing:
print("Preparing connection...")
self.isConnected = false
default:
print("Connection state changed: \(newState)")
break
}
}
}
connection?.start(queue: .main)
}
I am developing a program on my chip and attempting to establish a connection with the WiFi Aware demo app launched by iOS 26. Currently, I am encountering an issue during the pairing phase.
If I am the subscriber of the service and successfully complete the follow-up frame exchange of pairing bootstrapping, I see the PIN code displayed by iOS.
Question 1: How should I use this PIN code?
Question 2: Subsequently, I need to negotiate keys with iOS through PASN. What should I use as the password for the PASN SAE process?
If I am the subscriber of the service and successfully complete the follow-up frame exchange of pairing bootstrapping, I should display the PIN code.
Question 3: How do I generate this PIN code?
Question 4: Subsequently, I need to negotiate keys with iOS through PASN. What should I use as the password for the PASN SAE process?
Topic:
App & System Services
SubTopic:
Networking