My app uses local notifications based on the timing of events logged with Core Data.
Any time there is a significant change in my Core Data store on the device, I call a function called updateLocalNotifications()
that clears existing local notifications and sets up new ones based on the updated data in Core Data.
My NSPersistentStoreCoordinator
for Core Data is set up with NSPersistentStoreUbiquitousContentNameKey
, so it syncs across devices automatically using iCloud.
Ideally, if the user is running my app on two or more devices, I'd like to be able to run updateLocalNotifications()
on all devices whenever the Core Data on iCloud changes.
I have this simple code in AppDelegate to listen for and respond to changes to data on iCloud:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// update local notifications whenever new iCloud data is received
notificationCenter.addObserver(self, selector: #selector(updateLocalNotifications), name: NSPersistentStoreDidImportUbiquitousContentChangesNotification, object: nil)
...
return true
}
If the app is open and in the foreground on both devices and I log an event on one device, I get the NSPersistentStoreDidImportUbiquitousContentChangesNotification
on the other device within about 20 seconds.
The problem is I don't ever seem to get NSPersistentStoreDidImportUbiquitousContentChangesNotification
when the app is running in the background on the second device. I've done lots of digging, but can't seem to find whether the iCloud sync is actually supposed to be happening in the background, or will only ever happen when my app is in the foreground. I'm still testing this to see if it's just a longer update interval when the app is in the background.
Possible Solution #1 (doesn't seem feasible based on testing so far, but this is what I want to do)
At this point, I'm looking for a solution to get the second device to check iCloud for changes while it's in the background and so a NSPersistentStoreDidImportUbiquitousContentChangesNotification
is triggered when there are changes and firing this notification, even if it's less frequently than when the app is in the foreground. There are definitely drawbacks for this approach, like it won't be called if the person manually quits the app after launching it.
Possible Solution #2 (seems possible but complicated)
Another possible solution I'm considering would be to set up a server and use silent push notifications with content-available
. That way, when someone logs an event on one device I would ping the server and ask it to send a content-available
push to the user's other devices, and I could call updateLocalNotifications()
when responding to that push notification. This has a few drawbacks. One is that the content-available
push would not work if the app has not been launched after the device is booted or has been manually quit (similar to Solution #1). A second is that it involves a lot more overhead of setting up a server and pinging a server every time the events on a device change, even though that info is already being sent to a server via iCloud.
I've found a few other similar questions (like this one: How can I act on Core Data iCloud sync notification when the app is in the background?), but they don't put forward any possible solutions, so I thought it was worth posting my situation and possible solutions in case there are other people trying to work through a similar problem.
I would prefer a UX design solution for this problem.
It is questionable that the user wants to have your reminders pop up on all her devices. You should provide a setting where the user can switch them off, or rather, on. Make it clear to the user that the reminders will be device specific and that they will only be updated when the app is active, but based on the input from other devices.
For most users this will be expected and acceptable behavior.