Bug Check: CloudKit MacCatalyst didReceiveRemoteNotification
Asked Answered
U

1

5

I am using MacCatalyst to port an iOS/iPadOS app to MacOS. The app uses CloudKit and functions in all ways except one: the UIApplicationDelegate method, didReceiveRemoteNotification, is not called on the MacOS version when a CloudKit update is submitted from another device

Things that do work in the app:

  • Submitting CKDatabaseOperations including updates and subscriptions to CloudKit
  • Manually retrieving database updates from CloudKit
  • UIApplicationDelegate method didRegisterForRemoteNotificationsWithDeviceToken fires and UIApplication.isRegisteredForRemoteNotifications returns true when calling UIApplication.registerForRemoteNotifications
  • Setting the CKSubscription.NotificationInfo to invoke an alert notification which displays properly in MacOS
  • UNUserNotificationCenterDelegate method, willPresent, when an alert notification is invoked and the app is in the foreground
  • didReceiveRemoteNotification on iOS and iPad (physical devices)

Has anyone had UIApplicationDelegate method, didReceiveRemoteNotification, called when using MacCatalyst?

Update: The app did eventually fire the didReceiveRemoteNotification method 30 minutes after an update was sent, but on other updates, the method is not fired even after hours. Any ideas?

Underclothes answered 16/1, 2020 at 21:31 Comment(5)
Facing same issue in my project, Please share solution if you find solution.Glossology
Are you using simulators when testing the iOS and iPad or real devices? If you are using simulators would recommend trying a few real devices. This, however, will not solve the problem just I found sometimes the simulators do not update correctly. For the delegate not being called, I do not have an answer but will think about that.Hepta
I have a physical iPhone and iPad. They update to each other, and the Mac version pushes to the others just fine. The Mac version can pull updates manually, but it doesn't get notified when the other devices submit updatesUnderclothes
Alright, I actually have had the same problem at times but it is not constant, but I have not found a solution. I am using Swift I do not know if you are using Swift or SwiftUI but personally I have a theory that it could be related to Swift and for it to work perfectly you have to use SwiftUI but I have not tested this idea. The reason I state this too is because all the examples at like WWDC, for instence, all used SwiftUI, but that could be unrelated too.Hepta
@Underclothes have you figured out a solution to this? Facing the same issueHernandez
K
0

I have a possible solution, though the problem I saw was slightly different from what you described. Here's the quick version: use at least a .userInitiated qualityOfService on Catalyst.

Here's what I think is happening.

CKOperation.h provides this documentation:

@discussion CKOperations behave differently depending on how you set qualityOfService.
 *
 *  @code
 *  Quality of Service | timeoutIntervalForResource | Network Error Behavior | Discretionary Behavior
 *  -------------------+----------------------------+------------------------+-----------------------
 *  UserInteractive    | -1 (no enforcement)        | fail                   | nonDiscretionary
 *  UserInitiated      | -1 (no enforcement)        | fail                   | nonDiscretionary
 *  Default            | 1 week                     | fail                   | discretionary when app backgrounded
 *  Utility            | 1 week                     | internally retried     | discretionary when app backgrounded
 *  Background         | 1 week                     | internally retried     | discretionary
 *  @endcode
 * timeoutIntervalForResource
 * - the timeout interval for any network resources retrieved by this operation
 * - this can be overridden via CKOperationConfiguration's timeoutIntervalForResource property
 *
 * Network Error Behavior
 * - when a network request in service of a CKOperation fails due to a networking error, the operation may fail with that error, or internally retry the network request.  Only a subset of networking errors are retried, and limiting factors such as timeoutIntervalForResource are still applicable.
 *
 * Discretionary Behavior
 * - network requests in service of a CKOperation may be marked as discretionary
 * - discretionary network requests are scheduled at the description of the system for optimal performance
 *
 * CKOperations have a default qualityOfService of Default.

Note that the Discretionary Behavior for Default is "discretionary when app backgrounded", and that the description of Discretionary Behavior says that "discretionary network requests are scheduled at the [discretion] of the system for optimal performance". I think that's what's happening in Catalyst; if the app isn't in the foreground, requests become discretionary — i.e., deferrable. And, in my case, the deferral seemed to be indefinite.

Here's what I was seeing.

  • I launched the app on an iPhone
  • I launched the app on a Mac
  • I put the Mac app in the "background" (i.e., it was no longer active)
  • I made a change on the iPhone
  • The Mac received a remote notification
  • In response to the remote notification the Mac tried to download (fetch) records
  • The download request never completed

Here's what I did.

I was already assigning a CKOperationGroup to all of my CKOperations, and I was already assigning a value to defaultConfiguration.qualityOfService. On Catalyst I changed things so that the minimum qualityOfService I assigned was .userInitiated. That made the problem go away in testing. (To be clear, I tried many things; that was the one thing that worked.) I pushed a release out to production last night, and — so far at least — I no longer see the problem there either.

If you don't use CKOperationGroups, no worries, you can set qualityOfService directly on the CKOperations; that should work equally well, it just isn't exactly what I did.

I filed a bug with Apple through Feedback.

Keel answered 17/11, 2021 at 16:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.