ios app exit gracefully after handling a crash - ios

I have written my own crash handler for my iOS app - the reason why I did not use an existing one like Flurry or Crashlytics is not important.
My problem is that I am not able to call the default signal handler or exit the app gracefully. Instead after the app crashes it freezes on the last screen it was when it crashed instead of exiting the app like it would if I was not hooking on to signals.
My crash handler is simple and works fine. But the default handler is not called or the app does not close.
struct sigaction newSigAction;
static struct sigaction oldSigAction;
newSigAction.sa_sigaction = iOSSignalHandler;
newSigAction.sa_flags = SA_SIGINFO;
sigemptyset(&newSigAction.sa_mask);
sigaction(SIGQUIT, &newSigAction, &oldSigAction);
... (more signals attached to)
void iOSSignalHandler(int signal, siginfo_t *info, void *context) {
// handle crash
// then call default handler
(*oldSigAction.sa_sigaction)(signal, info, context);
}
I tried calling exit(0) but is there a better way to exit the app gracefully?
EDIT
To be more precise how do the crash reporting tools such has FLurry and Crashlytics handle the signal and exit the app, because in my case the default signal handler does not fire despite me calling it

Related

What part of the App Delegate life-cycle is called when an app in the foreground has an out of memory crash?

Trying to debug a crash that a user is having that isn't showing up in our crash reporting tool or in our log files. Have a theory it might be down to memory pressure, but not sure if applicationWillTerminate will be called if iOS kills an app application in the foreground. We write to our log file in applicationWillTerminate but it apparently isn't being called during this crash.
If the app crashes, no lifecycle method is called reliably. Instead you can create & register a global exception handler which gets invoked in this case:
func exceptionHandler(exception: NSException) {
print("*** UNHANDLED EXCEPTION ***")
print(exception)
print("CALL STACK:")
print(exception.callStackSymbols.joined(separator: "\n"))
}
Register this function using NSSetUncaughtExceptionHandler, e.g. in your UIApplicationDelegate.application:didFinishLaunchingWithOptions::
NSSetUncaughtExceptionHandler(exceptionHandler)
System had to trigger applicationWillTerminate if it up to kill the app. However you can't be sure how much time you have to before app actually will be killed. Maybe it just not enough time to write the log. Before killing app due to memory consumption system should send memory warning. You can test last one by simulating memory warning on Simulator. If applicationWillTerminate didn't called then want terminated by system and you crash not related directly to memory consumption.

Move to first screen/Home screen at Application Crash

- (void)applicationWillTerminate:(UIApplication *)application {
NSLog(#"Application is terminating now.");
}
This function is called when application is going to be terminated and i have added this just to add some lines of code to my question. In iOS when an application crashes at some stage and we have not handle that case properly, it will set the user to move to main screen (outside from that crashed application).
In android, i have seen in most of the applications if a person have not handle the crashing scenario it sets the user to move to home screen.
There should be any method that is going to be called when a crash occur and we can call the firstView at that stage.
I have not find that method/delegate so far in objective c/swift.
If anyone knows, you can answer here.
Note: Please don't suggest to use
#try {
} #catch (NSException *exception) {
} #finally {
}
as i'm asking in the sense that i have handle almost all the exception scenarios properly but asking in the case if some scenario fails or some other issue an application crashes on any device what is the workaround?
You can catch exceptions causing crashes with NSSetUncaughtExceptionHandler like so:
func exceptionHandler(exception : NSException) {
// Do something before the app is automatically terminated
print(exception.callStackSymbols)
}
NSSetUncaughtExceptionHandler(exceptionHandler)
This handler will be called right after the crash and before the app is force-closed.
You won't be able to stop the application from crashing but at least you can get the call stack and use it for logging and finding out what happened!
You cant do that in ios. the delegate applicationWillTerminate is called just before the app is terminating. There you cant avoid the app termination. Once the applicationWillTerminate is called, the app will terminate. The only way you can avoid crashing is to find out the issue & solving it. You can catch memory warnings in didRecieveMemoryWarning and you can catch exceptions in code which will give you some of the problems that causes crashes before crashing

iOS app being terminated issue

I've found that my iOS 5 app is sometimes unexpectedly quited and it does not seem to be due to an uncaught exception, since I've implemented uncaughtExceptionHandler in the app delegate class and I get nothing from there.
If it is because the system is terminating it, it looks like you can only be aware of that if it is in background state: I've read the following line in Apple's documentation.
The applicationWillTerminate: method is not called if your app is currently suspended.
So, if I'm not wrong, you can get the reason why your app is terminated by the system in these cases:
App was in background state
Low-memory event was triggered
Can I detect more causes of why the app is being terminated, in order to report the issue? Or is it possible that it is not currently being terminated, but moved to background without user interaction?
Thanks
NSSetUncaughtExceptionHandler() installs a handler for Objective-C exceptions (e.g. trying to access an NSArray item that does not exist). It does not catch the lower level signals like segmentation fault, bus error, illegal instruction, ..., things that happen when your app for example tries to access an invalid pointer address.
You can also install handlers for those:
#include <signal.h>
void signalHandler(int signal)
{
}
// Somewhere in your start-up code.
signal(SIGSEGV, signalHandler);

In IOS, is abort() the recommended way to respond to an unrecoverable error? [duplicate]

At some point in my application I have done this exit(0) which crashes my app. But I haven't figured out what method gets called when this executes.
I've put messages in:
(void)applicationWillTerminate:(UIApplication *)application
(void)applicationDidEnterBackground:(UIApplication *)application
But none of this seem to get called! Any idea about what method is called when exit(0) is done?
From Apple's Human User Guidelines...
Don’t Quit Programmatically
Never quit an iOS application programmatically because people tend to
interpret this as a crash. However, if external circumstances prevent
your application from functioning as intended, you need to tell your
users about the situation and explain what they can do about it.
Depending on how severe the application malfunction is, you have two
choices.
Display an attractive screen that describes the problem and suggests a
correction. A screen provides feedback that reassures users that
there’s nothing wrong with your application. It puts users in control,
letting them decide whether they want to take corrective action and
continue using your application or press the Home button and open a
different application
If only some of your application's features are not working, display
either a screen or an alert when people activate the feature. Display
the alert only when people try to access the feature that isn’t
functioning.
If you've decided that you are going to quit programmatically anyway...
In C, exit(0) will halt execution of the application. This means that no delegate methods or exception handlers will be called. So, if the goal is to make sure that some code gets called when the closes, even on a forced close, there may be another option. In your AppDelegate implement a custom method called something like -(void)applicaitonIsgoingAway. Call this method from within anywhere you want your exiting code to be called:
applicationWillTerminate
applicationDidEnterBackground
onUncaughtException
The first two are ones that you already mentioned in your question. The third can be a catch-all of sorts. It's a global exception handler. This next bit comes from a question on that very topic.
This exception handler will get called for any unhanded exceptions (which would otherwise crash your app). From within this handler, you can call applicaitonIsgoingAway, just like in the other 2 cases. From the other question that I mentioned above, you can find an answer similar to this.
void onUncaughtException(NSException* exception)
{
[[AppDelegate sharedInstance] applicationIsgoingAway];
}
But in order for this to work, you need to set this method up as the exception handler like so...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&onUncaughtException);
//There may already be more code in this method.
}
Now, you can quit the app programmatically by calling NSAssert(FALSE, #"Quitting the app programmatically."); As long as there is no other exception handler in place to catch this, your app will begin to crash, and your exception handler code will be called. in-turn calling applicationIsGoingAway.
When you call exit(0) you immediately terminate your application. 0 is a status code which means successful termination.
No other method is called, you application just dies. As a result end user may think app is just crashed.
Apple discourages you to call exit anywhere.
exit(0) is a C function that terminates your app's process therefore none of the application delegates methods will be called, the app will be killed immediately. Apple recommends strongly against your app quitting because it appears broken to the user.
There is no Apple-supported method to terminate your application programmatically. Calling exit is certainly out of the question. This causes all sorts of bugs (for example the multitasking switcher will break badly) as well as simply being wrong.
If you are trying to disable multitasking, you can do this with the UIApplicationExitsOnSuspend key in your Info.plist file (the title for the key is "Application does not run in background").
Other than that, it's up to your users to press the home button to close your application.
these methods will be called but you cannot use exit(0) you will need to press the back button to close your app then these methods will be called

pause event is not working properly in PhoneGap iPhone?

This is my code
//This is an event that fires when a PhoneGap application is put into the background.
document.addEventListener("pause", onPause, false);
//This is an event that fires when a PhoneGap application is retrieved from the background.
document.addEventListener("resume", onResume, false);
// Handle the pause event
function onPause(){
console.log("pause : app is put into background");
}
// Handle the resume event
function onResume() {
console.log("resume : app is put into foreground");
}
When i press the home button there is no log in the console however when I click the app (make it in foreground) then my log is
2011-11-22 12:11:37.206 Event[644:207] [INFO] pause : app is put into background
2011-11-22 12:11:37.206 Event[644:207] [INFO] resume : app is put into foreground
I don't know why pause function is called when it comes in foreground.
Is there anything that I'm doing wrong?
This is from the docs
iOS Quirks
In the pause handler, any calls that go through Objective-C will not work, nor will any calls that are interactive, like alerts. This means that you cannot call console.log (and its variants), or any calls from Plugins or the PhoneGap API. These will only be processed when the app resumes (processed on the next run-loop).
I suspect what is actually happening is that the console.log() from the pause event is not so much being fired on resume, as it's just that the system cannot output your console.log() until it comes back.
The Objective-C method in PhoneGapDelegate.m that fires the pause event (applicationWillEnterForeground:(UIApplication *)application) sends it to the JavaScript but by then the app is in the background and suspended. The JavaScript cannot receive the event until it re-enters the foreground.
To test this, simply background your app for a longer period of time... it should then cause their error:
void SendDelegateMessage(NSInvocation*): delegate (webView:decidePolicyForNavigationAction:request:frame:decisionListener:) failed to return after waiting 10 seconds. main run loop mode: kCFRunLoopDefaultMode
This appears to be a bug in PhoneGap. Perhaps you could raise an issue at: https://github.com/callback/callback-ios ?

Resources