How to implement test-flight crash reporting in swift - ios

I am developing an app in swift. I integrated test-flight SDK for remote logging. Now I want to use other test-flgiht SDK provided features. One of them is crash reporting. In the test-flight provided sample code c functions are there. How can I implement those c calls
The sample code test-flight provided
/*
My Apps Custom uncaught exception catcher, we do special stuff here, and TestFlight takes care of the rest
*/
void HandleExceptions(NSException *exception) {
NSLog(#"This is where we save the application data during a exception");
// Save application data on crash
}
/*
My Apps Custom signal catcher, we do special stuff here, and TestFlight takes care of the rest
*/
void SignalHandler(int sig) {
NSLog(#"This is where we save the application data during a signal");
// Save application data on crash
}
-(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// installs HandleExceptions as the Uncaught Exception Handler
NSSetUncaughtExceptionHandler(&HandleExceptions);
// create the signal action structure
struct sigaction newSignalAction;
// initialize the signal action structure
memset(&newSignalAction, 0, sizeof(newSignalAction));
// set SignalHandler as the handler in the signal action structure
newSignalAction.sa_handler = &SignalHandler;
// set SignalHandler as the handlers for SIGABRT, SIGILL and SIGBUS
sigaction(SIGABRT, &newSignalAction, NULL);
sigaction(SIGILL, &newSignalAction, NULL);
sigaction(SIGBUS, &newSignalAction, NULL);
// Call takeOff after install your own unhandled exception and signal handlers
[TestFlight takeOff:#"Insert your Application Token here"];
// continue with your application initialization
}
Link for the above code:http://help.testflightapp.com/customer/portal/articles/829558-how-do-i-implement-crash-reporting-
Any help would be appreciated.

Related

iOS requestTrackingAuthorization callback is not on the main thread

The iOS ATT Alert needs to be shown on startup before an app starts, so the remaining app code needs to be run in the completion handler (eg initialising advert code and starting the main game).
However, this crashes because the completion handler callback is not on the main thread (after the alert is actually shown and Allow or Ask App Not to Track is selected).
In iOS (Xamarin C# code):
public override void OnActivated(UIApplication application) // RequestTrackingAuthorization must be called when app is Active
{
if (!this.shownAlert)
{
this.shownAlert=true;
Debug.WriteLine("1) ThreadId={0}", Environment.CurrentManagedThreadId); // ThreadId=1
ATTrackingManager.RequestTrackingAuthorization(delegate (ATTrackingManagerAuthorizationStatus trackingManagerAuthorizationStatus)
{
Debug.WriteLine("2) ThreadId={0}", Environment.CurrentManagedThreadId); // ThreadId=7
});
}
}
Prints:
1) ThreadId=1
2) ThreadId=7
And the similarly in Unity:
Debug.WriteLine("1) ThreadId={0}", Environment.CurrentManagedThreadId); // ThreadId=1
ATTrackingStatusBinding.RequestAuthorizationTracking(delegate (int status)
{
Debug.WriteLine("2) ThreadId={0}", Environment.CurrentManagedThreadId); // ThreadId=4
});
This seems like a bug to me. So how do all the apps and games out there get this to work? Somehow switch to the main thread in the callback? I don’t see any examples of this.

this function must be called on the uimanager queue

on manual capture (like in lib docs) library fires error "this function must be called on the uimanager queue" and app crash.
https://github.com/Woonivers/react-native-document-scanner
Go to the folder:
node_modules/#woonivers/react-native-document-scanner/ios
Edit the file RNPdfScannerManager.m.
Change this line:
// - (dispatch_queue_t)methodQueue
// {
// return dispatch_get_main_queue();
// }
Then rebuild the app.

Custom NSUncaughtExceptionHandler call previous exception handler

My app includes crash reporting library that using NSSetUncaughtExceptionHandler in order to catch the crashes.
I need to implement custom action (log crash and display alert view) before\after the crash reporting implementation.
To achieve this behavior, first I'm keep a reference to previous UncaughtExceptionHandler using NSGetUncaughtExceptionHandler(), and than registering my custom exception handler and signals handler. In my custom handler I tried to execute previous handler before\after my custom actions, but this throws a signal SIGABRT for previousHandler(exception) (in both cases).
Here is the code example :
static NSUncaughtExceptionHandler *previousHandler;
void InstallUncaughtExceptionHandler()
{
// keep reference to previous handler
previousHandler = NSGetUncaughtExceptionHandler();
// register my custom exception handler
NSSetUncaughtExceptionHandler(&HandleException);
signal(SIGABRT, SignalHandler);
signal(SIGILL, SignalHandler);
signal(SIGSEGV, SignalHandler);
signal(SIGFPE, SignalHandler);
signal(SIGBUS, SignalHandler);
signal(SIGPIPE, SignalHandler);
}
void HandleException(NSException *exception)
{
// execute previous handler
previousHandler(exception);
// my custom actions
}
void SignalHandler(int signal)
{
NSLog(#"SignalHandler");
}
How can I execute previous handler without throws a signal ?
Any ideas why SignalHandler doesn't called when system throws a signal ?
Don't register the signal handlers. I have to obfuscate a bit the code presented below, but it's from a production app that's on the App Store:
AppDelegate application:didFinishLaunchingWithOptions:
fabricHandler = NSGetUncaughtExceptionHandler();
NSSetUncaughtExceptionHandler(&customUncaughtExceptionHandler);
Handler:
void customUncaughtExceptionHandler(NSException *exception) {
// Custom handling
if (fabricHandler) {
fabricHandler(exception);
}
}
The PreviousSignalHandler might
1) Reset all set signal handlers
2) Call abort
One of the reasons it will abort.
So you can do all the stuff you want to do and call the previous handler.
HTH

iOS - Catching exceptions in main()

So, I had an idea to catch unanticipated exceptions in main and try to cleanup and exit gracefully:
int main(int argc, char *argv[])
{
#autoreleasepool
{
//return UIApplicationMain(argc, argv, nil, NSStringFromClass([GRWAppDelegate class]));
#try
{
int retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([GRWAppDelegate class]));
return retVal;
}
#catch (NSException *exception)
{
[Utilities setPreferencesDefaults];
}
}
}
This does catch exceptions and updates the preference defaults.
I then thought, why exit at all, just cleanup and relaunch, so I wrapped everything in a while loop:
int main(int argc, char *argv[])
{
while (YES)
{
#autoreleasepool
{
...
}
}
}
Of course I wouldn't be here if that actually worked. Problem is, once it again executes
retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([GRWAppDelegate class]));
it immediately throws a new exception:
Assertion failure in void UIApplicationInstantiateSingleton(Class)(), /SourceCache/UIKit/UIKit-2380.17/UIApplication.m:2037
NSInternalInconsistencyException
#"There can only be one UIApplication instance."
Makes sense, so is there a way I can discard the existing singleton and replace it with a new one? (although I guess it's not really a singleton if I can)
Purpose is, I don't ever want the app to crash giving a bad user experience. Even if their state isn't completely restored, I would think that would still be better than just unexpectedly exiting.
I can try to handle possible expected exceptions, but this is to try to catch things that I haven't foreseen.
This should really only catch VERY unusual circumstances, so if it can't be done it's not that big of a deal, but I was wondering how best to deal with this type of situation.
That won't work because the exception mechanism does not cleanup properly when thrown across stack frames. Since you are catching the exception in main the exception has crossed several stack frames.
Apple explicitly states that exceptions are only to be used for unrecoverable programming errors.
See SO answer by bbum:
"Any exception that passes through system framework code will leave said framework in an undefined state.. Catching said exceptions and trying to recover from it will lead to memory leaks, undefined behaviour and crashing."
Also by bbum.
From Apple docs:
Important: You should reserve the use of exceptions for programming or unexpected runtime errors such as out-of-bounds collection access, attempts to mutate immutable objects, sending an invalid message, and losing the connection to the window server. You usually take care of these sorts of errors with exceptions when an application is being created rather than at runtime.
You can create a top level exception handler and set it as your default exception handler when you app first launches. The best place to do this would be the AppDelegate's applicationDidFinishLaunching: method.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&exceptionHandler);
// some UI configuration here..
return YES;
}
void exceptionHandler(NSException *exception)
{
[Utilities setPreferencesDefaults];
// You can also write exception message into a log file as well.
NSLog(#"Stack trace: %#", [exception callStackReturnAddresses]);
}

Catching NSException in main

The iOS application i took over has a way of handling NSExceptions differently than what i've seen before and wanted to know why it isn't working now.
In the main.m file the old developer has this logic in it:
int main(int argc, char *argv[])
{
#autoreleasepool {
int retVal = 0;
#try {
retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
#catch (NSException *exception) {
//
//Logic to save Exception in DataStore
//
NSLog(#"Exception - %#",[exception description]);
exit(EXIT_FAILURE);
}
return retVal;
}
}
When the app would get launched again you would receive a prompt to send the exception to us and if you confirmed it would sent it to our server.
I recently pushed an update more optimized for iOS 7 of the application and noticed that i don't get any of these error reports from crashed apps anymore.
So i tested it via the following code which i know gets called:
NSArray *array = [NSArray new];
id object = [array objectAtIndex:4];
To which i receive this:
2014-05-12 14:55:57.575 APPNAME[17989:60b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 4 beyond bounds for empty array'
*** First throw call stack:
(0x18ab0b09c 0x196a89d78 0x18aa0c680 0x10007f498 0x18d9e02c0 0x18da997d0 0x18da996cc 0x18da98ba0
0x18da98840 0x18da98564 0x18da984e4 0x18d9dad78 0x18d5d70cc 0x18d5d1c94 0x18d5d1b4c
0x18d5d13d4 0x18d5d1178 0x18d5caa30 0x18aacb7e0 0x18aac8a68 0x18aac8df4 0x18aa09b38
0x19042f830 0x18da480e8 0x100036b98 0x197073aa0)
libc++abi.dylib: terminating with uncaught exception of type NSException
As you can see the exception is not being logged or saved but rather it is completely uncaught.
2 Questions:
Is this bad practice? I don't think it is but i am a jr. developer and not really sure and if there is a better way to do this w/o third party service?
Do you know of any changes in iOS 7 that would affect this (UNTOUCHED) Logic?
Is this bad practice? I don't think it is but i am a jr. developer and
not really sure and if there is a better way to do this w/o third
party service?
Yes, it is bad practice. UIApplicationMain() is a black hole; once control is passed to that function, it is unlikely that any code beyond that call in main() will ever be invoked again.
It is also a naive implementation; it logs less information to stdout than the normal exception handling mechanism (which is the output you are seeing). It hides information that would be useful to debugging and would also, likely, bypass the standard crash reporting mechanism.
Note that there is also a global unhandled exception handling hook. I wouldn't recommend using it, but it does exist.
Do you know of any changes in iOS 7 that would affect this (UNTOUCHED)
Logic?
Not off hand, but I haven't looked. Again, though, UIApplicationMain() is a black hole; it doesn't typically return ever.
According to Exception Programming Topics you can use NSSetUncaughtExceptionHandler function to handle uncaught exceptions. Try the code below:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(handleUncaughtException);
#throw [NSException exceptionWithName:NSGenericException
reason:#"Test uncaught exception handling"
userInfo:nil];
return YES;
}
void handleUncaughtException(NSException *exception)
{
NSLog(#"Exception - %#",[exception description]);
exit(EXIT_FAILURE);
}

Resources