I have added date triggered local notifications to my app and now I want the user to be able to get the notification they set on one device on all of their devices that have the app. I save the notification they set in a core data entity (saving the notifcation identifier and date it's suppose to be triggered). The app uses a NSPersistentCloudKitContainer to sync the users devices together.
Since I save the notifications the user sets to this iCloud container, is there a way I can listen to iCloud changes in the app's background so when a notification is added in iCloud, I can read it and set it as a local notification on their other devices?
You can think of this as a user setting a reminder in the Apple reminders app and how that notification pops up on all of my iCloud devices at the time I set it at. I prefer to not make any type server to handle this because I am not familiar with using servers.
Thank you in advance for your help!
Yes, it is possible for NSPersistentCloudKitContainer to sync while your app is the background, and you can react to those changes by listening to any of these notifications: NSManagedObjectContextObjectsDidChange, NSPersistentCloudKitContainer.eventChangedNotification, and NSPersistentStoreRemoteChange (if enabled). There are some important caveats:
iOS may schedule an import to occur with a utility priority, which may or may not execute eventually.
This does not occur when your app is not running as the remote change notifications are non-launching, so for example, if you restart the device sync will not occur until you open the app again. Perhaps you could schedule background tasks to periodically attempt sync to try to keep up-to-date - I have not tried this.
This does seem to be working more reliably in iOS 16 vs 15 in my testing. I've documented my findings in the dev forums.
Related
My app uses a database synchronized between iPhone, watch and iCloud. Until recently, I used custom synchronization code.
Particularly, when data changes on the iPhone, the watch complications were updated via transferCurrentComplicationUserInfo(_:).
This updated the complications more or less immediately.
The new version of the app uses instead CoreData + CloudKit, and iPhone and watch are synchronized automatically with iCloud using the private database.
If, e.g., the iPhone updates data, this is automatically uploaded to iCloud, and iCloud sends a silent push notification to the watch to update the data there.
If I open the app on the watch, the update is applied, and the watch shows the new data. So far so good.
The problem is updating the complication data while the app does not run on the watch.
In my current version, the complications are only updated when the app is activated.
This is obviously not the idea of complications, and I am sure I am missing something.
How can I update the complications even if the app is terminated or in the background?
EDIT due to the comment of Paulw11:
The complication has to be updated as soon as possible after data have been changed on the iPhone.
Since this can happen any time, scheduling a background refresh task in the watch does not solve the problem.
Short answer:
It is possible to send push notifications to a watch, using a push type complication, but this is currently not possible with iCloud.
With iCloud one has to send a silent push, and to update the complications locally.
Long answer:
watchOS 6 implemented the PushKit framework:
PushKit notifications differ from the ones you handle with the User
Notifications framework. Instead of displaying an alert, badging your
app’s icon, or playing a sound, PushKit notifications wake up or
launch your app and give it time to respond.
It uses a PKPushRegistry object that lets you specify a PKPushType, among others complication. Docu:
Use this type of notification to deliver updated data related for your
watchOS app’s complication. The watchOS app’s complication must be
active on the user’s current clock face. If it is not, the system does
not deliver pushes of this type. For watchOS 6 and later, send the
push notification directly to Apple Watch.
The bad news:
PushKit requires a Remote Notification Server. There are many commercial server that let you send push notifications with a specific PKPushType, but iCloud does not.
With iCloud, and thus also with CoreData + CloudKit mirroring, one can store a subscription record in the respective database that generates an internal permanent query. When the query fires, iCloud sends a silent remote notification. It wakes up the app, and the payload lets you update the complications.
There are several subscription types that let iCloud respond to specific changes: CKDatabaseSubscription, CKRecordZoneSubscription, and CKQuerySubscription.
CoreData + CloudKit mirroring with a private database uses a specific zone named com.apple.coredata.cloudkit.zone, so here a CKRecordZoneSubscription may be appropriate, see here. It lets you also specify a recordType, so that push notifications are only sent when a record of this type is modified.
EDIT:
Warning: An update using silent remote notifications is only possible very rarely, and not every push may be handled. The docs say:
The system treats background notifications as low priority: you can
use them to refresh your app’s content, but the system doesn’t
guarantee their delivery. In addition, the system may throttle the
delivery of background notifications if the total number becomes
excessive. The number of background notifications allowed by the
system depends on current conditions, but don’t try to send more than
two or three per hour.
When a device receives a background notification, the system may hold
and delay the delivery of the notification, which can have the
following side effects: When the system receives a new background
notification, it discards the older notification and only holds the
newest one.
This app communicates with a hardware accessory. I would like to have the app woken up once every 24 hours to search for firmware updates for that hardware. If an update is available, a notification will be sent to the notification center and the user can tap it to open the app and download the update.
None of the background modes discussed here seem appropriate. The closest is "background fetch" which is meant for an app that "regularly downloads and processes small amounts of content from the network."
The problems with this (all can be worked around) are:
No way to specify how often to wake up to check for updates
An expectation that if content is available, the app will download it immediately (instead, I just want to send the user a notification so they know an update is available)
So should I use background fetch and work around its limitations, is there a different background mode or API that would be better suited, or is this something an app shouldn't do?
You can use background fetch for this, although you can't control if and when this happens (since the user can disable it). Instead of immediately downloading the firmware update, if you want to inform the user you can schedule a local notification to inform them.
Push notifications are a more appropriate solution for this problem though. Just send a push notification when a new firmware update is available.
Hi i am developing an app that will fetch one qoute from my server everyday and will do a local notification in that app and more when you get inside the app.
I started by implementing Push Notification but then i figured that Local Notifications is what i need.
Official Documentation
For example, applications that depend on servers for messages or data
can poll their servers for incoming items while running in the
background; if a message is ready to view or an update is ready to
download, they can then present a local notification immediately to
inform their users.
The work flow of my app is that i need the app to make a post request to get today's quote and fire a local notification for that (that's the hard part) then when user opens the app i think things are easy.
Th issue here is that that request has to be made while my app is not running.
I'm looking for some help on how to acheive that..
Thanks in advance
Apple introduced in iOS 7 something called Background fetch.
The new Background Fetch capability allows your application to ask to fetch data on a regular basis, so when the user launches or re-opens your application, it can start up with the most current data possible.
You can learn how to implement it here
Another option to consider iOS Silent Push notifications. This will let you update the user database without interacting with him. I'd go with Background fetch, though.
I don't think you can run your app in background unless your app meets one of the background modes specified by apple . If you run your app in background without enabling one of the background modes it may result in app rejection by apple .
Now for your requirement you can simply save the qoute for a particular date from server within local DB once a day whenever user runs the app . By setting local Notification repeat itself at morning everyday you can display qoute of that particular date .
I was wondering how some existing apps refresh their application data while the app isn't running. Lets say we have a rain alarm application. This application send you a (local?) notification when its about to rain in your current location or location you've manually entered. What's the best way to achieve something like this?
Is the application getting weather data on the device itself (even when the application is killed) to send a local notification when its about to rain? Doesn't this method drains the battery of my device?
Or do I need to create a standalone application which runs 24/7 and always checks the weather? It then searches a database to see who's device needs a remote notification.
Other methods are also appreciated.
In iOS6 and before, your app cannot run all the time you want in the background, the system will stop the app after a few seconds.
A way that your example can be achieved is sending push notifications from a remote server.
Note: In iOS7 it will be possible to wake you app when a notification is received and download content.
In my app, I want to check my database every 12 hours for an entry and if found, set a notification.In android,it is accomplished by using a service.But in ios services are not allowed.I tried to implement NSTimer,but it will be reset when the app goes to background.I want my service to be run when the app is on background. On research the only possible way I found is to use push notification.But if the network is disconnected,push notification will not work and notification will not be set that day.Is there any other possible way to implement my requirement please?
Long-running background processes are only allowed for VOIP applications that need to maintain an open connection to a server.
Push notifications are not guaranteed to be delivered, however, if your server sends your iOS device a push notification, the notification will be queued at the APNS server residing at Apple. When the target device is reconnected to APNS, the notification will be delivered.
The only way you can check the database is when your app is running. You can't do it when your app is on background.
Only VOIP, Music and Location based applications can run on background for long durations.
You can use UILocalNotification to alert the user to open your app.