PLCrashReporter: A Handy API for Reporting iPhone App Crashes

by Clint on February 7, 2009

If you’ve developed an iPhone/iPod Touch app and people are using it, you really want an easy way to get information about crashes when they occur. Apple does provide a mechanism for doing this: the iPhone OS records crash logs for on the device and when you sync it with iTunes the logs are copied to the user’s computer. (Apple has published an official document explaining all this in more detail.)

The problem with Apple’s mechanism is that you either need the user to manually dig up the files and send them to you (after they’ve done an iTunes sync, of course), or you need to write an OS X program to do it for them. Ugh. Fortunately, there are some alternatives.

I recently came across a great blog post by Christopher Atlan explaining how you can register your own “crash reporting” function that can, for example, upload a stack trace to a web server in between the time when you app barfs and when the iPhone OS shuts it down.

Another, perhaps slicker, option is to use Landon Fuller’s open-source library called “Plausible CrashReporter“, which not only creates a crash log for you, but also makes it easy to tell the user about it the next time they start the app, and ask them if they’d like to email or upload the report back to the developer. Slick.

Erica Sadun wrote an excellent article summarizing PLCrashReporter for Ars Technica. If you’re curious, here’s a code sample provided by the developer on one of his blog posts:

// from UIApplicationDelegate protocol
- (void) applicationDidFinishLaunching: (UIApplication *) application {
    PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
    NSError *error;

    /* Check if we previously crashed */
    if ([crashReporter hasPendingCrashReport])
        [self handleCrashReport];

    /* Enable the Crash Reporter */
    if (![crashReporter enableCrashReporterAndReturnError: &error])
        NSLog(@"Warning: Could not enable crash reporter: %@", error);

    ...
}

/**
 * Called to handle a pending crash report.
 */
- (void) handleCrashReport {
    PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
    NSData *crashData;
    NSError *error;

    /* Try loading the crash report */
    crashData = [crashReporter loadPendingCrashReportDataAndReturnError: &error];
    if (crashData == nil) {
        NSLog(@"Could not load crash report: %@", error);
        goto finish;
    }

    /* We could send the report from here, but we'll just print out
     * some debugging info instead */
    PLCrashReport *report = [[[PLCrashReport alloc] initWithData: crashData error: &error] autorelease];
    if (report == nil) {
        NSLog(@"Could not parse crash report");
        goto finish;
    }

    NSLog(@"Crashed on %@", report.systemInfo.timestamp);
    NSLog(@"Crashed with signal %@ (code %@, address=0x%" PRIx64 ")", report.signalInfo.name,
          report.signalInfo.code, report.signalInfo.address);

    /* Purge the report */
finish:
    [crashReporter purgePendingCrashReport];
    return;
}
Clint Harris is an independent software consultant living in Brooklyn, New York. He can be contacted directly at ten.sirrahtnilc@tnilc.