License | MIT |
ReleasedLast Release | Feb 2020 |
Maintained by Lukas Spieß, Microsoft, Clement Polet, Jae Lim, Alexander Chocron.
NOTE: With the release of HockeySDK 4.0.0-alpha.1 a bug was introduced which lead to the exclusion of the Application Support folder from iCloud and iTunes backups.
If you have been using one of the affected versions (4.0.0-alpha.2, Version 4.0.0-beta.1, 4.0.0, 4.1.0-alpha.1, 4.1.0-alpha.2, or Version 4.1.0-beta.1), please make sure to update to a newer version of our SDK as soon as you can.
HockeySDK-Mac implements support for using HockeyApp in your Mac applications.
The following feature is currently supported:
Collect crash reports: If you app crashes, a crash log with the same format as from the Apple Crash Reporter is written to the device's storage. If the user starts the app again, he is asked to submit the crash report to HockeyApp. This works for both beta and live apps, i.e. those submitted to the App Store!
User Metrics: Understand user behavior to improve your app. Track usage through daily and monthly active users, monitor crash impacted users, as well as customer engagement through session count. You can now track Custom Events in your app, understand user actions and see the aggregates on the HockeyApp portal.
Feedback: Collect feedback from your users from within your app and communicate directly with them using the HockeyApp backend.
Add analytics to Sparkle: If you are using Sparkle to provide app-updates (HockeyApp also supports Sparkle feeds for beta distribution) the SDK contains helpers to add some analytics data to each Sparkle request.
This document contains the following sections:
We recommend integration of our binary into your Xcode project to setup HockeySDK for your OS X app. You can also use our interactive SDK integration wizard in HockeyApp for Mac which covers all the steps from below. For other ways to setup the SDK, see Advanced Setup.
Please see the "How to create a new app" tutorial. This will provide you with an HockeyApp specific App Identifier to be used to initialize the SDK.
HockeySDK-Mac
. (Make sure not to use 3rd party unzip tools!)From our experience, 3rd-party libraries usually reside inside a subdirectory (let's call our subdirectory Vendor
), so if you don't have your project organized with a subdirectory for libraries, now would be a great start for it. To continue our example, create a folder called Vendor
inside your project directory and move the unzipped HockeySDK-Mac
-folder into it.
We recommend to use Xcode's group-feature to create a group for 3rd-party-libraries similar to the structure of our files on disk. For example, similar to the file structure in 2.3 above, our projects have a group called Vendor
.
Make sure the Project Navigator
is visible (⌘+1)
Drag & drop HockeySDK.framework
from your window in the Finder
into your project in Xcode and move it to the desired location in the Project Navigator
(e.g. into the group called Vendor
)
A popup will appear. Select Create groups for any added folders
and set the checkmark for your target. Then click Finish
.
Now we’ll make sure the framework is copied into your app bundle:
Project Navigator
(⌘+1).Build Phases
tab.Add Build Phase
button at the bottom and choose Add Copy Files
.Frameworks
from the Destination list.HockeySDK-Mac
from the Project Navigator left sidebar to the list in the new Copy Files phase.Make sure to sign the app, since the SDK will store user related input in the keychain for privacy reasons
Objective-C
AppDelegate.m
file.import
statements:@import HockeySDK;
applicationDidFinishLaunching:
[[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"APP_IDENTIFIER"];
// Do some additional configuration if needed here
[[BITHockeyManager sharedHockeyManager] startManager];
Swift
AppDelegate.swift
file.import HockeySDK
applicationWillFinishLaunching
BITHockeyManager.shared().configure(withIdentifier: "APP_IDENTIFIER")
// Do some additional configuration if needed here
BITHockeyManager.shared().start()
Note: In case of document based apps, invoke startManager
at the end of applicationDidFinishLaunching
, since otherwise you may lose the Apple events to restore, open untitled document etc.
If any crash report has been saved from the last time your application ran, startManager
will present a dialog to allow the user to submit it. Once done, or if there are no crash logs, it will then call back to your appDelegate
with showMainApplicationWindowForCrashManager:
(if implemented, see Improved startup crashes handling).
Congratulation, now you're all set to use HockeySDK!
CocoaPods is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like HockeySDK in your projects. To learn how to setup CocoaPods for your project, visit the official CocoaPods website.
Podfile
platform :osx, '10.9'
pod "HockeySDK-Mac"
The following options only show some of possibilities to interact and fine-tune the crash reporting feature. For more please check the full documentation of the BITCrashManager
class in our documentation.
The HockeySDK enables crash reporting per default. Crashes will be immediately sent to the server the next time the app is launched.
To provide you with the best crash reporting, we are using PLCrashReporter in Version 1.2 / Commit 356901d7f3ca3d46fbc8640f469304e2b755e461.
This feature can be disabled as follows:
Objective-C
[[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"APP_IDENTIFIER"];
[[BITHockeyManager sharedHockeyManager] setDisableCrashManager: YES]; //disable crash reporting
[[BITHockeyManager sharedHockeyManager] startManager];
Swift
BITHockeyManager.shared().configure(withIdentifier: "APP_IDENTIFIER")
BITHockeyManager.shared().isCrashManagerDisabled = true
BITHockeyManager.shared().start()
Crashes are send the next time the app starts. If crashManagerStatus
is set to BITCrashManagerStatusAutoSend
, crashes will be send without any user interaction, otherwise an alert will appear allowing the users to decide whether they want to send the report or not.
Objective-C
[[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"APP_IDENTIFIER"];
[[BITHockeyManager sharedHockeyManager].crashManager setAutoSubmitCrashReport: YES];
[[BITHockeyManager sharedHockeyManager] startManager];
Swift
BITHockeyManager.shared().configure(withIdentifier: "APP_IDENTIFIER")
BITHockeyManager.shared().crashManager.isAutoSubmitCrashReport = true
BITHockeyManager.shared().start()
The SDK is not sending the reports right when the crash happens deliberately, because it is not safe to implement such a mechanism, while being async-safe (any Objective-C code is NOT async-safe!) and not causing more danger, like a deadlock of the device. We found that users do start the app again because most don't know what happened, and you will get by far most of the reports.
Sending the reports on startup is done asynchronously (non-blocking). This is the only safe way to ensure that the app won't be possibly killed by the iOS watchdog process, because startup could take too long and the app could not react to any user input when network conditions are bad or connectivity might be very slow.
On Mac OS X there are three types of crashes that are not reported to a registered NSUncaughtExceptionHandler
:
NSUncaughtExceptionHandler
don't start working until after NSApplication
has finished calling all of its delegate methods!
Example:- (void)applicationDidFinishLaunching:(NSNotification *)note {
...
[NSException raise:@"ExceptionAtStartup" format:@"This will not be recognized!"];
...
}
NSUncaughtExceptionHandler
in NSApplication
only logs exceptions to the console and ends their processing. Resulting in exceptions that occur in the NSApplication
"scope" not occurring in a registered custom NSUncaughtExceptionHandler
.
Example:- (void)applicationDidFinishLaunching:(NSNotification *)note {
...
[self performSelector:@selector(delayedException) withObject:nil afterDelay:5];
...
}
- (void)delayedException {
NSArray *array = [NSArray array];
[array objectAtIndex:23];
}
- (IBAction)doExceptionCrash:(id)sender {
NSArray *array = [NSArray array];
[array objectAtIndex:23];
}
In general there are two solutions. The first one is to use an NSExceptionHandler
class instead of an NSUncaughtExceptionHandler
. But this has a few drawbacks which are detailed in BITCrashReportExceptionApplication.h
.
Instead we provide the optional NSApplication
subclass BITCrashExceptionApplication
which handles cases 2 and 3.
Installation:
Info.plist
Principal class
NSApplication
with BITCrashExceptionApplication
Alternatively, if you have your own NSApplication subclass, change it to be a subclass of BITCrashExceptionApplication
instead.
The BITHockeyManagerDelegate
protocol provides methods to add additional data to a crash report:
Objective-C
- (NSString *)userIDForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager;
Swift
optional public func userID(for hockeyManager: BITHockeyManager!, componentManager: BITHockeyBaseManager!) -> String!
Objective-C
- (NSString *)userNameForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager;
Swift
optional public func userName(for hockeyManager: BITHockeyManager!, componentManager: BITHockeyBaseManager!) -> String!
Objective-C
- (NSString *)userEmailForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager;
Swift
optional public func userEmail(for hockeyManager: BITHockeyManager!, componentManager: BITHockeyBaseManager!) -> String!
The BITCrashManagerDelegate
protocol (which is automatically included in BITHockeyManagerDelegate
) provides methods to add more crash specific data to a crash report:
Objective-C
-(NSString *)applicationLogForCrashManager:(BITCrashManager *)crashManager
Swift
optional public func applicationLog(for crashManager: BITCrashManager!) -> String!
Check the following tutorial for an example on how to add CocoaLumberjack log data: How to Add Application Specific Log Data on iOS or OS X
Objective-C
-(BITHockeyAttachment *)attachmentForCrashManager:(BITCrashManager *)crashManager
Swift
optional public func attachment(for crashManager: BITCrashManager!) -> BITHockeyAttachment!
Make sure to implement the protocol
Objective-C
@interface YourAppDelegate () <BITHockeyManagerDelegate> {}
@end
Swift
class YourAppDelegate: NSObject, BITHockeyManagerDelegate {
}
and set the delegate:
Objective-C
[[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"APP_IDENTIFIER"];
[[BITHockeyManager sharedHockeyManager] setDelegate: self];
[[BITHockeyManager sharedHockeyManager] startManager];
Swift
BITHockeyManager.shared().configure(withIdentifier: "APP_IDENTIFIER")
BITHockeyManager.shared().delegate = self
BITHockeyManager.shared().start()
HockeyApp automatically provides you with nice, intelligible, and informative metrics about how your app is used and by whom.
Just in case you want to opt-out of the automatic collection of anonymous users and sessions statistics, there is a way to turn this functionality off at any time:
Objective-C
[BITHockeyManager sharedHockeyManager].disableMetricsManager = YES;
Swift
BITHockeyManager.shared().isMetricsManagerDisabled = true
By tracking custom events, you can now get insight into how your customers use your app, understand their behavior and answer important business or user experience questions while improving your app.
Objective-C
BITMetricsManager *metricsManager = [BITHockeyManager sharedHockeyManager].metricsManager;
[metricsManager trackEventWithName:eventName]
Swift
let metricsManager = BITHockeyManager.shared().metricsManager
metricsManager.trackEvent(withName: eventName)
Limitations
It's possible to attach porperties and/or measurements to a custom event.
Objective-C
BITMetricsManager *metricsManager = [BITHockeyManager sharedHockeyManager].metricsManager;
NSDictionary *myProperties = @{@"Property 1" : @"Something",
@"Property 2" : @"Other thing",
@"Property 3" : @"Totally different thing"};
NSDictionary *myMeasurements = @{@"Measurement 1" : @1,
@"Measurement 2" : @2.34,
@"Measurement 3" : @2000000};
[metricsManager trackEventWithName:eventName properties:myProperties measurements:myMeasurements]
Swift
let myProperties = ["Property 1": "Something", "Property 2": "Other thing", "Property 3" : "Totally different thing."]
let myMeasurements = ["Measurement 1": 1, "Measurement 2": 2.3, "Measurement 3" : 30000]
let metricsManager = BITHockeyManager.shared().metricsManager
metricsManager.trackEvent(withName: eventName, properties: myProperties, measurements: myMeasurements)
BITFeedbackManager
lets your users communicate directly with you via the app and an integrated user interface. It provides a single threaded discussion with a user running your app. This feature is only enabled, if you integrate the actual view controllers into your app.
You should never create your own instance of BITFeedbackManager
but use the one provided by the [BITHockeyManager sharedHockeyManager]
:
Objective-C
[BITHockeyManager sharedHockeyManager].feedbackManager
Swift
BITHockeyManager.shared().feedbackManager
Please check the documentation of the BITFeedbackManager
class on more information on how to leverage this feature.
Install the Sparkle SDK: http://sparkle-project.org As of today (01/2016), Sparkle doesn't support Mac sandboxes. If you require this, check out the following discussion https://github.com/sparkle-project/Sparkle/issues/363
Set SUFeedURL
to https://rink.hockeyapp.net/api/2/apps/<APP_IDENTIFIER>
and replace <APP_IDENTIFIER>
with the same value used to initialize the HockeySDK
Create a .zip
file of your app bundle and upload that to HockeyApp.
sparkleUpdater.sendsSystemProfile = YES;
SUUpdater
to your appDelegate!):- (NSArray *)feedParametersForUpdater:(SUUpdater *)updater
sendingSystemProfile:(BOOL)sendingProfile {
return [[BITSystemProfile sharedSystemProfile] systemUsageData];
}
One example scenario is when the app is started or comes to foreground and when it goes to background or is terminated:
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
…
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
BITSystemProfile *bsp = [BITSystemProfile sharedSystemProfile];
[dnc addObserver:bsp selector:@selector(startUsage) name:NSApplicationDidBecomeActiveNotification object:nil];
[dnc addObserver:bsp selector:@selector(stopUsage) name:NSApplicationWillTerminateNotification object:nil];
[dnc addObserver:bsp selector:@selector(stopUsage) name:NSApplicationWillResignActiveNotification object:nil];
…
};
To check if data is send properly to HockeyApp and also see some additional SDK debug log data in the console, add the following line before startManager
:
Objective-C
[[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"APP_IDENTIFIER"];
[BITHockeyManager sharedHockeyManager].logLevel = BITLogLevelDebug;
[[BITHockeyManager sharedHockeyManager] startManager];
Swift
BITHockeyManager.shared().configure(withIdentifier: "APP_IDENTIFIER")
BITHockeyManager.shared().logLevel = BITLogLevel.debug
BITHockeyManager.shared().start()
Our documentation can be found on HockeyApp.
Make sure that the apps build setting has LD_RUNPATH_SEARCH_PATHS
set to @executable_path/../Frameworks
Make sure there is no All Exceptions
breakpoint active or limit it to Objective-C
only and exclude C++
.
Enable debug output to the console to see additional information from the SDK initializing the modules, sending and receiving network requests and more by adding the following code before calling startManager
:
[BITHockeyManager sharedHockeyManager].logLevel = BITLogLevelDebug;
We're looking forward to your contributions via pull requests.
Development environment
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.
You must sign a Contributor License Agreement before submitting your pull request. To complete the Contributor License Agreement (CLA), you will need to submit a request via the form and then electronically sign the CLA when you receive the email containing the link to the document. You need to sign the CLA only once to cover submission to any Microsoft OSS project.
If you have further questions or are running into trouble that cannot be resolved by any of the steps here, feel free to open a Github issue here or contact us at [email protected]