In my app I am using CLLocationManager and AdWhirl. I have made no specific development regarding background mode: I don't want my app to be working when it is in background, i.e. when the user press the "home button", GPS location should no be updated.
Yesterday evening I pressed "home button", and this morning the iPhone was out of battery. It's an iPhone 4 with iOS 4.1, not jailbreaked, and there is no background app running.
The battery was about 35% yesterday evening, and 0% this morning (iPhone was shutdown).
I have set breakpoint in my delegate, which is called each time GPS location is updated. When app is in background mode, delegate is not called. So I'm thinking GPS is really disabled in background mode: ok.
This morning, I am following battery drain: it's about 1% drop each 15 min. I think it a bit too much.
Should I do something specific when the app goes to background mode? Do you think this 1% drop is normal?
Yes, internet access and GPS are two big drains on battery. I don't know at all what you mean with normal, since no other apps are running you've concluded that that is in fact what happens :) Assuming you've tested with NO apps running and didn't get 1% per 15 minutes...
For adwhirl, it's unknown whether it already stops accessing the internet when the app goes into the background, but you can add this to your App Delegate:
- (void)applicationDidEnterBackground:(UIApplication *)application {
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
*/
[lm stopUpdatingLocation];
[adView ignoreAutoRefreshTimer]
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
/*
Called as part of transition from the background to the active state: here you can undo many of the changes made on entering the background.
*/
[adView doNotIgnoreAutoRefreshTimer]
[lm startUpdatingLocation];
}
(lm and adView are the Location Manager object and the adWhirlView, both declared in the App Delegate. I've found it more useful to do all location managing via methods I make in the App Delegate.)
Related
I've tried this iOS Sprite Kit tutorial and have created a similar app. However, I notice that when I press the home button to go to iOS home screen, I get a bad access exception in xCode. When I go back into the app, it starts from the beginning.
How can I properly close/minimize a Sprite Kit app to avoid that exception?
I tried this within the view controller presenting the scene, but it does not get called:
-(void)viewWillDisappear:(BOOL)animated
{
SKView * skView = (SKView *)self.view;
skView.paused = YES;
[super viewWillDisappear:animated];
}
I found out that there's Kobold Kit sprite engine built on top of Sprite Kit, after porting my project to that, i can minimize the app and restore it with the same stuff on the screen!
I believe that the proper way to handle minimizing an app is in the AppDelegate via these methods :
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
I have created GPS base Application.
In which App logged GPS data every 1 second.
App used the NSTimer to fetch GPS data every second.
This NSTimer is start in background. The NSTimer is start when app received the silent push notification from APNS.
I have seen a problem in iOS 7 that when Phone attached with power cable at that time timer call appropriately but without attached power cable timer stops while App in background.
Any inputs to resolve this issue greatly appreciated.
An NSTimer is not guaranteed to fire if your app is not in foreground. Once you unplug the cable the system puts your app into background to save battery.
Using an NSTimer is not the supported method to get location data. Your CLLocationManager will tell its delegate when there is a new location. No need to poll it.
If you need to track geolocation in background you need to declare location updates as a background mode from the capabilities tab in Xcode 5 target settings. Otherwise your location manager will stop delivering location updates once your app is not in foreground.
There are only few use cases that you can implement for foreground. If you don't want your application to be refused within review please don't use any hacks. Of course, you can use NSTimer in background, but it must be created in thread (runloop) of background task. But this background task lives for the only certain amount of time, so your timer must fire during this period. In other words, your first goal is to create background task, and only then you can use the timer. There are few cases suitable for your purpose (that allow you to create this task): 1.Monitor significant location changes or region 2.Fetch data (iOs 7). So please refer
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(#"BG fetch in action");
//the only 30 sec is allowed to perform all your actions
//during this period you can each second track GPS data
[self performSelector:#selector(finishBackgroundFetch:) withObject:completionHandler afterDelay:27];
[[NSNotificationCenter defaultCenter] postNotificationName:#"StartMyGPSRoutine" object:nil];
}
-(void)finishBackgroundFetch:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(#"BG fetch completion handler");
[[NSNotificationCenter defaultCenter] postNotificationName:#"ForceStopAnyBackgroundTaskCreatedWithStartMyGPSRoutine" object:nil];
completionHandler(UIBackgroundFetchResultNewData);
}
of your application delegate -- this will be useful in your case as well as monitor significant location changes.
You ought to put anywhere:
if ([[UIApplication sharedApplication] respondsToSelector:#selector(setMinimumBackgroundFetchInterval:)]) {
NSLog(#"Set Force BG interval to %ld", interval);
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:interval];
}
In my case I fetch the GPS data each 5 min so 27sec to complete this task is not so long. Anyway you can play with time intervals with XCode. Please refer Main Menu->Debug->Simulate Background Fetch
I am developing a game for the iPhone. I do not actually have an iPhone, so I am testing my game on an iPod device (version 4.2.1). When I press the home button the game starts from level one. I find this odd, since in the simulator, after pressing the home button, the game starts from the same state where I stopped. I am unsure as to why the behavior is different on the iPod, maybe I need to handle the AppDelegate method differently (is it not handled automatically depending upon the device?)
How can I handle this issue?
It appears that the device you are testing your app on does not support multi tasking.
The older iPod touches and iPhones do not support multi tasking an close the app rather than suspending them.
All device that can run iOS 4.3 or higher will support backgrounding. Devices that can't update above 4.2.1 will not support backgrounding and app will be closed if you press the home button.
You will need to save the game state in the apps delegate applicationWillTerminate:
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
Save the current game state here and read them in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
Hi I have read several questions on SO about applicationWillTerminate getting called and not getting called.
I wanted to summarize what I understood as there are several posts that speak differently.
For IOS (without multitasking) it is called always when home button is pressed.
For IOS 4 and above
a. it is not called when pressing home button (as the app moves to background)
b. it is called when closing the app from the multi tasking dock and if the app has a sudden terminate flag in info.plist disabled else it is not called. ( I set the "Application should get App Died events" and even then on closing the app from the multitasking dock the terminate function did not get called)
Based on that I had a couple of questions
Is it a good practise to set the Application should get App Died events flag? ( I set the "Application should get App Died events" and even then on closing the app from the multitasking dock the terminate function did not get called)
or
Is registering for "UIApplicationWillTerminateNotification" a better thing to do than the info.plist setting?
Basically I need to do some work only when the app terminates and NOT when it moves to background.
or
EDIT (1):
When the app is terminated the following is sent to the APP. How do I catch it?
Program received signal: “SIGKILL”.
EDIT (2):
Please note : It is not getting called in IOS 4 and above when removing from the multitasking dock. You might think it is. But in my case it is not.
I am asking if anyone knows why? Is there something else I am missing.
Also Note I set the "Application should get App Died events" and even then it is not getting called.
EDIT (3):
The answer for the following question also did not work.
applicationWillTerminate does not get invoked
Anybody facing the similar issue as me?
In short, unless you have UIApplicationExitsOnSuspend in your Info.plist set to YES, in iOS4 and above there is no guarantee that applicationWillTerminate: will ever get called.
As the documentation says:
For applications that support background execution, this method is
generally not called when the user quits the application because the
application simply moves to the background in that case. However, this
method may be called in situations where the application is running in
the background (not suspended) and the system needs to terminate it
for some reason
(Emphasis mine.)
If you need to do something before the app exits you need to do it in applicationDidEnterBackground:. There is no way to catch SIGKILL.
I see -applicationWillTerminate: getting called with the following test. In a new project (I used the 'Single View Application' template), add the following to the AppDelegate:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(#"%s", __PRETTY_FUNCTION__);
__block UIBackgroundTaskIdentifier identifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
if (identifier != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:identifier];
identifier = UIBackgroundTaskInvalid;
}
}];
dispatch_async(dispatch_get_main_queue(), ^{
for (int i=0; i < 20; i++) {
NSLog(#"%d", i);
sleep(1);
}
if (identifier != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:identifier];
identifier = UIBackgroundTaskInvalid;
}
});
}
- (void)applicationWillTerminate:(UIApplication *)application
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
This example will start a background task when the app enters the background. The task is just a 20s delay (with logging once a second) that keeps the app running in the background (note the difference between running in the background and suspended) long enough to allow it to be killed from the app switcher.
So, to test it, run the app, hit the home button to send the app to the background, then before the 20s delay is up, remove the app from the app switcher. After the end of the 20s, -applicationWillTerminate: is called. You can watch the console in Xcode to verify that this is the case.
I tried this in the iOS Simulator for iOS 5.1 and 6.1 (both iPhone) and saw it happen in both cases. I also tested on iPhone 4S running iOS 6.1.2 and saw the same behavior.
As I know, there are 3 situations that your application will die.
Terminated by the end user, you can do something in -[UIApplication applicationWillEnterBackground:], in which case, -[UIApplication applicationWillTerminate:] will NOT be called.
Dropped by the system, such as memory not enough, you can do something in -[UIApplication applicationWillTerminate:], in which case, we do NOT know whether applicationWillEnterBackground: has been called;
Crashed, nothing can be done except using some kind of Crash Reporting Tool. (Edited: catching SIGKILL is impossible)
Source: http://www.cocos2d-iphone.org/forum/topic/7386
I copied my state saving code from applicationWillTerminate to applicationDidEnterBackground and also added a multitaskingEnabled boolean so that I only call state saving in applicationDidEnterBackground. BECAUSE, there is one instance on a multitasking device where applicationWillTerminate is called: If the app is in the foreground and you power off the device. In that case, both applicationDidEnterBackground and applicationWillTerminate get called.
As we know that the App has only 5 sec when -applicationWillTerminate being called. So If someone want to update the server at that point. Than use
Synchronous call.
[NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:&error];
Note:- -applicationWillTerminate will not call if app is being killed from suspended state. Suspended state means app is not working anything in backgroupd. One of the solution for this is to use background task.
Based on Andrew's test, I understand the docs for applicationWillTerminate(_:) to be meant as having the following clarifications:
For apps that do not support background execution or are linked against iOS 3.x or earlier, this method is always called when the user quits the app. For apps that support background execution, this method is generally not called [right away] when the user quits the app because the app simply moves to the background in that case. However, this method may be called [instead of beginBackgroundTask(expirationHandler:)] in situations where the app is running in the background (not suspended) and the system needs to terminate it for some reason.
// absolute answer applicationWillTerminate
func applicationWillTerminate(application: UIApplication) {
print("applicatoinWillTerminate")
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
step 1: command + shift + h (double click(tab))
step 2: move app top side (kill)
step 3: applicationWillTerminate Work
My application is a coupon shopping,users will download the coupons in phone and when completed they will be directed for the automatic cash payment.
If a user downloads 5 coupons and inbetween gets a call as it is iOS4 it goes to background.
So when we press the home button also the application goes to background by this behaviour.I have save few data and restore the coupons when the user quits the application by homebutton.
But in iOS 4 behaviour homebutton press and phone call interruptions shows the same behaviour and calls the same functions,how i could differentiate between the 2.
Please this is a tedious function,please help me.......
Without multi-tasking: For applications that do not support background execution or are linked against iOS 3.x or earlier, applicationWillTerminate: method is always called when the user quits the application. For applications that support background execution, this method is generally not called when the user quits the application because the application simply moves to the background in that case.
With multi-tasking: You can implement applicationWillResignActive:delegate method in your app delegate, which gets called during temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
- (void)applicationWillResignActive:(UIApplication *)application {
flag = YES;
[self doCleanUp];
}
- (void)applicationWillTerminate:(UIApplication *)application {
if (!flag) [self doCleanUp];
}
iOS will not tell an app what caused an interruption such as a phone call, an SMS message, or a press of the home button. This is a deliberate design decision by Apple. Apple expects apps to be designed to exhibit the same behavior no matter what caused the interruption.