I'm making a simple app with a Today Widget extension that logs events.
The user can tap a button in the app or the related Today Widget to log an event. These events are saved with Core Data any time the button is pressed either place.
Whenever a new event is logged in the app, I run a function called updateLocalNotificationsFromCoreData(). It handles the setup of UILocalNotifications based on the most recent event in Core Data after clearing the appropriate existing notifications.
However, when a new event is logged from the Today Widget, I can't use this function because I need to register the Local Notification with UIApplication.sharedApplication().scheduleLocalNotification(), and UIApplication is not available in the Today Widget extension.
I realize I'll probably need do something unconventional or hacky to get this working, so I'm trying to evaluate possible approaches and come up with a relatively robust solution.
Basically, I want to find a way I can call my
updateLocalNotificationsFromCoreData() function right away any time a new event is logged.
If I can't do it every time an event is logged, an alternative would be to trigger the updateLocalNotificationsFromCoreData() function periodically (somewhat frequently) another way. Here are some solutions I was thinking about using, but I don't like any of them:
Do it in AppDelegate when the app is launched (or another state change)
One approach I'm thinking about is running my updateLocalNotificationsFromCoreData()function in AppDelegate somewhere, like didFinishLaunchingWithOptions.
The downside is that it would require the user to open the app periodically. If the user didn't open it much the notification behavior would be inconsistent. I'd prefer a solution where a user could interact with only the Today Widget and reliably get Local Notifications without ever opening the app.
Sync the events to a server and use Push Notifications
I've thought about syncing the data in Core Data to a server, then setting up Push Notifications to the user's phone based on that.
I don't like this, because I want the user to still be able to get notifications without an Internet connection. It also introduces a lot of extra overhead of syncing the data with a server.
Ping a server, and send a content-available Push Notification
When someone logs an event with the widget, I could ping a server. That server could send back a silent content-available push notification to trigger the app to run updateLocalNotificationsFromCoreData() in the background.
I found a similar question (Scheduling local notification from within a Today extension) where one answer proposes a similar solution. Unlike the previous solution, an Internet connection is not needed to receive the notifications, but an Internet connection would be required to make sure the notifications are up to date when a new event is logged.
Background fetch
I thought about using Background Fetch to fetch something arbitrary from a server, then run the updateLocalNotificationsFromCoreData(). This would be a way to trigger the update in the background, although it seems silly to fetch data if that data isn't being used, and seems like something for which an app could be rejected. There also seems to be a risk of the system not calling the background update regularly if the user doesn't open the app much and mostly uses the Today Widget.
Use background location updates
This seems like the dumbest approach, but I thought I would mention it anyway since I thought about it. I could use one of the low accuracy background location update modes to trigger updateLocalNotificationsFromCoreData().
It would require the user to allow location in the background, which would be hard to explain. And, it would require the user to at least move around a few blocks to trigger the function, which could provide an inconsistent user experience. Also, it would increase power consumption of the app for a silly reason.
I'd really appreciate fresh ideas about how I might be able to reliably schedule local notifications when Core Data changes on a device that doesn't have an Internet connection!
Or, if that doesn't seem possible, I'd appreciated feedback on which approach seems to make the most sense.
EDIT: I came up with a new solution. It's not ideal, but I think it's better than these other approaches I was considering. When someone taps the button to log the event, I launch the full app. It's annoying because I have all the data I need at that point to give the user feedback and log the event within the Today Widget without launching the app, but by launching the app I have the opportunity to check and schedule local notifications.
Also, in iOS 9 the annoyance on the user is slightly minimized because the system-wide "back" button will appear and let the user go back to the previous app easily once my app has launched from the Today Widget.
In the future I may try a solution where one of the server-based approaches above is used when an Internet connection is available, and I would then fall back to this system of opening the app only when the network connection is not available and I need to schedule the local notifications within the app.
Related
I Did lots of BG tasks in the past, But Trying to get data when app is killed (Even when user is giving Always permission) seems not to work.
I wonder if there is a solution for that.
To make things clear, I am not talking at the moment when app change from Active or Background even to suspended mode. I'm talking about if the user is using the app and set permissions but then kills the app and after that i need every hour to get data from the user and send data to them.
Is there a way to do that?
Can a Today widget help me with that? Does a Today widget "lives" all the time and i can get that from it 24/7?
Whet is working is CLLocation manager. This is working even when the app is killed. But only when the user is changing a location.
I need that to work when the user is in the same place also.
Non of the other methods work. Not BGTask (I need every hour on the hour and not when apple decide to do things), Nor Silent Push Notification for some reason (Regular ones work, but i Don't want to bother the user with a push every hour just for getting and sending data).
Sorry there is no code to show as this is a very general question. But i think that is very important one to many people and can't find an answer for that.
I need to notify user when a certain condition is met but that condition might or might not meet in months. I need to run condition check in background (even when app terminates) so that I could detect condition is met (even if it happens after 3 months). If condition is met then I need to send notification only to a single user (not all users).
I am not sure what is the best way of doing it. Local Notification or Push Notification? I can not schedule a local notification in advance because I don’t know when it will meet the condition. I think Push notification is not needed because I am sending only one notification to only one user in several days/months.
I also need to constantly run this check in background. I know it can be run infinitely in background by using location update (significant monitoring or background navigation). But my condition checking code doesn’t actually require location updates. As far as I understand, Apple allows only location update or network related task in background (for few minutes). That's why I am thinking of putting my code in background location update code.
In my opinion , I should use local notification and put my code in background location update code so that I could check constantly if certain condition is met. This background check will schedule local notification and show it to the user who is using that device. I don’t think it is possible to schedule a push notification by code running in background.
In summary, I have following 3 questions
Should I put my code in background location update? If not, what is the right approach of running my code infinitely in background without location update?
Will Apple reject application if I put my code in background location update while location update code doesn’t actually send/receive current location?
What kind of notification should I use in this kind of situation where I send notification to a single user after months? Would you use Local Notification? or Push Notification.
Please reply. Any help is truly appreciated.
Thanks in advance.
This is a bit of a tricky problem unfortunately.
Apple won't allow you to create long-running operations in the background. As you mentioned, you can add code in the background with location updates or audio, but neither of those are very good solutions since (1) Apple will likely reject you from the app store and (2) the user will probably close the app if they notice a big locations banner at the top of their phone (or a weird background audio signal), and closing the app will kill your operation. For any truly long-running tasks it's probably best to set up a server and run a cron job or equivalent long-running operation. It's the only way you can know that the task will continue running.
Sorry, I was just answering one at a time, but as I mentioned above, yes, they'll probably reject your code for that. As a rule of thumb: if you think the Apple-created code you're using wasn't meant for what you're using it for, Apple will probably reject your app.
It sounds like you should use a remote notification. If you do use a remote notification, you'll probably want some sort of backend anyway. You could use a local notification to notify a user after a few months, but you would need to know the exact time to send it up front, which it doesn't sound like you would.
In summary: Try to build a simple BE. Maybe use Firebase Functions or something, and also build an APNS system to send pushes. In the app, tell the server to start processing the information and send the push back when it's done. The situation sounds like a perfect use case for server-side logic.
Hope that helps!
I am looking for a good way how to make my app "upToDate". These are my requirements:
I have an RESTful Webservice, with tasks for different users. Every user has an iOS App, which should get automatically updated when the Server/Service assigned a task to that User.
So first ill created a manuall "Sync" Button, which checks for new Tasks. Fetches the data with Alamofire, and updated the UI.
But, my goal is automatically sync if there are new tasks.
So, ill guess there are 2 different ways to solve that:
1. Make a Background Fetch (with a NStimer?) every xx Minutes and check if there are new tasks.
After checking that tutorial here:
http://www.raywenderlich.com/92428/background-modes-ios-swift-tutorial i am not sure if a background fetch is a good way to solve that. In that case the App uses an scheduler, to check once for new updates, and not every xx minutes.
So in my case i would create an NStimer in the AppDelegate (maybe in applicationDidEnterBackground) and check every xx minutes for new data (but when there are 3 days not any new task, that would be unnecessary battery consumption, or?)
2. Using Push Notifications.
My other idea is to use Push Notifications, so when there is a new task, ill send a Push Notification an manually start the sync. In my opinion that would use less battery, because he will only start the sync when there is a new task available.
Generaly Questions about using Background Services
So ok, if the user finished the task, some data should be automatically uploaded to the server. Normally not a problem, with the manual sync ill check if there is something to upload. But, what if, when there is no internet connection (ill check if before uploading) - and the user do not press on "manual sync".
So i would prefer to check in my "Background Service" if ill got an Internet connection, and if yes - start uploading some data.
Ill know this is not a specific question, but ill think there are lots of users who have the same requirements and it would be great if someone can help me out whats the best way to solve that in the best and practical way.
Thanks in advance!
Background updates sound wonderful until you realise that Apple throttles them heavily: you can ask to be updated as frequently as possible, but iOS decides what that value actually means based on how often users open your app and when they do so. Apple considers background updates the kind of thing that should happen just before a user opens your app so the latest content is right there, rather than something that runs proactively in the background.
Your push notification solution is a better one, particularly if you use CloudKit to subscribe to record change events using CKSubscription and CKNotificationInfo. If you do this you'll automatically get push messages in your app, so you can get what you want with very little work. You can read my tutorial for more information on subscribing to CloudKit to get push messages.
I have an app that needs to update every time a java web application creates more data. Simple enough, right?
But I found out that my app can`t run in background to ask for more data periodically, and I think I need to use the push notification system. That seems to be overly complicated for a really small thing.
And then, reading about it, I found out that the push notification can never arrive! For example, if the app is offline when the push notification is sent but is online a few moments later.
So, in that case, how can I update the data? I only bring data from the server when the user logs in. I didn't want to do that every time the application became active...
I guess there is a simple solution but this is my first app, any help would be appreciated.
You see why you should read your question before posting it?
And then, reading about it, I found out that the push notification can
never arrive! For example, if the app is offline.
So, in that case, how can I update the data?
Guess what, if you are offline, there is not much you can do... Moving on to serious things:
iOS7 allows you to do periodic background fetchs (check the Multitasking Enhancements). Have this tutorial.
I'm trying to look for a way as to how I can notify a user of new updates based off of a .Net API that I created. Much like that notification you get on facebook, I just need to alert the user that something has been updated. So I'm thinking I need a function that runs in the background while my user uses the app combined with a NSTimer.
Based on my research (and on this question https://stackoverflow.com/a/14835300/639713) apparently you can only achieve such a thing for VOIP and location services. And that using push notification is the only way. Is it really the only option that I can use for such a need? Or are there any other ways?
Thank you for your time.
You have two options:
While your app is open, poll the server every so often to see if there are any updates to report.
This will work only as long as the user has your app open, and as you note, your app will only be allowed to stay open for a long time if it happens to be a VOIP or navigation app.
Use push notifications to push updates to the user’s device.
The disadvantage here is that you will need to write some server-side code to talk to Apple’s push notification servers (as described in this tutorial). This may or may not be a big deal in your particular situation, but it’s the only way to get data to the user when your app isn’t open.