Team-scoped keys introduce the ability to restrict your token authentication keys to either development or production environments. Topic-specific keys in addition to environment isolation allow you to associate each key with a specific Bundle ID streamlining key management.
For detailed instructions on accessing these features, read our updated documentation on establishing a token-based connection to APNs.
Delve into the world of built-in app and system services available to developers. Discuss leveraging these services to enhance your app's functionality and user experience.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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)
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?
Is it possible to write an iOS app or app extension to block an incoming call based on the area code (or some other portion of the incoming call number)?
The UIApplication background task mechanism allows you to prevent your app from being suspended for short periods of time. While the API involved is quite small, there’s still a bunch of things to watch out for.
The name background task is somewhat misappropriate. Specifically, beginBackgroundTask(expirationHandler:) doesn’t actually start any sort of background task, but rather it tells the system that you have started some ongoing work that you want to continue even if your app is in the background. You still have to write the code to create and manage that work. So it’s best to think of the background task API as raising a “don’t suspend me” assertion.
You must end every background task that you begin. Failure to do so will result in your app being killed by the watchdog. For this reason I recommend that you attach a name to each background task you start (by calling beginBackgroundTask(withName:expirationHandler:) rather than beginBackgroundTask(expirationHandler:)). A good name is critical for tracking down problems when things go wrong.
IMPORTANT Failing to end a background task is the number one cause of background task problems on iOS. This usually involves some easy-to-overlook error in bookkeeping that results in the app begining a background task and not ending it. For example, you might have a property that stores your current background task identifier (of type UIBackgroundTaskIdentifier). If you accidentally creates a second background task and store it in that property without calling endBackgroundTask on the identifier that’s currently stored there, the app will ‘leak’ a background task, something that will get it killed by the watchdog. One way to avoid this is to wrap the background task in an object; see the QRunInBackgroundAssertion post on this thread for an example.
Background tasks can end in one of two ways:
When your app has finished doing whatever it set out to do.
When the system calls the task’s expiry handler.
Your code is responsible for calling endBackgroundTask(_:) in both cases.
All background tasks must have an expiry handler that the system can use to ‘call in’ the task. The background task API allows the system to do that at any time.
Your expiry handler is your opportunity to clean things up. It should not return until everything is actually cleaned up. It must run quickly, that is, in less than a second or so. If it takes too long, your app will be killed by the watchdog.
Your expiry handler is called on the main thread.
It is legal to begin and end background tasks on any thread, but doing this from a secondary thread can be tricky because you have to coordinate that work with the expiry handler, which is always called on the main thread.
The system puts strict limits on the total amount of time that you can prevent suspension using background tasks. On current systems you can expect about 30 seconds.
IMPORTANT I’m quoting these numbers just to give you a rough idea of what to expect. The target values have changed in the past and may well change in the future, and the amount of time you actually get depends on the state of the system. The thing to remember here is that the exact value doesn’t matter as long as your background tasks have a functional expiry handler.
You can get a rough estimate of the amount of time available to you by looking at UIApplication’s backgroundTimeRemaining property.
IMPORTANT The value returned by backgroundTimeRemaining is an estimate and can change at any time. You must design your app to function correctly regardless of the value returned. It’s reasonable to use this property for debugging but we strongly recommend that you avoid using as part of your app’s logic.
IMPORTANT Basing app behaviour on the value returned by backgroundTimeRemaining is the number two cause of background task problems on iOS.
The system does not guarantee any background task execution time. It’s possible (albeit unlikely, as covered in the next point) that you’ll be unable to create a background task. And even if you do manage to create one, its expiry handler can be called at any time.
beginBackgroundTask(expirationHandler:) can fail, returning UIBackgroundTaskInvalid, to indicate that you the system is unable to create a background task. While this was a real possibility when background tasks were first introduced, where some devices did not support multitasking, you’re unlikely to see this on modern systems.
The background time ‘clock’ only starts to tick when the background task becomes effective. For example, if you start a background task while the app is in the foreground and then stay in the foreground, the background task remains dormant until your app moves to the background. This can help simplify your background task tracking logic.
The amount of background execution time you get is a property of your app, not a property of the background tasks themselves. For example, starting two background task in a row won’t give you 60 seconds of background execution time.
Notwithstanding the previous point, it can still make sense to create multiple background tasks, just to help with your tracking logic. For example, it’s common to create a background task for each job being done by your app, ending the task when the job is done.
Do not create too many background tasks. How many is too many? It’s absolutely fine to create tens of background tasks but creating thousands is not a good idea.
IMPORTANT iOS 11 introduced a hard limit on the number of background task assertions a process can have (currently about 1000, but the specific value may change in the future). If you see a crash report with the exception code 0xbada5e47, you’ve hit that limit.
Note The practical limit that you’re most likely to see here is the time taken to call your expiry handlers. The watchdog has a strict limit (a few seconds) on the total amount of time taken to run background task expiry handlers. If you have thousands of handlers, you may well run into this limit.
If you’re working in a context where you don’t have access to UIApplication (an app extension or on watchOS) you can achieve a similar effect using the performExpiringActivity(withReason:using:) method on ProcessInfo.
If your app ‘leaks’ a background task, it may end up being killed by the watchdog. This results in a crash report with the exception code 0x8badf00d (“ate bad food”).
IMPORTANT A leaked background task is not the only reason for an 0x8badf00d crash. You should look at the backtrace of the main thread to see if the main thread is stuck in your code, for example, in a synchronous networking request. If, however, the main thread is happily blocked in the run loop, a leaked background task should be your primary suspect.
Prior to iOS 11 information about any outstanding background tasks would appear in the resulting crash report (look for the text BKProcessAssertion). This information is not included by iOS 11 and later, but you can find equivalent information in the system log.
The system log is very noisy so it’s important that you give each of your background tasks an easy-to-find name.
For more system log hints and tips, see Your Friend the System Log.
iOS 13 introduced the Background Tasks framework. This supports two type of requests:
The BGAppRefreshTaskRequest class subsumes UIKit’s older background app refresh functionality.
The BGProcessingTaskRequest class lets you request extended background execution time, typically overnight.
WWDC 2020 Session 10063 Background execution demystified is an excellent summary of iOS’s background execution model. Watch it, learn it, love it!
For more background execution hints and tips, see Background Tasks Resources.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Revision History
2023-06-16 Added a link to my QRunInBackgroundAssertion post.
2022-06-08 Corrected a serious error in the discussion of BGProcessingTaskRequest. Replaced the basic system log info with a reference to Your Friend the System Log. Added a link to Background Tasks Resources. Made other minor editorial changes.
2021-02-27 Fixed the formatting. Added a reference to the Background Tasks framework and the Background execution demystified WWDC presentation. Minor editorial changes.
2019-01-20 Added a note about changes in the iOS 13 beta. Added a short discussion about beginning and ending background tasks on a secondary thread.
2018-02-28 Updated the task name discussion to account for iOS 11 changes. Added a section on how to debug ‘leaked’ background tasks.
2017-10-31 Added a note about iOS 11’s background task limit.
2017-09-12 Numerous updates to clarify various points.
2017-08-17 First posted.
Hey,I want to get nearby Wi-Fi network's SSID into the app using network extension framework.Right now I can get scan list by visiting the setting--->Wifi Screen but I want to get those Scan Result into the app without visiting the setting wifi screen.If anyone idea about it please let me know
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'm trying to read the contents of a file on the filesystem in a macOS Swift app (Xcode 9 / Swift 4).I'm using the following snippet for it:let path = "/my/path/string.txt"
let s = try! String(contentsOfFile: path)
print(s)My problem is the following:1. This works in a Playground2. This works when I use the Command Line Tool macOS app template3. This terminates in a permission error when I use the Cocoa App macOS app templateThe permission error is the following:Fatal error: 'try!' expression unexpectedly raised an error:
Error Domain=NSCocoaErrorDomain Code=257 "The file "data.txt" couldn't be opened because you don't have permission to view it."
UserInfo={NSFilePath=/my/path/data.txt, NSUnderlyingError=0x60c0000449b0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}I guess it's related to sandboxing but I found no information about it.1. How can I read from the filesystem in a sandboxed app? I mean there are so many GUI apps which need an Open File dialog, it cannot be a realistic restriction of sandboxed apps to not read files from outside the sandbox.2. Alternatively, how can I switch off sandboxing in Build Settings?3. Finally, I tried to compare the project.pbxproj files between the default Cocoa Apps and Command Line Tool template and I didn't see any meaningful difference, like something about security or sandbox. If not here, where are those settings stored?
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?
On iOS:When one receives a file of type .pages by email, Mail displays a large Pages icon and tapping on it opens Pages. (A long-press brings up the more complicated Actions screen).When one receives a file of type .vcf by email, Mail displays a large Contacts icon and tapping on it opens Contacts. (A long-press brings up the more complicated Actions screen).I have my own custom file type, .ripf, and I want to have the same behaviour because that is what my users will expect. Accordingly, in my app's Info.plist I have a CFBundleDocumentTypes dictionary providing a one-element LSItemContentTypes array referring to the name 'com.universalis.ripcard', and a UTExportedTypeDeclarations dictionary associating the UTTypeIdentifier 'com.universalis.ripcard' with a public.filename-extension 'ripf' and a public.mime-type 'text/vnd.universalis.ripcard'. All the other entries in those two dictionaries are present and correct as far as I can tell. Both CFBundleDocumentTypes[0].CFBundleTypeIconFiles and UTExportedTypeDeclarations[0].UTTypeIconFiles contain a list of icon files for the file type.(That rather long paragraph is to avoid boring people by including the entire Info.plist!)Some things do work..ripf files received via AirDrop bring up a suitable "Open with..." message which mentions my app, and tapping the message opens the app..ripf files received as an email attachment display as an icon. But it is the app's icon and not the icon of the file type.BUTTapping on a received file's icon does not open the app, but only opens the generic Actions screen, offering Message, Mail, WhatsApp, Notes, and only then (after the user has scrolled sideways) "Copy to..." my app.Now, the whole apparatus of CFBundleDocumentTypes and UTExportedTypeDeclarations is obscure and under-documented, and indeed the main documenation for the latter has a big warning at the top saying that it is obsolete and not being updated. That doesn't matter so much. What I need to know is:(Less important): How do I get the right file icon?(More important): How do I get my app to open when the icon is tapped, as Pages and Contacts do? There must be a way – unless special cases for those two apps are wired into iOS itself.
Dear all,In macOS Catalina we have the new NetworkExtension framework that can filter network trafic on a computer.In my usecase I need the PID of the process that is the originator of the network flow. I'm aware that PID are not a reliable way to identify a process (since PIDs can be reused), but in my usecase only PID can identify what I need.In handleNewFlow(_ flow: NEFilterFlow) we can get the sourceAppAuditToken (flow.sourceAppAuditToken), where sourceAppAuditToken is a Data type. Is there a way to convert this sourceAppAuditToken to a PID value?I'm also aware of getting the signature of the process (eventually the Bundle ID) with SecCodeCopySigningInformation / kSecCSDynamicInformation, but again in my usecase it does not help.A way to do this is to call "netstat" and look for the local port in the output and get the PID from there, but sometimes this is not very reliable.Any ideas how to do this?Regards,Alex
Hi all, I'm looking for the specifications for the accelerometers used in current iPhone and iPad devices, including the sensitivity and the update rates possible.
Despite the documentation saying it's 100Hz, I've not yet found it to be better than 50Hz on any of iPhone SE, 8 or 11, nor iPad mini or Pros.
Any help would be much appreciated!
A
Since running on iOS 14b1, I'm getting this in my log (I have Core Data logging enabled):
error: Store opened without NSPersistentHistoryTrackingKey but previously had been opened with NSPersistentHistoryTrackingKey - Forcing into Read Only mode store at 'file:///private/var/mobile/Containers/Shared/AppGroup/415B75A6-92C3-45FE-BE13-7D48D35909AF/StoreFile.sqlite'
As far as I can tell, it's impossible to open my store without that key set - it's in the init() of my NSPersistentContainer subclass, before anyone calls it to load stores.
Any ideas?
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!
Prior to iOS 14 our Dev server was routing universal links to our test devices just fine from both Xcode and TestFlight builds. But now that we've started testing on iOS 14 devices the links aren't being handled any more.
After doing some research we noticed the new configuration regarding Associated Domains for web servers that aren't reachable from the public internet.
https://developer.apple.com/documentation/safariservices/supporting_associated_domains
Starting with macOS 11 and iOS 14, apps no longer send requests for apple-app-site-association files directly to your web server. Instead, they send these requests to an Apple-managed content delivery network (CDN) dedicated to associated domains. While you’re developing your app, if your web server is unreachable from the public internet, you can use the alternate mode feature to bypass the CDN and connect directly to your private domain.You enable an alternate mode by adding a query string to your associated domain’s entitlement as follows:
<service>:<fully qualified domain>?mode=<alternate mode>
Given our Dev server is only reachable via a VPN we changed our project config to use the alternate mode:
<key>com.apple.developer.associated-domains</key>
<array>
<string>webcredentials:ourDevServerURL?mode=developer</string>
<string>applinks:ourDevServerURL?mode=developer</string>
</array>
But unfortunately that still doesn't work and in the console we can see the following swcd logs being generated after a fresh app install.
debug com.apple.swc 11:45:19.016561-0600 swcd entry Skipping domain si….va….com?mode=developer because developer mode is disabled
So what else do we need to get developer mode working for these app links?
One question I often see on DevForums and in my day DTS job is if a Core Data object managed by NSPersistentCloudKitContainer can be shared with other iCloud users.
The answer is yes but you need to do it using CloudKit API directly because NSPersistentCloudKitContainer doesn’t support CloudKit shared database (CKContainer.sharedCloudDatabase) today.
Assuming you have a Core Data object, let’s say a document, that you’d like to collaborate with your colleagues:
You are the document owner and can use NSPersistentCloudKitContainer to fully manages the document and synchronize it across your devices.
You can grab a CloudKit record associated with your document from NSPersistentCloudKitContainer using record(for:) or recordID(for:), and share it to your colleagues using UICloudSharingController. See our Sharing CloudKit Data with Other iCloud Users - https://developer.apple.com/documentation/cloudkit/sharing_cloudkit_data_with_other_icloud_users sample for how to share a CloudKit record.
After accepting the sharing, your colleague, as a participant, can view or edit the shared document. The document resides in the participant’s CloudKit shared database and you have to manage it with your own code.
When your colleague edits and saves the shared document, the changes go to the owner’s private database, and eventually synchronize to NSPersistentCloudKitContainer on the owner side.
As you can see, you need to implement #2 and #3 with your own code because NSPersistentCloudKitContainer can’t manage the data in the participant's shared database. If you have any difficulty after going through the above sample code, you can contact Apple’s DTS for help.
Hi,
I have been successful at writing Swift code using a NWListener to listen to WebSocket connections on a specific port, but I do not seem to be able to get the path from the URL for creating different types of connections.
For instance, differentiating between ws://127.0.0.1:80/updates and ws://127.0.0.1:80/changes.
I'd like to be able to get the "updates" or "changes" part when I receive the new connection notification.
Having more sample code around WebSockets and how the upgrade process works that would also be great.
Thank you !
Daniel Tapie
I am trying to follow the guidance for testing a Local Experience, as listed in the Testing Your App Clip’s Launch Experience - https://developer.apple.com/documentation/app_clips/testing_your_app_clip_s_launch_experience documentation. I have successfully created my App Clip target, and can confirm that running the App Clip on my device does launch the App Clip app as I expected. Further, I can successfully test the App Clip on device, by setting the _XCAppClipURL argument in the App Clip's scheme.
I would like to test a Local Experience. The documentation states that for testing Local Experiences;
To test your app clip’s invocation with a local experience, you don’t need to add the Associated Domains Entitlement, make changes to the Apple App Site Association file on your web server, or create an app clip experience for testing in TestFlight. Therefore, I should be able to configure a Local Experience with any desired domain in Settings -> Developer -> Local Experience, generate a QR code or NFC tag with that same URL, and the App Clip experience should appear. I have taken the following steps;
Built and run my App Clip on my local device.
In Settings -> Developer -> Local Experience, I have registered a new experience using a URL prefix https://somewebsite.com
Set my Bundle ID to com.mycompany.myapp.Clip, which exactly matches the Bundle Identifier, as listed in Xcode, under my App Clip target.
Generated a QR code which directs me to https://somewebsite.com
In theory, I believe I should be able to open the Camera app on my device, point the camera at the QR code, and the App Clip experience should appear. However, I received mixed experiences. 50% of the time, I receive a pop-up directing me to open https://somewebsite.com in Safari, the other 50% of the time, no banner or action occurs whatsoever.
Is this an issue anyone has faced before, or have I pursued these steps out of order?
There is an issue with our app when showing a dynamic watch notification. Our app would sometimes receive a push notification with extra payload. In wOS6, the notification would be sent to the watch and show a dynamic detailed notification based on the data within the notification. But ever since wOS7, the watch does not show the data that is being sent.
We found out that the UNNotification that is being passed through in WKUserNotificationInterfaceController via. [didReceive:notification:](https://developer.apple.com/documentation/watchkit/wkusernotificationinterfacecontroller/2963125-didreceive) has an empty [userInfo](https://developer.apple.com/documentation/usernotifications/unnotificationcontent/1649869-userinfo).
I was wondering if anyone else have that issue. Or was there a change in wOS7 that prevents the userInfo from being received by the watch? Thanks!
IMPORTANT The approach used by this code no longer works. See TN3179 Understanding local network privacy for a replacement.
Currently there is no way to explicitly trigger the local network privacy alert (r. 69157424). However, you can bring it up implicitly by sending dummy traffic to a local network address. The code below shows one way to do this. It finds all IPv4 and IPv6 addresses associated with broadcast-capable network interfaces and sends a UDP datagram to each one. This should trigger the local network privacy alert, assuming the alert hasn’t already been displayed for your app.
Oh, and if Objective-C is more your style, use this code instead.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
import Foundation
/// Does a best effort attempt to trigger the local network privacy alert.
///
/// It works by sending a UDP datagram to the discard service (port 9) of every
/// IP address associated with a broadcast-capable interface. This should
/// trigger the local network privacy alert, assuming the alert hasn’t already
/// been displayed for this app.
///
/// This code takes a ‘best effort’. It handles errors by ignoring them. As
/// such, there’s guarantee that it’ll actually trigger the alert.
///
/// - note: iOS devices don’t actually run the discard service. I’m using it
/// here because I need a port to send the UDP datagram to and port 9 is
/// always going to be safe (either the discard service is running, in which
/// case it will discard the datagram, or it’s not, in which case the TCP/IP
/// stack will discard it).
///
/// There should be a proper API for this (r. 69157424).
///
/// For more background on this, see [Triggering the Local Network Privacy Alert](https://developer.apple.com/forums/thread/663768).
func triggerLocalNetworkPrivacyAlert() {
let sock4 = socket(AF_INET, SOCK_DGRAM, 0)
guard sock4 >= 0 else { return }
defer { close(sock4) }
let sock6 = socket(AF_INET6, SOCK_DGRAM, 0)
guard sock6 >= 0 else { return }
defer { close(sock6) }
let addresses = addressesOfDiscardServiceOnBroadcastCapableInterfaces()
var message = [UInt8]("!".utf8)
for address in addresses {
address.withUnsafeBytes { buf in
let sa = buf.baseAddress!.assumingMemoryBound(to: sockaddr.self)
let saLen = socklen_t(buf.count)
let sock = sa.pointee.sa_family == AF_INET ? sock4 : sock6
_ = sendto(sock, &message, message.count, MSG_DONTWAIT, sa, saLen)
}
}
}
/// Returns the addresses of the discard service (port 9) on every
/// broadcast-capable interface.
///
/// Each array entry is contains either a `sockaddr_in` or `sockaddr_in6`.
private func addressesOfDiscardServiceOnBroadcastCapableInterfaces() -> [Data] {
var addrList: UnsafeMutablePointer<ifaddrs>? = nil
let err = getifaddrs(&addrList)
guard err == 0, let start = addrList else { return [] }
defer { freeifaddrs(start) }
return sequence(first: start, next: { $0.pointee.ifa_next })
.compactMap { i -> Data? in
guard
(i.pointee.ifa_flags & UInt32(bitPattern: IFF_BROADCAST)) != 0,
let sa = i.pointee.ifa_addr
else { return nil }
var result = Data(UnsafeRawBufferPointer(start: sa, count: Int(sa.pointee.sa_len)))
switch CInt(sa.pointee.sa_family) {
case AF_INET:
result.withUnsafeMutableBytes { buf in
let sin = buf.baseAddress!.assumingMemoryBound(to: sockaddr_in.self)
sin.pointee.sin_port = UInt16(9).bigEndian
}
case AF_INET6:
result.withUnsafeMutableBytes { buf in
let sin6 = buf.baseAddress!.assumingMemoryBound(to: sockaddr_in6.self)
sin6.pointee.sin6_port = UInt16(9).bigEndian
}
default:
return nil
}
return result
}
}
IMPORTANT This FAQ has been replaced by TN3179 Understanding local network privacy. I’m leaving this post in place as a historical curiosity, but please consult the technote going forward.
I regularly get asked questions about local network privacy. This is my attempt to collect together the answers for the benefit of all. Before you delve into the details, familiarise yourself with the basics by watching WWDC 2020 Session 10110 Support local network privacy in your app.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Local Network Privacy FAQ
With local network privacy, any app that wants to interact with devices on your network must ask for permission the first time that it attempts that access. Local network privacy is implemented on iOS, iPadOS, visionOS, and macOS. It’s not implemented on other platforms, most notably tvOS.
IMPORTANT macOS 15 (currently in beta) introduced local network privacy support to the Mac. WWDC 2024 Session 10123 What’s new in privacy is the official announcement. This works much like it does on iOS, but there are some subtle differences. I’ll update this FAQ as I gain more experience with this change.
Some common questions about local network privacy are:
FAQ-1 What is a local network?
FAQ-2 What operations require local network access?
FAQ-3 What operations require the multicast entitlement?
FAQ-4 Do I need the multicast entitlement?
FAQ-5 I’ve been granted the multicast entitlement; how do I enable it?
FAQ-6 Can App Clips access the local network?
FAQ-7 How does local network privacy work with app extensions?
FAQ-8 How do I explicitly trigger the local network privacy alert?
FAQ-9 How do I tell whether I’ve been granted local network access?
FAQ-10 How do I use the unsatisfied reason property?
FAQ-11 Do I need a local network usage description property?
FAQ-12 Can I test on the simulator?
FAQ-13 Once my app has displayed the local network privacy alert, how can I reset its state so that it shows again?
FAQ-14 How do I map my Multipeer Connectivity service type to an entry in the Bonjour services property?
FAQ-15 My app presents the local network privacy alert unexpectedly. Is there a way to track down the cause?
FAQ-16 On a small fraction of devices my app fails to present the local network privacy alert. What’s going on?
FAQ-17 Why does local network privacy get confused when I install two variants of my app?
FAQ-18 Can my app trigger the local network privacy alert when the device is on WWAN?
Revision History
2024-10-31 Added a link to this FAQ’s replacement, TN3179 Understanding local network privacy.
2024-07-22 Added a callout explaining that local network privacy is now an issue on macOS.
2023-10-31 Fixed a bug in the top-level FAQ that mistakenly removed some recent changes. Added FAQ-18.
2023-10-19 Added a preamble to clarify that local network privacy is only relevant on specific platforms.
2023-09-14 Added FAQ-17.
2023-08-29 Added FAQ-16.
2023-03-13 Added connecting a UDP socket to FAQ-2.
2022-10-04 Added screen shots to FAQ-11.
2022-09-22 Fixed the pointer from FAQ-9 to FAQ-10.
2022-09-19 Updated FAQ-3 to cover iOS 16 changes. Made other minor editorial changes.
2020-11-12 Made a minor tweak to FAQ-9.
2020-10-17 Added FAQ-15. Added a second suggestion to FAQ-13.
2020-10-16 First posted.