Show (local) notification when user closes app from task switcher - ios

I'd like to show a (local) notification to the user when my app is terminated, be it by iOS itself or by the user via the task switcher.
When iOS kills the app because of memory pressure the applicationWillTerminate function is called on my AppDelegate, so I can schedule a local notification in that case.
However, when the user kills the app by swiping it to the top in the task switcher, the applicationWillTerminate function is not called (as stated in the Apple docs and various answers here on SO). And yet, there are apps that still do succeed in showing a (local) notification to the user in that case (especially fitness tracking apps, e.g. Human), asking the user to restart the app so the background tracking can continue.
I can think of some (mostly awkward, or at least battery consuming) ways to get this done, but is there a nice way to show such a notification to the user? Especially to do so almost instantly after the app is killed by the user, which excludes a lot of possible workarounds with scheduling and cancelling local notifications every n seconds in the background ...

Found it ... apparently the apps that show a notification like the one I want to show do it by using background location updates to (re)schedule a local notification so it will never show up, and once they are killed by the user the notification stays active and fires.
Doesn't sound that nice, but probably it's the only way to do it apart from pinging the app from the server periodically.
It would be nice to have a more decent (and energy-efficient) way to do this, e.g. by consistently getting the time to do something just before an app is terminated, no matter the reason for termination.

I tried like this:
Must enable background mode (bluetooth, voip, location service)
Add this code in didFinishLaunchingWithOptions:
[self addLocalNotification];
[NSTimer scheduledTimerWithTimeInterval:9.0f
target:self
selector:#selector(addLocalNotification)
userInfo:nil
repeats:YES];
in addLocalNotification
- (void) addLocalNotification{
NSDate * theDate = [[NSDate date] dateByAddingTimeInterval:10]; // set a localnotificaiton for 10 seconds
UIApplication* app = [UIApplication sharedApplication];
NSArray* oldNotifications = [app scheduledLocalNotifications];
// Clear out the old notification before scheduling a new one.
if ([oldNotifications count] > 0)
[app cancelAllLocalNotifications];
// Create a new notification.
UILocalNotification* alarm = [[UILocalNotification alloc] init];
if (alarm)
{
alarm.fireDate = theDate;
alarm.timeZone = [NSTimeZone defaultTimeZone];
alarm.repeatInterval = 0;
alarm.alertBody =#"App must run" ;
[app scheduleLocalNotification:alarm];
}}
And it works for me. addLocalNotification will run as long as app run/background. Once it is Terminated already scheduled local notification will fire on time. Time interval we can change on our interest.

Related

iOS periodic background location updates which depends not only on significant location change

I have an app which must report user location even if it backgrounded or even killed (terminated). The issue is that the app should report the location not rare than 1 hour interval.
I'm using significant location change (SLC) to track all movements which is quite enough when user is on the go but once user stops no further updates is raised and the app has no opportunity to submit new location (while user stays in the same area but without SLC).
To cover this case I start to use Background fetches to periodically send updates location in background even without SLC). The issue here is that background fetches used to work quite often (every 20-30 min since I used then in another iOS 7.x app) but now with iOS8 / iOS9 I can get it only once a day or so which is not acceptable in my case. I have executed ton of tests, developed simple background fetch app which add a local notification on fetch. No luck to force it to work more often.
Here is my AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
return YES;
}
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
NSDate *now = [NSDate date];
localNotification.fireDate = now;
localNotification.alertBody = [NSString stringWithFormat:#"Background fetch!"];
localNotification.soundName = UILocalNotificationDefaultSoundName;
NSInteger number = [UIApplication sharedApplication].applicationIconBadgeNumber;
number++;
localNotification.applicationIconBadgeNumber = number;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
completionHandler(UIBackgroundFetchResultNewData);
}
All what is done here is to add local notification on every background fetch. I always finalize the background execution with UIBackgroundFetchResultNewData.
Do you have any suggestions on how to force background fetches to work more often (or prove links that it is not possible any more)?
Any alternative solutions to meet my requirement are also welcomed!
It turned out that background fetches in iOS depend a lot on what you are doing within the handler, especially network activity. Here the list of dependencies which you should consider trying to understand if and how often iOS will execute your fetch:
time you spend in handler
result (NoData, NewData)
error handling (you will be launched less likely if you code crashes
timeouts (your code execution could be interrupted by iOS)
power usage
network activity related to result (you MUST do a network request when saying that you have NewData, otherwise your fetch could be executed next time in a day or so never.
Apps that download small amounts of content quickly, and accurately
reflect when they had content available to download, are more likely
to receive execution time in the future than apps that take a long
time to download their content or that claim content was available
but then do not download anything.
The last item turned out to be crucial in my case, because for testing purposes I declared fetches and never tried to download anything. Once I started to use network in the handler, background fetches continue to work as expected every 15-30 minutes.
Apple docs:
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
I worked on a similar project. After trying various solutions, the only way I've found is the solution proposed here:
https://github.com/voyage11/Location
Here is the tutorial corresponding to the git:
http://mobileoop.com/getting-location-updates-for-ios-7-and-8-when-the-app-is-killedterminatedsuspended
All credits to https://stackoverflow.com/users/1995940/ricky
It's saved me a lot of time!

Automatic ON/OFF the GPS tracking in an app running in Background

How can i stop and start the GPS tracking when an application running in background. i Can able to stop tracking in the application, but didn't got any way to start the application. I looking for answers for followings.
1.whether i can use push notification silently to start GPS tracking.
2.I tried with local notification, but it require user interaction to start the process. Is there any best ways to do this.
My problem: Initially i can able start tracking the user location and can stop that after some time in background. I wanted to start the tracking next day. Im looking for a way to start tracking in background.
Actually my application is basically the location tracking application. if the launches the application, the app starts tracking until the time 8:00 pm (stops automatically). Again started tracking next day 8:00 am.
If you started location updates while your app is running in background, these updates will not last longer than whatever time iOS granted for your background task (currently 180 sec).
Location updates must be started while the app is active, doing this ensures the updates keep coming even after your app goes to background, assuming you configured your app background modes properly - see Capabilities/Background Modes/Location updates in Xcode.
Even though, if your app is terminated, the delivery of new location events stops altogether.
If you want to temporary suppress standard location updates, please use
allowDeferredLocationUpdatesUntilTraveled:timeout:
When updates are deferred, GPS receiver is still powered, but no CPU activity happens, as the receiver will not trigger events. I did not test power consumption in this mode myself, but people mention ~2% battery drain per hour.
Have you tried this
-(void)applicationDidEnterBackground {
[self.locationManager stopUpdatingLocation];
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalBackgroundUpdate
target:self.locationManager
selector:#selector(startUpdatingLocation)
userInfo:nil
repeats:YES];
}
Set intervalBackground Update to 1 day

Iphone Background task even after application in closed

I keep reading the documentation and is just not making sense. So i decided to ask the question. Applications on the Iphone like the clock which has an alarm on it. When i set the alarm and close the application the application still notify's me at 4:30am eventhough i have closed the application. Now my understanding is that in order for something like this to work you would have to have it running on the background at all times. This is the part that does not make sense. If i completely shut down the app by double clickin my home button and then swiping up to get rid of the app, how does the app monitor time if is no longer running in the background? Apple states that their are 5 states
1-NOT RUNNING
2-Inactive
3-Active
4-Background
5-Suspended
explanation of the above are located here
i would imagine that when i shut down an application the state is not running. However the alarm application still comes on. HOW? this is killing me. Is there a special state that only native apps can have?
Any information or further understanding would be greatly appreciated.
This is not the case Miguel. What you are looking for is:
https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/Reference/Reference.html
Using UILocalNotifications, your app does not have to keep track of time at all. It schedules a notification, and the operating system keeps track of it. I have built quite a few apps with notifications/alarms. I hope this is helpful.
You can use Local notifications.
iOS will notify user when your previously added local notification fires. [iOS will add notification but your app won't be running at all. When user will tap on the notification then the app will open.]
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UILocalNotification *notification = [[UILocalNotification alloc]init];
notification.repeatInterval = NSDayCalendarUnit;
[notification setAlertBody:#"Hello world"];
[notification setFireDate:[NSDate dateWithTimeIntervalSinceNow:1]];
[notification setTimeZone:[NSTimeZone defaultTimeZone]];
[application setScheduledLocalNotifications:[NSArray arrayWithObject:notification]];
}
Tutorial:
http://www.appcoda.com/ios-programming-local-notification-tutorial/
http://www.icodeblog.com/2010/07/29/iphone-programming-tutorial-local-notifications/
Concept guide:
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Introduction.html

How can I run an iOS voip app in the background without external signaling?

I'm developing a voip app for iPad. I know there are similar questions, but none of the offered solutions have worked so far. I already know that I have to set the voip flag in the info.plist file (I used xcode for that). I have also set the "application does not run in the background" to "no" (who made up that name?!?). I also configured the socket as voip using the following two lines:
CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
I read through the documentation and countless posts on SO and other forums, and there seem to be a few ways to get an app to run in the background forever. I have tried the following:
Start a long running background task, and restart the task when it fires. It was explained here on SO somewhere, but I can't find the post anymore so here is the pseudocode:
expirationHandler = ^{
if (inBackground) {
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];
}
};
inBackground = true;
bgTask = UIBackgroundTaskInvalid;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// inform others to stop tasks, if you like
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyApplicationEntersBackground" object:self];
inBackground = true;
while (inBackground) {
//send a keep alive to my server
sleep(5);
}
});
The second thing I tried was to use setKeepAliveTimeout like this:
[[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{
//send a keep alive to my server
}];
The first one seems to work very well (note that battery life and app-store approval are of no concern to me), but only when the application runs from xcode. When I put the app on the device and run it without debugger, the app stays alive for about 3 minutes and then it dies.
The second one seems to be how it is supposed to be, but my problem with it is that it has a minimum time of ten minutes. My server closes the connection after ten minutes of inactivity and setKeepAliveTimeout seems to be a bit inaccurate, so sometimes it is off by half a second or so (I've experienced 2 seconds one time). This means that once every ten minutes there is a chance that my session to the server is closed.
I use a protocol called XIMSS, used by the Communigate Pro server platform. Most voip apps seem to use SIP, which can send keep alive packets from the server, but that is not a option for me. So how can I make sure my app always wakes in time to send a keep alive? Is there anything that has an interval smaller than ten minutes?

(iOS) How can I speed up the reaction time of "didReceiveLocalNotification:"?

Background
I am in the early stages of learning iOS Development (and Objective C). After the latest tutorial I followed, I decided to take the lesson a little further.
After the tutorial, I had an Alarm Clock application that fired a LocalNotification at a time set by the user. Since the local notification only played the alarm sound while the app was in background mode, I didn't think it was much of an alarm clock. So I set out to add alarm functionality while the app was open and in focus.
Where I am now
My alarm clock application functions exactly as it should. If the app is open, the user receives a UIAlertView and the alarm sound.
The Problem
To trigger the UIAlertView, I am using the didReceiveLocalNotification: method.
There is a fairly big delay between the time set by the user and when didReceiveLocalNotification: is called. 38 seconds to be exact.
I may just be nitpicking, but it's killing me that I can't figure out why. I went out searching through GitHub to find some other examples, and they all seem to be following the same pattern as I am.
What might cause a delay like this? If this is normal behavior, what can be done to get rid of the delay?
Please let me know if any of my code might be helpful. As didReceiveLocalNotification: is a predefined method, and I have no control over when it is called, I'm not sure what code you might need.
Additional Information
Method for setting alarm time
- (void) scheduleLocalNotificationWithDate: (NSDate *) fireDate
{
UILocalNotification *backgroundNotification = [[UILocalNotification alloc] init];
backgroundNotification.fireDate = fireDate;
backgroundNotification.alertBody = #"Wake Up!";
backgroundNotification.soundName = #"My_Alarm.mp3";
[[UIApplication sharedApplication] scheduleLocalNotification: backgroundNotification];
}

Resources