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.

All subtopics

Post

Replies

Boosts

Views

Activity

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
752
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
9.2k
Apr ’21
Disable Scribble in UITextView
There are use cases where someone who's using an Apple Pencil may not want to enter text via Scribble. A simple example is writing "UIViewController" in a text view is unlikely to be successful. I'd like to disable Scribble in this case and let the keyboard become the input mechanism. (Disabling Scribble system-wide in Settings is both cumbersome and overkill.) The closest I can come to making this happen is by adding a UIScribbleInteraction on a UITextView and returning false when scribbleInteraction(shouldBeginAt:) is called. This disables Scribble on the text view, and prevents writing from being converted into text, but the input widget still appears on screen and isn't very useful. Here is a sample project that demonstrates the problem: http://files.iconfactory.net/craig/bugs/Scribbler.zip Hopefully, I'm doing something wrong here. If not, I'm happy to submit this as a FB. -ch
3
0
3k
Jun ’21
ASIdentifierManager.advertisingIdentifier hanging
Is there any threading assumption/requirement for ASIdentifierManager.advertisingIdentifier? Please see the complete issue and stack trace here. The main thread was waiting for the worker thread, which was blocked in ASIdentifierManager.advertisingIdentifier. Thread 68: 0 libsystem_kernel.dylib 0x188abf0f4 mach_msg_trap (in libsystem_kernel.dylib) + 8 1 libsystem_kernel.dylib 0x188abe5a0 mach_msg (in libsystem_kernel.dylib) + 72 2 libdispatch.dylib 0x188924880 _dispatch_mach_send_and_wait_for_reply (in libdispatch.dylib) + 500 3 libdispatch.dylib 0x188924d10 dispatch_mach_send_with_result_and_wait_for_reply$VARIANT$mp (in libdispatch.dylib) + 52 4 libxpc.dylib 0x188b8391c xpc_connection_send_message_with_reply_sync (in libxpc.dylib) + 204 5 Foundation 0x189aafa28 NSXPCCONNECTION_IS_WAITING_FOR_A_SYNCHRONOUS_REPLY (in Foundation) + 12 6 Foundation 0x189892f60 -[NSXPCConnection sendInvocation:orArguments:count:methodSignature:selector:withProxy:] (in Foundation) + 3608 7 CoreFoundation 0x188f3276c forwarding (in CoreFoundation) + 552 8 CoreFoundation 0x188f3475c forwarding_prep_0 (in CoreFoundation) + 92 9 CoreServices 0x1b1896ce4 -[LSApplicationWorkspace deviceIdentifierForAdvertising] (in CoreServices) + 160 10 AdSupport 0x198f70a60 -[ASIdentifierManager advertisingIdentifier] (in AdSupport) + 56 I don't see any thread related information in the document. I tried to recreate the scenario, but I could not reproduce the issue with the simplified test below. #import "ViewController.h" #import "AdSupport/AdSupport.h" #import "AppTrackingTransparency/AppTrackingTransparency.h" @interface ViewController () {  dispatch_queue_t _queue; } @end @implementation ViewController - (void)viewDidLoad {  [super viewDidLoad];  _queue = dispatch_queue_create("IdentityWorkerQueue", DISPATCH_QUEUE_SERIAL);  dispatch_set_target_queue(_queue,               dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));  if (@available(iOS 14, *)) {   [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:    ^(ATTrackingManagerAuthorizationStatus status) {    NSLog(@"Status: %lu", (unsigned long)status);   }];  } } - (IBAction)action:(id)sender {  __block NSString *adId1 = nil;  dispatch_async(self->_queue, ^{   sleep(1);   adId1 = ASIdentifierManager.sharedManager.advertisingIdentifier.UUIDString;  });  __block NSString *adId2 = nil;  dispatch_sync(self->_queue, ^{   adId2 = adId1;  }); } @end Is there any threading assumption/requirement for ASIdentifierManager.advertisingIdentifier? For example, would it wait for the main thread to finish a certain task when an error happens?
2
1
1.2k
Jun ’21
Widget not showing in "Widget Gallery"
Our app's widget often doesn't show up in the "Widget Gallery". Lots of our users complain about this issue. They can't see the widget in widget gallery after opening the app. In some cases, the widget does not appear in the widget gallery even after turning the phone off and on. I saw in another question that this is a bug. This bug will be fixed someday, but is there anything we can do before that?
3
0
2.0k
Jun ’21
Programmatically open popup in Safari Web Extension
I have a Safari web extension that needs the ability to open the popup when the user interacts with a modal coming from the content script. There is a native message handler that comes with the safari web extension when you first create it: import SafariServices import os.log class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { func beginRequest(with context: NSExtensionContext) { let item = context.inputItems[0] as! NSExtensionItem let message = item.userInfo?[SFExtensionMessageKey] os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@", message as! CVarArg) let response = NSExtensionItem() response.userInfo = [ SFExtensionMessageKey: [ "Response to": message ] ] print("hit") context.completeRequest(returningItems: [response], completionHandler: nil) } } I have the permissions to send a native message, I've seen some examples online where you can access the SFSafariApplication module from SafariServices and open the popover. But I can't seem to access SFSafariApplication in this module.
1
0
1.5k
Jul ’21
iOS Background Execution Limits
I regularly see questions, both here on DevForums and in my Day Job™ at DTS, that are caused by a fundamental misunderstanding of how background execution works on iOS. These come in many different variants, for example: How do I keep my app running continuously in the background? If I schedule a timer, how do I get it to fire when the screen is locked? How do I run code in the background every 15 minutes? How do I set up a network server that runs in the background? How can my app provide an IPC service to another one of my apps while it’s in the background? How can I resume my app in the background if it’s been ‘force quit’ by the user? The short answer to all of these is You can’t. iOS puts strict limits on background execution. Its default behaviour is to suspend your app shortly after the user has moved it to the background; this suspension prevents the process from running any code. There’s no general-purpose mechanism for: Running code continuously in the background Running code at some specific time in the background Running code periodically at a guaranteed interval Resuming in the background in response to a network or IPC request However, iOS does provide a wide range of special-purpose mechanisms for accomplishing specific user goals. For example: If you’re building a music player, use the audio background mode to continue playing after the user has moved your app to the background. If you’re building a timer app, use a local notification to notify the user when your timer has expired. If you’re building a video player app, use AVFoundation’s download support. Keep in mind that the above is just a short list of examples. There are many other special-purpose background execution mechanisms, so you should search the documentation for something appropriate to your needs. IMPORTANT Each of these mechanisms fulfils a specific purpose. Do not attempt to use them for some other purpose. Before using a background API, read clause 2.5.4 of the App Review Guidelines. Additionally, iOS provides some general-purpose mechanisms for background execution: To resume your app in the background in response to an event on your server, use a background notification (aka a ‘silent’ push). For more information, see Pushing background updates to your App. To request a small amount of background execution time to refresh your UI, use BGAppRefreshTaskRequest. To request extended background execution time, typically delivered overnight when the user is asleep, use BGProcessingTaskRequest. To prevent your app from being suspended for a short period of time so that you can complete some user task, use a UIApplication background task. For more information on this, see UIApplication Background Task Notes. To download or upload a large HTTP resource, use an NSURLSession background session. All of these mechanisms prevent you from abusing them to run arbitrary code in the background. As an example, consider the NSURLSession resume rate limiter. For more information about these limitations, and background execution in general, I strongly recommend that you watch WWDC 2020 Session 10063 Background execution demystified. It’s an excellent resource. Specifically, this talk addresses a common misconception about the app refresh mechanism (BGAppRefreshTaskRequest and the older background fetch API). Folks assume that app refresh will provide regular background execution time. That’s not the case. The system applies a range of heuristics to decide which apps get app refresh time and when. This is a complex issue, one that I’m not going to try to summarise here, but the take-home message is that, if you expect that the app refresh mechanism will grant you background execution time, say, every 15 minutes, you’ll be disappointed. In fact, there are common scenarios where it won’t grant you any background execution time at all! Watch the talk for the details. When the user ‘force quits’ an app by swiping up in the multitasking UI, iOS interprets that to mean that the user doesn’t want the app running at all. So: If the app is running, iOS terminates it. iOS also sets a flag that prevents the app from being launched in the background. That flag gets cleared when the user next launches the app manually. This gesture is a clear statement of user intent; there’s no documented way for your app to override the user’s choice. Note In some circumstances iOS will not honour this flag. The exact cases where this happens are not documented and have changed over time. Finally, if you have questions about background execution that aren’t covered by the resources listed here, please open a new thread on DevForums with the details. Tag it appropriately for the technology you’re using; if nothing specific springs to mind, use Background Tasks. Also, make sure to include details about the specific problem you’re trying to solve because, when it comes to background execution, the devil really is in the details. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Change history: 2024-03-21 Added a discussion of ‘force quit’. 2023-05-11 Added a paragraph that explains a common misconception about the app refresh mechanism. Made other minor editorial changes. 2021-08-12 Added more entries to the common questions list, this time related to networking and IPC. Made minor editorial changes. 2021-07-26 Extended the statement about what’s not possible to include “running code periodically at a guaranteed interval”. 2021-07-22 First posted.
0
0
17k
Jul ’21
EtreCheck (from Etresoft, Inc)
Hello I've noticed that this product, heavily promoted on the ASC forums for many years, is no longer available from the Apple App Store. Can anyone tell me the reason why the product is no longer supported? Friends have asked me if it is 'safe' to use. Is it? Note to moderator: If I'm asking in the wrong places, please redirect my question. Thank you.
7
0
3.6k
Aug ’21
NSPersistentCloudkitContainer Memory Leak -> Crash? (iOS 15 beta 4 & 5)
Background I have an established app in the App Store which has been using NSPersistentCloudkitContainer since iOS 13 without any issues. I've been running my app normally on an iOS device running the iOS 15 betas, mainly to see problems arise before my users see them. Ever since iOS 15 (beta 4) my app has failed to sync changes - no matter how small the change. An upload 'starts' but never completes. After a minute or so the app quits to the Home Screen and no useful information can be gleaned from crash reports. Until now I've had no idea what's going on. Possible Bug in the API? I've managed to replicate this behaviour on the simulator and on another device when building my app with Xcode 13 (beta 5) on iOS 15 (beta 5). It appears that NSPersistentCloudkitContainer has a memory leak and keeps ramping up the RAM consumption (and CPU at 100%) until the operating system kills the app. No code of mine is running. I'm not really an expert on these things and I tried to use Instruments to see if that would show me anything. It appears to be related to NSCloudkitMirroringDelegate getting 'stuck' somehow but I have no idea what to do with this information. My Core Data database is not tiny, but not massive by any means and NSPersistentCloudkitContainer has had no problems syncing to iCloud prior to iOS 15 (beta 4). If I restore my App Data (from an external backup file - 700MB with lots of many-many, many-one relationships, ckAssets, etc.) the data all gets added to Core Data without an issue at all. The console log (see below) then shows that a sync is created, scheduled & then started... but no data is uploaded. At this point the memory consumption starts and all I see is 'backgroundTask' warnings appear (only related to CloudKit) with no code of mine running. CoreData: CloudKit: CoreData+CloudKit: -[PFCloudKitExporter analyzeHistoryInStore:withManagedObjectContext:error:](501): <PFCloudKitExporter: 0x600000301450>: Exporting changes since (0): <NSPersistentHistoryToken - { "4B90A437-3D96-4AC9-A27A-E0F633CE5D9D" = 906; }> CoreData: CloudKit: CoreData+CloudKit: -[PFCloudKitExportContext processAnalyzedHistoryInStore:inManagedObjectContext:error:]_block_invoke_3(251): Finished processing analyzed history with 29501 metadata objects to create, 0 deleted rows without metadata. CoreData: CloudKit: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _scheduleAutomatedExportWithLabel:activity:completionHandler:](2800): <NSCloudKitMirroringDelegate: 0x6000015515c0> - Beginning automated export - ExportActivity: <CKSchedulerActivity: 0x60000032c500; containerID=<CKContainerID: 0x600002ed3240; containerIdentifier=iCloud.com.nitramluap.Somnus, containerEnvironment="Sandbox">, identifier=com.apple.coredata.cloudkit.activity.export.4B90A437-3D96-4AC9-A27A-E0F633CE5D9D, priority=2, xpcActivityCriteriaOverrides={ Priority=Utility }> CoreData: CloudKit: CoreData+CloudKit: -[NSCloudKitMirroringDelegate executeMirroringRequest:error:](765): <NSCloudKitMirroringDelegate: 0x6000015515c0>: Asked to execute request: <NSCloudKitMirroringExportRequest: 0x600002ed2a30> CBE1852D-7793-46B6-8314-A681D2038B38 2021-08-13 08:41:01.518422+1000 Somnus[11058:671570] [BackgroundTask] Background Task 68 ("CoreData: CloudKit Export"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(_:) for your task in a timely manner to avoid this. 2021-08-13 08:41:03.519455+1000 Somnus[11058:671570] [BackgroundTask] Background Task 154 ("CoreData: CloudKit Scheduling"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(_:) for your task in a timely manner to avoid this. Just wondering if anyone else is having a similar issue? It never had a problem syncing an initial database restore prior to iOS 15 (beta 4) and the problems started right after installing iOS 15 (beta 4). I've submitted this to Apple Feedback and am awaiting a response (FB9412346). If this is unfixable I'm in real trouble (and my users are going to be livid). Thanks in advance!
24
0
12k
Aug ’21
App clip: userActivity.webpageURL is "https://example.com" for no reason
Hi, when trying to test my app clip, if there's no link in the _XCAppClipURL environment variable in the scheme (Or TestFlight invocation), userActivity.webpageURL is "https://example.com" even though I don't have this link anywhere in my project. This is my code for getting the link (I'm using UI: func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {     guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,        let incomingURL = userActivity.webpageURL else {       return       }       print("Incoming URL: \(incomingURL)")     } I removed _XCAppClipURL from the environment variables in the scheme and when I run the code I get: Incoming URL: https://example.com Is this a bug? How can I get rid of this https://example.com URL?
2
1
1.2k
Aug ’21
Querying imported files and folders on iOS using NSMetadataQuery
Hi all, I’m trying to use NSMetadataQuery on iOS to track changes to folders users have imported from elsewhere but, no matter what I try, I get no results. Following the documentation for searching file metadata with NSMetadataQuery, I’m creating a live query (albeit in Swift) and listening for […]QueryDidFinishGathering and […]QueryDidUpdate. The former fires, with no results, and the latter never fires. I’ve also tried following the Synchronizing Documents in the iCloud Environment example, adding the appropriate Ubiquity keys to my Info.plist and .entitlements file, with no change. I’m importing files and folders using SwiftUI’s View.fileImporter(isPresented:allowedContentTypes:allowsMultipleSelection:onCompletion:), but can’t see how I might security-scope the NSMetadataQuery’s execution (if that’s even a thing?). My test project is on GitHub, but the main parts are below… My query method: extension NSMetadataQueryUbiquitousExternalDocumentsTestApp { func findAccessibleFiles() { query.stop() fileMonitor?.cancel() fileMonitor = Publishers.MergeMany( [ .NSMetadataQueryDidFinishGathering, .NSMetadataQueryDidUpdate ].map { NotificationCenter.default.publisher(for: $0) } ) .receive(on: DispatchQueue.main) .sink { notification in query.disableUpdates() defer { query.enableUpdates() } foundItems = query.results as! [NSMetadataItem] print("Query posted \(notification.name.rawValue) with results: \(query.results)") } query.searchScopes = [ NSMetadataQueryAccessibleUbiquitousExternalDocumentsScope ] query.predicate = NSPredicate( format: "%K LIKE %@", argumentArray: [NSMetadataItemFSNameKey, "*"] ) query.sortDescriptors = [ NSSortDescriptor(key: NSMetadataItemFSNameKey, ascending: true) ] if query.start() { print("Query started") } else { print("Query didn't start for some reason") } } } Info.plist: […] &lt;key&gt;NSUbiquitousContainers&lt;/key&gt; &lt;dict&gt; &lt;key&gt;iCloud.com.stevemarshall.AnnotateML&lt;/key&gt; &lt;dict&gt; &lt;key&gt;NSUbiquitousContainerIsDocumentScopePublic&lt;/key&gt; &lt;true/&gt; &lt;key&gt;NSUbiquitousContainerName&lt;/key&gt; &lt;string&gt;AnnotateML&lt;/string&gt; &lt;key&gt;NSUbiquitousContainerSupportedFolderLevels&lt;/key&gt; &lt;string&gt;ANY&lt;/string&gt; &lt;/dict&gt; &lt;/dict&gt; […]
3
0
2.3k
Sep ’21
What is causing this BadDeviceToken response from APNs?
I am trying to migrate to the new APNs Provider API. Here is how I've been registering for push notifications: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {     //-- Set Notification     if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)])     {         // iOS 8 Notifications: Registering for notifications and types         [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];         [application registerForRemoteNotifications];     }     else     {         // iOS < 8 Notifications         _storyBoard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];         [[UIApplication sharedApplication] registerForRemoteNotificationTypes:          (UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];     }     _storyBoard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];     [[UIApplication sharedApplication] registerForRemoteNotificationTypes:      (UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert)];     if (launchOptions != nil)     {         NSDictionary* dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];         if (dictionary != nil)         {             NSLog(@"Launched from push notification: %@", dictionary);             /*[self addMessageFromRemoteNotification:dictionary updateUI:NO];*/         }     }      return YES; } Within the last week, I have been using the following terminal command from Sending Push Notifications Using Command-Line Tools to successfully send a test push notification to a testing device. curl -v --header 'apns-topic: com.domain.appname' --header apns-push-type: alert --cert aps.cer --cert-type DER --key PushChatKey.pem --key-type PEM --data '{"aps":{"alert":"Test"}}' --http2  https://api.sandbox.push.apple.com/3/device/258ecf658e25256c8f06ddb1138d5d536ba0e760a96ebd12d3b1dbe112857c58 Recently after creating provisioning profile and adding it to Xcode, the app no longer prints the device token in the debug window. After removing the provisioning profile from my Apple Developer account under profiles, I tried using a backed up version of the app which still prints a device token to the debugger window. When I copy the device token and enter it into the terminal command to send another test push notification, the terminal output is a 400 status code : {"reason":"BadDeviceToken"}* Closing connection 1 curl -v --header 'apns-topic: com.domain.appname' --header apns-push-type: alert --cert aps.cer --cert-type DER --key PushChatKey.pem --key-type PEM --data '{"aps":{"alert":"Hello From Faunna"}}' --http2  https://api.sandbox.push.apple.com/3/device/a146d82d4acea02c9ef6de5838174292d0e2cd18a40be17fb79334c5003a0058 * Could not resolve host: alert * Closing connection 0 curl: (6) Could not resolve host: alert *   Trying 17.188.138.73... * TCP_NODELAY set * Connected to api.sandbox.push.apple.com (17.188.138.73) port 443 (#1) * ALPN, offering h2 * ALPN, offering http/1.1 Enter PEM pass phrase: * successfully set certificate verify locations: *   CAfile: /etc/ssl/cert.pem   CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Request CERT (13): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Certificate (11): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS handshake, CERT verify (15): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use h2 * Server certificate: *  subject: CN=api.development.push.apple.com; OU=management:idms.group.533599; O=Apple Inc.; ST=California; C=US *  start date: Feb  8 21:41:22 2021 GMT *  expire date: Mar 10 21:41:22 2022 GMT *  subjectAltName: host "api.sandbox.push.apple.com" matched cert's "api.sandbox.push.apple.com" *  issuer: CN=Apple Public Server RSA CA 12 - G1; O=Apple Inc.; ST=California; C=US *  SSL certificate verify ok. * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x7fbd4700aa00) > POST /3/device/a146d82d4acea02c9ef6de5838174292d0e2cd18a40be17fb79334c5003a0058 HTTP/2 > Host: api.sandbox.push.apple.com > User-Agent: curl/7.64.1 > Accept: */* > apns-topic: com.faunna.PushChat > Content-Length: 37 > Content-Type: application/x-www-form-urlencoded >  * Connection state changed (MAX_CONCURRENT_STREAMS == 1000)! * We are completely uploaded and fine < HTTP/2 400  < apns-id: 8DE6AA75-8E41-E95E-1FAF-51D93A8B3200 <  * Connection #1 to host api.sandbox.push.apple.com left intact {"reason":"BadDeviceToken"}* Closing connection 1 What is causing the bad device token output in this set up? And how should I be registering for remote notifications from this point forward?
5
2
24k
Sep ’21
Can't add new email address with iCloud+ Custom Domain
I've set up a couple of domains (seemingly) successfully with iCloud+ Custom Domains. All the DNS entries are correct. Now, when I attempt to add an email address I get the error "There was a problem with adding this email address. Please try again later." This has been happening for over 24 hours. I'm not quite sure how to proceed - I know this is in Beta, but I keep reading how it is working for other people so its hard to think this is a general problem. I'm adding entirely new domains so there is no chance that the email addresses are previously known by Apple / used for a previous AppleID. Any ideas please?
11
0
4.8k
Sep ’21
Adjust Latency Timer for the AppleUSBFTDI Driver
How do I adjust the latency timer for the AppleUSBFTDI driver? I am developing an app in Swift using Xcode on a MacBook Pro M1 running Big Sur, for clinical brain-computer interface (BCI) research. The app needs very low-latency streaming from an external USB device. The external device is a headset which connects via Bluetooth to an FT231X chip mounted on a USB-Serial dongle. The FT231X chip reads timestamped EEG data from the headset. The issue is that the AppleUSBFTDI driver is buffering the packets coming in from the headset, which causes jitter in the timestamps. Typically, with proprietary drivers from FTDI, the solution is to reconfigure them to reduce the latency timer to 1ms. The Info.plist is edited to add new key/value pairs. Is there a similar solution for Apple's built-in driver?
1
1
1.1k
Sep ’21
Shortcut Donations Not Working
I am implementing a couple custom intents in my app. Having completed the implementation of the custom intent definitions and the intent handlers which presumably should be called on voice command based on the suggestedInovocationPhrase, I am getting stumped with just getting IOS to recognize my shortcut donation. While the shortcut donation is executed multiple times from the view that I am trying to create the shortcut for, it is never being displayed in the shortcut app or on my lock screen as having been donated. In my settings App, I have turned on (under Developer) "Display Recent Shortcuts" and "Display Donations on Lock Screen". Here is the code that is executing each time I think I am making a donation: - (NSUserActivity *) CreateMyShortcut {     NSUserActivity *newActivity = [[NSUserActivity alloc] initWithActivityType: kMyShortCutActivityType];          if (@available(iOS 12.0, *)) {         newActivity.persistentIdentifier = kMyShortCutActivityType;         newActivity.eligibleForSearch = TRUE;         newActivity.eligibleForPrediction = TRUE;                  CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithContentType: UTTypeImage];                  newActivity.title = @"My Shortcut";         attributeSet.contentDescription = @"description";                  newActivity.suggestedInvocationPhrase = @"Create Widget";                  UIImage *image = [UIImage imageNamed:@"MyApp_Icon.jpg"];         NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(image)];         attributeSet.thumbnailData = imageData;                  newActivity.contentAttributeSet = attributeSet;     }     return newActivity; } This is called from the view that I want to create the shortcut for with the following code:     // Donate a shortcut to allow Siri to assist with creating a parts list     NSUserActivity *activity = [[MyDonationManager sharedInstance] CreateMyShortcut];     NSLog(@"Donating Siri Shortcut");     [activity becomeCurrent]; Is there something else I need to do?
3
0
1.7k
Sep ’21
Is subscription autoRenewStatus in StoreKit2 working correctly with Sandbox testing?
It seems that subscription status gives different results with XCode testing and Sandbox testing. I am using StoreKit2 to implement an IAP of an autorenewable subscription. I want to determine whether the subscription has been cancelled, so that the UI reflects that the subscription will stop after the expiry date and not be renewed. the 'willAutoRenew' property of the subscription status renewalInfo seems to do exactly what is required, and works fine in XCode testing. My setup is very similar to the StoreKit demo associated with the WWDC21 session available here: https://developer.apple.com/documentation/storekit/in-app_purchase/implementing_a_store_in_your_app_using_the_storekit_api/ To demonstrate its use, add: print(renewalInfo.willAutoRenew) after line 79 of the SubscriptionsView in the demo project. When you run the app, and purchase a Standard Navigation assistance subscription, the console shows 'true'. If you then cancel the subscription in XCode (Debug:StoreKit:Manage Transactions), the console will show 'false' as expected So far so good. My problem is that when I move to Sandbox testing, and cancel the subscription in another way (eg using the .manageSubscriptionsSheet view modifier, or in Settings:App Store:Sandbox Account), the willAutoRenew property remains true, even though the subscription is in fact cancelled (ie it disappears after the expiry date) Does anyone know a workaround to determine cancellation status?
7
0
4.9k
Sep ’21