Back to Resources

Blog

Posted May 25, 2023

Error and Crash Reporting in iOS App Extensions with Backtrace

In this article, we are going to take a look at how Backtrace SDK can help to automatically detect and report handled and unhandled exceptions, errors, and crashes that occur in your apps.

quote

We are living in a time where richer inter-app communication and tighter integration with the OS services is available in mobile, and iOS is no exception. iOS App extensions enable you to extend your reach beyond the process of presenting the UI. You can capture screen, intercept network, or interact with an Apple Watch while other apps are running in the foreground. 

These extensions run in their own, sandboxed processes, and require extra care to monitor them in production. In this post, we are going to take a look at how Backtrace SDK can help us in our example Keyboard Extension.

You can find a pair of sample projects below if you prefer jumping right into it.

Requirements

You'll need the latest Xcode and backtrace-cocoa SDK. CocoaPods CLI is not required.

Steps

Download SDK

Download the latest archive from backtrace-cocoa releases. Make sure you pick bitcode=YES embedded=YES flavor.

Launch your Xcode project.

Copy these into your project root by drag and dropping them into Project Navigator.

  • Rome/Backtrace.framework

  • Rome/Backtrace_PLCrashReporter.framework

  • Rome/Cassette.framework

Select your app and all extensions in the prompted dialog.

Error Monitoring Dialog Box

Configure Xcode Project

  1. Navigate to each build target's General settings (i.e., your app and each extension).

  2. Locate Framework, Libraries, and Embedded Content for apps and Frameworks and Libraries for extensions.

  3. Add all the new frameworks to your targets if missing. Set embedding settings as Embed without Signing.

  4. Navigate to Build Phases > Embed Frameworks and make sure all the frameworks are added there (app and extension targets).

  5. Navigate to Build Settings and change Debug Information Format to Dwarf with dSYM File (app and extension targets).

Add Sources

  • Create a new directory with Finder in your project and name it Backtrace.

  • Copy all ".h" files in Backtrace.framework/Headers and Backtrace_PLCrashReporter.framework/Headers into the newly created directory.

  • Go back to Xcode and add Backtrace by drag & dropping it into Project Navigator. If you get prompted to add bridging header files, accept it.

  • Make sure files are added to all targets in the prompted dialog.

Create a new Obj-C class in your project (i.e., BacktraceWrapper.h and BacktraceWrapper.m). If asked, allow Xcode to create bridging headers for the targets that utilize Swift.

BacktraceWrapper.h

1
#import <Foundation/Foundation.h>
2
3
NS_ASSUME_NONNULL_BEGIN
4
5
@interface BacktraceWrapper : NSObject
6
7
+(void)sendError:(NSError*)error attributes:(NSDictionary*)extra;
8
9
@end
10
11
NS_ASSUME_NONNULL_END

BacktraceWrapper.m

1
#import "BacktraceWrapper.h"
2
#if defined(__arm64__) && __arm64__
3
#import "Backtrace-Swift.h"
4
#import "Backtrace-PLCrashReporter-umbrella.h"
5
#endif
6
7
@implementation BacktraceWrapper
8
9
#pragma mark Globals
10
#if defined(__arm64__) && __arm64__
11
static BacktraceClient* client;
12
#endif
13
14
#pragma mark Private
15
16
+(void)initializeBacktrace {
17
#if defined(__arm64__) && __arm64__
18
if (client != nil) {
19
return;
20
}
21
22
BacktraceCredentials* credentials = [[BacktraceCredentials alloc] initWithSubmissionUrl: [NSURL URLWithString: @"https://submit.backtrace.io/BACKTRACE_SUBDOMAIN/BACKTRACE_SUBMISSION_TOKEN/plcrash"]];
23
24
BacktraceDatabaseSettings *dbSettings = [[BacktraceDatabaseSettings alloc] init];
25
dbSettings.maxRecordCount = 10;
26
27
BacktraceClientConfiguration *configuration = [[BacktraceClientConfiguration alloc]
28
initWithCredentials: credentials
29
dbSettings: dbSettings
30
reportsPerMin: 30 // Default is 30
31
allowsAttachingDebugger: FALSE // If false, disables backtrace during development
32
detectOOM: FALSE];
33
34
35
BacktraceCrashReporter* crashReporter = [[BacktraceCrashReporter alloc] initWithConfig: PLCrashReporterConfig.defaultConfiguration];
36
client = [[BacktraceClient alloc] initWithConfiguration:configuration crashReporter:crashReporter error:nil];
37
38
[client.metrics enableWithSettings:[[BacktraceMetricsSettings alloc] init]];
39
#endif
40
}
41
42
43
#pragma mark Public
44
45
+(void)sendError:(NSError*)error attributes:(NSDictionary*)extra {
46
#if defined(__arm64__) && __arm64__
47
[self initializeBacktrace];
48
[client sendWithError:error attachmentPaths:@[] completion:^(BacktraceResult * _Nonnull result) {
49
NSLog(@"Backtrace error sent: %@", [error description]);
50
}];
51
#endif
52
}
53
54
@end

Swift Support

If you want to expose BacktraceWrapper to your SWIFT files, add the following line to your bridging headers: 

#import "BacktraceWrapper.h"

BacktraceWrapper.sendError(error: Error) will become available to your Swift code.

Upload Symbols with CI

Once you are ready to distribute your app, run the commands below in your CI to upload debug symbols to Backtrace.

1
cd $DERIVED_DATA_PATH/Build/Products/Debug-iphoneos/
2
3
zip -r symbols.zip *.dSYM
4
curl --fail-with-body --data-binary @symbols.zip -X POST -H "Expect: gzip" "https://submit.backtrace.io/$BACKTRACE_SUBDOMAIN/$BACKTRACE_SYMBOLS_ACCESS_TOKEN/symbols"
5

Final Words

From now on, your extensions will have the same error reporting capabilities that your app has. We know how painful it can become to debug custom keyboards or video calls in production especially when they crash silently with no useful error messages. Those days are now in the past. 

We’d love to hear your feedback! We have recently added support for Swift Package Manager which will simplify working with App Extensions even further.

This article was originally published in January 2023 and has been updated in May 2023.

Diego Perini
Sr. Software Engineer
Published:
May 25, 2023
Share this post
Copy Share Link
© 2023 Sauce Labs Inc., all rights reserved. SAUCE and SAUCE LABS are registered trademarks owned by Sauce Labs Inc. in the United States, EU, and may be registered in other jurisdictions.