General:
Forums subtopic: App & System Services > Networking
TN3151 Choosing the right networking API
Networking Overview document — Despite the fact that this is in the archive, this is still really useful.
TLS for App Developers forums post
Choosing a Network Debugging Tool documentation
WWDC 2019 Session 712 Advances in Networking, Part 1 — This explains the concept of constrained networking, which is Apple’s preferred solution to questions like How do I check whether I’m on Wi-Fi?
TN3135 Low-level networking on watchOS
TN3179 Understanding local network privacy
Adapt to changing network conditions tech talk
Understanding Also-Ran Connections forums post
Extra-ordinary Networking forums post
Foundation networking:
Forums tags: Foundation, CFNetwork
URL Loading System documentation — NSURLSession, or URLSession in Swift, is the recommended API for HTTP[S] on Apple platforms.
Network framework:
Forums tag: Network
Network framework documentation — Network framework is the recommended API for TCP, UDP, and QUIC on Apple platforms.
Building a custom peer-to-peer protocol sample code (aka TicTacToe)
Implementing netcat with Network Framework sample code (aka nwcat)
Configuring a Wi-Fi accessory to join a network sample code
Moving from Multipeer Connectivity to Network Framework forums post
Network Extension (including Wi-Fi on iOS):
See Network Extension Resources
Wi-Fi Fundamentals
TN3111 iOS Wi-Fi API overview
Wi-Fi Aware framework documentation
Wi-Fi on macOS:
Forums tag: Core WLAN
Core WLAN framework documentation
Wi-Fi Fundamentals
Secure networking:
Forums tags: Security
Apple Platform Security support document
Preventing Insecure Network Connections documentation — This is all about App Transport Security (ATS).
Available trusted root certificates for Apple operating systems support article
Requirements for trusted certificates in iOS 13 and macOS 10.15 support article
About upcoming limits on trusted certificates support article
Apple’s Certificate Transparency policy support article
What’s new for enterprise in iOS 18 support article — This discusses new key usage requirements.
Technote 2232 HTTPS Server Trust Evaluation
Technote 2326 Creating Certificates for TLS Testing
QA1948 HTTPS and Test Servers
Miscellaneous:
More network-related forums tags: 5G, QUIC, Bonjour
On FTP forums post
Using the Multicast Networking Additional Capability forums post
Investigating Network Latency Problems forums post
WirelessInsights framework documentation
iOS Network Signal Strength
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
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
There is no available API that allows you to connect to Android. The current APIs that are provided are not compatible outside of the Apple Ecosystem. For example, Android requires you to set a service name and a password where iOS sets a service and a PIN authentication strategy in a specific format that’s not compatible. It looks like the implementation is not following the Wifi Aware Specifications.
To enable cross platform interoperability while providing security, could you adopt the same strategy as with Bluetooth and enable iOS users to enable the sharing and subscription of services with Everyone.
Topic:
App & System Services
SubTopic:
Networking
The environment:
macOS 12.0 ~ 15.6
A NetworkExtension NEFilterDataProvider configured with filterSockets = YES, filterPackets = NO, and it doesn't actually block any network connection.
QQMusic (download: https://y.qq.com/n/ryqq/download_detail/mac?ADTAG=YQQ) is constantly playing.
Any of the following operations can reproduce the issue:
Kill the NetworkExtension process and then restarted by the system.
Disable the NEFilterDataProvider, and then enable it.
When this problem occurs, there are two different phenomena on the NetworkExtension process:
It is zombie, or is in high CPU state (100%).
When the NetworkExtension process is zombie, obviously, the new network connections will enter it, and they can't be disposed by the old zombie process, so the network is disconnected.
Spindump-qqmusic-ne-zombie
When the NetworkExtension process is in high CPU state, its thread DispatchQueue "NEFilterExtensionProviderContext queue" is blocked in the kernel when calling close.
Spindump-qqmusic-ne-cpuhigh
In most cases, the network will recover after stopping QQ Music, that is the suspended zombie NetworkExtension process will exist or the cpu of it return to normal.
To reproduce the issue in a simple environment, I have tried many ways to simulate the network behavior of QQMusic, but all failed.
It seems that this issue is caused by UDP traffic of QQMusic, because everything is ok after blocking the UDP connections of QQMusic (the music is still playing at this time) in the NEFilterDataProvider.
When a VPN is active, RCS messaging does not work on iOS 18.
I work on an iOS VPN app, and we were very appreciative of the excludeCellularServices network flag that was released during the iOS 16 cycle. It's a great solution to ensure the VPN doesn't interfere with cellular network features from the cellular provider.
Separately - As a user, I'm excited that iOS 18 includes RCS messaging.
Unfortunately, RCS messaging is not working when our VPN is active (when checking on the iOS 18 release candidate). My guess is that RCS is not excluded from the VPN tunnel, even when excludeCellularServices is true. It seems like RCS should be added in this situation, as it is a cell provider service.
Can RCS be added as a service that is excluded from the VPN tunnel when excludeCellularServices is true? (I've also sent this via feedback assistant, as 15094270.)
I've implemented a custom VPN system extension for macOS, utilizing Packet Tunnel Provider.
One of the users reported a problem: he was connected to the VPN, and then his Mac entered sleep mode. Upon waking, the VPN is supposed to connect automatically (because of the on-demand rules).
The VPN's status changed to 'connecting', but it remained stuck in this status.
From my extension logs, I can see that the 'startTunnelWithOption()' function was called 2 minutes after the user clicked the 'connect' button.
From the system logs, I noticed some 'suspicious' logs, but I can't be sure if they are related to the problem. Some of them are:
kernel: (Sandbox) Sandbox: nesessionmanager(562) deny(1) system-fsctl (_IO "h" 47)
entitlement com.apple.developer.endpoint-security.client not present or not true (I don't need this entitlement at the extension)
nesessionmanager: [com.apple.networkextension:] NESMVPNSession[Primary Tunnel:XXXXXX(null)]: Skip a start command from YYYYY:session in state connecting
NetworkExtension.com.***: RunningBoard doesn't recognize submitted process - treating as a anonymous process
sysextd: activateDecision found existing entry of same version: state activated_enabled, ID FAE...
Are any of the logs related to the above problem? How can I debug such issues? What info should I get from the user?
Hi,
Since iOS 26 (and any other apple system with a 26 version) there is a very weird behavior in the whole apple ecosystem (iOS, iPadOS, macOS and visionOS).
I'm self-hosting a web project called mempool (https://github.com/Retropex/mempool). This project is entirely self-hosted on my own infrastructure, so I have advanced control to be sure it's just not an anti-DDoS feature that makes the bug happen.
So the bug is once I visit my website, for example this page (https://mempool.guide/tx/d86192252a6631831e55f814aea901e65407b6dbda77e1abdea8ec27861e9682) the OS will lose the ability to connect to the underlying IP of the domain (mempool.guide) but the issue seems to affect only the HTTPS/HTTP port (443/80). The issue is system wide, not only is Safari.
For exemple I have another domain that resolve to the same IP (haf.ovh) and if this link above trigger the bug then I will also lose the ability to connect to https://haf.ovh
A temporary fix that I have is that if I turn off wifi/cellular then I turn it on again I can connect again to my server again until the bug is triggered again.
I have done test with tcpdump on my server and the connection isn't making it to my server that's why I think it's an OS issue, especially given the fix above.
This issue can be reproduced on any apple device out of the box with a system with >v26.
All device (Mac, iPad, iPhone, vision) with version pre-26 are completely unaffected by the bug and can freely explore the website without loosing the connection
macOS is less affected by this bug, it can be random with it.
With iOS/iPadOS it's systematic.
Another thing to note is that the same URL on firefox/chrome for iOS doesn't trigger the bug.
Let me know if anyone has an idea on what's going on.
Thanks, Léo.
Hi Everyone,
I have a query regarding capturing an NWConnection instance inside the receive closure, which gets invoked whenever some raw bytes are received. I want to know whether this will create a strong retain cycle or not.
My understanding is that NWConnection holds a reference to the closure, and if I capture the NWConnection instance inside the closure, the closure will have a reference back to the connection, which, according to my understanding, creates a strong reference cycle.
Is my understanding correct? If so, how can we break the strong reference cycle — using a capture list, or is there any other way as well?
Thanks
While updating our test devices to iOS 26, we noticed that the connection between devices are flaky. Often when connecting to a Peer from a device running iOS 26 we can observe the invite coming through and when accepting said invite, both ends going to .connecting state and a while later going back to .notConnected within the peer(_ peerID: MCPeerID, didChange state: MCSessionState) function. This happens regularly and retrying the invitation process several times usually resolves it. Do anyone have any information or guidance on how to resolve this issue?
I am trying to setup a system-wide DNS-over-TLS for iOS that can be turned off and on from within the app, and I'm struggling with the implementation details. I've searched online, searched forums here, used ChatGPT, and I'm getting conflicting information or code that is simply wrong. I can't find example code that is valid and gets me moving forward.
I think I need to use NEDNSProxyProvider via the NetworkExtension. Does that sound correct? I have NetworkExtension -> DNS Proxy Capability set in both the main app and the DNSProxy extension.
Also, I want to make sure this is even possible without an MDM. I see conflicting information, some saying this is opened up, but things like https://developer.apple.com/documentation/Technotes/tn3134-network-extension-provider-deployment saying a device needs to be managed. How do private DNS apps do this without MDM?
From some responses in the forums it sounds like we need to parse the DNS requests that come in to the handleNewFlow function. Is there good sample code for this parsing?
I saw some helpful information from Eskimo (for instance https://developer.apple.com/forums/thread/723831 ) and Matt Eaton ( https://developer.apple.com/forums/thread/665480 )but I'm still confused.
So, if I have a DoT URL, is there good sample code somewhere for what startProxy, stopProxy, and handleNewFlow might look like? And valid code to call it from the main app?
We have a VPN application and we were required by the review team to change the text in the "Add VPN Configuration" dialog due to guideline 5.4.0 Legal: VPN Apps:
make it clear to the user what data is being collected and how it will be used in the permission request.
It appears that showing that information in the view preceding the VPN configuration adding attempt is no longer enough.
However we haven't found any changes in the API allowing to change the text in the mentioned dialog.
Is there a technical possibility to change the text in the add VPN configuration dialog?
Thank you
Hi,
I've encountered a strange behavior in the DNS Proxy Provider extension. Our app implements both DNS Proxy Provider and Content Filter Providers extensions, configured via MDM.
When the app is uninstalled, the behavior of the providers differs:
For Content Filter Providers (both Filter Control and Filter Data Providers), the providers stop as expected with the stop reason:
/** @const NEProviderStopReasonProviderDisabled The provider was disabled. */
case providerDisabled = 5
However, for the DNS Proxy Provider, the provider remains in the "Running" state, even though there is no app available to match the provider's bundle ID in the uploaded configuration profile.
When the app is reinstalled:
The Content Filter Providers start as expected.
The DNS Proxy Provider stops with the stop reason:
/** @const NEProviderStopReasonAppUpdate The NEProvider is being updated */
@available(iOS 13.0, *)
case appUpdate = 16
At this point, the DNS Proxy Provider remains in an 'Invalid' state. Reinstalling the app a second time seems to resolve the issue, with both the DNS Proxy Provider and Content Filter Providers starting as expected.
This issue seems to occur only if some time has passed after the DNS Proxy Provider entered the 'Running' state. It appears as though the system retains a stale configuration for the DNS Proxy Provider, even after the app has been removed.
Steps to reproduce:
Install the app and configure both DNS Proxy Provider and Content Filter Providers using MDM.
Uninstall the app.
Content Filter Providers are stopped as expected (NEProviderStopReason.providerDisabled = 5).
DNS Proxy Provider remains in the 'Running' state.
Reinstall the app.
Content Filter Providers start as expected.
DNS Proxy Provider stops with NEProviderStopReason.appUpdate (16) and remains 'Invalid'.
Reinstall the app again.
DNS Proxy Provider now starts as expected.
This behavior raises concerns about how the system manages the lifecycle of DNS Proxy Provider, because DNS Proxy Provider is matched with provider bundle id in .mobileconfig file.
Has anyone else experienced this issue? Any suggestions on how to address or debug this behavior would be highly appreciated.
Thank you!
We're encountering an issue with our Network Extension (utilizing NEPacketTunnelProvider and NETransparentProxy) on macOS 14.5 (23F79).
On some systems, the VPN fails to automatically start after a reboot despite calling startVPNTunnel(). There are no error messages.
Our code attempts to start the tunnel:
.......
do {
try manager.connection.startVPNTunnel()
Logger.default("Started tunnel successfully")
} catch {
Logger.error("Failed to launch tunnel")
}
......
System log analysis reveals the tunnel stopping due to userLogout (NEProviderStopReason(rawValue: 12)) during reboot.
However, the Transparent Proxy stops due to userInitiated (NEProviderStopReason(rawValue: 1)) for the same reboot.
We need to understand:
Why the VPNTunnel isn't starting automatically.
Why the userLogout reason is triggered during reboot.
Additional Context:
We have manually started the VPN from System Settings before reboot.
Hello,
Since the release of iOS 26.0, we are seeing DNS traffic being blocked from within our NEPacketTunnelExtension on some devices. We have not isolated exact reproduction steps, but DNS resolves successfully for a period of time after enabling "iCloud Private Relay" (varying from 1-day to 2-weeks), until it then fails as MDNSResponder then returns:
mDNSResponder [Q37046] DetermineUnicastQuerySuppression: Query suppressed for <mask.hash: 'REDACTED'> Addr (blocked by policy)
DNS resolution continues to fail for all domains with the above until the device is rebooted.
The Packet Tunnel intentionally does not have a DNS server set and this occurs for traffic from the Extension yet off-tunnel, which needs resolution from the system DNS server (and this configuration works perfectly for a period of time before being "blocked by policy").
The following do not resolve the issue once DNS queries are being "blocked by policy" on affected devices: disconnecting then reconnecting the vpn; toggling airplane mode for 10+ seconds; switching connection between WiFi & cellular data; disabling iCloud Private Relay.
We have currently only seen this on unmanaged devices running iOS 26.0 or 26.1 beta and with iCloud Private Relay enabled. We did not see this issue on iOS 16,17 nor 18. We also have not yet seen this when iCloud Private Relay is disabled nor on iOS 26.0.1, however we cannot confirm whether they too are also affected.
Is there a known a bug with iOS 26.0 & 26.1 Beta 1 that could cause this? How can we prevent DNS requests from NEPacketTunnelExtension being sporadically "blocked by policy" until the device is rebooted?
Many thanks in advance.
Hi there,
We are facing some issues regarding TLS connectivity:
Starting with iOS 26, the operating system refuses to open TLS sockets to local devices with self-signed certificates over Wi-Fi. In this situation, connection is no longer possible, even if the device is detected on the network with Bonjour.
We have not found a workaround for this problem.
We've tryied those solutions without success:
Added the 'NSAppTransportSecurity' key to the info.plist file, testing all its items, such as "NSAllowsLocalNetworking", "NSExceptionDomains", etc.
Various code changes to use properties such as "sec_protocol_options_set_local_identity" and "sec_protocol_options_set_tls_server_name" to no avail.
Brutally import the certificate files into the project and load them via, for example, "Bundle.main.url(forResource: "nice_INTERFACE_server_cert", withExtension: "crt")", using methods such as sec_trust_copy_ref and SecCertificateCopyData.
Download the .pem or .crt files to the iPhone, install them (now visible under "VPN & Device Management"), and then flag them as trusted by going to "Settings -> General -> Info -> Trust". certificates"
The most critical part seems to be the line
sec_protocol_options_set_verify_block(tlsOptions.securityProtocolOptions, { $2(true) }, queue)
whose purpose is to bypass certificate checks and validate all of them (as apps already do). However, on iOS26, if I set a breakpoint on leg$2(true),` it never gets there, while on iOS 18, it does.
I'll leave as example the part of the code that was tested the most below. Currently, on iOS26, the handler systematically falls back to .cancelled:
func startConnection(host: String, port: UInt16) {
self.queue = DispatchQueue(label: "socketQueue")
let tlsOptions = NWProtocolTLS.Options()
sec_protocol_options_set_verify_block(tlsOptions.securityProtocolOptions, { $2(true) }, queue)
let parameters = NWParameters(tls: tlsOptions)
self.nwConnection = NWConnection(host: .init(host), port: .init(rawValue: port)!, using: parameters)
self.nwConnection.stateUpdateHandler = { [weak self] state in
switch state {
case .setup:
break
case .waiting(let error):
self?.connectionDidFail(error: error)
case .preparing:
break
case .ready:
self?.didConnectSubject.onNext(Void())
case .failed(let error):
self?.connectionDidFail(error: error)
case .cancelled:
self?.didDisconnectSubject.onNext(nil)
@unknown default:
break
}
}
self.setupReceive()
self.nwConnection.start(queue: queue)
}
These are the prints made during the procedure. The ones with the dot are from the app, while the ones without are warnings/info from Xcode:
🔵 INFO WifiNetworkManager.connect():52 - Try to connect onto the interface access point with ssid NiceProView4A9151_AP
🔵 INFO WifiNetworkManager.connect():68 - Connected to NiceProView4A9151_AP
tcp_output [C13:2] flags=[R.] seq=215593821, ack=430284980, win=4096 state=CLOSED rcv_nxt=430284980, snd_una=215593821
nw_endpoint_flow_failed_with_error [C13 192.168.0.1:443 in_progress channel-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], dns, uses wifi, LQM: unknown)] already failing, returning
nw_connection_copy_protocol_metadata_internal_block_invoke [C13] Client called nw_connection_copy_protocol_metadata_internal on unconnected nw_connection
nw_connection_copy_protocol_metadata_internal_block_invoke [C13] Client called nw_connection_copy_protocol_metadata_internal on unconnected nw_connection
nw_connection_copy_connected_local_endpoint_block_invoke [C13] Client called nw_connection_copy_connected_local_endpoint on unconnected nw_connection
nw_connection_copy_connected_remote_endpoint_block_invoke [C13] Client called nw_connection_copy_connected_remote_endpoint on unconnected nw_connection
nw_connection_copy_protocol_metadata_internal_block_invoke [C14] Client called nw_connection_copy_protocol_metadata_internal on unconnected nw_connection
nw_connection_copy_protocol_metadata_internal_block_invoke [C14] Client called nw_connection_copy_protocol_metadata_internal on unconnected nw_connection
nw_connection_copy_connected_local_endpoint_block_invoke [C14] Client called nw_connection_copy_connected_local_endpoint on unconnected nw_connection
nw_connection_copy_connected_remote_endpoint_block_invoke [C14] Client called nw_connection_copy_connected_remote_endpoint on unconnected nw_connection
[C14 192.168.0.1:443 tcp, tls, attribution: developer] is already cancelled, ignoring cancel
[C14 192.168.0.1:443 tcp, tls, attribution: developer] is already cancelled, ignoring cancel
nw_connection_copy_protocol_metadata_internal_block_invoke [C15] Client called nw_connection_copy_protocol_metadata_internal on unconnected nw_connection
nw_connection_copy_protocol_metadata_internal_block_invoke [C15] Client called nw_connection_copy_protocol_metadata_internal on unconnected nw_connection
nw_connection_copy_connected_local_endpoint_block_invoke [C15] Client called nw_connection_copy_connected_local_endpoint on unconnected nw_connection
nw_connection_copy_connected_remote_endpoint_block_invoke [C15] Client called nw_connection_copy_connected_remote_endpoint on unconnected nw_connection
nw_connection_copy_protocol_metadata_internal_block_invoke [C16] Client called nw_connection_copy_protocol_metadata_internal on unconnected nw_connection
nw_connection_copy_protocol_metadata_internal_block_invoke [C16] Client called nw_connection_copy_protocol_metadata_internal on unconnected nw_connection
nw_connection_copy_connected_local_endpoint_block_invoke [C16] Client called nw_connection_copy_connected_local_endpoint on unconnected nw_connection
nw_connection_copy_connected_remote_endpoint_block_invoke [C16] Client called nw_connection_copy_connected_remote_endpoint on unconnected nw_connection
[C16 192.168.0.1:443 tcp, tls, attribution: developer] is already cancelled, ignoring cancel
[C16 192.168.0.1:443 tcp, tls, attribution: developer] is already cancelled, ignoring cancel
🔴 ERROR InterfaceDisconnectedViewModel.connect():51 - Sequence timeout.
Topic:
App & System Services
SubTopic:
Networking
Tags:
Foundation
Developer Tools
Nearby Interaction
iOS
On one test machine, our extension wouldn't load, because [NETransparentProxyManager loadAllFromPreferencesWithCompletionHandler] can't find a manager, saying Skipping configuration appname because it is of the wrong type. This is the first time I've seen this behaviour.
(The containing app tries to find a configuration, if it can't find it it creates one, then modifies whatever it found or created, then stores it. I don't have the right logging yet for that, so I can't see the error messages. [NSLog instead of os_log_error.])
Questions about FTP crop up from time-to-time here on DevForums. In most cases I write a general “don’t use FTP” response, but I don’t have time to go into all the details. I’ve created this post as a place to collect all of those details, so I can reference them in other threads.
IMPORTANT Apple’s official position on FTP is:
All our FTP APIs have been deprecated, and you should avoid using deprecated APIs.
Apple has been slowly removing FTP support from the user-facing parts of our system. The most recent example of this is that we removed the ftp command-line tool in macOS 10.13.
You should avoid the FTP protocol and look to adopt more modern alternatives.
The rest of this post is an informational explanation of the overall FTP picture.
This post is locked so I can keep it focused. If you have questions or comments, please do create a new thread in the App & System Services > Networking subtopic and I’ll respond there.
Don’t Use FTP
FTP is a very old and very crufty protocol. Certain things that seem obvious to us now — like being able to create a GUI client that reliably shows a directory listing in a platform-independent manner — aren’t possible to do in FTP. However, by far the biggest problem with FTP is that it provides no security [1]. Specifically, the FTP protocol:
Provides no on-the-wire privacy, so anyone can see the data you transfer
Provides no client-authenticates-server authentication, so you have no idea whether you’re talking to the right server
Provides no data integrity, allowing an attacker to munge your data in transit
Transfers user names and passwords in the clear
Using FTP for anonymous downloads may be acceptable (see the explanation below) but most other uses of FTP are completely inappropriate for the modern Internet.
IMPORTANT You should only use FTP for anonymous downloads if you have an independent way to check the integrity of the data you’ve downloaded. For example, if you’re downloading a software update, you could use code signing to check its integrity. If you don’t check the integrity of the data you’ve downloaded, an attacker could substitute a malicious download instead. This would be especially bad in, say, the software update case.
These fundamental problems with the FTP protocol mean that it’s not a priority for Apple. This is reflected in the available APIs, which is the subject of the next section.
FTP APIs
Apple provides two FTP APIs:
All Apple platforms provide FTP downloads via URLSession.
Most Apple platforms (everything except watchOS) support CFFTPStream, which allows for directory listings, downloads, uploads, and directory creation.
All of these FTP APIs are now deprecated:
URLSession was deprecated for the purposes of FTP in the 2022 SDKs (macOS 13, iOS 16, iPadOS 16, tvOS 16, watchOS 9) [2].
CFFTPStream was deprecated in the 2016 SDKs (macOS 10.11, iOS 9, iPadOS 9, tvOS 9).
CFFTPStream still works about as well as it ever did, which is not particularly well. Specifically:
There is at least one known crashing bug (r. 35745763), albeit one that occurs quite infrequently.
There are clear implementation limitations — like the fact that CFFTPCreateParsedResourceListing assumes a MacRoman text encoding (r. 7420589) — that won’t be fixed.
If you’re looking for an example of how to use these APIs, check out SimpleFTPSample.
Note This sample hasn’t been updated since 2013 and is unlikely to ever be updated given Apple’s position on FTP.
The FTP support in URLSession has significant limitations:
It only supports FTP downloads; there’s no support for uploads or any other FTP operations.
It doesn’t support resumable FTP downloads [3].
It doesn’t work in background sessions. That prevents it from running FTP downloads in the background on iOS.
It’s only supported in classic loading mode. See the usesClassicLoadingMode property and the doc comments in <Foundation/NSURLSession.h>.
If Apple’s FTP APIs are insufficient for your needs, you’ll need to write or acquire your own FTP library. Before you do that, however, consider switching to an alternative protocol. After all, if you’re going to go to the trouble of importing a large FTP library into your code base, you might as well import a library for a better protocol. The next section discusses some options in this space.
Alternative Protocols
There are numerous better alternatives to FTP:
HTTPS is by far the best alternative to FTP, offering good security, good APIs on Apple platforms, good server support, and good network compatibility. Implementing traditional FTP operations over HTTPS can be a bit tricky. One possible way forward is to enable DAV extensions on the server.
FTPS is FTP over TLS (aka SSL). While FTPS adds security to the protocol, which is very important, it still inherits many of FTP’s other problems. Personally I try to avoid this protocol.
SFTP is a file transfer protocol that’s completely unrelated to FTP. It runs over SSH, making it a great alternative in many of the ad hoc setups that traditionally use FTP.
Apple doesn’t have an API for either FTPS or SFTP, although on macOS you may be able to make some headway by invoking the sftp command-line tool.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] In another thread someone asked me about FTP’s other problems, those not related to security, so let’s talk about that.
One of FTP’s implicit design goals was to provide cross-platform support that exposes the target platform. You can think of FTP as being kinda like telnet. When you telnet from Unix to VMS, it doesn’t aim to abstract away VMS commands, so that you can type Unix commands at the VMS prompt. Rather, you’re expected to run VMS commands. FTP is (a bit) like that.
This choice made sense back when the FTP protocol was invented. Folks were expecting to use FTP via a command-line client, so there was a human in the loop. If they ran a command and it produced VMS-like output, that was fine because they knew that they were FTPing into a VMS machine.
However, most users today are using GUI clients, and this design choice makes it very hard to create a general GUI client for FTP. Let’s consider the simple problem of getting the contents of a directory. When you send an FTP LIST command, the server would historically run the platform native directory list command and pipe the results back to you. To create a GUI client you have to parse that data to extract the file names. Doing that is a serious challenge. Indeed, just the first step, working out the text encoding, is a challenge. Many FTP servers use UTF-8, but some use ISO-Latin-1, some use other standard encodings, some use Windows code pages, and so on.
I say “historically” above because there have been various efforts to standardise this stuff, both in the RFCs and in individual server implementations. However, if you’re building a general client you can’t rely on these efforts. After all, the reason why folks continue to use FTP is because of it widespread support.
[2] To quote the macOS 13 Ventura Release Notes:
FTP is deprecated for URLSession and related APIs. Please adopt
modern secure networking protocols such as HTTPS. (92623659)
[3] Although you can implement resumable downloads using the lower-level CFFTPStream API, courtesy of the kCFStreamPropertyFTPFileTransferOffset property.
Revision History
2025-10-06 Explained that URLSession only supports FTP in classic loading mode. Made other minor editorial changes.
2024-04-15 Added a footnote about FTP’s other problems. Made other minor editorial changes.
2022-08-09 Noted that the FTP support in URLSession is now deprecated. Made other minor editorial changes.
2021-04-06 Fixed the formatting. Fixed some links.
2018-02-23 First posted.
After pairing and having subscribed to a service, and even after having exchanged messages, the service fails after a period of time and both devices need to pair again.
Topic:
App & System Services
SubTopic:
Networking
I have a Vision Pro app, which I intend to use Apple-Hosted Background Assets for some of my videos after watching:
https://developer.apple.com/videos/play/wwdc2025/325
I added a Apple-Hosted, Managed extension.
New Target -> Background Download -> Apple-Hosted, Managed
After creating an Archive, I tried uploading it to TestFlight, it complains about a DTPlatformName error in my Info.plist. So I added the following :
<key>DTPlatformName</key>
<string>xros</string>
With which, I managed to upload the app with the extension to TestFlight. However, when I tried installing the app on TestFlight to Vision Pro, it gives me an error that says the app cannot be verified.
Any help or pointers is greatly appreciated.
Info.plist
Entitlements
I haven’t been able to get this to work at any level! I’m running into multiple issues, any light shed on any of these would be nice:
I can’t implement a bloom filter that produces the same output as can be found in the SimpleURLFilter sample project, after following the textual description of it that’s available in the documentation. No clue what my implementation is doing wrong, and because of the nature of hashing, there is no way to know. Specifically:
The web is full of implementations of FNV-1a and MurmurHash3, and they all produce different hashes for the same input. Can we get the proper hashes for some sample strings, so we know which is the “correct” one?
Similarly, different implementations use different encodings for the strings to hash. Which should we use here?
The formulas for numberOfBits and numberOfHashes give Doubles and assign them to Ints. It seems we should do this conversing by rounding them, is this correct?
Can we get a sample correct value for the combined hash, so we can verify our implementations against it?
Or ignoring all of the above, can we have the actual code instead of a textual description of it? 😓
I managed to get Settings to register my first attempt at this extension in beta 1. Now, in beta 2, any other project (including the sample code) will redirect to Settings, show the Allow/Deny message box, I tap Allow, and then nothing happens. This must be a bug, right?
Whenever I try to enable the only extension that Settings accepted (by setting its isEnabled to true), its status goes to .stopped and the error is, of course, .unknown. How do I debug this?
While the extension is .stopped, ALL URL LOADS are blocked on the device. Is this to be expected? (shouldFailClosed is set to false)
Is there any way to manually reload the bloom filter? My app ships blocklist updates with background push, so it would be wasteful to fetch the filter at a fixed interval. If so, can we opt out of the periodic fetch altogether?
I initially believed the API to be near useless because I didn’t know of its “fuzzy matching” capabilities, which I’ve discovered by accident in a forum post. It’d be nice if those were documented somewhere!
Thanks!!
Hello,
I have been playing around the the SimpleURLFilter sample code. I keep getting this error upon installed the filter profile on the device:
mapError unexpected error domain NEVPNConnectionErrorDomainPlugin code 7
which then causes this error:
Received filter status change: <FilterStatus: 'stopped' errorMessage: 'The operation couldn’t be completed. (NetworkExtension.NEURLFilterManager.Error error 14.)'>
I can't find much info about code 7.
Here is the configuration I am trying to run:
<Configuration: pirServerURL: 'http://MyComputer.local:8080' pirAuthenticationToken: 'AAAA' pirPrivacyPassIssuerURL: 'http://MyComputer.local:8080' enabled: 'true' shouldFailClosed: 'true' controlProviderBundleIdentifier: 'krpaul.SimpleURLFilter.SimpleURLFilterExtension' prefilterFetchInterval: '2700.0'>
I've been wondering what is the memory limit for network extensions. Specifically, I'm using the NEPacketTunnelProvider extension point.The various posts on this forum mention 5 MB and 6 MB for 32-bit and 64-bit respectively. However I find that (at least on iOS 10) the upper limit seems to be 15 MB. Is this the new memory limit for extensions?