Post

Replies

Boosts

Views

Activity

launchApplicationAtURL - Launched Application "Verifying" since Catalina
We have a test tool our engineers use to launch various versions of our application during development and verification. Each daily build of our application is stored on a server. As well, each push of a change generates a new build of our application that is stored on a server. These are added to a database and the developer application accesses the server via REST to find the desired version to run, retrieves a server path and launches the application. This tool is valuable in finding pushes that introduced regressions. The developer application (Runner) is using the launchApplicationAtURL:options:configuration:error: (deprecated I know) to launch the app. Prior to Catalina, this was working great. However, as of Catalina, this process is taking a VERY long time due to the app needing to be "verified". the app seems to need to be copied to the users machine and verified. It only occurs the first launch, but as most of the time the users are running new push or daily builds, it has made the app useless. With the new remote work environment it is even worse as VPN copy can take forever. I have switched to using NSTask with a shell script to open the executable in the bundle. If I add the developer tool (Runner) to the Developer Tools in Privacy this seems to launch the application without the need for verification. However this just seems wrong. It also provides little feedback to know when the application is up and running, which makes my user experience poor. As well many of the systems we use this tool on for verification do not have Developer Tools installed. They are VMs. Is there a way for me to use the launchApplicationAtURL:options:configuration:error: (or the new openApplicationAtURL:configuration:completionHandler:) to launch these versions of the application without the need for the lengthy verification process? Adding our application to the Developer Tools did not seem to help.
2
0
999
Jun ’20
CloudKit/CoreData requests in Extension
Is there any way I can access my CloudKit container from my Siri Intent Extension? I'd like to query my data in response to a Shortcut Intent. My first thought was to add the CloudKit capability to my project, but when I create a new project in Xcode 12 using CloudKit it doesn't show me the iCloud options when adding capabilities to my Intent. There are noticeably few capabilities displayed. Is it expected that users can access CloudKit data from extensions, or would my AppDelegate need to handle this intent from my main app target
2
0
1.2k
Jun ’20
Debugging WidgetKit install error "Failed to get descriptors for extensionBundleID"
I'm trying to create an iOS 14 WidgetKit widget. It's compiling, but when I try to run it, on either simulator or device, I get the error below: Any suggestions on how to debug this? Details SendProcessControlEvent:toPid: encountered an error: Error Domain=com.apple.dt.deviceprocesscontrolservice Code=8 "Failed to show Widget 'com.myapp.dev.WidgetKitExtension' error: Error Domain=SBAvocadoDebuggingControllerErrorDomain Code=1 "Failed to get descriptors for extensionBundleID (com.myapp.dev.WidgetKitExtension)" UserInfo={NSLocalizedDescription=Failed to get descriptors for extensionBundleID (com.myapp.dev.WidgetKitExtension)}." UserInfo={NSLocalizedDescription=Failed to show Widget 'com.myapp.dev.WidgetKitExtension' error: Error Domain=SBAvocadoDebuggingControllerErrorDomain Code=1 "Failed to get descriptors for extensionBundleID (com.myapp.dev.WidgetKitExtension)" UserInfo={NSLocalizedDescription=Failed to get descriptors for extensionBundleID (com.myapp.dev.WidgetKitExtension)}., NSUnderlyingError=0x7fc0b0d12540 {Error Domain=SBAvocadoDebuggingControllerErrorDomain Code=1 "Failed to get descriptors for extensionBundleID (com.myapp.dev.WidgetKitExtension)" UserInfo={NSLocalizedDescription=Failed to get descriptors for extensionBundleID (com.myapp.dev.WidgetKitExtension)}}} Domain: DTXMessage Code: 1- System Information macOS Version 10.15.5 (Build 19F101) Xcode 12.0 (17177)
34
0
22k
Jun ’20
Protocol availability inconsistencies related to modern serial layers
I am currently writing a iPadOS application to act as a companion to the desktop version that controls a piece of hardware via a USB CDC serial connection. Due to modern iPads having USB-C ports for the last 2 years and the ability to attach certain USB devices via adaptors since the origin of the 30pin doc connector I would expect protocol availability to be fairly complete. So then why is it that the headers required to use USB CDC serial don't exist and if you make them yourself you need to use illegal symbols so you can't upload it to App Store connect. Where as USB CDC ethernet has full support along with Bluetooth RFCOMM (rs232 serial over bluetooth) and even USB MIDI given that midi is a superset of serial. So why isn't there a USB CDC serial kit/api/even just allowing a data stream to the TTY/CU port? If there is a way please tell me what it is and point me to the documentation.
11
0
5.6k
Jul ’20
How to "upgrade" an HTTP connection to a WebSocket
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
2
0
3.6k
Sep ’20
Updating Widgets from StaticConfiguration to IntentConfiguration Requires Re-Installation
I'm updating my widget from StaticConfiguration to IntentConfiguration. When I do so, existing widgets installed within simulators and on my iPhone device either show a blank screen or a placeholder screen and fail to initialize. Is there a safe way to upgrade my widget configuration? I would hate to break the widget for our existing users and force them to manually reinstall.
9
0
2.7k
Sep ’20
Notification payload is missing in watch since wOS7
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!
7
0
1.9k
Sep ’20
iOS 14 CoreFoundation crash with EXC_BREAKPOINT
Hi, I am facing a strange issue in my app with iOS14 there is a intermittent crash, i am using NetServiceBrowser for MDNS discovery not sure if that is causing the problem crash log has below information: Crashed: com.apple.main-thread 0 CoreFoundation 0x1a906c4c4 CFAssertMismatchedTypeID + 108 1 CoreFoundation 0x1a8f7db0c CFRunLoopSourceRemoveFromRunLoop + 298 2 CFNetwork 0x1a96255b0 CFNetServiceBrowserStopSearch + 460 3 CoreFoundation 0x1a8f81240 CFRUNLOOPISCALLINGOUTTOASOURCE0PERFORMFUNCTION + 24 4 CoreFoundation 0x1a8f81140 CFRunLoopDoSource0 + 204 5 CoreFoundation 0x1a8f80488 CFRunLoopDoSources0 + 256 6 CoreFoundation 0x1a8f7aa40 CFRunLoopRun + 776 7 CoreFoundation 0x1a8f7a200 CFRunLoopRunSpecific + 572 8 GraphicsServices 0x1bf075598 GSEventRunModal + 160 9 UIKitCore 0x1ab840004 -[UIApplication run] + 1052 10 UIKitCore 0x1ab8455d8 UIApplicationMain + 164
29
1
12k
Oct ’20
Triggering the Local Network Privacy Alert
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 } }
0
0
6.8k
Oct ’20
Local Network Privacy FAQ
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.
0
0
18k
Oct ’20
Local Network Privacy FAQ-2
This post is part of the Local Network Privacy FAQ. What operations require local network access? The general rule is that outgoing traffic to a local network address requires that the user grant your app local network access. Common scenarios include: Making an outgoing TCP connection — yes Listening for and accepting incoming TCP connections — no Sending a UDP unicast — yes Sending a UDP multicast — yes Sending a UDP broadcast — yes Connecting a UDP socket — yes Receiving an incoming UDP unicast — no Receiving an incoming UDP multicast — yes Receiving an incoming UDP broadcast — yes These TCP and UDP checks are done at the lowest levels of the system and thus apply to all networking APIs. This includes Network framework, BSD Sockets, NSStream, and NSURLSession, and any other protocols that you layer on top of those. IMPORTANT Receiving an incoming UDP multicast or broadcast does not currently require local network access but, because we hope to change that in a future update, our advice right now is that you write your code as if did (r. 69792887, 70017649). Resolving link-local DNS names (those ending with local, per RFC 6762) requires local network access. Again, this check applies to a wide variety of APIs including <dns_sd.h>, <net_db.h>, Network framework, NSStream, and NSURLSession. Finally, all Bonjour operations require local network access: Registering a service with Bonjour — yes Browsing for Bonjour services — yes Resolving a Bonjour service — yes Again, these checks apply to all APIs that use Bonjour, including <dns_sd.h>, Network framework, NSNetService, and Multipeer Connectivity. Note You must declare the Bonjour service types you use in your Info.plist. See FAQ-14 How do I map my Multipeer Connectivity service type to an entry in the Bonjour services property? for details. Bonjour-based services where you don’t see any details of the network do not require local network access. These include: AirPlay — no Printing via UIKit — no Back to the FAQ
0
0
6.5k
Oct ’20
Local Network Privacy FAQ-15
This post is part of the Local Network Privacy FAQ - https://developer.apple.com/forums/thread/663858. My app presents the local network privacy alert unexpectedly. Is there a way to track down the cause? If the alert is correlated with something you do in your app then you can step through your code to see what triggers it. However, in some cases this won’t help. For example, some third-party libraries automatically run code in your app that triggers the local network privacy alert. One option here is to start removing any third-party libraries from your app until you figure out which one is triggering it, and then raise this issue with the library’s vendor. If you get completely stuck then start a new thread here on DevForums - https://developer.apple.com/forums/ and I’ll try to help out there. Make sure to tag your thread with one of the standard networking tags (Bonjour, CFNetwork, or Network). Back to the FAQ - https://developer.apple.com/forums/thread/663858
1
0
3.0k
Oct ’20
Big Sur - LaunchAgents - Load error 5: input/output error
Hi all, I am having a mysterious problem trying to load a user LaunchAgent under Big Sur - It is the .plist of gniemetz's automount.sh  https://github.com/gniemetz/automount for mounting SMB shares via pwd access from the Keychain - Placed the .sh into /usr/local/bin, chmod 644 and chown user:staff Placed the LaunchAgent .plist into ~/Library/LaunchAgents (created LaunchAgents it as it didn't exist), same chmod/chown. drwxr-xr-x&amp;amp;#9;&amp;amp;#9;3&amp;amp;#9; users&amp;amp;#9;&amp;amp;#9; 96 Nov&amp;amp;#9;1 22:13 LaunchAgents ~/Library/LaunchAgentsrw-r--r--&amp;amp;#9;&amp;amp;#9;1&amp;amp;#9; users&amp;amp;#9; 1038 Nov&amp;amp;#9;1 22:13 it.niemetz.automount.plist /usr/local drwxr-xr-x&amp;amp;#9;&amp;amp;#9;4 root&amp;amp;#9;&amp;amp;#9;wheel&amp;amp;#9;&amp;amp;#9;128 Nov&amp;amp;#9;1 21:52 bin /usr/local/binrwxr-xr-x&amp;amp;#9;&amp;amp;#9;1 root&amp;amp;#9;&amp;amp;#9;wheel&amp;amp;#9;30310 Oct 29 21:58 automount.sh then the following: Load failed: 5: Input/output error For the life of me, I cannot find anywhere what this means... launchctl start ~/Library/LaunchAgents/it.niemetz.automount.plist completes with no errors, syntax also parses OK /Users//Library/LaunchAgents/it.niemetz.automount.plist: OK I have added Terminal and /bin/bash to Full Disk Access under Security... Launching the script manually as /usr/local/bin/automount.sh works fine. Console shows system.log shows this when load -w is run: 00:27:14 mac-mini-Big-Sur com.apple.xpc.launchd[1] (com.apple.xpc.launchd.user.domain.1000002.100006.Aqua): entering bootstrap mode Nov&amp;amp;#9;3 00:27:14 mac-mini-Big-Sur com.apple.xpc.launchd[1] (com.apple.xpc.launchd.user.domain.1000002.100006.Aqua): exiting bootstrap mode For easy reference the .plist is pasted at the end - Anyone seen this error before? Thanks! ++ Label it.niemetz.automount LimitLoadToSessionType Aqua RunAtLoad WatchPaths /etc/resolv.conf /Library/Preferences/SystemConfiguration/NetworkInterfaces.plist /Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist ProgramArguments /usr/local/bin/automount.sh --mountall
20
2
34k
Nov ’20
Enable local network access during iOS UI test in iOS14
We are building an iOS app that connects to a device using Bluetooth. To test unhappy flow scenarios for this app, we'd like to power cycle the device we are connecting to by using an IoT power switch that connects to the local network using WiFi (a Shelly Plug-S). In my test code on iOS13, I was able to do a local HTTP call to the IP address of the power switch and trigger a power cycle using its REST interface. In iOS 14 this is no longer possible, probably due to new restrictions regarding local network usage without permissions (see: https://developer.apple.com/videos/play/wwdc2020/10110 ). When running the test and trying a local network call to the power switch in iOS14, I get the following error: Task <D206B326-1820-43CA-A54C-5B470B4F1A79>.<2> finished with error [-1009] Error Domain=NSURLErrorDomain Code=-1009 "The internet connection appears to be offline." UserInfo={_kCFStreamErrorCodeKey=50, NSUnderlyingError=0x2833f34b0 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <D206B326-1820-43CA-A54C-5B470B4F1A79>.<2>, _NSURLErrorRelatedURLSessionTaskErrorKey=("LocalDataTask <D206B326-1820-43CA-A54C-5B470B4F1A79>.<2>"), NSLocalizedDescription=The internet connection appears to be offline., NSErrorFailingURLStringKey=http://192.168.22.57/relay/0?turn=on, NSErrorFailingURLKey=http://192.168.22.57/relay/0?turn=on, _kCFStreamErrorDomainKey=1} An external network call (to google.com) works just fine in the test. I have tried fixing this by adding the following entries to the Info.plist of my UI test target: <key>NSLocalNetworkUsageDescription</key> <string>Local network access is needed for tests</string> <key>NSBonjourServices</key> <array> <string>_http._tcp</string> </array> <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict> However, this has no effect. I have also tried adding these entries to the Info.plist of my app target to see if that makes a difference, but it doesn't. I'd also rather not add these entries to my app's Info.plist, because the app does not need local network access. Only the test does. Does anyone know how to enable local network access during an iOS UI test in iOS14?
12
1
13k
Dec ’20
RealityKit : Why ARGeoTrackingConfiguration is not available everywhere ?
Hi, The ARkit is a great tool, I have my small app doing things, and it's fun! but I wanted to try to migrate from ARWorldConfiguration to ARGeoTrackingConfiguration - https://developer.apple.com/documentation/arkit/argeotrackingconfiguration and then we can see that this configuration is limited to a couples of USA only cites. But I can't manage to figure Why and if, in the near future, this will be expanded world wide ?
2
0
1.5k
Jan ’21
Bonjour for discovering a specific device's ip
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!
26
0
13k
Feb ’21
Disable Wi-Fi Assist when app is connected to specific Wi-Fi
Hello, I have an app that talks with physical device over Wi-Fi. The app can send commands and receives a stream of data from it. This commutation happens over Wi-Fi (which has no access to the internet) As a result OS will throw Wi-Fi Assist alert, and offer switch to cellular data. How to avoid this alert? In my scenario if user disconnects from Wi-Fi, he loses access to physical device. In About Wi-Fi Assist - https://support.apple.com/en-us/HT205296 it is mentioned Wi-Fi Assist doesn’t activate with some third-party apps that stream audio or video, or download attachments, like an email app, as they might use large amounts of data. Well my app does download large amount of data from the device. Could my app be eligible for this exception?
2
0
579
Mar ’21
On File System Permissions
Modern versions of macOS use a file system permission model that’s far more complex than the traditional BSD rwx model, and this post is my attempt at explaining that model. If you have a question about this, post it here on DevForums. Put your thread in the App & System Services > Core OS topic area and tag it with Files and Storage. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" On File System Permissions Modern versions of macOS have four different file system permission mechanisms: Traditional BSD permissions Access control lists (ACLs) App Sandbox Mandatory access control (MAC) The first two were introduced a long time ago and rarely trip folks up. The second two are newer, more complex, and specific to macOS, and thus are the source of some confusion. This post is my attempt to clear that up. Error Codes App Sandbox and the mandatory access control system are both implemented using macOS’s sandboxing infrastructure. When a file system operation fails, check the error to see whether it was blocked by this sandboxing infrastructure. If an operation was blocked by BSD permissions or ACLs, it fails with EACCES (Permission denied, 13). If it was blocked by something else, it’ll fail with EPERM (Operation not permitted, 1). If you’re using Foundation’s FileManager, these error are both reported as Foundation errors, for example, the NSFileReadNoPermissionError error. To recover the underlying error, get the NSUnderlyingErrorKey property from the info dictionary. App Sandbox File system access within the App Sandbox is controlled by two factors. The first is the entitlements on the main executable. There are three relevant groups of entitlements: The com.apple.security.app-sandbox entitlement enables the App Sandbox. This denies access to all file system locations except those on a built-in allowlist (things like /System) or within the app’s containers. The various “standard location” entitlements extend the sandbox to include their corresponding locations. The various “file access temporary exceptions” entitlements extend the sandbox to include the items listed in the entitlement. Collectively this is known as your static sandbox. The second factor is dynamic sandbox extensions. The system issues these extensions to your sandbox based on user behaviour. For example, if the user selects a file in the open panel, the system issues a sandbox extension to your process so that it can access that file. The type of extension is determined by the main executable’s entitlements: com.apple.security.files.user-selected.read-only results in an extension that grants read-only access. com.apple.security.files.user-selected.read-write results in an extension that grants read/write access. Note There’s currently no way to get a dynamic sandbox extension that grants executable access. For all the gory details, see this post. These dynamic sandbox extensions are tied to your process; they go away when your process terminates. To maintain persistent access to an item, use a security-scoped bookmark. See Accessing files from the macOS App Sandbox. To pass access between processes, use an implicit security scoped bookmark, that is, a bookmark that was created without an explicit security scope (no .withSecurityScope flag) and without disabling the implicit security scope (no .withoutImplicitSecurityScope flag)). If you have access to a directory — regardless of whether that’s via an entitlement or a dynamic sandbox extension — then, in general, you have access to all items in the hierarchy rooted at that directory. This does not overrule the MAC protection discussed below. For example, if the user grants you access to ~/Library, that does not give you access to ~/Library/Mail because the latter is protected by MAC. Finally, the discussion above is focused on a new sandbox, the thing you get when you launch a sandboxed app from the Finder. If a sandboxed process starts a child process, that child process inherits its sandbox from its parent. For information on what happens in that case, see the Note box in Enabling App Sandbox Inheritance. IMPORTANT The child process inherits its parent process’s sandbox regardless of whether it has the com.apple.security.inherit entitlement. That entitlement exists primarily to act as a marker for App Review. App Review requires that all main executables have the com.apple.security.app-sandbox entitlement, and that entitlements starts a new sandbox by default. Thus, any helper tool inside your app needs the com.apple.security.inherit entitlement to trigger inheritance. However, if you’re not shipping on the Mac App Store you can leave off both of these entitlement and the helper process will inherit its parent’s sandbox just fine. The same applies if you run a built-in executable, like /bin/sh, as a child process. When the App Sandbox blocks something, it typically generates a sandbox violation report. For information on how to view these reports, see Discovering and diagnosing App Sandbox violations. To learn more about the App Sandbox, see the various links in App Sandbox Resources. For information about how to embed a helper tool in a sandboxed app, see Embedding a Command-Line Tool in a Sandboxed App. Mandatory Access Control Mandatory access control (MAC) has been a feature of macOS for many releases, but it’s become a lot more prominent since macOS 10.14. There are many flavours of MAC but the ones you’re most likely to encounter are: Full Disk Access (macOS 10.14 and later) Files and Folders (macOS 10.15 and later) App container protection (macOS 14 and later) App group container protection (macOS 15 and later) Data Vaults (see below) and other internal techniques used by various macOS subsystems Mandatory access control, as the name suggests, is mandatory; it’s not an opt-in like the App Sandbox. Rather, all processes on the system, including those running as root, as subject to MAC. Data Vaults are not a third-party developer opportunity. See this post if you’re curious. In the Full Disk Access and Files and Folders cases, users grant a program a MAC privilege using System Settings > Privacy & Security. Some MAC privileges are per user (Files and Folders) and some are system wide (Full Disk Access). If you’re not sure, run this simple test: On a Mac with two users, log in as user A and enable the MAC privilege for a program. Now log in as user B. Does the program have the privilege? If a process tries to access an item restricted by MAC, the system may prompt the user to grant it access there and then. For example, if an app tries to access the desktop, you’ll see an alert like this: “AAA” would like to access files in your Desktop folder. [Don’t Allow] [OK] To customise this message, set Files and Folders properties in your Info.plist. This system only displays this alert once. It remembers the user’s initial choice and returns the same result thereafter. This relies on your code having a stable code signing identity. If your code is unsigned, or signed ad hoc (“Signed to Run Locally” in Xcode parlance), the system can’t tell that version N+1 of your code is the same as version N, and thus you’ll encounter excessive prompts. Note For information about how that works, see TN3127 Inside Code Signing: Requirements. The Files and Folders prompts only show up if the process is running in a GUI login session. If not, the operation is allowed or denied based on existing information. If there’s no existing information, the operation is denied by default. For more information about app and app group container protection, see the links in Trusted Execution Resources. For more information about app groups in general, see App Groups: macOS vs iOS: Fight! On managed systems the site admin can use the com.apple.TCC.configuration-profile-policy payload to assign MAC privileges. For testing purposes you can reset parts of TCC using the tccutil command-line tool. For general information about that tool, see its man page. For a list of TCC service names, see the posts on this thread. Note TCC stands for transparency, consent, and control. It’s the subsystem within macOS that manages most of the privileges visible in System Settings > Privacy & Security. TCC has no API surface, but you see its name in various places, including the above-mentioned configuration profile payload and command-line tool, and the name of its accompanying daemon, tccd. While tccutil is an easy way to do basic TCC testing, the most reliable way to test TCC is in a VM, restoring to a fresh snapshot between each test. If you want to try this out, crib ideas from Testing a Notarised Product. The MAC privilege mechanism is heavily dependent on the concept of responsible code. For example, if an app contains a helper tool and the helper tool triggers a MAC prompt, we want: The app’s name and usage description to appear in the alert. The user’s decision to be recorded for the whole app, not that specific helper tool. That decision to show up in System Settings under the app’s name. For this to work the system must be able to tell that the app is the responsible code for the helper tool. The system has various heuristics to determine this and it works reasonably well in most cases. However, it’s possible to break this link. I haven’t fully research this but my experience is that this most often breaks when the child process does something ‘odd’ to break the link, such as trying to daemonise itself. If you’re building a launchd daemon or agent and you find that it’s not correctly attributed to your app, add the AssociatedBundleIdentifiers property to your launchd property list. See the launchd.plist man page for the details. Scripting MAC presents some serious challenges for scripting because scripts are run by interpreters and the system can’t distinguish file system operations done by the interpreter from those done by the script. For example, if you have a script that needs to manipulate files on your desktop, you wouldn’t want to give the interpreter that privilege because then any script could do that. The easiest solution to this problem is to package your script as a standalone program that MAC can use for its tracking. This may be easy or hard depending on the specific scripting environment. For example, AppleScript makes it easy to export a script as a signed app, but that’s not true for shell scripts. TCC and Main Executables TCC expects its bundled clients — apps, app extensions, and so on — to use a native main executable. That is, it expects the CFBundleExecutable property to be the name of a Mach-O executable. If your product uses a script as its main executable, you’re likely to encounter TCC problems. To resolve these, switch to using a Mach-O executable. For an example of how you might do that, see this post. Revision History 2024-11-08 Added info about app group container protection. Clarified that Data Vaults are just one example of the techniques used internally by macOS. Made other editorial changes. 2023-06-13 Replaced two obsolete links with links to shiny new official documentation: Accessing files from the macOS App Sandbox and Discovering and diagnosing App Sandbox violations. Added a short discussion of app container protection and a link to WWDC 2023 Session 10053 What’s new in privacy. 2023-04-07 Added a link to my post about executable permissions. Fixed a broken link. 2023-02-10 In TCC and Main Executables, added a link to my native trampoline code. Introduced the concept of an implicit security scoped bookmark. Introduced AssociatedBundleIdentifiers. Made other minor editorial changes. 2022-04-26 Added an explanation of the TCC initialism. Added a link to Viewing Sandbox Violation Reports.  Added the TCC and Main Executables section. Made significant editorial changes. 2022-01-10 Added a discussion of the file system hierarchy. 2021-04-26 First posted.
0
0
8.2k
Apr ’21