mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
Merge branch 'develop' into feature/#19-verifyBetaUsers
Conflicts: Support/HockeySDK.xcodeproj/project.pbxproj
This commit is contained in:
commit
b25796742e
@ -31,10 +31,30 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
#ifndef __IPHONE_6_1
|
||||||
|
#define __IPHONE_6_1 60100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Header style depending on the iOS version
|
||||||
|
*/
|
||||||
|
typedef NS_ENUM(NSUInteger, BITAppStoreHeaderStyle) {
|
||||||
|
/**
|
||||||
|
* Default is iOS 6 style
|
||||||
|
*/
|
||||||
|
BITAppStoreHeaderStyleDefault = 0,
|
||||||
|
/**
|
||||||
|
* Draw header in the iOS 7 style
|
||||||
|
*/
|
||||||
|
BITAppStoreHeaderStyleOS7 = 1
|
||||||
|
};
|
||||||
|
|
||||||
@interface BITAppStoreHeader : UIView
|
@interface BITAppStoreHeader : UIView
|
||||||
|
|
||||||
@property (nonatomic, copy) NSString *headerText;
|
@property (nonatomic, copy) NSString *headerText;
|
||||||
@property (nonatomic, copy) NSString *subHeaderText;
|
@property (nonatomic, copy) NSString *subHeaderText;
|
||||||
@property (nonatomic, strong) UIImage *iconImage;
|
@property (nonatomic, strong) UIImage *iconImage;
|
||||||
|
@property (nonatomic, assign) BITAppStoreHeaderStyle style;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -36,7 +36,8 @@
|
|||||||
|
|
||||||
#define kLightGrayColor BIT_RGBCOLOR(235, 235, 235)
|
#define kLightGrayColor BIT_RGBCOLOR(235, 235, 235)
|
||||||
#define kDarkGrayColor BIT_RGBCOLOR(186, 186, 186)
|
#define kDarkGrayColor BIT_RGBCOLOR(186, 186, 186)
|
||||||
#define kWhiteBackgroundColor BIT_RGBCOLOR(245, 245, 245)
|
#define kWhiteBackgroundColorDefault BIT_RGBCOLOR(245, 245, 245)
|
||||||
|
#define kWhiteBackgroundColorOS7 BIT_RGBCOLOR(255, 255, 255)
|
||||||
#define kImageHeight 72
|
#define kImageHeight 72
|
||||||
#define kImageBorderRadius 12
|
#define kImageBorderRadius 12
|
||||||
#define kImageLeftMargin 14
|
#define kImageLeftMargin 14
|
||||||
@ -54,7 +55,8 @@
|
|||||||
- (id)initWithFrame:(CGRect)frame {
|
- (id)initWithFrame:(CGRect)frame {
|
||||||
if ((self = [super initWithFrame:frame])) {
|
if ((self = [super initWithFrame:frame])) {
|
||||||
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||||
self.backgroundColor = kWhiteBackgroundColor;
|
self.backgroundColor = kWhiteBackgroundColorDefault;
|
||||||
|
self.style = BITAppStoreHeaderStyleDefault;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -66,20 +68,35 @@
|
|||||||
CGRect bounds = self.bounds;
|
CGRect bounds = self.bounds;
|
||||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||||
|
|
||||||
// draw the gradient
|
if (self.style == BITAppStoreHeaderStyleDefault) {
|
||||||
NSArray *colors = [NSArray arrayWithObjects:(id)kDarkGrayColor.CGColor, (id)kLightGrayColor.CGColor, nil];
|
// draw the gradient
|
||||||
CGGradientRef gradient = CGGradientCreateWithColors(CGColorGetColorSpace((__bridge CGColorRef)[colors objectAtIndex:0]), (__bridge CFArrayRef)colors, (CGFloat[2]){0, 1});
|
NSArray *colors = [NSArray arrayWithObjects:(id)kDarkGrayColor.CGColor, (id)kLightGrayColor.CGColor, nil];
|
||||||
CGPoint top = CGPointMake(CGRectGetMidX(bounds), bounds.size.height - 3);
|
CGGradientRef gradient = CGGradientCreateWithColors(CGColorGetColorSpace((__bridge CGColorRef)[colors objectAtIndex:0]), (__bridge CFArrayRef)colors, (CGFloat[2]){0, 1});
|
||||||
CGPoint bottom = CGPointMake(CGRectGetMidX(bounds), CGRectGetMaxY(bounds));
|
CGPoint top = CGPointMake(CGRectGetMidX(bounds), bounds.size.height - 3);
|
||||||
CGContextDrawLinearGradient(context, gradient, top, bottom, 0);
|
CGPoint bottom = CGPointMake(CGRectGetMidX(bounds), CGRectGetMaxY(bounds));
|
||||||
CGGradientRelease(gradient);
|
CGContextDrawLinearGradient(context, gradient, top, bottom, 0);
|
||||||
|
CGGradientRelease(gradient);
|
||||||
|
} else {
|
||||||
|
// draw the line
|
||||||
|
CGContextRef ctx = UIGraphicsGetCurrentContext();
|
||||||
|
CGContextSetLineWidth(ctx, 1.0);
|
||||||
|
CGContextSetStrokeColorWithColor(ctx, kDarkGrayColor.CGColor);
|
||||||
|
CGContextMoveToPoint(ctx, 0, CGRectGetMaxY(bounds));
|
||||||
|
CGContextAddLineToPoint( ctx, CGRectGetMaxX(bounds), CGRectGetMaxY(bounds));
|
||||||
|
CGContextStrokePath(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
// icon
|
// icon
|
||||||
[_iconImage drawAtPoint:CGPointMake(kImageLeftMargin, kImageTopMargin)];
|
[_iconImage drawAtPoint:CGPointMake(kImageLeftMargin, kImageTopMargin)];
|
||||||
|
|
||||||
|
[super drawRect:rect];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)layoutSubviews {
|
- (void)layoutSubviews {
|
||||||
|
if (self.style == BITAppStoreHeaderStyleOS7)
|
||||||
|
self.backgroundColor = kWhiteBackgroundColorOS7;
|
||||||
|
|
||||||
[super layoutSubviews];
|
[super layoutSubviews];
|
||||||
|
|
||||||
CGFloat globalWidth = self.frame.size.width;
|
CGFloat globalWidth = self.frame.size.width;
|
||||||
|
@ -33,13 +33,23 @@
|
|||||||
#import "BITHockeyBaseManager.h"
|
#import "BITHockeyBaseManager.h"
|
||||||
|
|
||||||
|
|
||||||
// hockey crash manager status
|
/**
|
||||||
typedef enum {
|
* Crash Manager status
|
||||||
|
*/
|
||||||
|
typedef NS_ENUM(NSUInteger, BITCrashManagerStatus) {
|
||||||
|
/**
|
||||||
|
* Crash reporting is disabled
|
||||||
|
*/
|
||||||
BITCrashManagerStatusDisabled = 0,
|
BITCrashManagerStatusDisabled = 0,
|
||||||
|
/**
|
||||||
|
* User is asked each time before sending
|
||||||
|
*/
|
||||||
BITCrashManagerStatusAlwaysAsk = 1,
|
BITCrashManagerStatusAlwaysAsk = 1,
|
||||||
|
/**
|
||||||
|
* Each crash report is send automatically
|
||||||
|
*/
|
||||||
BITCrashManagerStatusAutoSend = 2
|
BITCrashManagerStatusAutoSend = 2
|
||||||
} BITCrashManagerStatus;
|
};
|
||||||
extern NSString *const kBITCrashManagerStatus;
|
|
||||||
|
|
||||||
|
|
||||||
@protocol BITCrashManagerDelegate;
|
@protocol BITCrashManagerDelegate;
|
||||||
@ -72,8 +82,10 @@ extern NSString *const kBITCrashManagerStatus;
|
|||||||
very slow.
|
very slow.
|
||||||
|
|
||||||
More background information on this topic can be found in the following blog post by Landon Fuller, the
|
More background information on this topic can be found in the following blog post by Landon Fuller, the
|
||||||
developer of [PLCrashReporter](https://code.google.com/p/plcrashreporter/), about writing reliable and
|
developer of [PLCrashReporter](https://www.plcrashreporter.org), about writing reliable and
|
||||||
safe crash reporting: [Reliable Crash Reporting](http://goo.gl/WvTBR)
|
safe crash reporting: [Reliable Crash Reporting](http://goo.gl/WvTBR)
|
||||||
|
|
||||||
|
@warning If you start the app with the Xcode debugger attached, detecting crashes will _NOT_ be enabled!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@interface BITCrashManager : BITHockeyBaseManager
|
@interface BITCrashManager : BITHockeyBaseManager
|
||||||
@ -97,11 +109,7 @@ extern NSString *const kBITCrashManagerStatus;
|
|||||||
|
|
||||||
Defines if the crash reporting feature should be disabled, ask the user before
|
Defines if the crash reporting feature should be disabled, ask the user before
|
||||||
sending each crash report or send crash reportings automatically without
|
sending each crash report or send crash reportings automatically without
|
||||||
asking.. This must be assigned one of the following:
|
asking.
|
||||||
|
|
||||||
- `BITCrashManagerStatusDisabled`: Crash reporting is disabled
|
|
||||||
- `BITCrashManagerStatusAlwaysAsk`: User is asked each time before sending
|
|
||||||
- `BITCrashManagerStatusAutoSend`: Each crash report is send automatically
|
|
||||||
|
|
||||||
The default value is `BITCrashManagerStatusAlwaysAsk`. You can allow the user
|
The default value is `BITCrashManagerStatusAlwaysAsk`. You can allow the user
|
||||||
to switch from `BITCrashManagerStatusAlwaysAsk` to
|
to switch from `BITCrashManagerStatusAlwaysAsk` to
|
||||||
@ -121,6 +129,27 @@ extern NSString *const kBITCrashManagerStatus;
|
|||||||
@property (nonatomic, assign) BITCrashManagerStatus crashManagerStatus;
|
@property (nonatomic, assign) BITCrashManagerStatus crashManagerStatus;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trap fatal signals via a Mach exception server.
|
||||||
|
*
|
||||||
|
* By default the SDK is using the safe and proven in-process BSD Signals for catching crashes.
|
||||||
|
* This option provides an option to enable catching fatal signals via a Mach exception server
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
|
* We strongly advice _NOT_ to enable Mach exception handler in release versions of your apps!
|
||||||
|
*
|
||||||
|
* Default: _NO_
|
||||||
|
*
|
||||||
|
* @warning The Mach exception handler executes in-process, and will interfere with debuggers when
|
||||||
|
* they attempt to suspend all active threads (which will include the Mach exception handler).
|
||||||
|
* Mach-based handling should _NOT_ be used when a debugger is attached. The SDK will not
|
||||||
|
* enabled catching exceptions if the app is started with the debugger running. If you attach
|
||||||
|
* the debugger during runtime, this may cause issues the Mach exception handler is enabled!
|
||||||
|
* @see isDebuggerAttached
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign, getter=isMachExceptionHandlerEnabled) BOOL enableMachExceptionHandler;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Flag that determines if an "Always" option should be shown
|
Flag that determines if an "Always" option should be shown
|
||||||
|
|
||||||
@ -173,4 +202,19 @@ extern NSString *const kBITCrashManagerStatus;
|
|||||||
*/
|
*/
|
||||||
@property (nonatomic, readonly) NSTimeInterval timeintervalCrashInLastSessionOccured;
|
@property (nonatomic, readonly) NSTimeInterval timeintervalCrashInLastSessionOccured;
|
||||||
|
|
||||||
|
|
||||||
|
///-----------------------------------------------------------------------------
|
||||||
|
/// @name Helper
|
||||||
|
///-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if a debugger is attached to the app process
|
||||||
|
*
|
||||||
|
* This is only invoked once on app startup and can not detect if the debugger is being
|
||||||
|
* attached during runtime!
|
||||||
|
*
|
||||||
|
* @return BOOL if the debugger is attached on app startup
|
||||||
|
*/
|
||||||
|
- (BOOL)isDebuggerAttached;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
|
|
||||||
#import "BITHockeyManagerPrivate.h"
|
#import "BITHockeyManagerPrivate.h"
|
||||||
#import "BITHockeyBaseManagerPrivate.h"
|
#import "BITHockeyBaseManagerPrivate.h"
|
||||||
#import "BITCrashManagerPrivate.h"
|
|
||||||
#import "BITCrashReportTextFormatter.h"
|
#import "BITCrashReportTextFormatter.h"
|
||||||
|
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
@ -79,6 +78,7 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
BOOL _sendingInProgress;
|
BOOL _sendingInProgress;
|
||||||
BOOL _isSetup;
|
BOOL _isSetup;
|
||||||
|
|
||||||
|
BITPLCrashReporter *_plCrashReporter;
|
||||||
NSUncaughtExceptionHandler *_exceptionHandler;
|
NSUncaughtExceptionHandler *_exceptionHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +89,7 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
_showAlwaysButton = NO;
|
_showAlwaysButton = NO;
|
||||||
_isSetup = NO;
|
_isSetup = NO;
|
||||||
|
|
||||||
|
_plCrashReporter = nil;
|
||||||
_exceptionHandler = nil;
|
_exceptionHandler = nil;
|
||||||
|
|
||||||
_crashIdenticalCurrentVersion = YES;
|
_crashIdenticalCurrentVersion = YES;
|
||||||
@ -163,6 +164,11 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
|
|
||||||
#pragma mark - Private
|
#pragma mark - Private
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save all settings
|
||||||
|
*
|
||||||
|
* This saves the list of approved crash reports
|
||||||
|
*/
|
||||||
- (void)saveSettings {
|
- (void)saveSettings {
|
||||||
NSString *errorString = nil;
|
NSString *errorString = nil;
|
||||||
|
|
||||||
@ -180,6 +186,11 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all settings
|
||||||
|
*
|
||||||
|
* This contains the list of approved crash reports
|
||||||
|
*/
|
||||||
- (void)loadSettings {
|
- (void)loadSettings {
|
||||||
NSString *errorString = nil;
|
NSString *errorString = nil;
|
||||||
NSPropertyListFormat format;
|
NSPropertyListFormat format;
|
||||||
@ -202,6 +213,9 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all crash reports and stored meta data for each from the file system and keychain
|
||||||
|
*/
|
||||||
- (void)cleanCrashReports {
|
- (void)cleanCrashReports {
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
|
|
||||||
@ -218,6 +232,16 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
[self saveSettings];
|
[self saveSettings];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract all app sepcific UUIDs from the crash reports
|
||||||
|
*
|
||||||
|
* This allows us to send the UUIDs in the XML construct to the server, so the server does not need to parse the crash report for this data.
|
||||||
|
* The app specific UUIDs help to identify which dSYMs are needed to symbolicate this crash report.
|
||||||
|
*
|
||||||
|
* @param report The crash report from PLCrashReporter
|
||||||
|
*
|
||||||
|
* @return XML structure with the app sepcific UUIDs
|
||||||
|
*/
|
||||||
- (NSString *) extractAppUUIDs:(BITPLCrashReport *)report {
|
- (NSString *) extractAppUUIDs:(BITPLCrashReport *)report {
|
||||||
NSMutableString *uuidString = [NSMutableString string];
|
NSMutableString *uuidString = [NSMutableString string];
|
||||||
NSArray *uuidArray = [BITCrashReportTextFormatter arrayOfAppUUIDsForCrashReport:report];
|
NSArray *uuidArray = [BITCrashReportTextFormatter arrayOfAppUUIDsForCrashReport:report];
|
||||||
@ -235,6 +259,11 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
return uuidString;
|
return uuidString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the userID from the delegate which should be stored with the crash report
|
||||||
|
*
|
||||||
|
* @return The userID value
|
||||||
|
*/
|
||||||
- (NSString *)userIDForCrashReport {
|
- (NSString *)userIDForCrashReport {
|
||||||
NSString *userID = @"";
|
NSString *userID = @"";
|
||||||
|
|
||||||
@ -248,12 +277,15 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
return userID;
|
return userID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the userName from the delegate which should be stored with the crash report
|
||||||
|
*
|
||||||
|
* @return The userName value
|
||||||
|
*/
|
||||||
- (NSString *)userNameForCrashReport {
|
- (NSString *)userNameForCrashReport {
|
||||||
NSString *username = @"";
|
NSString *username = @"";
|
||||||
|
|
||||||
if (self.delegate && [self.delegate respondsToSelector:@selector(userNameForCrashManager:)]) {
|
if (self.delegate && [self.delegate respondsToSelector:@selector(userNameForCrashManager:)]) {
|
||||||
if (!self.isAppStoreEnvironment)
|
|
||||||
NSLog(@"[HockeySDK] DEPRECATED: Please use BITHockeyManagerDelegate's userNameForHockeyManager:componentManager: or userIDForHockeyManager:componentManager: instead.");
|
|
||||||
username = [self.delegate userNameForCrashManager:self] ?: @"";
|
username = [self.delegate userNameForCrashManager:self] ?: @"";
|
||||||
}
|
}
|
||||||
if ([BITHockeyManager sharedHockeyManager].delegate &&
|
if ([BITHockeyManager sharedHockeyManager].delegate &&
|
||||||
@ -266,12 +298,15 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the userEmail from the delegate which should be stored with the crash report
|
||||||
|
*
|
||||||
|
* @return The userEmail value
|
||||||
|
*/
|
||||||
- (NSString *)userEmailForCrashReport {
|
- (NSString *)userEmailForCrashReport {
|
||||||
NSString *useremail = @"";
|
NSString *useremail = @"";
|
||||||
|
|
||||||
if (self.delegate && [self.delegate respondsToSelector:@selector(userEmailForCrashManager:)]) {
|
if (self.delegate && [self.delegate respondsToSelector:@selector(userEmailForCrashManager:)]) {
|
||||||
if (!self.isAppStoreEnvironment)
|
|
||||||
NSLog(@"[HockeySDK] DEPRECATED: Please use BITHockeyManagerDelegate's userEmailForHockeyManager:componentManager: instead.");
|
|
||||||
useremail = [self.delegate userEmailForCrashManager:self] ?: @"";
|
useremail = [self.delegate userEmailForCrashManager:self] ?: @"";
|
||||||
}
|
}
|
||||||
if ([BITHockeyManager sharedHockeyManager].delegate &&
|
if ([BITHockeyManager sharedHockeyManager].delegate &&
|
||||||
@ -284,13 +319,55 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
return useremail;
|
return useremail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Public
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the debugger is attached
|
||||||
|
*
|
||||||
|
* Taken from https://github.com/plausiblelabs/plcrashreporter/blob/2dd862ce049e6f43feb355308dfc710f3af54c4d/Source/Crash%20Demo/main.m#L96
|
||||||
|
*
|
||||||
|
* @return `YES` if the debugger is attached to the current process, `NO` otherwise
|
||||||
|
*/
|
||||||
|
- (BOOL)isDebuggerAttached {
|
||||||
|
static BOOL debuggerIsAttached = NO;
|
||||||
|
|
||||||
|
static dispatch_once_t debuggerPredicate;
|
||||||
|
dispatch_once(&debuggerPredicate, ^{
|
||||||
|
struct kinfo_proc info;
|
||||||
|
size_t info_size = sizeof(info);
|
||||||
|
int name[4];
|
||||||
|
|
||||||
|
name[0] = CTL_KERN;
|
||||||
|
name[1] = KERN_PROC;
|
||||||
|
name[2] = KERN_PROC_PID;
|
||||||
|
name[3] = getpid();
|
||||||
|
|
||||||
|
if (sysctl(name, 4, &info, &info_size, NULL, 0) == -1) {
|
||||||
|
NSLog(@"[HockeySDK] ERROR: Checking for a running debugger via sysctl() failed: %s", strerror(errno));
|
||||||
|
debuggerIsAttached = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!debuggerIsAttached && (info.kp_proc.p_flag & P_TRACED) != 0)
|
||||||
|
debuggerIsAttached = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return debuggerIsAttached;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - PLCrashReporter
|
#pragma mark - PLCrashReporter
|
||||||
|
|
||||||
// Called to handle a pending crash report.
|
/**
|
||||||
|
* Process new crash reports provided by PLCrashReporter
|
||||||
|
*
|
||||||
|
* Parse the new crash report and gather additional meta data from the app which will be stored along the crash report
|
||||||
|
*/
|
||||||
- (void) handleCrashReport {
|
- (void) handleCrashReport {
|
||||||
BITPLCrashReporter *crashReporter = [BITPLCrashReporter sharedReporter];
|
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
|
|
||||||
|
if (!_plCrashReporter) return;
|
||||||
|
|
||||||
[self loadSettings];
|
[self loadSettings];
|
||||||
|
|
||||||
// check if the next call ran successfully the last time
|
// check if the next call ran successfully the last time
|
||||||
@ -301,7 +378,7 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
[self saveSettings];
|
[self saveSettings];
|
||||||
|
|
||||||
// Try loading the crash report
|
// Try loading the crash report
|
||||||
NSData *crashData = [[NSData alloc] initWithData:[crashReporter loadPendingCrashReportDataAndReturnError: &error]];
|
NSData *crashData = [[NSData alloc] initWithData:[_plCrashReporter loadPendingCrashReportDataAndReturnError: &error]];
|
||||||
|
|
||||||
NSString *cacheFilename = [NSString stringWithFormat: @"%.0f", [NSDate timeIntervalSinceReferenceDate]];
|
NSString *cacheFilename = [NSString stringWithFormat: @"%.0f", [NSDate timeIntervalSinceReferenceDate]];
|
||||||
|
|
||||||
@ -311,35 +388,39 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
// get the startup timestamp from the crash report, and the file timestamp to calculate the timeinterval when the crash happened after startup
|
// get the startup timestamp from the crash report, and the file timestamp to calculate the timeinterval when the crash happened after startup
|
||||||
BITPLCrashReport *report = [[BITPLCrashReport alloc] initWithData:crashData error:&error];
|
BITPLCrashReport *report = [[BITPLCrashReport alloc] initWithData:crashData error:&error];
|
||||||
|
|
||||||
if ([report.processInfo respondsToSelector:@selector(processStartTime)]) {
|
if (report == nil) {
|
||||||
if (report.systemInfo.timestamp && report.processInfo.processStartTime) {
|
BITHockeyLog(@"WARNING: Could not parse crash report");
|
||||||
_timeintervalCrashInLastSessionOccured = [report.systemInfo.timestamp timeIntervalSinceDate:report.processInfo.processStartTime];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES];
|
|
||||||
|
|
||||||
// write the meta file
|
|
||||||
NSMutableDictionary *metaDict = [NSMutableDictionary dictionaryWithCapacity:4];
|
|
||||||
NSString *applicationLog = @"";
|
|
||||||
NSString *errorString = nil;
|
|
||||||
|
|
||||||
[self addStringValueToKeychain:[self userNameForCrashReport] forKey:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserName]];
|
|
||||||
[self addStringValueToKeychain:[self userEmailForCrashReport] forKey:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserEmail]];
|
|
||||||
[self addStringValueToKeychain:[self userIDForCrashReport] forKey:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]];
|
|
||||||
|
|
||||||
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(applicationLogForCrashManager:)]) {
|
|
||||||
applicationLog = [self.delegate applicationLogForCrashManager:self] ?: @"";
|
|
||||||
}
|
|
||||||
[metaDict setObject:applicationLog forKey:kBITCrashMetaApplicationLog];
|
|
||||||
|
|
||||||
NSData *plist = [NSPropertyListSerialization dataFromPropertyList:(id)metaDict
|
|
||||||
format:NSPropertyListBinaryFormat_v1_0
|
|
||||||
errorDescription:&errorString];
|
|
||||||
if (plist) {
|
|
||||||
[plist writeToFile:[NSString stringWithFormat:@"%@.meta", [_crashesDir stringByAppendingPathComponent: cacheFilename]] atomically:YES];
|
|
||||||
} else {
|
} else {
|
||||||
BITHockeyLog(@"ERROR: Writing crash meta data failed. %@", error);
|
if ([report.processInfo respondsToSelector:@selector(processStartTime)]) {
|
||||||
|
if (report.systemInfo.timestamp && report.processInfo.processStartTime) {
|
||||||
|
_timeintervalCrashInLastSessionOccured = [report.systemInfo.timestamp timeIntervalSinceDate:report.processInfo.processStartTime];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES];
|
||||||
|
|
||||||
|
// write the meta file
|
||||||
|
NSMutableDictionary *metaDict = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||||
|
NSString *applicationLog = @"";
|
||||||
|
NSString *errorString = nil;
|
||||||
|
|
||||||
|
[self addStringValueToKeychain:[self userNameForCrashReport] forKey:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserName]];
|
||||||
|
[self addStringValueToKeychain:[self userEmailForCrashReport] forKey:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserEmail]];
|
||||||
|
[self addStringValueToKeychain:[self userIDForCrashReport] forKey:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]];
|
||||||
|
|
||||||
|
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(applicationLogForCrashManager:)]) {
|
||||||
|
applicationLog = [self.delegate applicationLogForCrashManager:self] ?: @"";
|
||||||
|
}
|
||||||
|
[metaDict setObject:applicationLog forKey:kBITCrashMetaApplicationLog];
|
||||||
|
|
||||||
|
NSData *plist = [NSPropertyListSerialization dataFromPropertyList:(id)metaDict
|
||||||
|
format:NSPropertyListBinaryFormat_v1_0
|
||||||
|
errorDescription:&errorString];
|
||||||
|
if (plist) {
|
||||||
|
[plist writeToFile:[NSString stringWithFormat:@"%@.meta", [_crashesDir stringByAppendingPathComponent: cacheFilename]] atomically:YES];
|
||||||
|
} else {
|
||||||
|
BITHockeyLog(@"ERROR: Writing crash meta data failed. %@", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -352,9 +433,14 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
|
|
||||||
[self saveSettings];
|
[self saveSettings];
|
||||||
|
|
||||||
[crashReporter purgePendingCrashReport];
|
[_plCrashReporter purgePendingCrashReport];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there are any crash reports available which the user did not approve yet
|
||||||
|
*
|
||||||
|
* @return `YES` if there are crash reports pending that are not approved, `NO` otherwise
|
||||||
|
*/
|
||||||
- (BOOL)hasNonApprovedCrashReports {
|
- (BOOL)hasNonApprovedCrashReports {
|
||||||
if (!_approvedCrashReports || [_approvedCrashReports count] == 0) return YES;
|
if (!_approvedCrashReports || [_approvedCrashReports count] == 0) return YES;
|
||||||
|
|
||||||
@ -367,6 +453,11 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there are any new crash reports that are not yet processed
|
||||||
|
*
|
||||||
|
* @return `YES` if ther eis at least one new crash report found, `NO` otherwise
|
||||||
|
*/
|
||||||
- (BOOL)hasPendingCrashReport {
|
- (BOOL)hasPendingCrashReport {
|
||||||
if (_crashManagerStatus == BITCrashManagerStatusDisabled) return NO;
|
if (_crashManagerStatus == BITCrashManagerStatusDisabled) return NO;
|
||||||
|
|
||||||
@ -406,7 +497,13 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
|
|
||||||
#pragma mark - Crash Report Processing
|
#pragma mark - Crash Report Processing
|
||||||
|
|
||||||
// slightly delayed startup processing, so we don't keep the first runloop on startup busy for too long
|
/**
|
||||||
|
* Delayed startup processing for everything that does not to be done in the app startup runloop
|
||||||
|
*
|
||||||
|
* - Checks if there is another exception handler installed that may block ours
|
||||||
|
* - Present UI if the user has to approve new crash reports
|
||||||
|
* - Send pending approved crash reports
|
||||||
|
*/
|
||||||
- (void)invokeDelayedProcessing {
|
- (void)invokeDelayedProcessing {
|
||||||
BITHockeyLog(@"INFO: Start delayed CrashManager processing");
|
BITHockeyLog(@"INFO: Start delayed CrashManager processing");
|
||||||
|
|
||||||
@ -463,70 +560,93 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// begin the startup process
|
/**
|
||||||
|
* Main startup sequence initializing PLCrashReporter if it wasn't disabled
|
||||||
|
*/
|
||||||
- (void)startManager {
|
- (void)startManager {
|
||||||
if (_crashManagerStatus == BITCrashManagerStatusDisabled) return;
|
if (_crashManagerStatus == BITCrashManagerStatusDisabled) return;
|
||||||
|
|
||||||
if (!_isSetup) {
|
if (!_isSetup) {
|
||||||
BITPLCrashReporter *crashReporter = [BITPLCrashReporter sharedReporter];
|
static dispatch_once_t plcrPredicate;
|
||||||
NSError *error = NULL;
|
dispatch_once(&plcrPredicate, ^{
|
||||||
|
/* Configure our reporter */
|
||||||
|
|
||||||
// Check if we previously crashed
|
PLCrashReporterSignalHandlerType signalHandlerType = PLCrashReporterSignalHandlerTypeBSD;
|
||||||
if ([crashReporter hasPendingCrashReport]) {
|
if (self.isMachExceptionHandlerEnabled) {
|
||||||
_didCrashInLastSession = YES;
|
signalHandlerType = PLCrashReporterSignalHandlerTypeMach;
|
||||||
[self handleCrashReport];
|
|
||||||
}
|
|
||||||
|
|
||||||
// PLCrashReporter is throwing an NSException if it is being enabled again
|
|
||||||
// even though it already is enabled
|
|
||||||
@try {
|
|
||||||
// Multiple exception handlers can be set, but we can only query the top level error handler (uncaught exception handler).
|
|
||||||
//
|
|
||||||
// To check if PLCrashReporter's error handler is successfully added, we compare the top
|
|
||||||
// level one that is set before and the one after PLCrashReporter sets up its own.
|
|
||||||
//
|
|
||||||
// With delayed processing we can then check if another error handler was set up afterwards
|
|
||||||
// and can show a debug warning log message, that the dev has to make sure the "newer" error handler
|
|
||||||
// doesn't exit the process itself, because then all subsequent handlers would never be invoked.
|
|
||||||
//
|
|
||||||
// Note: ANY error handler setup BEFORE HockeySDK initialization will not be processed!
|
|
||||||
|
|
||||||
// get the current top level error handler
|
|
||||||
NSUncaughtExceptionHandler *initialHandler = NSGetUncaughtExceptionHandler();
|
|
||||||
|
|
||||||
// Enable the Crash Reporter
|
|
||||||
if (![crashReporter enableCrashReporterAndReturnError: &error])
|
|
||||||
NSLog(@"[HockeySDK] WARNING: Could not enable crash reporter: %@", [error localizedDescription]);
|
|
||||||
|
|
||||||
// get the new current top level error handler, which should now be the one from PLCrashReporter
|
|
||||||
NSUncaughtExceptionHandler *currentHandler = NSGetUncaughtExceptionHandler();
|
|
||||||
|
|
||||||
// do we have a new top level error handler? then we were successful
|
|
||||||
if (currentHandler && currentHandler != initialHandler) {
|
|
||||||
_exceptionHandler = currentHandler;
|
|
||||||
|
|
||||||
BITHockeyLog(@"INFO: Exception handler successfully initialized.");
|
|
||||||
} else {
|
|
||||||
// this should never happen, theoretically only if NSSetUncaugtExceptionHandler() has some internal issues
|
|
||||||
NSLog(@"[HockeySDK] ERROR: Exception handler could not be set. Make sure there is no other exception handler set up!");
|
|
||||||
}
|
}
|
||||||
}
|
BITPLCrashReporterConfig *config = [[BITPLCrashReporterConfig alloc] initWithSignalHandlerType: signalHandlerType
|
||||||
@catch (NSException * e) {
|
symbolicationStrategy: PLCrashReporterSymbolicationStrategyAll];
|
||||||
NSLog(@"[HockeySDK] WARNING: %@", [e reason]);
|
_plCrashReporter = [[BITPLCrashReporter alloc] initWithConfiguration: config];
|
||||||
}
|
|
||||||
|
|
||||||
_isSetup = YES;
|
// Check if we previously crashed
|
||||||
|
if ([_plCrashReporter hasPendingCrashReport]) {
|
||||||
|
_didCrashInLastSession = YES;
|
||||||
|
[self handleCrashReport];
|
||||||
|
}
|
||||||
|
|
||||||
|
// The actual signal and mach handlers are only registered when invoking `enableCrashReporterAndReturnError`
|
||||||
|
// So it is safe enough to only disable the following part when a debugger is attached no matter which
|
||||||
|
// signal handler type is set
|
||||||
|
// We only check for this if we are not in the App Store environment
|
||||||
|
|
||||||
|
BOOL debuggerIsAttached = NO;
|
||||||
|
if (![self isAppStoreEnvironment]) {
|
||||||
|
if ([self isDebuggerAttached]) {
|
||||||
|
debuggerIsAttached = YES;
|
||||||
|
NSLog(@"[HockeySDK] WARNING: Detecting crashes is NOT enabled due to running the app with a debugger attached.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!debuggerIsAttached) {
|
||||||
|
// Multiple exception handlers can be set, but we can only query the top level error handler (uncaught exception handler).
|
||||||
|
//
|
||||||
|
// To check if PLCrashReporter's error handler is successfully added, we compare the top
|
||||||
|
// level one that is set before and the one after PLCrashReporter sets up its own.
|
||||||
|
//
|
||||||
|
// With delayed processing we can then check if another error handler was set up afterwards
|
||||||
|
// and can show a debug warning log message, that the dev has to make sure the "newer" error handler
|
||||||
|
// doesn't exit the process itself, because then all subsequent handlers would never be invoked.
|
||||||
|
//
|
||||||
|
// Note: ANY error handler setup BEFORE HockeySDK initialization will not be processed!
|
||||||
|
|
||||||
|
// get the current top level error handler
|
||||||
|
NSUncaughtExceptionHandler *initialHandler = NSGetUncaughtExceptionHandler();
|
||||||
|
|
||||||
|
// PLCrashReporter may only be initialized once. So make sure the developer
|
||||||
|
// can't break this
|
||||||
|
NSError *error = NULL;
|
||||||
|
|
||||||
|
// Enable the Crash Reporter
|
||||||
|
if (![_plCrashReporter enableCrashReporterAndReturnError: &error])
|
||||||
|
NSLog(@"[HockeySDK] WARNING: Could not enable crash reporter: %@", [error localizedDescription]);
|
||||||
|
|
||||||
|
// get the new current top level error handler, which should now be the one from PLCrashReporter
|
||||||
|
NSUncaughtExceptionHandler *currentHandler = NSGetUncaughtExceptionHandler();
|
||||||
|
|
||||||
|
// do we have a new top level error handler? then we were successful
|
||||||
|
if (currentHandler && currentHandler != initialHandler) {
|
||||||
|
_exceptionHandler = currentHandler;
|
||||||
|
|
||||||
|
BITHockeyLog(@"INFO: Exception handler successfully initialized.");
|
||||||
|
} else {
|
||||||
|
// this should never happen, theoretically only if NSSetUncaugtExceptionHandler() has some internal issues
|
||||||
|
NSLog(@"[HockeySDK] ERROR: Exception handler could not be set. Make sure there is no other exception handler set up!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_isSetup = YES;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[self performSelector:@selector(invokeDelayedProcessing) withObject:nil afterDelay:0.5];
|
[self performSelector:@selector(invokeDelayedProcessing) withObject:nil afterDelay:0.5];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send all approved crash reports
|
||||||
|
*
|
||||||
|
* Gathers all collected data and constructs the XML structure and starts the sending process
|
||||||
|
*/
|
||||||
- (void)sendCrashReports {
|
- (void)sendCrashReports {
|
||||||
// send it to the next runloop
|
|
||||||
[self performSelector:@selector(performSendingCrashReports) withObject:nil afterDelay:1.0f];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)performSendingCrashReports {
|
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
|
|
||||||
NSMutableString *crashes = nil;
|
NSMutableString *crashes = nil;
|
||||||
@ -670,6 +790,13 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
|
|||||||
|
|
||||||
#pragma mark - Networking
|
#pragma mark - Networking
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the XML data to the server
|
||||||
|
*
|
||||||
|
* Wraps the XML structure into a POST body and starts sending the data asynchronously
|
||||||
|
*
|
||||||
|
* @param xml The XML data that needs to be send to the server
|
||||||
|
*/
|
||||||
- (void)postXML:(NSString*)xml {
|
- (void)postXML:(NSString*)xml {
|
||||||
NSMutableURLRequest *request = nil;
|
NSMutableURLRequest *request = nil;
|
||||||
NSString *boundary = @"----FOO";
|
NSString *boundary = @"----FOO";
|
||||||
|
@ -208,8 +208,9 @@ NSInteger binaryImageSort(id binary1, id binary2, void *context);
|
|||||||
processPath = report.processInfo.processPath;
|
processPath = report.processInfo.processPath;
|
||||||
|
|
||||||
/* Remove username from the path */
|
/* Remove username from the path */
|
||||||
processPath = [processPath stringByAbbreviatingWithTildeInPath];
|
if ([processPath length] > 0)
|
||||||
if ([[processPath substringToIndex:1] isEqualToString:@"~"])
|
processPath = [processPath stringByAbbreviatingWithTildeInPath];
|
||||||
|
if ([processPath length] > 0 && [[processPath substringToIndex:1] isEqualToString:@"~"])
|
||||||
processPath = [NSString stringWithFormat:@"/Users/USER%@", [processPath substringFromIndex:1]];
|
processPath = [NSString stringWithFormat:@"/Users/USER%@", [processPath substringFromIndex:1]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,8 +413,10 @@ NSInteger binaryImageSort(id binary1, id binary2, void *context);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Remove username from the image path */
|
/* Remove username from the image path */
|
||||||
NSString *imageName = [imageInfo.imageName stringByAbbreviatingWithTildeInPath];
|
NSString *imageName = @"";
|
||||||
if ([[imageName substringToIndex:1] isEqualToString:@"~"])
|
if (imageInfo.imageName && [imageInfo.imageName length] > 0)
|
||||||
|
imageName = [imageInfo.imageName stringByAbbreviatingWithTildeInPath];
|
||||||
|
if ([imageName length] > 0 && [[imageName substringToIndex:1] isEqualToString:@"~"])
|
||||||
imageName = [NSString stringWithFormat:@"/Users/USER%@", [imageName substringFromIndex:1]];
|
imageName = [NSString stringWithFormat:@"/Users/USER%@", [imageName substringFromIndex:1]];
|
||||||
|
|
||||||
[text appendFormat: fmt,
|
[text appendFormat: fmt,
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#import "BITHockeyHelper.h"
|
#import "BITHockeyHelper.h"
|
||||||
#import "BITFeedbackManagerPrivate.h"
|
#import "BITFeedbackManagerPrivate.h"
|
||||||
|
|
||||||
|
#import "BITHockeyBaseManagerPrivate.h"
|
||||||
|
|
||||||
|
|
||||||
@interface BITFeedbackActivity()
|
@interface BITFeedbackActivity()
|
||||||
|
|
||||||
@ -87,14 +89,14 @@
|
|||||||
|
|
||||||
- (UIViewController *)activityViewController {
|
- (UIViewController *)activityViewController {
|
||||||
// TODO: return compose controller with activity content added
|
// TODO: return compose controller with activity content added
|
||||||
BITFeedbackComposeViewController *composeViewController = [[BITHockeyManager sharedHockeyManager].feedbackManager feedbackComposeViewController];
|
BITFeedbackManager *manager = [BITHockeyManager sharedHockeyManager].feedbackManager;
|
||||||
|
|
||||||
|
BITFeedbackComposeViewController *composeViewController = [manager feedbackComposeViewController];
|
||||||
composeViewController.delegate = self;
|
composeViewController.delegate = self;
|
||||||
[composeViewController prepareWithItems:_items];
|
[composeViewController prepareWithItems:_items];
|
||||||
|
|
||||||
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: composeViewController];
|
UINavigationController *navController = [manager customNavigationControllerWithRootViewController:composeViewController
|
||||||
navController.navigationBar.barStyle = [[[BITHockeyManager sharedHockeyManager] feedbackManager] barStyle];
|
presentationStyle:UIModalPresentationFormSheet];
|
||||||
navController.navigationBar.tintColor = [[[BITHockeyManager sharedHockeyManager] feedbackManager] tintColor];
|
|
||||||
navController.modalPresentationStyle = UIModalPresentationFormSheet;
|
|
||||||
navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
|
navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
|
||||||
|
|
||||||
return navController;
|
return navController;
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
#import "BITFeedbackComposeViewController.h"
|
#import "BITFeedbackComposeViewController.h"
|
||||||
#import "BITFeedbackUserDataViewController.h"
|
#import "BITFeedbackUserDataViewController.h"
|
||||||
|
|
||||||
|
#import "BITHockeyBaseManagerPrivate.h"
|
||||||
|
|
||||||
#import "BITHockeyHelper.h"
|
#import "BITHockeyHelper.h"
|
||||||
|
|
||||||
|
|
||||||
@ -222,10 +224,8 @@
|
|||||||
BITFeedbackUserDataViewController *userController = [[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped];
|
BITFeedbackUserDataViewController *userController = [[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped];
|
||||||
userController.delegate = self;
|
userController.delegate = self;
|
||||||
|
|
||||||
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:userController];
|
UINavigationController *navController = [self.manager customNavigationControllerWithRootViewController:userController
|
||||||
navController.navigationBar.barStyle = [self.manager barStyle];
|
presentationStyle:UIModalPresentationFormSheet];
|
||||||
navController.navigationBar.tintColor = [self.manager tintColor];
|
|
||||||
navController.modalPresentationStyle = UIModalPresentationFormSheet;
|
|
||||||
|
|
||||||
[self presentViewController:navController animated:YES completion:nil];
|
[self presentViewController:navController animated:YES completion:nil];
|
||||||
}
|
}
|
||||||
|
@ -31,15 +31,40 @@
|
|||||||
#import "BITFeedbackMessage.h"
|
#import "BITFeedbackMessage.h"
|
||||||
#import "BITAttributedLabel.h"
|
#import "BITAttributedLabel.h"
|
||||||
|
|
||||||
typedef enum {
|
/**
|
||||||
|
* Cell style depending on the iOS version
|
||||||
|
*/
|
||||||
|
typedef NS_ENUM(NSUInteger, BITFeedbackListViewCellPresentatationStyle) {
|
||||||
|
/**
|
||||||
|
* Default is iOS 6 style
|
||||||
|
*/
|
||||||
|
BITFeedbackListViewCellPresentatationStyleDefault = 0,
|
||||||
|
/**
|
||||||
|
* Draw cells in the iOS 7 style
|
||||||
|
*/
|
||||||
|
BITFeedbackListViewCellPresentatationStyleOS7 = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cell background style
|
||||||
|
*/
|
||||||
|
typedef NS_ENUM(NSUInteger, BITFeedbackListViewCellBackgroundStyle) {
|
||||||
|
/**
|
||||||
|
* For even rows
|
||||||
|
*/
|
||||||
BITFeedbackListViewCellBackgroundStyleNormal = 0,
|
BITFeedbackListViewCellBackgroundStyleNormal = 0,
|
||||||
|
/**
|
||||||
|
* For uneven rows
|
||||||
|
*/
|
||||||
BITFeedbackListViewCellBackgroundStyleAlternate = 1
|
BITFeedbackListViewCellBackgroundStyleAlternate = 1
|
||||||
} BITFeedbackListViewCellBackgroundStyle;
|
};
|
||||||
|
|
||||||
@interface BITFeedbackListViewCell : UITableViewCell
|
@interface BITFeedbackListViewCell : UITableViewCell
|
||||||
|
|
||||||
@property (nonatomic, strong) BITFeedbackMessage *message;
|
@property (nonatomic, strong) BITFeedbackMessage *message;
|
||||||
|
|
||||||
|
@property (nonatomic) BITFeedbackListViewCellPresentatationStyle style;
|
||||||
|
|
||||||
@property (nonatomic) BITFeedbackListViewCellBackgroundStyle backgroundStyle;
|
@property (nonatomic) BITFeedbackListViewCellBackgroundStyle backgroundStyle;
|
||||||
|
|
||||||
@property (nonatomic, strong) BITAttributedLabel *labelText;
|
@property (nonatomic, strong) BITAttributedLabel *labelText;
|
||||||
|
@ -33,6 +33,9 @@
|
|||||||
#define BACKGROUNDCOLOR_DEFAULT BIT_RGBCOLOR(245, 245, 245)
|
#define BACKGROUNDCOLOR_DEFAULT BIT_RGBCOLOR(245, 245, 245)
|
||||||
#define BACKGROUNDCOLOR_ALTERNATE BIT_RGBCOLOR(235, 235, 235)
|
#define BACKGROUNDCOLOR_ALTERNATE BIT_RGBCOLOR(235, 235, 235)
|
||||||
|
|
||||||
|
#define BACKGROUNDCOLOR_DEFAULT_OS7 BIT_RGBCOLOR(255, 255, 255)
|
||||||
|
#define BACKGROUNDCOLOR_ALTERNATE_OS7 BIT_RGBCOLOR(255, 255, 255)
|
||||||
|
|
||||||
#define TEXTCOLOR_TITLE BIT_RGBCOLOR(75, 75, 75)
|
#define TEXTCOLOR_TITLE BIT_RGBCOLOR(75, 75, 75)
|
||||||
|
|
||||||
#define TEXTCOLOR_DEFAULT BIT_RGBCOLOR(25, 25, 25)
|
#define TEXTCOLOR_DEFAULT BIT_RGBCOLOR(25, 25, 25)
|
||||||
@ -69,6 +72,7 @@
|
|||||||
if (self) {
|
if (self) {
|
||||||
// Initialization code
|
// Initialization code
|
||||||
_backgroundStyle = BITFeedbackListViewCellBackgroundStyleNormal;
|
_backgroundStyle = BITFeedbackListViewCellBackgroundStyleNormal;
|
||||||
|
_style = BITFeedbackListViewCellPresentatationStyleDefault;
|
||||||
|
|
||||||
_message = nil;
|
_message = nil;
|
||||||
|
|
||||||
@ -99,6 +103,22 @@
|
|||||||
|
|
||||||
#pragma mark - Private
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (UIColor *)backgroundColor {
|
||||||
|
if (self.backgroundStyle == BITFeedbackListViewCellBackgroundStyleNormal) {
|
||||||
|
if (self.style == BITFeedbackListViewCellPresentatationStyleDefault) {
|
||||||
|
return BACKGROUNDCOLOR_DEFAULT;
|
||||||
|
} else {
|
||||||
|
return BACKGROUNDCOLOR_DEFAULT_OS7;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (self.style == BITFeedbackListViewCellPresentatationStyleDefault) {
|
||||||
|
return BACKGROUNDCOLOR_ALTERNATE;
|
||||||
|
} else {
|
||||||
|
return BACKGROUNDCOLOR_ALTERNATE_OS7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)isSameDayWithDate1:(NSDate*)date1 date2:(NSDate*)date2 {
|
- (BOOL)isSameDayWithDate1:(NSDate*)date1 date2:(NSDate*)date2 {
|
||||||
NSCalendar* calendar = [NSCalendar currentCalendar];
|
NSCalendar* calendar = [NSCalendar currentCalendar];
|
||||||
|
|
||||||
@ -126,17 +146,11 @@
|
|||||||
accessoryViewBackground.clipsToBounds = YES;
|
accessoryViewBackground.clipsToBounds = YES;
|
||||||
|
|
||||||
// colors
|
// colors
|
||||||
if (_backgroundStyle == BITFeedbackListViewCellBackgroundStyleNormal) {
|
accessoryViewBackground.backgroundColor = [self backgroundColor];
|
||||||
accessoryViewBackground.backgroundColor = BACKGROUNDCOLOR_DEFAULT;
|
self.contentView.backgroundColor = [self backgroundColor];
|
||||||
self.contentView.backgroundColor = BACKGROUNDCOLOR_DEFAULT;
|
self.labelTitle.backgroundColor = [self backgroundColor];
|
||||||
self.labelTitle.backgroundColor = BACKGROUNDCOLOR_DEFAULT;
|
self.labelText.backgroundColor = [self backgroundColor];
|
||||||
self.labelText.backgroundColor = BACKGROUNDCOLOR_DEFAULT;
|
|
||||||
} else {
|
|
||||||
accessoryViewBackground.backgroundColor = BACKGROUNDCOLOR_ALTERNATE;
|
|
||||||
self.contentView.backgroundColor = BACKGROUNDCOLOR_ALTERNATE;
|
|
||||||
self.labelTitle.backgroundColor = BACKGROUNDCOLOR_ALTERNATE;
|
|
||||||
self.labelText.backgroundColor = BACKGROUNDCOLOR_ALTERNATE;
|
|
||||||
}
|
|
||||||
self.labelTitle.textColor = TEXTCOLOR_TITLE;
|
self.labelTitle.textColor = TEXTCOLOR_TITLE;
|
||||||
if (_message.status == BITFeedbackMessageStatusSendPending || _message.status == BITFeedbackMessageStatusSendInProgress) {
|
if (_message.status == BITFeedbackMessageStatusSendPending || _message.status == BITFeedbackMessageStatusSendInProgress) {
|
||||||
[self.labelText setTextColor:TEXTCOLOR_PENDING];
|
[self.labelText setTextColor:TEXTCOLOR_PENDING];
|
||||||
|
@ -38,11 +38,14 @@
|
|||||||
#import "BITFeedbackMessage.h"
|
#import "BITFeedbackMessage.h"
|
||||||
#import "BITAttributedLabel.h"
|
#import "BITAttributedLabel.h"
|
||||||
|
|
||||||
|
#import "BITHockeyBaseManagerPrivate.h"
|
||||||
|
|
||||||
#import "BITHockeyHelper.h"
|
#import "BITHockeyHelper.h"
|
||||||
#import <QuartzCore/QuartzCore.h>
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
|
|
||||||
#define DEFAULT_BACKGROUNDCOLOR BIT_RGBCOLOR(245, 245, 245)
|
#define DEFAULT_BACKGROUNDCOLOR BIT_RGBCOLOR(245, 245, 245)
|
||||||
|
#define DEFAULT_BACKGROUNDCOLOR_OS7 BIT_RGBCOLOR(255, 255, 255)
|
||||||
#define DEFAULT_TEXTCOLOR BIT_RGBCOLOR(75, 75, 75)
|
#define DEFAULT_TEXTCOLOR BIT_RGBCOLOR(75, 75, 75)
|
||||||
|
|
||||||
#define BUTTON_BORDERCOLOR BIT_RGBCOLOR(175, 175, 175)
|
#define BUTTON_BORDERCOLOR BIT_RGBCOLOR(175, 175, 175)
|
||||||
@ -118,10 +121,18 @@
|
|||||||
self.tableView.dataSource = self;
|
self.tableView.dataSource = self;
|
||||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||||
[self.tableView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
|
[self.tableView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
|
||||||
[self.tableView setBackgroundColor:[UIColor colorWithRed:0.82 green:0.84 blue:0.84 alpha:1]];
|
if ([self.manager isPreiOS7Environment]) {
|
||||||
[self.tableView setSeparatorColor:[UIColor colorWithRed:0.79 green:0.79 blue:0.79 alpha:1]];
|
[self.tableView setBackgroundColor:[UIColor colorWithRed:0.82 green:0.84 blue:0.84 alpha:1]];
|
||||||
|
[self.tableView setSeparatorColor:[UIColor colorWithRed:0.79 green:0.79 blue:0.79 alpha:1]];
|
||||||
|
} else {
|
||||||
|
[self.tableView setBackgroundColor:[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1]];
|
||||||
|
}
|
||||||
|
|
||||||
self.view.backgroundColor = DEFAULT_BACKGROUNDCOLOR;
|
if ([self.manager isPreiOS7Environment]) {
|
||||||
|
self.view.backgroundColor = DEFAULT_BACKGROUNDCOLOR;
|
||||||
|
} else {
|
||||||
|
self.view.backgroundColor = DEFAULT_BACKGROUNDCOLOR_OS7;
|
||||||
|
}
|
||||||
|
|
||||||
id refreshClass = NSClassFromString(@"UIRefreshControl");
|
id refreshClass = NSClassFromString(@"UIRefreshControl");
|
||||||
if (refreshClass) {
|
if (refreshClass) {
|
||||||
@ -234,10 +245,8 @@
|
|||||||
BITFeedbackUserDataViewController *userController = [[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped];
|
BITFeedbackUserDataViewController *userController = [[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped];
|
||||||
userController.delegate = self;
|
userController.delegate = self;
|
||||||
|
|
||||||
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:userController];
|
UINavigationController *navController = [self.manager customNavigationControllerWithRootViewController:userController
|
||||||
navController.navigationBar.barStyle = [self.manager barStyle];
|
presentationStyle:UIModalPresentationFormSheet];
|
||||||
navController.navigationBar.tintColor = [self.manager tintColor];
|
|
||||||
navController.modalPresentationStyle = UIModalPresentationFormSheet;
|
|
||||||
|
|
||||||
[self presentViewController:navController animated:YES completion:nil];
|
[self presentViewController:navController animated:YES completion:nil];
|
||||||
}
|
}
|
||||||
@ -245,10 +254,8 @@
|
|||||||
- (void)newFeedbackAction:(id)sender {
|
- (void)newFeedbackAction:(id)sender {
|
||||||
BITFeedbackComposeViewController *composeController = [[BITFeedbackComposeViewController alloc] init];
|
BITFeedbackComposeViewController *composeController = [[BITFeedbackComposeViewController alloc] init];
|
||||||
|
|
||||||
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:composeController];
|
UINavigationController *navController = [self.manager customNavigationControllerWithRootViewController:composeController
|
||||||
navController.navigationBar.barStyle = [self.manager barStyle];
|
presentationStyle:UIModalPresentationFormSheet];
|
||||||
navController.navigationBar.tintColor = [self.manager tintColor];
|
|
||||||
navController.modalPresentationStyle = UIModalPresentationFormSheet;
|
|
||||||
|
|
||||||
[self presentViewController:navController animated:YES completion:nil];
|
[self presentViewController:navController animated:YES completion:nil];
|
||||||
}
|
}
|
||||||
@ -449,18 +456,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// button
|
// button
|
||||||
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
UIButton *button = nil;
|
||||||
button.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
if ([self.manager isPreiOS7Environment]) {
|
||||||
UIImage *stretchableButton = [bit_imageNamed(@"buttonRoundedRegular.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0];
|
button = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
UIImage *stretchableHighlightedButton = [bit_imageNamed(@"buttonRoundedRegularHighlighted.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0];
|
button.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||||
[button setBackgroundImage:stretchableButton forState:UIControlStateNormal];
|
UIImage *stretchableButton = [bit_imageNamed(@"buttonRoundedRegular.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0];
|
||||||
[button setBackgroundImage:stretchableHighlightedButton forState:UIControlStateHighlighted];
|
UIImage *stretchableHighlightedButton = [bit_imageNamed(@"buttonRoundedRegularHighlighted.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0];
|
||||||
|
[button setBackgroundImage:stretchableButton forState:UIControlStateNormal];
|
||||||
|
[button setBackgroundImage:stretchableHighlightedButton forState:UIControlStateHighlighted];
|
||||||
|
|
||||||
[[button titleLabel] setShadowOffset:CGSizeMake(0, 1)];
|
[[button titleLabel] setShadowOffset:CGSizeMake(0, 1)];
|
||||||
[[button titleLabel] setFont:[UIFont boldSystemFontOfSize:14.0]];
|
[[button titleLabel] setFont:[UIFont boldSystemFontOfSize:14.0]];
|
||||||
|
|
||||||
|
[button setTitleColor:BUTTON_TEXTCOLOR forState:UIControlStateNormal];
|
||||||
|
[button setTitleShadowColor:BUTTON_TEXTCOLOR_SHADOW forState:UIControlStateNormal];
|
||||||
|
} else {
|
||||||
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1
|
||||||
|
button = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
[button setTitleColor:BUTTON_TEXTCOLOR forState:UIControlStateNormal];
|
|
||||||
[button setTitleShadowColor:BUTTON_TEXTCOLOR_SHADOW forState:UIControlStateNormal];
|
|
||||||
if (indexPath.section == 0) {
|
if (indexPath.section == 0) {
|
||||||
topGap = 22;
|
topGap = 22;
|
||||||
if ([self.manager numberOfMessages] == 0) {
|
if ([self.manager numberOfMessages] == 0) {
|
||||||
@ -489,14 +504,18 @@
|
|||||||
[button addTarget:self action:@selector(setUserDataAction:) forControlEvents:UIControlEventTouchUpInside];
|
[button addTarget:self action:@selector(setUserDataAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
} else {
|
} else {
|
||||||
topGap = 0.0f;
|
topGap = 0.0f;
|
||||||
[[button titleLabel] setShadowOffset:CGSizeMake(0, -1)];
|
if ([self.manager isPreiOS7Environment]) {
|
||||||
UIImage *stretchableDeleteButton = [bit_imageNamed(@"buttonRoundedDelete.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0];
|
[[button titleLabel] setShadowOffset:CGSizeMake(0, -1)];
|
||||||
UIImage *stretchableDeleteHighlightedButton = [bit_imageNamed(@"buttonRoundedDeleteHighlighted.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0];
|
UIImage *stretchableDeleteButton = [bit_imageNamed(@"buttonRoundedDelete.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0];
|
||||||
[button setBackgroundImage:stretchableDeleteButton forState:UIControlStateNormal];
|
UIImage *stretchableDeleteHighlightedButton = [bit_imageNamed(@"buttonRoundedDeleteHighlighted.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0];
|
||||||
[button setBackgroundImage:stretchableDeleteHighlightedButton forState:UIControlStateHighlighted];
|
[button setBackgroundImage:stretchableDeleteButton forState:UIControlStateNormal];
|
||||||
|
[button setBackgroundImage:stretchableDeleteHighlightedButton forState:UIControlStateHighlighted];
|
||||||
|
|
||||||
[button setTitleColor:BUTTON_DELETE_TEXTCOLOR forState:UIControlStateNormal];
|
[button setTitleColor:BUTTON_DELETE_TEXTCOLOR forState:UIControlStateNormal];
|
||||||
[button setTitleShadowColor:BUTTON_DELETE_TEXTCOLOR_SHADOW forState:UIControlStateNormal];
|
[button setTitleShadowColor:BUTTON_DELETE_TEXTCOLOR_SHADOW forState:UIControlStateNormal];
|
||||||
|
} else {
|
||||||
|
[button setTitleColor:BUTTON_DELETE_BACKGROUNDCOLOR forState:UIControlStateNormal];
|
||||||
|
}
|
||||||
|
|
||||||
[button setTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonDeleteAllMessages") forState:UIControlStateNormal];
|
[button setTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonDeleteAllMessages") forState:UIControlStateNormal];
|
||||||
[button addTarget:self action:@selector(deleteAllMessagesAction:) forControlEvents:UIControlEventTouchUpInside];
|
[button addTarget:self action:@selector(deleteAllMessagesAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
@ -513,7 +532,11 @@
|
|||||||
statusLabel.font = [UIFont systemFontOfSize:10];
|
statusLabel.font = [UIFont systemFontOfSize:10];
|
||||||
statusLabel.textColor = DEFAULT_TEXTCOLOR;
|
statusLabel.textColor = DEFAULT_TEXTCOLOR;
|
||||||
statusLabel.textAlignment = kBITTextLabelAlignmentCenter;
|
statusLabel.textAlignment = kBITTextLabelAlignmentCenter;
|
||||||
statusLabel.backgroundColor = DEFAULT_BACKGROUNDCOLOR;
|
if ([self.manager isPreiOS7Environment]) {
|
||||||
|
statusLabel.backgroundColor = DEFAULT_BACKGROUNDCOLOR;
|
||||||
|
} else {
|
||||||
|
statusLabel.backgroundColor = DEFAULT_BACKGROUNDCOLOR_OS7;
|
||||||
|
}
|
||||||
statusLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
statusLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||||
|
|
||||||
statusLabel.text = [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackListLastUpdated"),
|
statusLabel.text = [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackListLastUpdated"),
|
||||||
@ -543,6 +566,12 @@
|
|||||||
cell.backgroundStyle = BITFeedbackListViewCellBackgroundStyleNormal;
|
cell.backgroundStyle = BITFeedbackListViewCellBackgroundStyleNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ([self.manager isPreiOS7Environment]) {
|
||||||
|
cell.style = BITFeedbackListViewCellPresentatationStyleDefault;
|
||||||
|
} else {
|
||||||
|
cell.style = BITFeedbackListViewCellPresentatationStyleOS7;
|
||||||
|
}
|
||||||
|
|
||||||
BITFeedbackMessage *message = [self.manager messageAtIndex:indexPath.row];
|
BITFeedbackMessage *message = [self.manager messageAtIndex:indexPath.row];
|
||||||
cell.message = message;
|
cell.message = message;
|
||||||
cell.labelText.delegate = self;
|
cell.labelText.delegate = self;
|
||||||
|
@ -59,20 +59,20 @@
|
|||||||
The UIBarStyle of the update user interface navigation bar.
|
The UIBarStyle of the update user interface navigation bar.
|
||||||
|
|
||||||
Default is UIBarStyleBlackOpaque
|
Default is UIBarStyleBlackOpaque
|
||||||
@see tintColor
|
@see navigationBarTintColor
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) UIBarStyle barStyle;
|
@property (nonatomic, assign) UIBarStyle barStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The tint color of the update user interface navigation bar.
|
The navigationbar tint color of the update user interface navigation bar.
|
||||||
|
|
||||||
The tintColor is used by default, you can either overwrite it `tintColor`
|
The navigationBarTintColor is used by default, you can either overwrite it `navigationBarTintColor`
|
||||||
or define another `barStyle` instead.
|
or define another `barStyle` instead.
|
||||||
|
|
||||||
Default is RGB(25, 25, 25)
|
Default is RGB(25, 25, 25)
|
||||||
@see barStyle
|
@see barStyle
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, strong) UIColor *tintColor;
|
@property (nonatomic, strong) UIColor *navigationBarTintColor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The UIModalPresentationStyle for showing the update user interface when invoked
|
The UIModalPresentationStyle for showing the update user interface when invoked
|
||||||
|
@ -43,6 +43,10 @@
|
|||||||
#import <mach-o/ldsyms.h>
|
#import <mach-o/ldsyms.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __IPHONE_6_1
|
||||||
|
#define __IPHONE_6_1 60100
|
||||||
|
#endif
|
||||||
|
|
||||||
@implementation BITHockeyBaseManager {
|
@implementation BITHockeyBaseManager {
|
||||||
UINavigationController *_navController;
|
UINavigationController *_navController;
|
||||||
|
|
||||||
@ -56,8 +60,12 @@
|
|||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_serverURL = BITHOCKEYSDK_URL;
|
_serverURL = BITHOCKEYSDK_URL;
|
||||||
|
|
||||||
_barStyle = UIBarStyleBlackOpaque;
|
if ([self isPreiOS7Environment]) {
|
||||||
self.tintColor = BIT_RGBCOLOR(25, 25, 25);
|
_barStyle = UIBarStyleBlackOpaque;
|
||||||
|
self.navigationBarTintColor = BIT_RGBCOLOR(25, 25, 25);
|
||||||
|
} else {
|
||||||
|
_barStyle = UIBarStyleDefault;
|
||||||
|
}
|
||||||
_modalPresentationStyle = UIModalPresentationFormSheet;
|
_modalPresentationStyle = UIModalPresentationFormSheet;
|
||||||
|
|
||||||
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||||
@ -92,6 +100,28 @@
|
|||||||
return (_appIdentifier ? bit_URLEncodedString(_appIdentifier) : bit_URLEncodedString([self mainBundleIdentifier]));
|
return (_appIdentifier ? bit_URLEncodedString(_appIdentifier) : bit_URLEncodedString([self mainBundleIdentifier]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isPreiOS7Environment {
|
||||||
|
static BOOL isPreiOS7Environment = YES;
|
||||||
|
static dispatch_once_t checkOS;
|
||||||
|
|
||||||
|
dispatch_once(&checkOS, ^{
|
||||||
|
// we only perform this runtime check if this is build against at least iOS7 base SDK
|
||||||
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1
|
||||||
|
// runtime check according to
|
||||||
|
// https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/TransitionGuide/SupportingEarlieriOS.html
|
||||||
|
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
|
||||||
|
isPreiOS7Environment = YES;
|
||||||
|
} else {
|
||||||
|
isPreiOS7Environment = NO;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
isPreiOS7Environment = YES;
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
|
||||||
|
return isPreiOS7Environment;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString *)getDevicePlatform {
|
- (NSString *)getDevicePlatform {
|
||||||
size_t size;
|
size_t size;
|
||||||
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
|
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
|
||||||
@ -152,6 +182,24 @@
|
|||||||
return visibleWindow;
|
return visibleWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide a custom UINavigationController with customized appearance settings
|
||||||
|
*
|
||||||
|
* @param viewController The root viewController
|
||||||
|
* @param modalPresentationStyle The modal presentation style
|
||||||
|
*
|
||||||
|
* @return A UINavigationController
|
||||||
|
*/
|
||||||
|
- (UINavigationController *)customNavigationControllerWithRootViewController:(UIViewController *)viewController presentationStyle:(UIModalPresentationStyle)modalPresentationStyle {
|
||||||
|
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
|
||||||
|
navController.navigationBar.barStyle = self.barStyle;
|
||||||
|
if (self.navigationBarTintColor)
|
||||||
|
navController.navigationBar.tintColor = self.navigationBarTintColor;
|
||||||
|
navController.modalPresentationStyle = self.modalPresentationStyle;
|
||||||
|
|
||||||
|
return navController;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)showView:(UIViewController *)viewController {
|
- (void)showView:(UIViewController *)viewController {
|
||||||
UIViewController *parentViewController = nil;
|
UIViewController *parentViewController = nil;
|
||||||
|
|
||||||
@ -166,8 +214,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// use topmost modal view
|
// use topmost modal view
|
||||||
while (parentViewController.modalViewController) {
|
while (parentViewController.presentedViewController) {
|
||||||
parentViewController = parentViewController.modalViewController;
|
parentViewController = parentViewController.presentedViewController;
|
||||||
}
|
}
|
||||||
|
|
||||||
// special addition to get rootViewController from three20 which has it's own controller handling
|
// special addition to get rootViewController from three20 which has it's own controller handling
|
||||||
@ -183,10 +231,7 @@
|
|||||||
|
|
||||||
if (_navController != nil) _navController = nil;
|
if (_navController != nil) _navController = nil;
|
||||||
|
|
||||||
_navController = [[UINavigationController alloc] initWithRootViewController:viewController];
|
_navController = [self customNavigationControllerWithRootViewController:viewController presentationStyle:_modalPresentationStyle];
|
||||||
_navController.navigationBar.barStyle = _barStyle;
|
|
||||||
_navController.navigationBar.tintColor = _tintColor;
|
|
||||||
_navController.modalPresentationStyle = _modalPresentationStyle;
|
|
||||||
|
|
||||||
if (parentViewController) {
|
if (parentViewController) {
|
||||||
_navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
|
_navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
/** the value this object was initialized with */
|
/** the value this object was initialized with */
|
||||||
- (BOOL)isAppStoreEnvironment;
|
- (BOOL)isAppStoreEnvironment;
|
||||||
|
|
||||||
|
/** Check if the device is running an iOS version previous to iOS 7 */
|
||||||
|
- (BOOL)isPreiOS7Environment;
|
||||||
|
|
||||||
/** by default, just logs the message
|
/** by default, just logs the message
|
||||||
|
|
||||||
can be overriden by subclasses to do their own error handling,
|
can be overriden by subclasses to do their own error handling,
|
||||||
@ -42,6 +45,7 @@
|
|||||||
- (NSString *)executableUUID;
|
- (NSString *)executableUUID;
|
||||||
|
|
||||||
/** UI helpers */
|
/** UI helpers */
|
||||||
|
- (UINavigationController *)customNavigationControllerWithRootViewController:(UIViewController *)viewController presentationStyle:(UIModalPresentationStyle)presentationStyle;
|
||||||
- (UIWindow *)findVisibleWindow;
|
- (UIWindow *)findVisibleWindow;
|
||||||
- (void)showView:(UIViewController *)viewController;
|
- (void)showView:(UIViewController *)viewController;
|
||||||
|
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
|
|
||||||
#import "BITHockeyManagerPrivate.h"
|
#import "BITHockeyManagerPrivate.h"
|
||||||
#import "BITHockeyBaseManagerPrivate.h"
|
#import "BITHockeyBaseManagerPrivate.h"
|
||||||
#import "BITCrashManagerPrivate.h"
|
|
||||||
#import "BITUpdateManagerPrivate.h"
|
#import "BITUpdateManagerPrivate.h"
|
||||||
#import "BITStoreUpdateManagerPrivate.h"
|
#import "BITStoreUpdateManagerPrivate.h"
|
||||||
#import "BITFeedbackManagerPrivate.h"
|
#import "BITFeedbackManagerPrivate.h"
|
||||||
@ -356,9 +355,11 @@
|
|||||||
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
||||||
|
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||||
+ (void)disableJMCCrashReporter {
|
+ (void)disableJMCCrashReporter {
|
||||||
id jmcInstance = [self jmcInstance];
|
id jmcInstance = [self jmcInstance];
|
||||||
id jmcOptions = [jmcInstance performSelector:@selector(options)];
|
SEL optionsSelector = @selector(options);
|
||||||
|
id jmcOptions = [jmcInstance performSelector:optionsSelector];
|
||||||
SEL crashReporterSelector = @selector(setCrashReportingEnabled:);
|
SEL crashReporterSelector = @selector(setCrashReportingEnabled:);
|
||||||
|
|
||||||
BOOL value = NO;
|
BOOL value = NO;
|
||||||
@ -374,13 +375,14 @@
|
|||||||
+ (BOOL)checkJMCConfiguration:(NSDictionary *)configuration {
|
+ (BOOL)checkJMCConfiguration:(NSDictionary *)configuration {
|
||||||
return (([configuration isKindOfClass:[NSDictionary class]]) &&
|
return (([configuration isKindOfClass:[NSDictionary class]]) &&
|
||||||
([[configuration valueForKey:@"enabled"] boolValue]) &&
|
([[configuration valueForKey:@"enabled"] boolValue]) &&
|
||||||
([[configuration valueForKey:@"url"] length] > 0) &&
|
([(NSString *)[configuration valueForKey:@"url"] length] > 0) &&
|
||||||
([[configuration valueForKey:@"key"] length] > 0) &&
|
([(NSString *)[configuration valueForKey:@"key"] length] > 0) &&
|
||||||
([[configuration valueForKey:@"project"] length] > 0));
|
([(NSString *)[configuration valueForKey:@"project"] length] > 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
||||||
|
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||||
+ (void)applyJMCConfiguration:(NSDictionary *)configuration {
|
+ (void)applyJMCConfiguration:(NSDictionary *)configuration {
|
||||||
id jmcInstance = [self jmcInstance];
|
id jmcInstance = [self jmcInstance];
|
||||||
SEL configureSelector = @selector(configureJiraConnect:projectKey:apiKey:);
|
SEL configureSelector = @selector(configureJiraConnect:projectKey:apiKey:);
|
||||||
|
@ -48,12 +48,31 @@
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __IPHONE_6_1
|
||||||
|
#define __IPHONE_6_1 60100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Button style depending on the iOS version
|
||||||
|
*/
|
||||||
|
typedef NS_ENUM(NSUInteger, BITStoreButtonStyle) {
|
||||||
|
/**
|
||||||
|
* Default is iOS 6 style
|
||||||
|
*/
|
||||||
|
BITStoreButtonStyleDefault = 0,
|
||||||
|
/**
|
||||||
|
* Draw buttons in the iOS 7 style
|
||||||
|
*/
|
||||||
|
BITStoreButtonStyleOS7 = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Simulate the Paymeny-Button from the AppStore
|
// Simulate the Paymeny-Button from the AppStore
|
||||||
// The interface is flexible, so there is now fixed order
|
// The interface is flexible, so there is now fixed order
|
||||||
@interface BITStoreButton : UIButton
|
@interface BITStoreButton : UIButton
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)frame;
|
- (id)initWithFrame:(CGRect)frame;
|
||||||
- (id)initWithPadding:(CGPoint)padding;
|
- (id)initWithPadding:(CGPoint)padding style:(BITStoreButtonStyle)style;
|
||||||
|
|
||||||
// action delegate
|
// action delegate
|
||||||
@property (nonatomic, weak) id<BITStoreButtonDelegate> buttonDelegate;
|
@property (nonatomic, weak) id<BITStoreButtonDelegate> buttonDelegate;
|
||||||
@ -64,6 +83,11 @@
|
|||||||
|
|
||||||
// align helper
|
// align helper
|
||||||
@property (nonatomic, assign) CGPoint customPadding;
|
@property (nonatomic, assign) CGPoint customPadding;
|
||||||
|
|
||||||
|
// align helper
|
||||||
|
@property (nonatomic, assign) BITStoreButtonStyle style;
|
||||||
|
|
||||||
|
|
||||||
- (void)alignToSuperview;
|
- (void)alignToSuperview;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -58,7 +58,10 @@
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
@implementation BITStoreButton
|
@implementation BITStoreButton {
|
||||||
|
CALayer *_defaultBorderLayer;
|
||||||
|
CALayer *_inActiveBorderLayer;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - private
|
#pragma mark - private
|
||||||
|
|
||||||
@ -90,9 +93,19 @@
|
|||||||
|
|
||||||
// show white or gray text, depending on the state
|
// show white or gray text, depending on the state
|
||||||
if (self.buttonData.isEnabled) {
|
if (self.buttonData.isEnabled) {
|
||||||
[self setTitleColor:BIT_RGBCOLOR(106, 106, 106) forState:UIControlStateNormal];
|
if (self.style == BITStoreButtonStyleDefault) {
|
||||||
|
[self setTitleColor:BIT_RGBCOLOR(106, 106, 106) forState:UIControlStateNormal];
|
||||||
|
} else {
|
||||||
|
[self setTitleColor:BIT_RGBCOLOR(35, 111, 251) forState:UIControlStateNormal];
|
||||||
|
[_defaultBorderLayer setHidden:NO];
|
||||||
|
[_inActiveBorderLayer setHidden:YES];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
[self setTitleColor:BIT_RGBCOLOR(148, 150, 151) forState:UIControlStateNormal];
|
[self setTitleColor:BIT_RGBCOLOR(148, 150, 151) forState:UIControlStateNormal];
|
||||||
|
if (self.style == BITStoreButtonStyleOS7) {
|
||||||
|
[_defaultBorderLayer setHidden:YES];
|
||||||
|
[_inActiveBorderLayer setHidden:NO];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate optimal new size
|
// calculate optimal new size
|
||||||
@ -149,32 +162,53 @@
|
|||||||
// register for touch events
|
// register for touch events
|
||||||
[self addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
[self addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
|
||||||
// main gradient layer
|
|
||||||
CAGradientLayer *gradient = [CAGradientLayer layer];
|
|
||||||
gradient.colors = @[(id)BIT_RGBCOLOR(243, 243, 243).CGColor, (id)BIT_RGBCOLOR(222, 222, 222).CGColor];
|
|
||||||
gradient.locations = @[[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:1.0]];
|
|
||||||
gradient.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(frame), CGRectGetHeight(frame));
|
|
||||||
gradient.cornerRadius = 2.5;
|
|
||||||
gradient.needsDisplayOnBoundsChange = YES;
|
|
||||||
[self.layer addSublayer:gradient];
|
|
||||||
|
|
||||||
// border layers for more sex!
|
|
||||||
CALayer *borderLayer = [CALayer layer];
|
|
||||||
borderLayer.borderColor = [BIT_RGBCOLOR(191, 191, 191) CGColor];
|
|
||||||
borderLayer.borderWidth = 1.0;
|
|
||||||
borderLayer.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(frame), CGRectGetHeight(frame));
|
|
||||||
borderLayer.cornerRadius = 2.5;
|
|
||||||
borderLayer.needsDisplayOnBoundsChange = YES;
|
|
||||||
[self.layer addSublayer:borderLayer];
|
|
||||||
|
|
||||||
[self bringSubviewToFront:self.titleLabel];
|
[self bringSubviewToFront:self.titleLabel];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithPadding:(CGPoint)padding {
|
- (id)initWithPadding:(CGPoint)padding style:(BITStoreButtonStyle)style {
|
||||||
if ((self = [self initWithFrame:CGRectMake(0, 0, 40, BIT_MIN_HEIGHT)])) {
|
CGRect frame = CGRectMake(0, 0, 40, BIT_MIN_HEIGHT);
|
||||||
|
if ((self = [self initWithFrame:frame])) {
|
||||||
_customPadding = padding;
|
_customPadding = padding;
|
||||||
|
_style = style;
|
||||||
|
|
||||||
|
if (style == BITStoreButtonStyleDefault) {
|
||||||
|
// main gradient layer
|
||||||
|
CAGradientLayer *gradient = [CAGradientLayer layer];
|
||||||
|
gradient.colors = @[(id)BIT_RGBCOLOR(243, 243, 243).CGColor, (id)BIT_RGBCOLOR(222, 222, 222).CGColor];
|
||||||
|
gradient.locations = @[[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:1.0]];
|
||||||
|
gradient.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(frame), CGRectGetHeight(frame));
|
||||||
|
gradient.cornerRadius = 2.5;
|
||||||
|
gradient.needsDisplayOnBoundsChange = YES;
|
||||||
|
[self.layer addSublayer:gradient];
|
||||||
|
}
|
||||||
|
|
||||||
|
// border layers for more sex!
|
||||||
|
_defaultBorderLayer = [CALayer layer];
|
||||||
|
if (style == BITStoreButtonStyleDefault) {
|
||||||
|
_defaultBorderLayer.borderColor = [BIT_RGBCOLOR(191, 191, 191) CGColor];
|
||||||
|
} else {
|
||||||
|
_defaultBorderLayer.borderColor = [BIT_RGBCOLOR(35, 111, 251) CGColor];
|
||||||
|
}
|
||||||
|
_defaultBorderLayer.borderWidth = 1.0;
|
||||||
|
_defaultBorderLayer.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(frame), CGRectGetHeight(frame));
|
||||||
|
_defaultBorderLayer.cornerRadius = 2.5;
|
||||||
|
_defaultBorderLayer.needsDisplayOnBoundsChange = YES;
|
||||||
|
[self.layer addSublayer:_defaultBorderLayer];
|
||||||
|
|
||||||
|
if (style == BITStoreButtonStyleOS7) {
|
||||||
|
_inActiveBorderLayer = [CALayer layer];
|
||||||
|
_inActiveBorderLayer.borderColor = [BIT_RGBCOLOR(148, 150, 151) CGColor];
|
||||||
|
_inActiveBorderLayer.borderWidth = 1.0;
|
||||||
|
_inActiveBorderLayer.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(frame), CGRectGetHeight(frame));
|
||||||
|
_inActiveBorderLayer.cornerRadius = 2.5;
|
||||||
|
_inActiveBorderLayer.needsDisplayOnBoundsChange = YES;
|
||||||
|
[self.layer addSublayer:_inActiveBorderLayer];
|
||||||
|
[_inActiveBorderLayer setHidden:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self bringSubviewToFront:self.titleLabel];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,6 @@
|
|||||||
#import "BITHockeyBaseManager.h"
|
#import "BITHockeyBaseManager.h"
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BITUpdateAuthorizationDenied,
|
|
||||||
BITUpdateAuthorizationAllowed,
|
|
||||||
BITUpdateAuthorizationPending
|
|
||||||
} BITUpdateAuthorizationState;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BITUpdateCheckStartup = 0,
|
BITUpdateCheckStartup = 0,
|
||||||
BITUpdateCheckDaily = 1,
|
BITUpdateCheckDaily = 1,
|
||||||
@ -189,39 +183,6 @@ typedef enum {
|
|||||||
@property (nonatomic, assign, getter=isShowingDirectInstallOption) BOOL showDirectInstallOption;
|
@property (nonatomic, assign, getter=isShowingDirectInstallOption) BOOL showDirectInstallOption;
|
||||||
|
|
||||||
|
|
||||||
///-----------------------------------------------------------------------------
|
|
||||||
/// @name Authorization
|
|
||||||
///-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
Flag that determines if each update should be authenticated
|
|
||||||
|
|
||||||
If enabled each update will be authenticated on startup against the HockeyApp servers.
|
|
||||||
The process will basically validate if the current device is part of the provisioning
|
|
||||||
profile on the server. If not, it will present a blocking view on top of the apps UI
|
|
||||||
so that no interaction is possible.
|
|
||||||
|
|
||||||
When running the app from the App Store, this setting is ignored.
|
|
||||||
|
|
||||||
*Default*: _NO_
|
|
||||||
@see authenticationSecret
|
|
||||||
@warning This only works when using Ad-Hoc provisioning profiles!
|
|
||||||
*/
|
|
||||||
@property (nonatomic, assign, getter=isRequireAuthorization) BOOL requireAuthorization;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The authentication token from HockeyApp.
|
|
||||||
|
|
||||||
Set the token to the `Secret ID` which HockeyApp provides for every app.
|
|
||||||
|
|
||||||
When running the app from the App Store, this setting is ignored.
|
|
||||||
|
|
||||||
@see requireAuthorization
|
|
||||||
*/
|
|
||||||
@property (nonatomic, strong) NSString *authenticationSecret;
|
|
||||||
|
|
||||||
|
|
||||||
///-----------------------------------------------------------------------------
|
///-----------------------------------------------------------------------------
|
||||||
/// @name Expiry
|
/// @name Expiry
|
||||||
///-----------------------------------------------------------------------------
|
///-----------------------------------------------------------------------------
|
||||||
|
@ -216,34 +216,6 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
|
|||||||
return @"invalid";
|
return @"invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Authorization
|
|
||||||
|
|
||||||
- (NSString *)authenticationToken {
|
|
||||||
return [BITHockeyMD5([NSString stringWithFormat:@"%@%@%@%@",
|
|
||||||
_authenticationSecret,
|
|
||||||
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
|
|
||||||
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"],
|
|
||||||
[self deviceIdentifier]
|
|
||||||
]
|
|
||||||
) lowercaseString];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BITUpdateAuthorizationState)authorizationState {
|
|
||||||
NSString *version = [[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateAuthorizedVersion];
|
|
||||||
NSString *token = [self stringValueFromKeychainForKey:kBITUpdateAuthorizedToken];
|
|
||||||
|
|
||||||
if (version != nil && token != nil) {
|
|
||||||
if ([version compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] == NSOrderedSame) {
|
|
||||||
// if it is denied, block the screen permanently
|
|
||||||
if ([token compare:[self authenticationToken]] != NSOrderedSame) {
|
|
||||||
return BITUpdateAuthorizationDenied;
|
|
||||||
} else {
|
|
||||||
return BITUpdateAuthorizationAllowed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return BITUpdateAuthorizationPending;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Cache
|
#pragma mark - Cache
|
||||||
|
|
||||||
@ -361,8 +333,6 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
|
|||||||
_lastCheckFailed = NO;
|
_lastCheckFailed = NO;
|
||||||
_currentAppVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
_currentAppVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||||
_blockingView = nil;
|
_blockingView = nil;
|
||||||
_requireAuthorization = NO;
|
|
||||||
_authenticationSecret = nil;
|
|
||||||
_lastCheck = nil;
|
_lastCheck = nil;
|
||||||
_uuid = [[self executableUUID] copy];
|
_uuid = [[self executableUUID] copy];
|
||||||
_versionUUID = nil;
|
_versionUUID = nil;
|
||||||
@ -439,7 +409,8 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.barStyle = UIBarStyleBlack;
|
if ([self isPreiOS7Environment])
|
||||||
|
self.barStyle = UIBarStyleBlack;
|
||||||
[self showView:[self hockeyViewController:YES]];
|
[self showView:[self hockeyViewController:YES]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,87 +531,9 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
|
|||||||
return checkForUpdate;
|
return checkForUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)checkForAuthorization {
|
|
||||||
NSMutableString *parameter = [NSMutableString stringWithFormat:@"api/2/apps/%@", [self encodedAppIdentifier]];
|
|
||||||
|
|
||||||
[parameter appendFormat:@"?format=json&authorize=yes&app_version=%@&udid=%@&sdk=%@&sdk_version=%@&uuid=%@",
|
|
||||||
bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]),
|
|
||||||
([self isAppStoreEnvironment] ? @"appstore" : bit_URLEncodedString([self deviceIdentifier])),
|
|
||||||
BITHOCKEY_NAME,
|
|
||||||
BITHOCKEY_VERSION,
|
|
||||||
_uuid
|
|
||||||
];
|
|
||||||
|
|
||||||
// build request & send
|
|
||||||
NSString *url = [NSString stringWithFormat:@"%@%@", self.serverURL, parameter];
|
|
||||||
BITHockeyLog(@"INFO: Sending api request to %@", url);
|
|
||||||
|
|
||||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:1 timeoutInterval:10.0];
|
|
||||||
[request setHTTPMethod:@"GET"];
|
|
||||||
[request setValue:@"Hockey/iOS" forHTTPHeaderField:@"User-Agent"];
|
|
||||||
|
|
||||||
NSURLResponse *response = nil;
|
|
||||||
NSError *error = NULL;
|
|
||||||
BOOL failed = YES;
|
|
||||||
|
|
||||||
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
|
|
||||||
|
|
||||||
if ([responseData length]) {
|
|
||||||
NSString *responseString = [[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding];
|
|
||||||
|
|
||||||
if (responseString && [responseString dataUsingEncoding:NSUTF8StringEncoding]) {
|
|
||||||
NSDictionary *feedDict = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error];
|
|
||||||
|
|
||||||
// server returned empty response?
|
|
||||||
if (![feedDict count]) {
|
|
||||||
[self reportError:[NSError errorWithDomain:kBITUpdateErrorDomain
|
|
||||||
code:BITUpdateAPIServerReturnedEmptyResponse
|
|
||||||
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Server returned empty response.", NSLocalizedDescriptionKey, nil]]];
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
BITHockeyLog(@"INFO: Received API response: %@", responseString);
|
|
||||||
NSString *token = [[feedDict objectForKey:@"authcode"] lowercaseString];
|
|
||||||
failed = NO;
|
|
||||||
if ([[self authenticationToken] compare:token] == NSOrderedSame) {
|
|
||||||
// identical token, activate this version
|
|
||||||
|
|
||||||
// store the new data
|
|
||||||
[[NSUserDefaults standardUserDefaults] setObject:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:kBITUpdateAuthorizedVersion];
|
|
||||||
[self addStringValueToKeychain:token forKey:kBITUpdateAuthorizedToken];
|
|
||||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
||||||
|
|
||||||
self.requireAuthorization = NO;
|
|
||||||
self.blockingView = nil;
|
|
||||||
|
|
||||||
// now continue with an update check right away
|
|
||||||
if (self.checkForUpdateOnLaunch) {
|
|
||||||
[self checkForUpdate];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// different token, block this version
|
|
||||||
BITHockeyLog(@"INFO: AUTH FAILURE: %@", [self authenticationToken]);
|
|
||||||
|
|
||||||
// store the new data
|
|
||||||
[[NSUserDefaults standardUserDefaults] setObject:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:kBITUpdateAuthorizedVersion];
|
|
||||||
[self addStringValueToKeychain:token forKey:kBITUpdateAuthorizedToken];
|
|
||||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
||||||
|
|
||||||
[self showBlockingScreen:BITHockeyLocalizedString(@"UpdateAuthorizationDenied") image:@"authorize_denied.png"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failed) {
|
|
||||||
[self showBlockingScreen:BITHockeyLocalizedString(@"UpdateAuthorizationOffline") image:@"authorize_request.png"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)checkForUpdate {
|
- (void)checkForUpdate {
|
||||||
if (![self isAppStoreEnvironment] && ![self isUpdateManagerDisabled]) {
|
if (![self isAppStoreEnvironment] && ![self isUpdateManagerDisabled]) {
|
||||||
if ([self expiryDateReached]) return;
|
if ([self expiryDateReached]) return;
|
||||||
if (self.requireAuthorization) return;
|
|
||||||
|
|
||||||
if (self.isUpdateAvailable && [self hasNewerMandatoryVersion]) {
|
if (self.isUpdateAvailable && [self hasNewerMandatoryVersion]) {
|
||||||
[self showCheckForUpdateAlert];
|
[self showCheckForUpdateAlert];
|
||||||
@ -735,38 +628,6 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// checks whether this app version is authorized
|
|
||||||
- (BOOL)appVersionIsAuthorized {
|
|
||||||
if (self.requireAuthorization && !_authenticationSecret) {
|
|
||||||
[self reportError:[NSError errorWithDomain:kBITUpdateErrorDomain
|
|
||||||
code:BITUpdateAPIClientAuthorizationMissingSecret
|
|
||||||
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Authentication secret is not set but required.", NSLocalizedDescriptionKey, nil]]];
|
|
||||||
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!self.requireAuthorization) {
|
|
||||||
self.blockingView = nil;
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if TARGET_IPHONE_SIMULATOR
|
|
||||||
NSLog(@"Authentication checks only work on devices. Using the simulator will always return being authorized.");
|
|
||||||
return YES;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
BITUpdateAuthorizationState state = [self authorizationState];
|
|
||||||
if (state == BITUpdateAuthorizationDenied) {
|
|
||||||
[self showBlockingScreen:BITHockeyLocalizedString(@"UpdateAuthorizationDenied") image:@"authorize_denied.png"];
|
|
||||||
} else if (state == BITUpdateAuthorizationAllowed) {
|
|
||||||
self.requireAuthorization = NO;
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// begin the startup process
|
// begin the startup process
|
||||||
- (void)startManager {
|
- (void)startManager {
|
||||||
if (![self isAppStoreEnvironment]) {
|
if (![self isAppStoreEnvironment]) {
|
||||||
@ -776,16 +637,8 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
|
|||||||
|
|
||||||
[self checkExpiryDateReached];
|
[self checkExpiryDateReached];
|
||||||
if (![self expiryDateReached]) {
|
if (![self expiryDateReached]) {
|
||||||
if (![self appVersionIsAuthorized]) {
|
if ([self checkForTracker] || ([self isCheckForUpdateOnLaunch] && [self shouldCheckForUpdates])) {
|
||||||
if ([self authorizationState] == BITUpdateAuthorizationPending) {
|
[self performSelector:@selector(checkForUpdate) withObject:nil afterDelay:1.0f];
|
||||||
[self showBlockingScreen:BITHockeyLocalizedString(@"UpdateAuthorizationProgress") image:@"authorize_request.png"];
|
|
||||||
|
|
||||||
[self performSelector:@selector(checkForAuthorization) withObject:nil afterDelay:0.0f];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ([self checkForTracker] || ([self isCheckForUpdateOnLaunch] && [self shouldCheckForUpdates])) {
|
|
||||||
[self performSelector:@selector(checkForUpdate) withObject:nil afterDelay:1.0f];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -74,12 +74,6 @@
|
|||||||
// initiates app-download call. displays an system UIAlertView
|
// initiates app-download call. displays an system UIAlertView
|
||||||
- (BOOL)initiateAppDownload;
|
- (BOOL)initiateAppDownload;
|
||||||
|
|
||||||
// checks whether this app version is authorized
|
|
||||||
- (BOOL)appVersionIsAuthorized;
|
|
||||||
|
|
||||||
// start checking for an authorization key
|
|
||||||
- (void)checkForAuthorization;
|
|
||||||
|
|
||||||
// get/set current active hockey view controller
|
// get/set current active hockey view controller
|
||||||
@property (nonatomic, strong) BITUpdateViewController *currentHockeyViewController;
|
@property (nonatomic, strong) BITUpdateViewController *currentHockeyViewController;
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
#import "BITUpdateManagerPrivate.h"
|
#import "BITUpdateManagerPrivate.h"
|
||||||
#import "BITUpdateViewControllerPrivate.h"
|
#import "BITUpdateViewControllerPrivate.h"
|
||||||
|
#import "BITHockeyBaseManagerPrivate.h"
|
||||||
|
|
||||||
|
|
||||||
#define kWebCellIdentifier @"PSWebTableViewCell"
|
#define kWebCellIdentifier @"PSWebTableViewCell"
|
||||||
@ -62,6 +63,14 @@
|
|||||||
|
|
||||||
#pragma mark - Private
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (UIColor *)backgroundColor {
|
||||||
|
if ([self.updateManager isPreiOS7Environment]) {
|
||||||
|
return BIT_RGBCOLOR(235, 235, 235);
|
||||||
|
} else {
|
||||||
|
return BIT_RGBCOLOR(255, 255, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)restoreStoreButtonStateAnimated:(BOOL)animated {
|
- (void)restoreStoreButtonStateAnimated:(BOOL)animated {
|
||||||
if (_isAppStoreEnvironment) {
|
if (_isAppStoreEnvironment) {
|
||||||
[self setAppStoreButtonState:AppStoreButtonStateOffline animated:animated];
|
[self setAppStoreButtonState:AppStoreButtonStateOffline animated:animated];
|
||||||
@ -169,7 +178,7 @@
|
|||||||
[self realignPreviousVersionButton];
|
[self realignPreviousVersionButton];
|
||||||
} else {
|
} else {
|
||||||
self.tableView.tableFooterView = nil;
|
self.tableView.tableFooterView = nil;
|
||||||
self.tableView.backgroundColor = BIT_RGBCOLOR(235, 235, 235);
|
self.tableView.backgroundColor = [self backgroundColor];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,8 +209,7 @@
|
|||||||
} else {
|
} else {
|
||||||
cell.webViewContent = [NSString stringWithFormat:@"<p><b>%@</b>%@<br/><small>%@</small></p><p>%@</p>", [appVersion versionString], installed, dateAndSizeString, [appVersion notesOrEmptyString]];
|
cell.webViewContent = [NSString stringWithFormat:@"<p><b>%@</b>%@<br/><small>%@</small></p><p>%@</p>", [appVersion versionString], installed, dateAndSizeString, [appVersion notesOrEmptyString]];
|
||||||
}
|
}
|
||||||
cell.cellBackgroundColor = BIT_RGBCOLOR(235, 235, 235);
|
cell.cellBackgroundColor = [self backgroundColor];
|
||||||
|
|
||||||
[cell addWebView];
|
[cell addWebView];
|
||||||
// hack
|
// hack
|
||||||
cell.textLabel.text = @"";
|
cell.textLabel.text = @"";
|
||||||
@ -269,6 +277,11 @@
|
|||||||
[self.tableView addSubview:topView];
|
[self.tableView addSubview:topView];
|
||||||
|
|
||||||
_appStoreHeader = [[BITAppStoreHeader alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kAppStoreViewHeight)];
|
_appStoreHeader = [[BITAppStoreHeader alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kAppStoreViewHeight)];
|
||||||
|
if ([self.updateManager isPreiOS7Environment]) {
|
||||||
|
_appStoreHeader.style = BITAppStoreHeaderStyleDefault;
|
||||||
|
} else {
|
||||||
|
_appStoreHeader.style = BITAppStoreHeaderStyleOS7;
|
||||||
|
}
|
||||||
[self updateAppStoreHeader];
|
[self updateAppStoreHeader];
|
||||||
|
|
||||||
NSString *iconString = nil;
|
NSString *iconString = nil;
|
||||||
@ -323,7 +336,11 @@
|
|||||||
|
|
||||||
self.tableView.tableHeaderView = _appStoreHeader;
|
self.tableView.tableHeaderView = _appStoreHeader;
|
||||||
|
|
||||||
BITStoreButton *storeButton = [[BITStoreButton alloc] initWithPadding:CGPointMake(5, 58)];
|
BITStoreButtonStyle buttonStyle = BITStoreButtonStyleDefault;
|
||||||
|
if (![self.updateManager isPreiOS7Environment]) {
|
||||||
|
buttonStyle = BITStoreButtonStyleOS7;
|
||||||
|
}
|
||||||
|
BITStoreButton *storeButton = [[BITStoreButton alloc] initWithPadding:CGPointMake(5, 58) style:buttonStyle];
|
||||||
storeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
|
storeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
|
||||||
storeButton.buttonDelegate = self;
|
storeButton.buttonDelegate = self;
|
||||||
[self.tableView.tableHeaderView addSubview:storeButton];
|
[self.tableView.tableHeaderView addSubview:storeButton];
|
||||||
@ -430,7 +447,7 @@
|
|||||||
|
|
||||||
if (rowHeight == 0) {
|
if (rowHeight == 0) {
|
||||||
rowHeight = indexPath.row == 0 ? 250 : 44; // fill screen on startup
|
rowHeight = indexPath.row == 0 ? 250 : 44; // fill screen on startup
|
||||||
self.tableView.backgroundColor = BIT_RGBCOLOR(235, 235, 235);
|
self.tableView.backgroundColor = [self backgroundColor];
|
||||||
}
|
}
|
||||||
|
|
||||||
return rowHeight;
|
return rowHeight;
|
||||||
|
@ -17,22 +17,10 @@ Pod::Spec.new do |s|
|
|||||||
'yourself when the network becomse reachable.'
|
'yourself when the network becomse reachable.'
|
||||||
|
|
||||||
s.source_files = 'Classes'
|
s.source_files = 'Classes'
|
||||||
|
s.resource_bundle = { 'HockeySDKResources' => ['Resources/*.png', 'Resources/*.lproj'] }
|
||||||
s.requires_arc = true
|
s.requires_arc = true
|
||||||
s.preserve_paths = 'Resources', 'Support', 'Vendor'
|
s.preserve_paths = 'Resources', 'Support', 'Vendor'
|
||||||
s.frameworks = 'CoreText', 'QuartzCore', 'SystemConfiguration', 'CrashReporter', 'CoreGraphics', 'UIKit'
|
s.frameworks = 'CoreText', 'QuartzCore', 'SystemConfiguration', 'CrashReporter', 'CoreGraphics', 'UIKit'
|
||||||
s.xcconfig = { 'FRAMEWORK_SEARCH_PATHS' => '"$(PODS_ROOT)/HockeySDK/Vendor"',
|
s.xcconfig = { 'FRAMEWORK_SEARCH_PATHS' => '"$(PODS_ROOT)/HockeySDK/Vendor"',
|
||||||
'GCC_PREPROCESSOR_DEFINITIONS' => %{$(inherited) BITHOCKEY_VERSION="@\\"#{s.version}\\""} }
|
'GCC_PREPROCESSOR_DEFINITIONS' => %{$(inherited) BITHOCKEY_VERSION="@\\"#{s.version}\\""} }
|
||||||
|
|
||||||
s.post_install do |library_representation|
|
|
||||||
Dir.chdir File.join(library_representation.sandbox_dir, 'HockeySDK/Support') do
|
|
||||||
command = "xcodebuild -project HockeySDK.xcodeproj -target HockeySDKResources CONFIGURATION_BUILD_DIR=../Resources"
|
|
||||||
command << " 2>&1 > /dev/null"
|
|
||||||
unless system(command)
|
|
||||||
raise ::Pod::Informative, "Failed to generate HockeySDK resources bundle"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
File.open(library_representation.copy_resources_script_path, 'a') do |file|
|
|
||||||
file.puts "install_resource 'HockeySDK/Resources/HockeySDKResources.bundle'"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -43,9 +43,3 @@ This documentation provides integrated help in Xcode for all public APIs and a s
|
|||||||
3. Copy the content into ~`/Library/Developer/Shared/Documentation/DocSet`
|
3. Copy the content into ~`/Library/Developer/Shared/Documentation/DocSet`
|
||||||
|
|
||||||
The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.0.0/](http://hockeyapp.net/help/sdk/ios/3.0.0/)
|
The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.0.0/](http://hockeyapp.net/help/sdk/ios/3.0.0/)
|
||||||
|
|
||||||
## Nightly Builds
|
|
||||||
|
|
||||||
You can download nightly builds of the develop branch from [cisimple.com](https://www.cisimple.com/jobs/qsx70pbsrjlf60nlq). Builds are triggered at midnight (UTC) if we had pushed commits to our repository in the past 24 hours.
|
|
||||||
|
|
||||||
<a href="https://www.cisimple.com/jobs/qsx70pbsrjlf60nlq"><img src='https://www.cisimple.com/jobs/qsx70pbsrjlf60nlq/build_status.png'/></a>
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.7 KiB |
@ -88,8 +88,6 @@
|
|||||||
1E59559B15B6FDA500A03429 /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
1E59559B15B6FDA500A03429 /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
1E5955C615B71C8600A03429 /* authorize_denied.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BB15B71C8600A03429 /* authorize_denied.png */; };
|
1E5955C615B71C8600A03429 /* authorize_denied.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BB15B71C8600A03429 /* authorize_denied.png */; };
|
||||||
1E5955C715B71C8600A03429 /* authorize_denied@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */; };
|
1E5955C715B71C8600A03429 /* authorize_denied@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */; };
|
||||||
1E5955C815B71C8600A03429 /* authorize_request.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BD15B71C8600A03429 /* authorize_request.png */; };
|
|
||||||
1E5955C915B71C8600A03429 /* authorize_request@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BE15B71C8600A03429 /* authorize_request@2x.png */; };
|
|
||||||
1E5955CA15B71C8600A03429 /* bg.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BF15B71C8600A03429 /* bg.png */; };
|
1E5955CA15B71C8600A03429 /* bg.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BF15B71C8600A03429 /* bg.png */; };
|
||||||
1E5955CB15B71C8600A03429 /* buttonHighlight.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C015B71C8600A03429 /* buttonHighlight.png */; };
|
1E5955CB15B71C8600A03429 /* buttonHighlight.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C015B71C8600A03429 /* buttonHighlight.png */; };
|
||||||
1E5955CC15B71C8600A03429 /* buttonHighlight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */; };
|
1E5955CC15B71C8600A03429 /* buttonHighlight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */; };
|
||||||
@ -104,7 +102,6 @@
|
|||||||
1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E561621FBB70070AB92 /* BITCrashManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E561621FBB70070AB92 /* BITCrashManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
1E754E5D1621FBB70070AB92 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E571621FBB70070AB92 /* BITCrashManager.m */; };
|
1E754E5D1621FBB70070AB92 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E571621FBB70070AB92 /* BITCrashManager.m */; };
|
||||||
1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
1E754E5F1621FBB70070AB92 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */; };
|
|
||||||
1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */; };
|
1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */; };
|
||||||
1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */; };
|
1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */; };
|
||||||
1E7A45FC16F54FB5005B08F1 /* OCHamcrestIOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E7A45FA16F54FB5005B08F1 /* OCHamcrestIOS.framework */; };
|
1E7A45FC16F54FB5005B08F1 /* OCHamcrestIOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E7A45FA16F54FB5005B08F1 /* OCHamcrestIOS.framework */; };
|
||||||
@ -231,8 +228,6 @@
|
|||||||
1E59557215B6F84D00A03429 /* ru */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/HockeySDK.strings; sourceTree = "<group>"; };
|
1E59557215B6F84D00A03429 /* ru */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/HockeySDK.strings; sourceTree = "<group>"; };
|
||||||
1E5955BB15B71C8600A03429 /* authorize_denied.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = authorize_denied.png; sourceTree = "<group>"; };
|
1E5955BB15B71C8600A03429 /* authorize_denied.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = authorize_denied.png; sourceTree = "<group>"; };
|
||||||
1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "authorize_denied@2x.png"; sourceTree = "<group>"; };
|
1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "authorize_denied@2x.png"; sourceTree = "<group>"; };
|
||||||
1E5955BD15B71C8600A03429 /* authorize_request.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = authorize_request.png; sourceTree = "<group>"; };
|
|
||||||
1E5955BE15B71C8600A03429 /* authorize_request@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "authorize_request@2x.png"; sourceTree = "<group>"; };
|
|
||||||
1E5955BF15B71C8600A03429 /* bg.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bg.png; sourceTree = "<group>"; };
|
1E5955BF15B71C8600A03429 /* bg.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bg.png; sourceTree = "<group>"; };
|
||||||
1E5955C015B71C8600A03429 /* buttonHighlight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = buttonHighlight.png; sourceTree = "<group>"; };
|
1E5955C015B71C8600A03429 /* buttonHighlight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = buttonHighlight.png; sourceTree = "<group>"; };
|
||||||
1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "buttonHighlight@2x.png"; sourceTree = "<group>"; };
|
1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "buttonHighlight@2x.png"; sourceTree = "<group>"; };
|
||||||
@ -254,7 +249,6 @@
|
|||||||
1E754E561621FBB70070AB92 /* BITCrashManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManager.h; sourceTree = "<group>"; };
|
1E754E561621FBB70070AB92 /* BITCrashManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManager.h; sourceTree = "<group>"; };
|
||||||
1E754E571621FBB70070AB92 /* BITCrashManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashManager.m; sourceTree = "<group>"; };
|
1E754E571621FBB70070AB92 /* BITCrashManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashManager.m; sourceTree = "<group>"; };
|
||||||
1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerDelegate.h; sourceTree = "<group>"; };
|
1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerDelegate.h; sourceTree = "<group>"; };
|
||||||
1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerPrivate.h; sourceTree = "<group>"; };
|
|
||||||
1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashReportTextFormatter.h; sourceTree = "<group>"; };
|
1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashReportTextFormatter.h; sourceTree = "<group>"; };
|
||||||
1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashReportTextFormatter.m; sourceTree = "<group>"; };
|
1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashReportTextFormatter.m; sourceTree = "<group>"; };
|
||||||
1E7A45FA16F54FB5005B08F1 /* OCHamcrestIOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OCHamcrestIOS.framework; sourceTree = "<group>"; };
|
1E7A45FA16F54FB5005B08F1 /* OCHamcrestIOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OCHamcrestIOS.framework; sourceTree = "<group>"; };
|
||||||
@ -334,8 +328,6 @@
|
|||||||
children = (
|
children = (
|
||||||
1E5955BB15B71C8600A03429 /* authorize_denied.png */,
|
1E5955BB15B71C8600A03429 /* authorize_denied.png */,
|
||||||
1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */,
|
1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */,
|
||||||
1E5955BD15B71C8600A03429 /* authorize_request.png */,
|
|
||||||
1E5955BE15B71C8600A03429 /* authorize_request@2x.png */,
|
|
||||||
1E5955BF15B71C8600A03429 /* bg.png */,
|
1E5955BF15B71C8600A03429 /* bg.png */,
|
||||||
1E5955C015B71C8600A03429 /* buttonHighlight.png */,
|
1E5955C015B71C8600A03429 /* buttonHighlight.png */,
|
||||||
1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */,
|
1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */,
|
||||||
@ -463,7 +455,6 @@
|
|||||||
1E754E561621FBB70070AB92 /* BITCrashManager.h */,
|
1E754E561621FBB70070AB92 /* BITCrashManager.h */,
|
||||||
1E754E571621FBB70070AB92 /* BITCrashManager.m */,
|
1E754E571621FBB70070AB92 /* BITCrashManager.m */,
|
||||||
1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */,
|
1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */,
|
||||||
1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */,
|
|
||||||
1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */,
|
1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */,
|
||||||
1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */,
|
1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */,
|
||||||
);
|
);
|
||||||
@ -622,7 +613,6 @@
|
|||||||
1E49A4D0161222B900463151 /* BITWebTableViewCell.h in Headers */,
|
1E49A4D0161222B900463151 /* BITWebTableViewCell.h in Headers */,
|
||||||
1E49A4D8161222D400463151 /* HockeySDKPrivate.h in Headers */,
|
1E49A4D8161222D400463151 /* HockeySDKPrivate.h in Headers */,
|
||||||
1EC69F601615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */,
|
1EC69F601615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */,
|
||||||
1E754E5F1621FBB70070AB92 /* BITCrashManagerPrivate.h in Headers */,
|
|
||||||
E48A3DEC17B3ED1C00924C3D /* BITAuthenticator.h in Headers */,
|
E48A3DEC17B3ED1C00924C3D /* BITAuthenticator.h in Headers */,
|
||||||
1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */,
|
1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */,
|
||||||
1EACC97B162F041E007578C5 /* BITAttributedLabel.h in Headers */,
|
1EACC97B162F041E007578C5 /* BITAttributedLabel.h in Headers */,
|
||||||
@ -743,8 +733,6 @@
|
|||||||
files = (
|
files = (
|
||||||
1E5955C615B71C8600A03429 /* authorize_denied.png in Resources */,
|
1E5955C615B71C8600A03429 /* authorize_denied.png in Resources */,
|
||||||
1E5955C715B71C8600A03429 /* authorize_denied@2x.png in Resources */,
|
1E5955C715B71C8600A03429 /* authorize_denied@2x.png in Resources */,
|
||||||
1E5955C815B71C8600A03429 /* authorize_request.png in Resources */,
|
|
||||||
1E5955C915B71C8600A03429 /* authorize_request@2x.png in Resources */,
|
|
||||||
1E5955CA15B71C8600A03429 /* bg.png in Resources */,
|
1E5955CA15B71C8600A03429 /* bg.png in Resources */,
|
||||||
1E5955CB15B71C8600A03429 /* buttonHighlight.png in Resources */,
|
1E5955CB15B71C8600A03429 /* buttonHighlight.png in Resources */,
|
||||||
1E5955CC15B71C8600A03429 /* buttonHighlight@2x.png in Resources */,
|
1E5955CC15B71C8600A03429 /* buttonHighlight@2x.png in Resources */,
|
||||||
|
Binary file not shown.
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
// This must be included before any other PLCrashReporter includes, as
|
// This must be included before any other PLCrashReporter includes, as
|
||||||
// it redefines symbol names
|
// it redefines symbol names
|
||||||
#import "PLCrashReporterNamespace.h"
|
#import "PLCrashNamespace.h"
|
||||||
|
|
||||||
#import "PLCrashReporter.h"
|
#import "PLCrashReporter.h"
|
||||||
#import "PLCrashReport.h"
|
#import "PLCrashReport.h"
|
||||||
@ -93,6 +93,9 @@ typedef enum {
|
|||||||
|
|
||||||
/** The crash report log file is corrupt or invalid */
|
/** The crash report log file is corrupt or invalid */
|
||||||
PLCrashReporterErrorCrashReportInvalid = 2,
|
PLCrashReporterErrorCrashReportInvalid = 2,
|
||||||
|
|
||||||
|
/** An attempt to use a resource which was in use at the time in a manner which would have conflicted with the request. */
|
||||||
|
PLCrashReporterErrorResourceBusy = 3
|
||||||
} PLCrashReporterError;
|
} PLCrashReporterError;
|
||||||
|
|
||||||
|
|
||||||
@ -233,7 +236,65 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @page mach_exceptions Mach Exceptions on iOS
|
* @page mach_exceptions Mach Exceptions on Mac OS X and iOS
|
||||||
|
*
|
||||||
|
* PLCrashReporter includes support for monitoring crashes via an in-process Mach exception handler. On Mac OS X, the
|
||||||
|
* Mach exception implementation is fully supported using entirely public API. On iOS, the APIs required are not fully
|
||||||
|
* public -- more details on the implications of this for exception handling on iOS may be found in
|
||||||
|
* @ref mach_exceptions_ios below.
|
||||||
|
*
|
||||||
|
* It is worth noting that even where the Mach exception APIs are fully supported, kernel-internal constants, as well
|
||||||
|
* as architecture-specific trap information, may be required to fully interpret a Mach exception's root cause.
|
||||||
|
*
|
||||||
|
* For example, the EXC_SOFTWARE exception is dispatched for four different failure types, using the exception
|
||||||
|
* code to differentiate failure types:
|
||||||
|
* - Non-existent system call invoked (SIGSYS)
|
||||||
|
* - Write on a pipe with no reader (SIGPIPE)
|
||||||
|
* - Abort program (SIGABRT)
|
||||||
|
* - Kill program (SIGKILL)
|
||||||
|
*
|
||||||
|
* Of those four types, only the constant required to interpret the SIGKILL behavior (EXC_SOFT_SIGNAL) is publicly defined.
|
||||||
|
* Of the remaining three failure types, the constant values are kernel implementation-private, defined only in the available
|
||||||
|
* kernel sources. On iOS, these sources are unavailable, and while they generally do match the Mac OS X implementation, there
|
||||||
|
* are no gaurantees that this is -- or will remain -- the case in the future.
|
||||||
|
*
|
||||||
|
* Likewise, interpretation of particular fault types requires information regarding the underlying machine traps
|
||||||
|
* that triggered the Mach exceptions. For example, a floating point trap on x86/x86-64 will trigger an EXC_ARITHMETIC,
|
||||||
|
* with a subcode value containing the value of the FPU status register. Determining the exact FPU cause requires
|
||||||
|
* extracting the actual exception flags from status register as per the x86 architecture documentation. The exact format
|
||||||
|
* of this subcode value is not actually documented outside the kernel, and may change in future releases.
|
||||||
|
*
|
||||||
|
* While we have the advantage of access to the x86 kernel sources, the situation on ARM is even less clear. The actual
|
||||||
|
* use of the Mach exception codes and subcodes is largely undefined by both headers and publicly available documentation,
|
||||||
|
* and the available x86 kernel sources are of little use in interpreting this data.
|
||||||
|
*
|
||||||
|
* As such, while Mach exceptions may catch some cases that BSD signals can not, they are not a perfect solution,
|
||||||
|
* and may also provide less insight into the actual failures that occur. By comparison, the BSD signal interface
|
||||||
|
* is both fully defined and architecture independent, with any necessary interpretation of the Mach exception
|
||||||
|
* codes handled in-kernel at the time of exception dispatch. It is generally recommended by Apple as the preferred
|
||||||
|
* interface, and should generally be preferred by PLCrashReporter API clients.
|
||||||
|
*
|
||||||
|
* @section mach_exceptions_compatibility Compatibility Issues
|
||||||
|
*
|
||||||
|
* @subsection Debuggers
|
||||||
|
*
|
||||||
|
* Enabling in-process Mach exception handlers will conflict with any attached debuggers; the debugger
|
||||||
|
* may suspend the processes Mach exception handling thread, which will result in any exception messages
|
||||||
|
* sent via the debugger being lost, as the in-process handler will be unable to receive and forward
|
||||||
|
* the messages.
|
||||||
|
*
|
||||||
|
* @subsection Managed Runtimes (Xamarin, Unity)
|
||||||
|
*
|
||||||
|
* A Mach exception handler may conflict with any managed runtime that registers a BSD signal handler that
|
||||||
|
* can safely handle otherwise fatal signals, allowing execution to proceed. This includes products
|
||||||
|
* such as Xamarin for iOS.
|
||||||
|
*
|
||||||
|
* In such a case, PLCrashReporter will write a crash report for non-fatal signals, as there is no
|
||||||
|
* immediate mechanism for determining whether a signal handler exists and that it can safely
|
||||||
|
* handle the failure. This can result in unexpected delays in application execution, increased I/O to
|
||||||
|
* disk, and other undesirable operations.
|
||||||
|
*
|
||||||
|
* @section mach_exceptions_ios Mach Exceptions on iOS
|
||||||
*
|
*
|
||||||
* The APIs required for Mach exception handling are not fully public on iOS. Unfortunately, there are a number
|
* The APIs required for Mach exception handling are not fully public on iOS. Unfortunately, there are a number
|
||||||
* of crash states that can only be handled with Mach exception handlers:
|
* of crash states that can only be handled with Mach exception handlers:
|
||||||
|
105
Vendor/CrashReporter.framework/Versions/A/Headers/PLCrashFeatureConfig.h
vendored
Normal file
105
Vendor/CrashReporter.framework/Versions/A/Headers/PLCrashFeatureConfig.h
vendored
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Author: Landon Fuller <landonf@plausible.coop>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012-2013 Plausible Labs Cooperative, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation
|
||||||
|
* files (the "Software"), to deal in the Software without
|
||||||
|
* restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following
|
||||||
|
* conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PLCRASH_FEATURE_CONFIG_H
|
||||||
|
#define PLCRASH_FEATURE_CONFIG_H
|
||||||
|
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* Build-time configuration for PLCrashReporter.
|
||||||
|
*
|
||||||
|
* This is used to automatically enable/disable features on a per-platform and per-configuration
|
||||||
|
* basis; it may also be used by third-party vendors to configure a custom build of PLCrashReporter.
|
||||||
|
*
|
||||||
|
* @defgroup build_config Build Configuration
|
||||||
|
* @ingroup constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Defaults
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For release builds, disable unused unwind implementations on targets that do not use them. For non-release
|
||||||
|
* builds, we include the unwind implementations to allow testing on a broader range of targets; it's possible
|
||||||
|
* that both compact and/or DWARF unwinding could be implemented by Apple for iOS/ARM in the future.
|
||||||
|
*/
|
||||||
|
#ifdef PLCF_RELEASE_BUILD
|
||||||
|
# if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
|
||||||
|
# ifndef PLCRASH_FEATURE_UNWIND_DWARF
|
||||||
|
# define PLCRASH_FEATURE_UNWIND_DWARF 0
|
||||||
|
# endif
|
||||||
|
# ifndef PLCRASH_FEATURE_UNWIND_COMPACT
|
||||||
|
# define PLCRASH_FEATURE_UNWIND_COMPACT 0
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configuration Flags
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef PLCRASH_FEATURE_MACH_EXCEPTIONS
|
||||||
|
/**
|
||||||
|
* If true, enable Mach exception support. On Mac OS X, the Mach exception implementation is fully supported,
|
||||||
|
* using publicly available API. On iOS, the APIs required for a complete implementation are not public. However, a
|
||||||
|
* popular commercial crash reporter is now shipping with support for Mach exceptions, which implies that either
|
||||||
|
* they've received special dispensation to use private APIs / private structures, they've found another way to do
|
||||||
|
* it, or they're just using undocumented functionality and hoping for the best.
|
||||||
|
*
|
||||||
|
* The exposed surface of undocumented API usage is relatively low, and there has been strong user demand to
|
||||||
|
* implement Mach exception handling regardless of concerns over API visiblity. Given this, we've enabled
|
||||||
|
* Mach exception handling by default, and provided both build-time and runtime configuration
|
||||||
|
* to disable its use.
|
||||||
|
*
|
||||||
|
* For more information on the potential issues with enabling mach exception support, @sa @ref mach_exceptions.
|
||||||
|
*/
|
||||||
|
# define PLCRASH_FEATURE_MACH_EXCEPTIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PLCRASH_FEATURE_UNWIND_DWARF
|
||||||
|
/** If true, enable DWARF unwinding support. DWARF unwinding is currently only used by Mac OS X. */
|
||||||
|
# define PLCRASH_FEATURE_UNWIND_DWARF 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef PLCRASH_FEATURE_UNWIND_COMPACT
|
||||||
|
/** If true, enable compact unwinding support. This is only used by Mac OS X. */
|
||||||
|
# define PLCRASH_FEATURE_UNWIND_COMPACT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* PLCRASH_FEATURE_CONFIG_H */
|
@ -35,6 +35,7 @@
|
|||||||
* This may be used to avoid symbol conflicts between multiple libraries
|
* This may be used to avoid symbol conflicts between multiple libraries
|
||||||
* that may both incorporate PLCrashReporter.
|
* that may both incorporate PLCrashReporter.
|
||||||
*/
|
*/
|
||||||
|
// #define PLCRASHREPORTER_PREFIX AcmeCo
|
||||||
#define PLCRASHREPORTER_PREFIX BIT
|
#define PLCRASHREPORTER_PREFIX BIT
|
||||||
|
|
||||||
#ifdef PLCRASHREPORTER_PREFIX
|
#ifdef PLCRASHREPORTER_PREFIX
|
||||||
@ -66,5 +67,14 @@
|
|||||||
#define PLCrashReportHostOperatingSystem PLNS(PLCrashReportHostOperatingSystem)
|
#define PLCrashReportHostOperatingSystem PLNS(PLCrashReportHostOperatingSystem)
|
||||||
#define PLCrashReporterErrorDomain PLNS(PLCrashReporterErrorDomain)
|
#define PLCrashReporterErrorDomain PLNS(PLCrashReporterErrorDomain)
|
||||||
#define PLCrashReporterException PLNS(PLCrashReporterException)
|
#define PLCrashReporterException PLNS(PLCrashReporterException)
|
||||||
|
#define PLCrashHostInfo PLNS(PLCrashHostInfo)
|
||||||
|
#define PLCrashMachExceptionPort PLNS(PLCrashMachExceptionPort)
|
||||||
|
#define PLCrashMachExceptionPortSet PLNS(PLCrashMachExceptionPortSet)
|
||||||
|
#define PLCrashProcessInfo PLNS(PLCrashProcessInfo)
|
||||||
|
#define PLCrashReporterConfig PLNS(PLCrashReporterConfig)
|
||||||
|
#define PLCrashUncaughtExceptionHandler PLNS(PLCrashUncaughtExceptionHandler)
|
||||||
|
#define PLCrashMachExceptionForward PLNS(PLCrashMachExceptionForward)
|
||||||
|
#define PLCrashSignalHandlerForward PLNS(PLCrashSignalHandlerForward)
|
||||||
|
#define plcrash_signal_handler PLNS(plcrash_signal_handler)
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -32,6 +32,7 @@
|
|||||||
#import "PLCrashReportBinaryImageInfo.h"
|
#import "PLCrashReportBinaryImageInfo.h"
|
||||||
#import "PLCrashReportExceptionInfo.h"
|
#import "PLCrashReportExceptionInfo.h"
|
||||||
#import "PLCrashReportMachineInfo.h"
|
#import "PLCrashReportMachineInfo.h"
|
||||||
|
#import "PLCrashReportMachExceptionInfo.h"
|
||||||
#import "PLCrashReportProcessInfo.h"
|
#import "PLCrashReportProcessInfo.h"
|
||||||
#import "PLCrashReportProcessorInfo.h"
|
#import "PLCrashReportProcessorInfo.h"
|
||||||
#import "PLCrashReportRegisterInfo.h"
|
#import "PLCrashReportRegisterInfo.h"
|
||||||
@ -99,6 +100,9 @@ typedef struct _PLCrashReportDecoder _PLCrashReportDecoder;
|
|||||||
/** Signal info */
|
/** Signal info */
|
||||||
PLCrashReportSignalInfo *_signalInfo;
|
PLCrashReportSignalInfo *_signalInfo;
|
||||||
|
|
||||||
|
/** Mach exception info */
|
||||||
|
PLCrashReportMachExceptionInfo *_machExceptionInfo;
|
||||||
|
|
||||||
/** Thread info (PLCrashReportThreadInfo instances) */
|
/** Thread info (PLCrashReportThreadInfo instances) */
|
||||||
NSArray *_threads;
|
NSArray *_threads;
|
||||||
|
|
||||||
@ -153,6 +157,18 @@ typedef struct _PLCrashReportDecoder _PLCrashReportDecoder;
|
|||||||
*/
|
*/
|
||||||
@property(nonatomic, readonly) PLCrashReportSignalInfo *signalInfo;
|
@property(nonatomic, readonly) PLCrashReportSignalInfo *signalInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mach exception information, if available. This will only be included in the
|
||||||
|
* case that encoding crash reporter's exception-based reporting was enabled, and a Mach
|
||||||
|
* exception was caught.
|
||||||
|
*
|
||||||
|
* @warning If Mach exception information is available, the legacy signalInfo property will also be provided; this
|
||||||
|
* s required to maintain backwards compatibility with the established API. Note, however, that the signal info may be derived from the
|
||||||
|
* Mach exception info by the encoding crash reporter, and thus may not exactly match the kernel exception-to-signal
|
||||||
|
* mappings implemented in xnu. As such, when Mach exception info is available, its use should be preferred.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) PLCrashReportMachExceptionInfo *machExceptionInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread information. Returns a list of PLCrashReportThreadInfo instances.
|
* Thread information. Returns a list of PLCrashReportThreadInfo instances.
|
||||||
*/
|
*/
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Author: Andreas Linde <mail@andreaslinde.de>
|
* Author: Landon Fuller <landonf@plausiblelabs.com>
|
||||||
* Kent Sutherland
|
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH.
|
* Copyright (c) 2013 Plausible Labs Cooperative, Inc.
|
||||||
* Copyright (c) 2011 Andreas Linde & Kent Sutherland.
|
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
@ -30,15 +28,21 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface PLCrashReportMachExceptionInfo : NSObject {
|
||||||
|
@private
|
||||||
|
/** The Mach exception type. */
|
||||||
|
uint64_t _type;
|
||||||
|
|
||||||
@interface BITCrashManager () {
|
/** The Mach exception codes, represented as an ordered array of NSNumber instances. */
|
||||||
|
NSArray *_codes;
|
||||||
}
|
}
|
||||||
|
|
||||||
//// set the server URL
|
- (id) initWithType: (uint64_t) type codes: (NSArray *) codes;
|
||||||
//@property (nonatomic, retain) NSString *serverURL;
|
|
||||||
//
|
/** The Mach exception type. */
|
||||||
//- (id)initWithAppIdentifier:(NSString *)appIdentifier;
|
@property(nonatomic, readonly) uint64_t type;
|
||||||
//
|
|
||||||
//- (void)startManager;
|
/** The Mach exception codes, represented as an ordered array of 64-bit unsigned NSNumber instances. */
|
||||||
|
@property(nonatomic, readonly) NSArray *codes;
|
||||||
|
|
||||||
@end
|
@end
|
@ -29,6 +29,11 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <mach/mach.h>
|
#import <mach/mach.h>
|
||||||
|
|
||||||
|
#import "PLCrashReporterConfig.h"
|
||||||
|
|
||||||
|
@class PLCrashMachExceptionServer;
|
||||||
|
@class PLCrashMachExceptionPortSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup functions
|
* @ingroup functions
|
||||||
*
|
*
|
||||||
@ -60,16 +65,38 @@ typedef struct PLCrashReporterCallbacks {
|
|||||||
/** An arbitrary user-supplied context value. This value may be NULL. */
|
/** An arbitrary user-supplied context value. This value may be NULL. */
|
||||||
void *context;
|
void *context;
|
||||||
|
|
||||||
/** The callback used to report caught signal information. In version 0 of this structure, all crashes will be
|
/**
|
||||||
* reported via this function. */
|
* The callback used to report caught signal information. In version 0 of this structure, all crashes will be
|
||||||
|
* reported via this function.
|
||||||
|
*
|
||||||
|
* @warning When using PLCrashReporterSignalHandlerTypeMach, the siginfo_t argument to this function will be derived
|
||||||
|
* from the Mach exception data, and may be incorrect, or may otherwise not match the expected data as provided via
|
||||||
|
* PLCrashReporterSignalHandlerTypeBSD. In addition, the provided ucontext_t value will be zero-initialized, and will
|
||||||
|
* not provide valid thread state.
|
||||||
|
*
|
||||||
|
* This callback will be deprecated in favor of a Mach-compatible replacement in a future release; support is maintained
|
||||||
|
* here to allow clients that rely on post-crash callbacks without thread state to make use of Mach exceptions.
|
||||||
|
*/
|
||||||
PLCrashReporterPostCrashSignalCallback handleSignal;
|
PLCrashReporterPostCrashSignalCallback handleSignal;
|
||||||
} PLCrashReporterCallbacks;
|
} PLCrashReporterCallbacks;
|
||||||
|
|
||||||
@interface PLCrashReporter : NSObject {
|
@interface PLCrashReporter : NSObject {
|
||||||
@private
|
@private
|
||||||
|
/** Reporter configuration */
|
||||||
|
PLCrashReporterConfig *_config;
|
||||||
|
|
||||||
/** YES if the crash reporter has been enabled */
|
/** YES if the crash reporter has been enabled */
|
||||||
BOOL _enabled;
|
BOOL _enabled;
|
||||||
|
|
||||||
|
#if PLCRASH_FEATURE_MACH_EXCEPTIONS
|
||||||
|
/** The backing Mach exception server, if any. Nil if the reporter has not been enabled, or if
|
||||||
|
* the configured signal handler type is not PLCrashReporterSignalHandlerTypeMach. */
|
||||||
|
PLCrashMachExceptionServer *_machServer;
|
||||||
|
|
||||||
|
/** Previously registered Mach exception ports, if any. */
|
||||||
|
PLCrashMachExceptionPortSet *_previousMachPorts;
|
||||||
|
#endif /* PLCRASH_FEATURE_MACH_EXCEPTIONS */
|
||||||
|
|
||||||
/** Application identifier */
|
/** Application identifier */
|
||||||
NSString *_applicationIdentifier;
|
NSString *_applicationIdentifier;
|
||||||
|
|
||||||
@ -82,6 +109,8 @@ typedef struct PLCrashReporterCallbacks {
|
|||||||
|
|
||||||
+ (PLCrashReporter *) sharedReporter;
|
+ (PLCrashReporter *) sharedReporter;
|
||||||
|
|
||||||
|
- (instancetype) initWithConfiguration: (PLCrashReporterConfig *) config;
|
||||||
|
|
||||||
- (BOOL) hasPendingCrashReport;
|
- (BOOL) hasPendingCrashReport;
|
||||||
|
|
||||||
- (NSData *) loadPendingCrashReportData;
|
- (NSData *) loadPendingCrashReportData;
|
||||||
|
165
Vendor/CrashReporter.framework/Versions/A/Headers/PLCrashReporterConfig.h
vendored
Normal file
165
Vendor/CrashReporter.framework/Versions/A/Headers/PLCrashReporterConfig.h
vendored
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* Author: Landon Fuller <landonf@plausible.coop>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013 Plausible Labs Cooperative, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation
|
||||||
|
* files (the "Software"), to deal in the Software without
|
||||||
|
* restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following
|
||||||
|
* conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "PLCrashFeatureConfig.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup enums
|
||||||
|
* Supported mechanisms for trapping and handling crashes.
|
||||||
|
*/
|
||||||
|
typedef NS_ENUM(NSUInteger, PLCrashReporterSignalHandlerType) {
|
||||||
|
/**
|
||||||
|
* Trap fatal signals via a sigaction(2)-registered BSD signal handler.
|
||||||
|
*
|
||||||
|
* PLCrashReporter's signal handler will supersede previously registered handlers; existing
|
||||||
|
* handlers will not be called. This behavior may be modified in a future release, and should
|
||||||
|
* not be relied upon as a mechanism to prevent existing signal handlers from being called.
|
||||||
|
*
|
||||||
|
* There are some limitations to signal-based crash handling on Mac OS X and iOS; specifically:
|
||||||
|
*
|
||||||
|
* - On Mac OS X, stack overflows will only be handled on the thread on which
|
||||||
|
* the crash reporter was initialized. This should generally be the main thread.
|
||||||
|
* - On iOS 6.0 and later, any stack overflows will not be handled due to sigaltstack() being
|
||||||
|
* non-functional on the device. (see rdar://13002712 - SA_ONSTACK/sigaltstack() ignored on iOS).
|
||||||
|
* - Some exit paths in Apple's Libc will deregister a signal handler before firing SIGABRT, resulting
|
||||||
|
* in the signal handler never being called (see rdar://14313497 - ___abort() disables SIGABRT signal
|
||||||
|
* handlers prior to raising SIGABRT). These __abort()-based checks are:
|
||||||
|
* - Implemented for unsafe memcpy/strcpy/snprintf C functions.
|
||||||
|
* - Only enabled when operating on a fixed-width target buffer (in which case the
|
||||||
|
* compiler rewrites the function calls to the built-in variants, and provides the fixed-width length as an argument).
|
||||||
|
* - Only trigger in the case that the source data exceeds the size of the fixed width target
|
||||||
|
* buffer, and the maximum length argument either isn't supplied by the caller (eg, when using strcpy),
|
||||||
|
* or a too-long argument is supplied (eg, strncpy with a length argument longer than the target buffer),
|
||||||
|
* AND that argument can't be checked at compile-time.
|
||||||
|
*/
|
||||||
|
PLCrashReporterSignalHandlerTypeBSD = 0,
|
||||||
|
|
||||||
|
#if PLCRASH_FEATURE_MACH_EXCEPTIONS
|
||||||
|
/**
|
||||||
|
* Trap fatal signals via a Mach exception server.
|
||||||
|
*
|
||||||
|
* If any existing Mach exception server has been registered for the task, exceptions will be forwarded to that
|
||||||
|
* exception handler. Should the exceptions be handled by an existing handler, no report will be generated
|
||||||
|
* by PLCrashReporter.
|
||||||
|
*
|
||||||
|
* @par Mac OS X
|
||||||
|
*
|
||||||
|
* On Mac OS X, the Mach exception implementation is fully supported, using publicly available API -- note,
|
||||||
|
* however, that some kernel-internal constants, as well as architecture-specific trap information,
|
||||||
|
* may be required to fully interpret a Mach exception's root cause.
|
||||||
|
*
|
||||||
|
* @par iOS
|
||||||
|
*
|
||||||
|
* On iOS, the APIs required for a complete implementation are not fully public.
|
||||||
|
*
|
||||||
|
* The exposed surface of undocumented API usage is relatively low, and there has been strong user demand to
|
||||||
|
* implement Mach exception handling regardless of concerns over API visiblity. Given this, we've included
|
||||||
|
* Mach exception handling as an optional feature, with both build-time and runtime configuration
|
||||||
|
* to disable its inclusion or use, respectively.
|
||||||
|
*
|
||||||
|
* @par Debugger Incompatibility
|
||||||
|
*
|
||||||
|
* The Mach exception handler executes in-process, and will interfere with debuggers when they attempt to
|
||||||
|
* suspend all active threads (which will include the Mach exception handler). Mach-based handling
|
||||||
|
* should not be used when a debugger is attached.
|
||||||
|
*
|
||||||
|
* @par More Details
|
||||||
|
*
|
||||||
|
* For more information, refer to @ref mach_exceptions.
|
||||||
|
*/
|
||||||
|
PLCrashReporterSignalHandlerTypeMach = 1
|
||||||
|
#endif /* PLCRASH_FEATURE_MACH_EXCEPTIONS */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup enums
|
||||||
|
* Supported mechanisms for performing local symbolication.
|
||||||
|
*
|
||||||
|
* Local symbolication is performed using inexact heuristics and symbol data available at runtime; it may
|
||||||
|
* return information that is incorrect. This may still be useful in the case where DWARF data is unavailable
|
||||||
|
* for a given build; in that case, it can provide function and method names (though not line numbers) for a
|
||||||
|
* crash report that may otherwise be unusable.
|
||||||
|
*
|
||||||
|
* Note, however, this comes at the cost of a significant increase in code that must run within the critical
|
||||||
|
* crash reporting section, where failures may result in crash reports being corrupted or left unwritten. In
|
||||||
|
* addition, some of the provided symbolication strategies rely on knowledge of runtime internals that may
|
||||||
|
* change in future iOS releases. Given that DWARF symbolication data will <em>always</em> be more accurate, and
|
||||||
|
* the risks inherent in executing considerably more code at crash time, it is strongly recommended that local
|
||||||
|
* symbolication only be enabled for non-release builds.
|
||||||
|
*
|
||||||
|
* Multiple symbolication strategies may be enabled, in which case a best-match heuristic will be applied to the
|
||||||
|
* results.
|
||||||
|
*/
|
||||||
|
typedef NS_OPTIONS(NSUInteger, PLCrashReporterSymbolicationStrategy) {
|
||||||
|
/** No symbolication. */
|
||||||
|
PLCrashReporterSymbolicationStrategyNone = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the standard binary symbol table. On iOS, this alone will return
|
||||||
|
* incomplete results, as most symbols are rewritten to the common '\<redacted>' string.
|
||||||
|
*/
|
||||||
|
PLCrashReporterSymbolicationStrategySymbolTable = 1 << 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use Objective-C metadata to find method and class names. This relies on detailed parsing
|
||||||
|
* of the Objective-C runtime data, including undefined flags and other runtime internals. As such,
|
||||||
|
* it may return incorrect data should the runtime be changed incompatibly.
|
||||||
|
*/
|
||||||
|
PLCrashReporterSymbolicationStrategyObjC = 1 << 1,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable all available symbolication strategies.
|
||||||
|
*/
|
||||||
|
PLCrashReporterSymbolicationStrategyAll = (PLCrashReporterSymbolicationStrategySymbolTable|PLCrashReporterSymbolicationStrategyObjC)
|
||||||
|
};
|
||||||
|
|
||||||
|
@interface PLCrashReporterConfig : NSObject {
|
||||||
|
@private
|
||||||
|
/** The configured signal handler type. */
|
||||||
|
PLCrashReporterSignalHandlerType _signalHandlerType;
|
||||||
|
|
||||||
|
/** The configured symbolication strategy. */
|
||||||
|
PLCrashReporterSymbolicationStrategy _symbolicationStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype) defaultConfiguration;
|
||||||
|
|
||||||
|
- (instancetype) init;
|
||||||
|
- (instancetype) initWithSignalHandlerType: (PLCrashReporterSignalHandlerType) signalHandlerType
|
||||||
|
symbolicationStrategy: (PLCrashReporterSymbolicationStrategy) symbolicationStrategy;
|
||||||
|
|
||||||
|
/** The configured signal handler type. */
|
||||||
|
@property(nonatomic, readonly) PLCrashReporterSignalHandlerType signalHandlerType;
|
||||||
|
|
||||||
|
/** The configured symbolication strategy. */
|
||||||
|
@property(nonatomic, readonly) PLCrashReporterSymbolicationStrategy symbolicationStrategy;
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
@ -95,101 +95,3 @@ This example code is based on CocoaLumberjack logging into log files:
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
## Advanced HowTo
|
|
||||||
|
|
||||||
If you want to restrict the log files to contain only the data from the last application run (from app start until it crashed, ignoring all suspend and resume actions), you follow these steps. (Thanks to Michael Tyson for this hint!)
|
|
||||||
|
|
||||||
4. Adjust CocoaLumberjack to initialize a new log file per application start
|
|
||||||
|
|
||||||
[_fileLogger performSelector:@selector(currentLogFileHandle)]; // init log file prior to rolling
|
|
||||||
[_fileLogger rollLogFile];
|
|
||||||
[_fileLogger performSelector:@selector(currentLogFileHandle)]; // re-init log file to apply roll
|
|
||||||
|
|
||||||
5. And when loading the prior (crashed) application run log file, stop the iteration over the log files before the most current one (which is the new session, the one after the crash):
|
|
||||||
|
|
||||||
// we start from the last (oldest) one, and stop just before the newest (which is the log for the session after the crash)
|
|
||||||
for (int index = count - 1; index > 0; index--) {
|
|
||||||
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
@interface BITAppDelegate () <BITCrashManagerDelegate> {}
|
|
||||||
@property (nonatomic) DDFileLogger *fileLogger;
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
@implementation BITAppDelegate
|
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
|
||||||
[self.window makeKeyAndVisible];
|
|
||||||
|
|
||||||
// initialize before HockeySDK, so the delegate can access the file logger!
|
|
||||||
_fileLogger = [[DDFileLogger alloc] init];
|
|
||||||
_fileLogger.maximumFileSize = (1024 * 64); // 64 KByte
|
|
||||||
_fileLogger.logFileManager.maximumNumberOfLogFiles = 1;
|
|
||||||
[_fileLogger performSelector:@selector(currentLogFileHandle)]; // init log file prior to rolling
|
|
||||||
[_fileLogger rollLogFile];
|
|
||||||
[_fileLogger performSelector:@selector(currentLogFileHandle)]; // re-init log file to apply roll
|
|
||||||
[DDLog addLogger:_fileLogger];
|
|
||||||
|
|
||||||
[[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"<>"
|
|
||||||
delegate:nil];
|
|
||||||
|
|
||||||
[[BITHockeyManager sharedHockeyManager] startManager];
|
|
||||||
|
|
||||||
// add Xcode console logger if not running in the App Store
|
|
||||||
if (![[BITHockeyManager sharedHockeyManager] isAppStoreEnvironment]) {
|
|
||||||
PSDDFormatter *psLogger = [[[PSDDFormatter alloc] init] autorelease];
|
|
||||||
[[DDTTYLogger sharedInstance] setLogFormatter:psLogger];
|
|
||||||
|
|
||||||
[DDLog addLogger:[DDTTYLogger sharedInstance]];
|
|
||||||
|
|
||||||
[DDLog addLogger:[DDNSLoggerLogger sharedInstance]];
|
|
||||||
}
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the log content with a maximum byte size
|
|
||||||
- (NSString *) getLogFilesContentWithMaxSize:(NSInteger)maxSize {
|
|
||||||
NSMutableString *description = [NSMutableString string];
|
|
||||||
|
|
||||||
NSArray *sortedLogFileInfos = [[_fileLogger logFileManager] sortedLogFileInfos];
|
|
||||||
NSUInteger count = [sortedLogFileInfos count];
|
|
||||||
|
|
||||||
// we start from the last (oldest) one, and stop just before the newest (which is the log for the session after the crash)
|
|
||||||
for (int index = count - 1; index > 0; index--) {
|
|
||||||
DDLogFileInfo *logFileInfo = [sortedLogFileInfos objectAtIndex:index];
|
|
||||||
|
|
||||||
NSData *logData = [[NSFileManager defaultManager] contentsAtPath:[logFileInfo filePath]];
|
|
||||||
if ([logData length] > 0) {
|
|
||||||
NSString *result = [[NSString alloc] initWithBytes:[logData bytes]
|
|
||||||
length:[logData length]
|
|
||||||
encoding: NSUTF8StringEncoding];
|
|
||||||
|
|
||||||
[description appendString:result];
|
|
||||||
[result release];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([description length] > maxSize) {
|
|
||||||
description = (NSMutableString *)[description substringWithRange:NSMakeRange([description length]-maxSize-1, maxSize)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - BITCrashManagerDelegate
|
|
||||||
|
|
||||||
- (NSString *)applicationLogForCrashManager:(BITCrashManager *)crashManager {
|
|
||||||
NSString *description = [self getLogFilesContentWithMaxSize:5000]; // 5000 bytes should be enough!
|
|
||||||
if ([description length] == 0) {
|
|
||||||
return nil;
|
|
||||||
} else {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
Loading…
x
Reference in New Issue
Block a user