Hello I am planning to develop a simple iPhone game. I would like to be able to distinguish between a genuine crash, and the user killing the app ( by double tapping home screen and long-clicking it to kill it) .
Can someone please shed some light on what exactly happens when the user kill the app through the multitasking bar.
If your app is in the background and suspended when the user kills it, it will receive no notification. This accounts for the majority of cases.
If your app is currently running in the background (there are only very specific categories of apps that can do that), then it receives applicationWillTerminate.
Indeed, Apple is very clear as to the fact that you should save any relevant data before entering the background. Have a look at this (chapter "Responding to Application Termination"):
Even if you develop your application using iOS SDK 4 and later, you must still be prepared for your application to be killed without any notification. The user can kill applications explicitly using the multitasking UI. In addition, if memory becomes constrained, the system might remove applications from memory to make more room. If your application is currently suspended, the system kills your application and removes it from memory without any notice. However, if your application is currently running in the background state (in other words, not suspended), the system calls the applicationWillTerminate: method of your application delegate. Your application cannot request additional background execution time from this method.
EDIT:
about the "saying sorry" thing...
you can certainly do that on the next launch. simply store a key in NSUserDefaults and remove it when the app enters the background (I hope all this sounds familiar to you, otherwise look into the UIApplicationDelegate protocol).
when the app starts up, you check the key; if it is there, then the app was not closed by the user; if the app is not there, then the user at least moved the app to the background and did not experience any sudden termination...
For iOS6 and later there is a way to do this. A side effect of State Restoration is that it will delete the state when there is either a crash during restore or a user manually kills the app. You can use this to your advantage to detect a user manually killing the app.
From the documentation:
Be aware that the system automatically deletes an app’s preserved state when the user force quits the app. Deleting the preserved state information when the app is killed is a safety precaution. (The system also deletes preserved state if the app crashes at launch time as a similar safety precaution.) If you want to test your app’s ability to restore its state, you should not use the multitasking bar to kill the app during debugging. Instead, use Xcode to kill the app or kill the app programmatically by installing a temporary command or gesture to call exit on demand.
The following code assumes that you already have a BOOL for crash detection called _didCrashInLastSession. There are different approaches for getting this value such as this 3rd party library. In your code call the method [self getLaunchType] to see which type of launch you are dealing with and act on that accordingly. Put the following in your AppDelegate.m:
typedef NS_ENUM(NSInteger, LaunchType) {
LaunchTypeUnknown,
LaunchTypeNewInstall,
LaunchTypeNormalLaunch,
LaunchTypeCrashedLastSession,
LaunchTypeUserManualQuit,
};
static BOOL hadStateToRestore = NO;
static NSString * const kAppHasEverRunKey = #"appHasEverRun";
- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder
{
// Called when going into the background
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:kAppHasEverRunKey];
[[NSUserDefaults standardUserDefaults] synchronize];
return YES;
}
- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder
{
// Called on start up
hadStateToRestore = YES;
return YES;
}
- (LaunchType)getLaunchType
{
if (_didCrashInLastSession) {
return LaunchTypeCrashedLastSession;
}
if (![[NSUserDefaults standardUserDefaults] boolForKey:kAppHasEverRunKey]) {
return LaunchTypeNewInstall;
}
if (!hadStateToRestore) {
return LaunchTypeUserManualQuit;
}
return LaunchTypeNormalLaunch;
}
Update: At least one 3rd party SDK breaks this technique: Urban Airship.
You can do it through your device also.
Connect your device to your machine.
Run xcode and go to organizer.
There select your device and device logs.
There you can also see crash logs of your app or game.
Related
I have loaded some values into local documents in my application. When the application is running app writes, say, 50 records.
Now, when the user force-closes the app and starts it again: The files only write the new records 50+existing 50.
How to handle this issue?
If your application is force-quit completely, you do not have an opportunity to write out additional data. No more of your code is run.
If you are talking about the force quit that happens when your app is in the background and the OS wants to free up memory, you must implement a callback in your application delegate (you can use notifications too but let's keep it simple) and observe when the OS places your app in the background. At that point, write your data to disk:
#implementaton MyAppDelegate
- (void)applicationDidEnterBackground: (UIApplication *)application {
[myDatabase commit];
[myFiles save];
[myWhatever doWhatever];
// etc.
}
#end
When press the lock button in app,system will call :
-(void) applicationWillResignActive:(UIApplication *)application and
-(void) applicationDidEnterBackground:(UIApplication *)application
So how can I do to make my app only resignActive but not enter background,and I can run my timer when screen locked(Timer can't execute in background mode).
One method is set the property "Application does not run in background" in .plist to YES,it worked, but my app can never enter background again,however I want it will enter background when press the home button.
Update: I want to play some music in my app at a certain time,just like a music alarm,and I still want it works fine when the screen locked,because keep the screen on may waste a lot of battery,and I don't need to do any thing when user press the home button and exit my app.
Open your Info.plist file and add Application does not run in background. Set value to YES.
Application must have special privileges to do any processing in background such as Audio service/Voip service/Location service.
"I can run my timer when screen locked(Timer can't execute in background mode)"
you cannot run a timer in background which will keep running without using any tentrum and doing so...apple will not accept your application on appstore - that's the worst side if you are targeting appstore...
You can not prevent your app from entering the background. This is decided by the operating system (iOS) and is out of control from applications. However, from reading your updated question, I don't think this is what you need to do.
You can execute background tasks with [UIApplication beginBackgroundTaskWithExpirationHandler;] (see reference). If you want to have something happening after a certain interval, check out [UIApplication scheduleLocalNotification:].
Some services such as VOIP, Audio and CoreLocation are allowed to run in background. Using these for other than their intended purposes (for example, playing silent audio) may risk your app being rejected.
Note that there is nothing you can do to prevent your application from entering the background. It is just that some tasks are allowed to execute in the background. Because of this, you cannot do GUI operations and NSTimers will probably not fire (at least I know some cases where they don't).
It would help knowing what you want to run in the background in order to suggest a solution.
Unless you are playing audio BEFORE the move to background you cannot start audio playback when the app is moved to the background or the screen is locked (which has some weird specifics) suffice to say, its as if you were in the background without actually receiving the applicationDidEnterBackground notification.
The best you can do is schedule a local notification, but in this case your music is limited to 30 seconds and must be part of your application bundle.
I don't mind using private API's or anything of the kind that Apple doesn't like, but would prefer a quick solution that doesn't stuff like playing silence in the background or swizzling.
Obviously this isn't for the app store so please no lecturing :)
So how do you run in the background without any restrictions like "backgrounder"? I didn't manage to find an answer besides some that point people to different directions, but maybe since then someone managed to dig it up already.
Update:
This solution no longer appears to be sufficient (~ iOS 7+ or 7.1+). I'm leaving the original answer for historical reference, and in case it helps produce a future solution based on this obsolete one:
It depends on what you mean by app. If you're talking about a non-graphical background service, then what you want is a Launch Daemon. See here for how to create a launch daemon.
If you have a normal UI application, but when the user presses the home button, you want it to stay awake in the background for an unlimited time, then you can use some undocumented Background Modes in your app's Info.plist file:
<key>UIBackgroundModes</key>
<array>
<string>continuous</string>
<string>unboundedTaskCompletion</string>
</array>
Then, when iOS is ready to put your app into the background (e.g. user presses home button), you can do this, in your app delegate:
#property (nonatomic, assign) UIBackgroundTaskIdentifier bgTask;
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Delay execution of my block for 15 minutes.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 15 * 60 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
NSLog(#"I'm still alive!");
});
self.bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
// should never get here under normal circumstances
[application endBackgroundTask: self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
NSLog(#"I'm going away now ....");
}];
}
Normally, iOS only gives you up to 10 minutes for your UI application to work in the background. With the undocumented background mode, you'll be able to keep alive past that 10 minute limit.
Note: this does not require hooking with MobileSubstrate. If you're using the second method (undocumented Background Modes), then it does require installing your app in /Applications/, not in the normal sandbox area (/var/mobile/Applications/).
Depending on what your "app" is going to do, you can hook MobileSubstrate. This will load with SpringBoard and essentially run "in the background".
If you want to write an actual application, then you can also write a "Dynamic Library" which will be loaded with SpringBoard by MobileSUbstrate. You can talk back and forth between this dylib and your app by using NSNotificationCenter; creating and posting notifications.
first of all, I know there is only support for voip, audio and location apps to run in background and that they will run just while the audio is been played or while using location services, etc.
What I want to know is if there is a way to keep my app running on background fully operational, doesn't matter the impact on battery's life.
That way the user of my app can select from settings to keep alive the app whenever he wants and just for the amount of time he wish. e.g if he is waiting for something that requires the app to be running, after receiving the messages he can turn off the keep alive functionality.
I don't know if this is possible but I had read some post that say so but unfortunately they didn't say how to =(
UPDATE: In this tutorial, I found that Acrobits has two apps on the Apple Store that "can force the application to stay alive and awake in the background". So there is a way to do this?
From ioS 7 onwards, there are newer ways for apps to run in background. Apple now recognizes that apps have to constantly download and process data constantly.
Here is the new list of all the apps which can run in background.
Apps that play audible content to the user while in the background, such as a music player app
Apps that record audio content while in the background.
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Apps that need to download and process new content regularly
Apps that receive regular updates from external accessories
You can declare app's supported background tasks in Info.plist using X Code 5+. For eg. adding UIBackgroundModes key to your app’s Info.plist file and adding a value of 'fetch' to the array allows your app to regularly download and processes small amounts of content from the network. You can do the same in the 'capabilities' tab of Application properties in XCode 5 (attaching a snapshot)
You can find more about this in Apple documentation
You can perform tasks for a limited time after your application is directed to go to the background, but only for the duration provided. Running for longer than this will cause your application to be terminated. See the "Completing a Long-Running Task in the Background" section of the iOS Application Programming Guide for how to go about this.
Others have piggybacked on playing audio in the background as a means of staying alive as a background process, but Apple will only accept such an application if the audio playback is a legitimate function. Item 2.16 on Apple's published review guidelines states:
Multitasking apps may only use
background services for their intended
purposes: VoIP, audio playback,
location, task completion, local
notifications, etc
If any background task runs more than 10 minutes,then the task will be suspended and code block specified with beginBackgroundTaskWithExpirationHandler is called to clean up the task. background remaining time can be checked with [[UIApplication sharedApplication] backgroundTimeRemaining].
Initially when the App is in foreground backgroundTimeRemaining is set to bigger value. When the app goes to background, you can see backgroundTimeRemaining value decreases from 599.XXX ( 1o minutes). once the backgroundTimeRemaining becomes ZERO, the background task will be suspended.
//1)Creating iOS Background Task
__block UIBackgroundTaskIdentifier background_task;
background_task = [application beginBackgroundTaskWithExpirationHandler:^ {
//This code block is execute when the application’s
//remaining background time reaches ZERO.
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//### background task starts
//#### background task ends
});
//2)Making background task Asynchronous
if([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)])
{
NSLog(#"Multitasking Supported");
__block UIBackgroundTaskIdentifier background_task;
background_task = [application beginBackgroundTaskWithExpirationHandler:^ {
//Clean up code. Tell the system that we are done.
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
}];
**//Putting All together**
//To make the code block asynchronous
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//### background task starts
NSLog(#"Running in the background\n");
while(TRUE)
{
NSLog(#"Background time Remaining: %f",[[UIApplication sharedApplication] backgroundTimeRemaining]);
[NSThread sleepForTimeInterval:1]; //wait for 1 sec
}
//#### background task ends
//Clean up code. Tell the system that we are done.
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
});
}
else
{
NSLog(#"Multitasking Not Supported");
}
For running on stock iOS devices, make your app an audio player/recorder or a VOIP app, a legitimate one for submitting to the App store, or a fake one if only for your own use.
Even this won't make an app "fully operational" whatever that is, but restricted to limited APIs.
Depends what it does. If your app takes up too much memory, or makes calls to functions/classes it shouldn't, SpringBoard may terminate it. However, it will most likely be rejected by Apple, as it does not follow their 7 background uses.
May be the link will Help bcz u might have to implement the code in Appdelegate in app run in background method ..
Also consult the developer.apple.com site for application class
Here is link for runing app in background
While going through the iOS-4 Multitasking for fast context switching, I have a doubt regarding save last state of application.
Do applications have to manually save the last state in "- (void)applicationDidEnterBackground:(UIApplication *)application"? Or iOS-4 will take care of it?
In the video it's mentioned as follows:
-(void)applicationDidEnterBackground:(UIApplication *)application {
// save app state
[self saveState];
// reduce memory usages
....
// prepare UI
....
// close listening sockets
....
}
Thanks in advance,
Sunil
Once your application has entered background, there's no guarantee it will ever come back to the foreground. It may at any point in time be terminated, without notification of any kind. Thus, entering background, you want to save the state or risk losing it.
To quote Apple (source: http://developer.apple.com/iphone/library/documentation/iphone/conceptual/iphoneosprogrammingguide/BackgroundExecution/BackgroundExecution.html),
Save your application state before moving to the background. During low-memory conditions, background applications are purged from memory to free up space. Suspended applications are purged first, and no notice is given to the application before it is purged. As a result, before moving to the background, an application should always save enough state information to reconstitute itself later if necessary. Restoring your application to its previous state also provides consistency for the user, who will see a snapshot of your application’s main window briefly when it is relaunched.
Do applications have to manually save the last state in "- (void)applicationDidEnterBackground:(UIApplication *)application"? Or iOS-4 will take care of it?
Yes, if you want your app to restore after it's been killed, you need to manually save state here.
you should use these 2 methods in your app delegate to save current state before entering background/terminate.
- (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)applicationWillTerminate:(UIApplication *)application {
/*
Called when the application is about to terminate.
See also applicationDidEnterBackground:.
*/
}