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.
Moving to Fewer, Larger Transfers forums post
Testing Background Session Code forums post
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
NWEndpoint History and Advice 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
Created
IMPORTANT The resume rate limiter is now covered by the official documentation. See Use background sessions efficiently within Downloading files in the background. So, the following is here purely for historical perspective.
NSURLSession’s background session support on iOS includes a resume rate limiter. This limiter exists to prevent apps from abusing the background session support in order to run continuously in the background. It works as follows:
nsurlsessiond (the daemon that does all the background session work) maintains a delay value for your app.
It doubles that delay every time it resumes (or relaunches) your app.
It resets that delay to 0 when the user brings your app to the front.
It also resets the delay to 0 if the delay period elapses without it having resumed your app.
When your app creates a new task while it is in the background, the task does not start until that delay has expired.
To understand the impact of this, consider what happens when you download 10 resources. If you pass them to the background session all at once, you see something like this:
Your app creates tasks 1 through 10 in the background session.
nsurlsessiond starts working on the first few tasks.
As tasks complete, nsurlsessiond starts working on subsequent ones.
Eventually all the tasks complete and nsurlsessiond resumes your app.
Now consider what happens if you only schedule one task at a time:
Your app creates task 1.
nsurlsessiond starts working on it.
When it completes, nsurlsessiond resumes your app.
Your app creates task 2.
nsurlsessiond delays the start of task 2 a little bit.
nsurlsessiond starts working on task 2.
When it completes, nsurlsessiond resumes your app.
Your app creates task 3.
nsurlsessiond delays the start of task 3 by double the previous amount.
nsurlsessiond starts working on task 3.
When it completes, nsurlsessiond resumes your app.
Steps 8 through 11 repeat, and each time the delay doubles. Eventually the delay gets so large that it looks like your app has stopped making progress.
If you have a lot of tasks to run then you can mitigate this problem by starting tasks in batches. That is, rather than start just one task in step 1, you would start 100. This only helps up to a point. If you have thousands of tasks to run, you will eventually start seeing serious delays. In that case it’s much better to change your design to use fewer, larger transfers.
Note All of the above applies to iOS 8 and later. Things worked differently in iOS 7. There’s a post on DevForums that explains the older approach.
Finally, keep in mind that there may be other reasons for your task not starting. Specifically, if the task is flagged as discretionary (because you set the discretionary flag when creating the task’s session or because the task was started while your app was in the background), the task may be delayed for other reasons (low power, lack of Wi-Fi, and so on).
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
(r. 22323366)
Hi,I am trying to create an NAT64 Network with Sharing options to test my Apps.I did follow the guide provided here https://forums.developer.apple.com/thread/14213But even with the option key pressed the "Create NAT64 Network" check box is still missing.I am using a OS X 10.11Any ideas?!
Transport Layer Security (TLS) is the most important security protocol on the Internet today. Most notably, TLS puts the S into HTTPS, adding security to the otherwise insecure HTTP protocol.
IMPORTANT TLS is the successor to the Secure Sockets Layer (SSL) protocol. SSL is no longer considered secure and it’s now rarely used in practice, although many folks still say SSL when they mean TLS.
TLS is a complex protocol. Much of that complexity is hidden from app developers but there are places where it’s important to understand specific details of the protocol in order to meet your requirements. This post explains the fundamentals of TLS, concentrating on the issues that most often confuse app developers.
Note The focus of this is TLS-PKI, where PKI stands for public key infrastructure. This is the standard TLS as deployed on the wider Internet. There’s another flavour of TLS, TLS-PSK, where PSK stands for pre-shared key. This has a variety of uses, but an Apple platforms we most commonly see it with local traffic, for example, to talk to a Wi-Fi based accessory. For more on how to use TLS, both TLS-PKI and TLS-PSK, in a local context, see TLS For Accessory Developers.
Server Certificates
For standard TLS to work the server must have a digital identity, that is, the combination of a certificate and the private key matching the public key embedded in that certificate. TLS Crypto Magic™ ensures that:
The client gets a copy of the server’s certificate.
The client knows that the server holds the private key matching the public key in that certificate.
In a typical TLS handshake the server passes the client a list of certificates, where item 0 is the server’s certificate (the leaf certificate), item N is (optionally) the certificate of the certificate authority that ultimately issued that certificate (the root certificate), and items 1 through N-1 are any intermediate certificates required to build a cryptographic chain of trust from 0 to N.
Note The cryptographic chain of trust is established by means of digital signatures. Certificate X in the chain is issued by certificate X+1. The owner of certificate X+1 uses their private key to digitally sign certificate X. The client verifies this signature using the public key embedded in certificate X+1. Eventually this chain terminates in a trusted anchor, that is, a certificate that the client trusts by default. Typically this anchor is a self-signed root certificate from a certificate authority.
Note Item N is optional for reasons I’ll explain below. Also, the list of intermediate certificates may be empty (in the case where the root certificate directly issued the leaf certificate) but that’s uncommon for servers in the real world.
Once the client gets the server’s certificate, it evaluates trust on that certificate to confirm that it’s talking to the right server. There are three levels of trust evaluation here:
Basic X.509 trust evaluation checks that there’s a cryptographic chain of trust from the leaf through the intermediates to a trusted root certificate. The client has a set of trusted root certificates built in (these are from well-known certificate authorities, or CAs), and a site admin can add more via a configuration profile.
This step also checks that none of the certificates have expired, and various other more technical criteria (like the Basic Constraints extension).
Note This explains why the server does not have to include the root certificate in the list of certificates it passes to the client; the client has to have the root certificate installed if trust evaluation is to succeed.
In addition, TLS trust evaluation (per RFC 2818) checks that the DNS name that you connected to matches the DNS name in the certificate. Specifically, the DNS name must be listed in the Subject Alternative Name extension.
Note The Subject Alternative Name extension can also contain IP addresses, although that’s a much less well-trodden path. Also, historically it was common to accept DNS names in the Common Name element of the Subject but that is no longer the case on Apple platforms.
App Transport Security (ATS) adds its own security checks.
Basic X.509 and TLS trust evaluation are done for all TLS connections. ATS is only done on TLS connections made by URLSession and things layered on top URLSession (like WKWebView). In many situations you can override trust evaluation; for details, see Technote 2232 HTTPS Server Trust Evaluation). Such overrides can either tighten or loosen security. For example:
You might tighten security by checking that the server certificate was issued by a specific CA. That way, if someone manages to convince a poorly-managed CA to issue them a certificate for your server, you can detect that and fail.
You might loosen security by adding your own CA’s root certificate as a trusted anchor.
IMPORTANT If you rely on loosened security you have to disable ATS. If you leave ATS enabled, it requires that the default server trust evaluation succeeds regardless of any customisations you do.
Mutual TLS
The previous section discusses server trust evaluation, which is required for all standard TLS connections. That process describes how the client decides whether to trust the server. Mutual TLS (mTLS) is the opposite of that, that is, it’s the process by which the server decides whether to trust the client.
Note mTLS is commonly called client certificate authentication. I avoid that term because of the ongoing industry-wide confusion between certificates and digital identities. While it’s true that, in mTLS, the server authenticates the client certificate, to set this up on the client you need a digital identity, not a certificate.
mTLS authentication is optional. The server must request a certificate from the client and the client may choose to supply one or not (although if the server requests a certificate and the client doesn’t supply one it’s likely that the server will then fail the connection).
At the TLS protocol level this works much like it does with the server certificate. For the client to provide this certificate it must apply a digital identity, known as the client identity, to the connection. TLS Crypto Magic™ assures the server that, if it gets a certificate from the client, the client holds the private key associated with that certificate.
Where things diverge is in trust evaluation. Trust evaluation of the client certificate is done on the server, and the server uses its own rules to decided whether to trust a specific client certificate. For example:
Some servers do basic X.509 trust evaluation and then check that the chain of trust leads to one specific root certificate; that is, a client is trusted if it holds a digital identity whose certificate was issued by a specific CA.
Some servers just check the certificate against a list of known trusted client certificates.
When the client sends its certificate to the server it actually sends a list of certificates, much as I’ve described above for the server’s certificates. In many cases the client only needs to send item 0, that is, its leaf certificate. That’s because:
The server already has the intermediate certificates required to build a chain of trust from that leaf to its root.
There’s no point sending the root, as I discussed above in the context of server trust evaluation.
However, there are no hard and fast rules here; the server does its client trust evaluation using its own internal logic, and it’s possible that this logic might require the client to present intermediates, or indeed present the root certificate even though it’s typically redundant. If you have problems with this, you’ll have to ask the folks running the server to explain its requirements.
Note If you need to send additional certificates to the server, pass them to the certificates parameter of the method you use to create your URLCredential (typically init(identity:certificates:persistence:)).
One thing that bears repeating is that trust evaluation of the client certificate is done on the server, not the client. The client doesn’t care whether the client certificate is trusted or not. Rather, it simply passes that certificate the server and it’s up to the server to make that decision.
When a server requests a certificate from the client, it may supply a list of acceptable certificate authorities [1]. Safari uses this to filter the list of client identities it presents to the user. If you are building an HTTPS server and find that Safari doesn’t show the expected client identity, make sure you have this configured correctly. If you’re building an iOS app and want to implement a filter like Safari’s, get this list using:
The distinguishedNames property, if you’re using URLSession
The sec_protocol_metadata_access_distinguished_names routine, if you’re using Network framework
[1] See the certificate_authorities field in Section 7.4.4 of RFC 5246, and equivalent features in other TLS versions.
Self-Signed Certificates
Self-signed certificates are an ongoing source of problems with TLS. There’s only one unequivocally correct place to use a self-signed certificate: the trusted anchor provided by a certificate authority.
One place where a self-signed certificate might make sense is in a local environment, that is, securing a connection between peers without any centralised infrastructure. However, depending on the specific circumstances there may be a better option. TLS For Accessory Developers discusses this topic in detail.
Finally, it’s common for folks to use self-signed certificates for testing. I’m not a fan of that approach. Rather, I recommend the approach described in QA1948 HTTPS and Test Servers. For advice on how to set that up using just your Mac, see TN2326 Creating Certificates for TLS Testing.
TLS Standards
RFC 6101 The Secure Sockets Layer (SSL) Protocol Version 3.0 (historic)
RFC 2246 The TLS Protocol Version 1.0
RFC 4346 The Transport Layer Security (TLS) Protocol Version 1.1
RFC 5246 The Transport Layer Security (TLS) Protocol Version 1.2
RFC 8446 The Transport Layer Security (TLS) Protocol Version 1.3
RFC 4347 Datagram Transport Layer Security
RFC 6347 Datagram Transport Layer Security Version 1.2
RFC 9147 The Datagram Transport Layer Security (DTLS) Protocol Version 1.3
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Revision History:
2025-11-21 Clearly defined the terms TLS-PKI and TLS-PSK.
2024-03-19 Adopted the term mutual TLS in preference to client certificate authentication throughout, because the latter feeds into the ongoing certificate versus digital identity confusion. Defined the term client identity. Added the Self-Signed Certificates section. Made other minor editorial changes.
2023-02-28 Added an explanation mTLS acceptable certificate authorities.
2022-12-02 Added links to the DTLS RFCs.
2022-08-24 Added links to the TLS RFCs. Made other minor editorial changes.
2022-06-03 Added a link to TLS For Accessory Developers.
2021-02-26 Fixed the formatting. Clarified that ATS only applies to URLSession. Minor editorial changes.
2020-04-17 Updated the discussion of Subject Alternative Name to account for changes in the 2019 OS releases. Minor editorial updates.
2018-10-29 Minor editorial updates.
2016-11-11 First posted.
At WWDC 2015 Apple announced two major enhancements to the Network Extension framework:
Network Extension providers — These are app extensions that let you insert your code at various points within the networking stack, including:
Packet tunnels via NEPacketTunnelProvider
App proxies via NEAppProxyProvider
Content filters via NEFilterDataProvider and NEFilterControlProvider
Hotspot Helper (NEHotspotHelper) — This allows you to create an app that assists the user in navigating a hotspot (a Wi-Fi network where the user must interact with the network in order to get access to the wider Internet).
Originally, using any of these facilities required authorisation from Apple. Specifically, you had to apply for, and be granted access to, a managed capability. In Nov 2016 this policy changed for Network Extension providers. Any developer can now use the Network Extension provider capability like they would any other capability.
There is one exception to this rule: Network Extension app push providers, introduced by iOS 14 in 2020, still requires that Apple authorise the use of a managed capability. To apply for that, follow the link in Local push connectivity.
Also, the situation with Hotspot Helpers remains the same: Using a Hotspot Helper, requires that Apple authorise that use via a managed capability. To apply for that, follow the link in Hotspot helper.
IMPORTANT Pay attention to this quote from the documentation:
NEHotspotHelper is only useful for hotspot integration. There are
both technical and business restrictions that prevent it from being
used for other tasks, such as accessory integration or Wi-Fi based
location.
The rest of this document answers some frequently asked questions about the Nov 2016 change.
#1 — Has there been any change to the OS itself?
No, this change only affects the process by which you get the capabilities you need in order to use existing Network Extension framework facilities. Previously these were managed capabilities, meaning their use was authorised by Apple. Now, except for app push providers and Hotspot Helper, you can enable the necessary capabilities using Xcode’s Signing & Capabilities editor or the Developer website.
IMPORTANT Some Network Extension providers have other restrictions on their use. For example, a content filter can only be used on a supervised device. These restrictions are unchanged. See TN3134 Network Extension provider deployment for the details.
#2 — How exactly do I enable the Network Extension provider capability?
In the Signing & Capabilities editor, add the Network Extensions capability and then check the box that matches the provider you’re creating.
In the Certificates, Identifiers & Profiles section of the Developer website, when you add or edit an App ID, you’ll see a new capability listed, Network Extensions. Enable that capability in your App ID and then regenerate the provisioning profiles based on that App ID.
A newly generated profile will include the com.apple.developer.networking.networkextension entitlement in its allowlist; this is an array with an entry for each of the supported Network Extension providers. To confirm that this is present, dump the profile as shown below.
$ security cms -D -i NETest.mobileprovision
…
<plist version="1.0">
<dict>
…
<key>Entitlements</key>
<dict>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
<string>content-filter-provider</string>
<string>app-proxy-provider</string>
… and so on …
</array>
…
</dict>
…
</dict>
</plist>
#3 — I normally use Xcode’s Signing & Capabilities editor to manage my entitlements. Do I have to use the Developer website for this?
No. Xcode 11 and later support this capability in the Signing & Capabilities tab of the target editor (r. 28568128 ).
#4 — Can I still use Xcode’s “Automatically manage signing” option?
Yes. Once you modify your App ID to add the Network Extension provider capability, Xcode’s automatic code signing support will include the entitlement in the allowlist of any profiles that it generates based on that App ID.
#5 — What should I do if I previously applied for the Network Extension provider managed capability and I’m still waiting for a reply?
Consider your current application cancelled, and use the new process described above.
#6 — What should I do if I previously applied for the Hotspot Helper managed capability and I’m still waiting for a reply?
Apple will continue to process Hotspot Helper managed capability requests and respond to you in due course.
#7 — What if I previously applied for both Network Extension provider and Hotspot Helper managed capabilities?
Apple will ignore your request for the Network Extension provider managed capability and process it as if you’d only asked for the Hotspot Helper managed capability.
#8 — On the Mac, can Developer ID apps host Network Extension providers?
Yes, but there are some caveats:
This only works on macOS 10.15 or later.
Your Network Extension provider must be packaged as a system extension, not an app extension.
You must use the *-systemextension values for the Network Extension entitlement (com.apple.developer.networking.networkextension).
For more on this, see Exporting a Developer ID Network Extension.
#9 — After moving to the new process, my app no longer has access to the com.apple.managed.vpn.shared keychain access group. How can I regain that access?
Access to this keychain access group requires another managed capability. If you need that, please open a DTS code-level support request and we’ll take things from there.
IMPORTANT This capability is only necessary if your VPN supports configuration via a configuration profile and needs to access credentials from that profile (as discussed in the Profile Configuration section of the NETunnelProviderManager Reference). Many VPN apps don’t need this facility.
If you were previously granted the Network Extension managed capability (via the process in place before Nov 2016), make sure you mention that; restoring your access to the com.apple.managed.vpn.shared keychain access group should be straightforward in that case.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Revision History
2025-11-11 Removed the discussion of TSI assets because those are no longer a thing.
2025-09-12 Adopted the code-level support request terminology. Made other minor editorial changes.
2023-01-11 Added a discussion of Network Extension app push providers. Added a link to Exporting a Developer ID Network Extension. Added a link to TN3134. Made significant editorial changes.
2020-02-27 Fixed the formatting. Updated FAQ#3. Made minor editorial changes.
2020-02-16 Updated FAQ#8 to account for recent changes. Updated FAQ#3 to account for recent Xcode changes. Made other editorial changes.
2016-01-25 Added FAQ#9.
2016-01-6 Added FAQ#8.
2016-11-11 Added FAQ#5, FAQ#6 and FAQ#7.
2016-11-11 First posted.
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?
I've implemented a VPN app with Packet Tunnel Provider for MacOS and iOS.I have two questions regarding the Extension's sleep/wake functions:1. If the VPN configuration is set with disconnectOnSleep = false, and at the extension I'm sending keep-alives every X seconds, What would happen when the device enters sleep mode? Will it keep sending keep-alive (because the VPN is configured with disconnectOnSleep=false) ?2. If the VPN configuration is set with disconnectOnSleep = true, and also isOnDemandEnabled = true. When the device enters sleep mode, do I need to disconnect the VPN myself? Or the OS would take care of it? And if I should disconnect it myself, the on-demand won't try to turn it on again (because the on-demand) ?
I was wondering if anybody knows if it's possible for an app to use a QR code to join a Wi-Fi network - the same functionality as the iOS 11 Camera app?I have some code reading a QR Code that looks something like - "WIFI:S:name-of-network;T:WPA;P:password;;"This QR code works perfectly in the native camera app - asking the user if they'd like to join the Wi-Fi network and successfully joining if they do.When I scan the QR code in my own code, I get the following error: canOpenURL: failed for URL: "WIFI:S:name-of-network;T:WPA;P:password;;" - error: "The operation couldn’t be completed. (OSStatus error -10814.)"In my app, I've got URL Schemes for "prefs" and have added "wifi" in LSApplicationQueriesSchemes.Am I doing something wrong, or is this simply not possible?If it's not possible, is there anyway to use the iOS native camera functionality within an app?
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.
Hello,
A quick background:
I am developing an App that receives a data stream from a device through its Wi-Fi network. The device itself is not connected to the internet, so the app won't be either.
Now, I am adding a new feature to the App that would require internet connection during the data stream. Consequently, my users would need to use their cellular data.
On later versions of iPhone, the phone would occasionally detect the lack of internet connection and asks the user via a pop-up if they want to use their cellular data. However, this behavior is not consistent.
So my question is- can we programmatically invoke this pop-up so the user can connect to the internet?
Or even better- can we program the App to use cellular data while still being connected to a Wi-Fi network?
Note:
I have seen mixed answers on the internet whether this is doable or not, and I know that users are able do it themselves by manually configuring their IP in their WiFi settings page, but I doubt this operation can be done through the App for security reasons.
Thanks!
I am pretty sure iOS 13.4 (beta and later) did support Coded PHY (Long Range). Tested devices are iPhone SE2 and iPhone 11 Pro.
However, it seems iOS 14 removed the support of Coded PHY, accidentally or on purpose, I don't know?
The same PHY update request returns "1M PHY" in iOS 14, but "Coded PHY" in iOS 13 (13.4 beta and later).
Anyone knows why?
Samson
Hi, I'm new to swift programming and right now writing an app for esp8266-controlled lamp device. My lamp is broadcasting it's own IP through bonjour. So all I want is to discover any lamps in my network (http.tcp) and to read name and value. Is there any example of such implementation? All I found so far is old or a lit bit complicated for such simple question. Thanks in advance!
Hi,
I have a problem with my OpenVPN connection on my app with iOS 14.4.
I perform my VPN configuration from an oven file, with a NETunnelProviderManager protocol, but when I perform the startVPNTunnel, it starts connecting and immediately disconnects. The error I see in the logs is the following:
NESMVPNSession[Primary Tunnel:OpenVPN Client: -----(null)]: status changed to disconnected, last stop reason Plugin was disabled
This happens to me when running my app on a physical iPad.
Regards
import NetworkExtension
import OpenVPNAdapter
class VPNConnection {
var connectionStatus = "Disconnected"
var myProviderManager: NETunnelProviderManager?
func manageConnectionChanges( manager:NETunnelProviderManager ) - String {
NSLog("Waiting for changes");
var status = "Disconnected"
NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: manager.connection, queue: OperationQueue.main, using: { notification in
let baseText = "VPN Status is "
switch manager.connection.status {
case .connected:
status = "Connected"
case .connecting:
status = "Connecting"
case .disconnected:
status = "Disconnected"
case .disconnecting:
status = "Disconnecting"
case .invalid:
status = "Invalid"
case .reasserting:
status = "Reasserting"
default:
status = "Connected"
}
self.connectionStatus = status
NSLog(baseText+status)
});
return status
}
func createProtocolConfiguration() - NETunnelProviderProtocol {
guard
let configurationFileURL = Bundle.main.url(forResource: "app-vpn", withExtension: "ovpn"),
let configurationFileContent = try? Data(contentsOf: configurationFileURL)
else {
fatalError()
}
let tunnelProtocol = NETunnelProviderProtocol()
tunnelProtocol.serverAddress = ""
tunnelProtocol.providerBundleIdentifier = "com.app.ios"
tunnelProtocol.providerConfiguration = ["ovpn": String(data: configurationFileContent, encoding: .utf8)! as Any]
tunnelProtocol.disconnectOnSleep = false
return tunnelProtocol
}
func startConnection(completion:@escaping () - Void){
self.myProviderManager?.loadFromPreferences(completionHandler: { (error) in
guard error == nil else {
// Handle an occurred error
return
}
do {
try self.myProviderManager?.connection.startVPNTunnel()
print("Tunnel started")
} catch {
fatalError()
}
})
}
func loadProviderManager(completion:@escaping () - Void) {
NETunnelProviderManager.loadAllFromPreferences { (managers, error) in
guard error == nil else {
fatalError()
return
}
self.myProviderManager = managers?.first ?? NETunnelProviderManager()
self.manageConnectionChanges(manager: self.myProviderManager!)
self.myProviderManager?.loadFromPreferences(completionHandler: { (error) in
guard error == nil else {
fatalError()
return
}
let tunnelProtocol = self.createProtocolConfiguration()
self.myProviderManager?.protocolConfiguration = tunnelProtocol
self.myProviderManager?.localizedDescription = "OpenVPN Client Ubic"
self.myProviderManager?.isEnabled = true
self.myProviderManager?.isOnDemandEnabled = false
self.myProviderManager?.saveToPreferences(completionHandler: { (error) in
if error != nil {
// Handle an occurred error
fatalError()
}
self.startConnection {
print("VPN loaded")
}
})
})
}
}
}
Aloha. Opening and closing VPN tunnels results in as many utun interfaces as the amount of times the tunnel has been opened. These interfaces stay present and seem to be removed only upon system reboot.
We are using the NetworkExtension as a SystemExtension on macOS to create the virtual interfaces.
Is this the normal behaviour. Has anybody else experienced this?
utun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1380
inet6 fe80::8038:c353:17cd:c422%utun0 prefixlen 64 scopeid 0xf
nd6 options=201<PERFORMNUD,DAD>
utun1: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 2000
inet6 fe80::cfb6:1324:d7e9:5d5%utun1 prefixlen 64 scopeid 0x10
nd6 options=201<PERFORMNUD,DAD>
utun2: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1300
options=6463<RXCSUM,TXCSUM,TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
utun3: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1300
options=6463<RXCSUM,TXCSUM,TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
utun4: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1300
options=6463<RXCSUM,TXCSUM,TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
utun5: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1300
options=6463<RXCSUM,TXCSUM,TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
utun6: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1300
options=6463<RXCSUM,TXCSUM,TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
utun7: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1300
options=6463<RXCSUM,TXCSUM,TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
utun8: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1300
options=6463<RXCSUM,TXCSUM,TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
Dear Girls, Guys and Engineers.
I'm currently building a Home Network Scanner App for People which want to know which Bonjour Devices are in her/his Home Network environment. From an older Question I got the answer, that I need an Entitlement to do this.
I started to work on the App and requested the Multicast Entitlement from Apple. They gave me the Entitlement for my App and now I'm trying to discover all devices in my Home Network but I got stuck and need Help.
I only test direct on device, like the recommendation. I also verified that my app is build with the multicast entitlement there where no problems. My problem is now, that is still not possible to discover all Bonjour services in my Home Network with the Help of the NWBrowser.
Can you please help me to make it work ?
I tried to scan for the generic service type:
let browser = NWBrowser(for: .bonjour(type: "_services._dns-sd._udp.", domain: nil), using: .init())
but this is still not working even tough I have the entitlement and the app was verified that the entitlement is correctly enabled
if I scan for this service type, I got the following error:
[browser] nw_browser_fail_on_dns_error_locked [B1] Invalid meta query type specified. nw_browser_start_dns_browser_locked failed: BadParam(-65540)
So what's the correct way now to find all devices in the home network ?
Thank you and best regards
Vinz
I'm developing a per-app VPN iOS app with Wireguard. For that, I created a configuration file with payload type "com.apple.vpn.managed.applayer". Using the MDM server I installed some apps which need to use the VPN connection. But when I open these apps, I could see the VPN getting enabled in the device. The VPN icon appears on the notification bar but no internet connection. The VPN and internet is working correctly if I change the payload type to "com.apple.vpn.managed" in configuration file.
General:
Forums subtopic: App & System Services > Networking
DevForums tag: Network Extension
Network Extension framework documentation
Routing your VPN network traffic article
Filtering traffic by URL sample code
Filtering Network Traffic sample code
TN3120 Expected use cases for Network Extension packet tunnel providers technote
TN3134 Network Extension provider deployment technote
TN3165 Packet Filter is not API technote
Network Extension and VPN Glossary forums post
Debugging a Network Extension Provider forums post
Exporting a Developer ID Network Extension forums post
Network Extension vs ad hoc techniques on macOS forums post
Network Extension Provider Packaging forums post
NWEndpoint History and Advice forums post
Extra-ordinary Networking forums post
Wi-Fi management:
Wi-Fi Fundamentals forums post
TN3111 iOS Wi-Fi API overview technote
How to modernize your captive network developer news post
iOS Network Signal Strength forums post
See also Networking Resources.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Our app has a network extension (as I've mentioned lots 😄). We do an upgrade by downloading the new package, stopping & removing all of our components except for the network extension, and then installing the new package, which then loads a LaunchAgent causing the containing app to run. (The only difference between a new install and upgrade is the old extension is left running, but not having anything to tell it what to do, just logs and continues.)
On some (but not all) upgrades... nothing ends up able to communicate via XPC with the Network Extension. My simplest cli program to talk to it gets
Could not create proxy: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named blah was invalidated: failed at lookup with error 3 - No such process." UserInfo={NSDebugDescription=The connection to service named bla was invalidated: failed at lookup with error 3 - No such process.}
Could not communicate with blah
Restarting the extension by doing a kill -9 doesn't fix it; neither does restarting the control daemon. The only solution we've come across so far is rebooting.
I filed FB11086599 about this, but has anyone thoughts about this?
This issue has cropped up many times here on DevForums. Someone recently opened a DTS tech support incident about it, and I used that as an opportunity to post a definitive response here.
If you have questions or comments about this, start a new thread and tag it with Network so that I see it.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
iOS Network Signal Strength
The iOS SDK has no general-purpose API that returns Wi-Fi or cellular signal strength in real time. Given that this has been the case for more than 10 years, it’s safe to assume that it’s not an accidental omission but a deliberate design choice.
For information about the Wi-Fi APIs that are available on iOS, see TN3111 iOS Wi-Fi API overview.
Network performance
Most folks who ask about this are trying to use the signal strength to estimate network performance. This is a technique that I specifically recommend against. That’s because it produces both false positives and false negatives:
The network signal might be weak and yet your app has excellent connectivity. For example, an iOS device on stage at WWDC might have terrible WWAN and Wi-Fi signal but that doesn’t matter because it’s connected to the Ethernet.
The network signal might be strong and yet your app has very poor connectivity. For example, if you’re on a train, Wi-Fi signal might be strong in each carriage but the overall connection to the Internet is poor because it’s provided by a single over-stretched WWAN.
The only good way to determine whether connectivity is good is to run a network request and see how it performs. If you’re issuing a lot of requests, use the performance of those requests to build a running estimate of how well the network is doing. Indeed, Apple practices what we preach here: This is exactly how HTTP Live Streaming works.
Remember that network performance can change from moment to moment. The user’s train might enter or leave a tunnel, the user might step into a lift, and so on. If you build code to estimate the network performance, make sure it reacts to such changes.
Keeping all of the above in mind, iOS 26 beta has two new APIs related to this issue:
Network framework now offers a linkQuality property. See this post for my take on how to use this effectively.
The WirelessInsights framework can notify you of anticipated WWAN condition changes.
But what about this code I found on the ’net?
Over the years various folks have used various unsupported techniques to get around this limitation. If you find code on the ’net that, say, uses KVC to read undocumented properties, or grovels through system logs, or walks the view hierarchy of the status bar, don’t use it. Such techniques are unsupported and, assuming they haven’t broken yet, are likely to break in the future.
But what about Hotspot Helper?
Hotspot Helper does have an API to read Wi-Fi signal strength, namely, the signalStrength property. However, this is not a general-purpose API. Like the rest of Hotspot Helper, this is tied to the specific use case for which it was designed. This value only updates in real time for networks that your hotspot helper is managing, as indicated by the isChosenHelper property.
But what about MetricKit?
MetricKit is so cool. Amongst other things, it supports the MXCellularConditionMetric payload, which holds a summary of the cellular conditions while your app was running. However, this is not a real-time signal strength value.
But what if I’m working for a carrier?
This post is about APIs in the iOS SDK. If you’re working for a carrier, discuss your requirements with your carrier’s contact at Apple.
Revision History
2025-07-02 Updated to cover new features in the iOS 16 beta. Made other minor editorial changes.
2022-12-01 First posted.
I can build the SimpleFirewall application (https://developer.apple.com/documentation/networkextension/filtering_network_traffic ) using xcode:
After I run the application, seems can't block any traffic.
I find there is some logs from network extension process:
networkd_settings_read_from_file Sandbox is preventing this process from reading networkd settings file at "/Library/Preferences/com.apple.networkd.plist", please add an exception.
Any step I am missing ?