diff --git a/Classes/BITAttributedLabel.h b/Classes/BITAttributedLabel.h old mode 100755 new mode 100644 diff --git a/Classes/BITAttributedLabel.m b/Classes/BITAttributedLabel.m old mode 100755 new mode 100644 diff --git a/Classes/BITAuthenticator.m b/Classes/BITAuthenticator.m index 4c53eab6eb..6ccc33bea4 100644 --- a/Classes/BITAuthenticator.m +++ b/Classes/BITAuthenticator.m @@ -108,19 +108,19 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44}; // make sure this is called after startManager so all modules are fully setup if (!_isSetup) { + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(authenticateInstallation) object:nil]; [self performSelector:@selector(authenticateInstallation) withObject:nil afterDelay:0.1]; + } else { + switch ([[UIApplication sharedApplication] applicationState]) { + case UIApplicationStateActive: + [self authenticate]; + break; + case UIApplicationStateBackground: + case UIApplicationStateInactive: + // do nothing, wait for active state + break; + } } - - switch ([[UIApplication sharedApplication] applicationState]) { - case UIApplicationStateActive: - [self authenticate]; - break; - case UIApplicationStateBackground: - case UIApplicationStateInactive: - // do nothing, wait for active state - break; - } - [self registerObservers]; } @@ -156,6 +156,10 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44}; } - (void)alertOnFailureStoringTokenInKeychain { + if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) { + return; + } + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:BITHockeyLocalizedString(@"HockeyAuthenticationViewControllerStorageError") delegate:self @@ -607,7 +611,6 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44}; case BITAuthenticatorIdentificationTypeHockeyAppEmail: case BITAuthenticatorIdentificationTypeAnonymous: case BITAuthenticatorIdentificationTypeHockeyAppUser: - NSAssert(NO, @"Should only be called for Device and WebAuth identificationType"); return NO; } diff --git a/Classes/BITCrashAttachment.h b/Classes/BITCrashAttachment.h new file mode 100644 index 0000000000..482e0c004c --- /dev/null +++ b/Classes/BITCrashAttachment.h @@ -0,0 +1,66 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2014 HockeyApp, Bit Stadium GmbH. + * 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 + +/** + * Provides support to add binary attachments to crash reports + * + * This is used by `[BITCrashManagerDelegate attachmentForCrashManager:]` + */ +@interface BITCrashAttachment : NSObject + +/** + * The filename the attachment should get + */ +@property (nonatomic, readonly, strong) NSString *filename; + +/** + * The attachment data as NSData object + */ +@property (nonatomic, readonly, strong) NSData *attachmentData; + +/** + * The content type of your data as MIME type + */ +@property (nonatomic, readonly, strong) NSString *contentType; + +/** + * Create an BITCrashAttachment instance with a given filename and NSData object + * + * @param filename The filename the attachment should get + * @param attachmentData The attachment data as NSData + * @param contentType The content type of your data as MIME type + * + * @return An instsance of BITCrashAttachment + */ +- (instancetype)initWithFilename:(NSString *)filename + attachmentData:(NSData *)attachmentData + contentType:(NSString *)contentType; + +@end diff --git a/Classes/BITCrashAttachment.m b/Classes/BITCrashAttachment.m new file mode 100644 index 0000000000..def32d2583 --- /dev/null +++ b/Classes/BITCrashAttachment.m @@ -0,0 +1,64 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2014 HockeyApp, Bit Stadium GmbH. + * 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 "BITCrashAttachment.h" + +@implementation BITCrashAttachment + +- (instancetype)initWithFilename:(NSString *)filename + attachmentData:(NSData *)attachmentData + contentType:(NSString *)contentType +{ + if (self = [super init]) { + _filename = filename; + _attachmentData = attachmentData; + _contentType = contentType; + } + + return self; +} + + +#pragma mark - NSCoder + +- (void)encodeWithCoder:(NSCoder *)encoder { + [encoder encodeObject:self.filename forKey:@"filename"]; + [encoder encodeObject:self.attachmentData forKey:@"data"]; + [encoder encodeObject:self.contentType forKey:@"contentType"]; +} + +- (id)initWithCoder:(NSCoder *)decoder { + if ((self = [super init])) { + _filename = [decoder decodeObjectForKey:@"filename"]; + _attachmentData = [decoder decodeObjectForKey:@"data"]; + _contentType = [decoder decodeObjectForKey:@"contentType"]; + } + return self; +} + +@end diff --git a/Classes/BITCrashManager.h b/Classes/BITCrashManager.h index 6025d95b7c..2bb4f00fc2 100644 --- a/Classes/BITCrashManager.h +++ b/Classes/BITCrashManager.h @@ -34,6 +34,11 @@ @class BITCrashDetails; +/** + * Custom block that handles the alert that prompts the user whether he wants to send crash reports + */ +typedef void(^CustomAlertViewHandler)(); + /** * Crash Manager status @@ -54,6 +59,54 @@ typedef NS_ENUM(NSUInteger, BITCrashManagerStatus) { }; +/** + * Prototype of a callback function used to execute additional user code. Called upon completion of crash + * handling, after the crash report has been written to disk. + * + * @param context The API client's supplied context value. + * + * @see `BITCrashManagerCallbacks` + * @see `[BITCrashManager setCrashCallbacks:]` + */ +typedef void (*BITCrashManagerPostCrashSignalCallback)(void *context); + +/** + * This structure contains callbacks supported by `BITCrashManager` to allow the host application to perform + * additional tasks prior to program termination after a crash has occured. + * + * @see `BITCrashManagerPostCrashSignalCallback` + * @see `[BITCrashManager setCrashCallbacks:]` + */ +typedef struct BITCrashManagerCallbacks { + /** An arbitrary user-supplied context value. This value may be NULL. */ + void *context; + + /** + * The callback used to report caught signal information. + */ + BITCrashManagerPostCrashSignalCallback handleSignal; +} BITCrashManagerCallbacks; + +/** + * Crash Manager alert user input + */ +typedef NS_ENUM(NSUInteger, BITCrashManagerUserInput) { + /** + * User chose not to send the crash report + */ + BITCrashManagerUserInputDontSend = 0, + /** + * User wants the crash report to be sent + */ + BITCrashManagerUserInputSend = 1, + /** + * User chose to always send crash reports + */ + BITCrashManagerUserInputAlwaysSend = 2 + +}; + + @protocol BITCrashManagerDelegate; /** @@ -229,15 +282,18 @@ typedef NS_ENUM(NSUInteger, BITCrashManagerStatus) { * * _Async-Safe Functions_ * - * A subset of functions are defined to be async-safe by the OS, and are safely callable from within a signal handler. If you do implement a custom post-crash handler, it must be async-safe. A table of POSIX-defined async-safe functions and additional information is available from the CERT programming guide - SIG30-C, see https://www.securecoding.cert.org/confluence/display/seccode/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers + * A subset of functions are defined to be async-safe by the OS, and are safely callable from within a signal handler. If you do implement a custom post-crash handler, it must be async-safe. A table of POSIX-defined async-safe functions and additional information is available from the [CERT programming guide - SIG30-C](https://www.securecoding.cert.org/confluence/display/seccode/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers). * * Most notably, the Objective-C runtime itself is not async-safe, and Objective-C may not be used within a signal handler. * * Documentation taken from PLCrashReporter: https://www.plcrashreporter.org/documentation/api/v1.2-rc2/async_safety.html * + * @see `BITCrashManagerPostCrashSignalCallback` + * @see `BITCrashManagerCallbacks` + * * @param callbacks A pointer to an initialized PLCrashReporterCallback structure, see https://www.plcrashreporter.org/documentation/api/v1.2-rc2/struct_p_l_crash_reporter_callbacks.html */ -- (void)setCrashCallbacks: (PLCrashReporterCallbacks *) callbacks; +- (void)setCrashCallbacks: (BITCrashManagerCallbacks *) callbacks; /** @@ -272,6 +328,26 @@ typedef NS_ENUM(NSUInteger, BITCrashManagerStatus) { */ @property (nonatomic, readonly) BOOL didCrashInLastSession; +/** + Provides an interface to handle user input from a custom alert + + @param userInput On this input depends, whether crash reports are sent, always sent or not sent and deleted. + @param userProvidedCrashDescription The content of this optional string will be attached to the crash report as the description and allows to ask the user for e.g. additional comments or info + + @return Returns YES if the input is a valid option and successfully triggered further processing of the crash report + @see BITCrashManagerUserInput + */ +- (BOOL)handleUserInput:(BITCrashManagerUserInput)userInput withUserProvidedCrashDescription:(NSString*)userProvidedCrashDescription; + +/** + Lets you set a custom block which handles showing a custom UI and asking the user + whether he wants to send the crash report. + + @param alertViewHandler A block that is responsible for loading, presenting and and dismissing your custom user interface which prompts the user if he wants to send crash reports. The block is also responsible for triggering further processing of the crash reports. + + @warning Block needs to call the `handleUserInput:withUserProvidedCrashDescription` method! + */ +- (void) setAlertViewHandler:(CustomAlertViewHandler)alertViewHandler; /** Indicates if the app was killed while being in foreground from the iOS diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index 6ce744277e..5e14349ae5 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -32,12 +32,16 @@ #if HOCKEYSDK_FEATURE_CRASH_REPORTER +#import + #import #import #import "HockeySDKPrivate.h" #import "BITHockeyHelper.h" +#import "BITHockeyAppClient.h" +#import "BITCrashAttachment.h" #import "BITHockeyBaseManagerPrivate.h" #import "BITCrashManagerPrivate.h" #import "BITCrashReportTextFormatter.h" @@ -52,6 +56,11 @@ #define kBITCrashMetaUserEmail @"BITCrashMetaUserEmail" #define kBITCrashMetaUserID @"BITCrashMetaUserID" #define kBITCrashMetaApplicationLog @"BITCrashMetaApplicationLog" +#define kBITCrashMetaAttachment @"BITCrashMetaAttachment" + +// internal keys +NSString *const KBITAttachmentDictIndex = @"index"; +NSString *const KBITAttachmentDictAttachment = @"attachment"; NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; @@ -69,9 +78,28 @@ NSString *const kBITFakeCrashDeviceModel = @"BITFakeCrashDeviceModel"; NSString *const kBITFakeCrashAppBinaryUUID = @"BITFakeCrashAppBinaryUUID"; NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; + +static BITCrashManagerCallbacks bitCrashCallbacks = { + .context = NULL, + .handleSignal = NULL +}; + +// proxy implementation for PLCrashReporter to keep our interface stable while this can change +static void plcr_post_crash_callback (siginfo_t *info, ucontext_t *uap, void *context) { + if (bitCrashCallbacks.handleSignal != NULL) + bitCrashCallbacks.handleSignal(context); +} + +static PLCrashReporterCallbacks plCrashCallbacks = { + .version = 0, + .context = NULL, + .handleSignal = plcr_post_crash_callback +}; + + @interface BITCrashManager () -@property (nonatomic, strong) NSFileManager *fileManager; +@property (nonatomic, copy, setter = setAlertViewHandler:) CustomAlertViewHandler alertViewHandler; @end @@ -80,10 +108,11 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; NSMutableArray *_crashFiles; NSString *_crashesDir; + NSString *_lastCrashFilename; NSString *_settingsFile; NSString *_analyzerInProgressFile; NSFileManager *_fileManager; - + PLCrashReporterCallbacks *_crashCallBacks; BOOL _crashIdenticalCurrentVersion; @@ -127,6 +156,7 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; _didLogLowMemoryWarning = NO; _approvedCrashReports = [[NSMutableDictionary alloc] init]; + _alertViewHandler = nil; _fileManager = [[NSFileManager alloc] init]; _crashFiles = [[NSMutableArray alloc] init]; @@ -187,9 +217,9 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; NSString *errorString = nil; NSMutableDictionary *rootObj = [NSMutableDictionary dictionaryWithCapacity:2]; - if (_approvedCrashReports && [_approvedCrashReports count] > 0) + if (_approvedCrashReports && [_approvedCrashReports count] > 0) { [rootObj setObject:_approvedCrashReports forKey:kBITCrashApprovedReports]; - + } NSData *plist = [NSPropertyListSerialization dataFromPropertyList:(id)rootObj format:NSPropertyListBinaryFormat_v1_0 errorDescription:&errorString]; @@ -234,13 +264,11 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; NSError *error = NULL; for (NSUInteger i=0; i < [_crashFiles count]; i++) { - [_fileManager removeItemAtPath:[_crashFiles objectAtIndex:i] error:&error]; - [_fileManager removeItemAtPath:[[_crashFiles objectAtIndex:i] stringByAppendingString:@".meta"] error:&error]; - + NSString *filename = [_crashFiles objectAtIndex:i]; NSString *cacheFilename = [[_crashFiles objectAtIndex:i] lastPathComponent]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserName]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserEmail]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]]; + + [self cleanFilesAndKeychainWithFileName:filename CacheFilename:cacheFilename Error:error]; + } [_crashFiles removeAllObjects]; [_approvedCrashReports removeAllObjects]; @@ -248,9 +276,74 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; [self saveSettings]; } +- (void)cleanFilesAndKeychainWithFileName:(NSString *)filename CacheFilename:(NSString *)cacheFilename Error:(NSError *)error{ + [_fileManager removeItemAtPath:filename error:&error]; + [_fileManager removeItemAtPath:[NSString stringWithFormat:@"%@.data", filename] error:&error]; + [_fileManager removeItemAtPath:[NSString stringWithFormat:@"%@.meta", filename] error:&error]; + [_fileManager removeItemAtPath:[NSString stringWithFormat:@"%@.desc", filename] error:&error]; + + [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserName]]; + [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserEmail]]; + [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]]; +} + +- (void)persistAttachment:(BITCrashAttachment *)attachment withFilename:(NSString *)filename { + NSString *attachmentFilename = [filename stringByAppendingString:@".data"]; + NSMutableData *data = [[NSMutableData alloc] init]; + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; + + [archiver encodeObject:attachment forKey:kBITCrashMetaAttachment]; + + [archiver finishEncoding]; + + [data writeToFile:attachmentFilename atomically:YES]; +} + +- (void)persistUserProvidedCrashDescription:(NSString *)userProvidedCrashDescription { + if (userProvidedCrashDescription && [userProvidedCrashDescription length] > 0) { + NSError *error; + [userProvidedCrashDescription writeToFile:[NSString stringWithFormat:@"%@.desc", [_crashesDir stringByAppendingPathComponent: _lastCrashFilename]] atomically:YES encoding:NSUTF8StringEncoding error:&error]; + } +} + +/** + * Read the attachment data from the stored file + * + * @param filename The crash report id + * + * @return an BITCrashAttachment instance or nil + */ +- (BITCrashAttachment *)attachmentForCrashReport:(NSString *)filename { + NSString *attachmentFilename = [filename stringByAppendingString:@".data"]; + + if (![_fileManager fileExistsAtPath:attachmentFilename]) + return nil; + + + NSData *codedData = [[NSData alloc] initWithContentsOfFile:attachmentFilename]; + if (!codedData) + return nil; + + NSKeyedUnarchiver *unarchiver = nil; + + @try { + unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:codedData]; + } + @catch (NSException *exception) { + return nil; + } + + if ([unarchiver containsValueForKey:kBITCrashMetaAttachment]) { + BITCrashAttachment *attachment = [unarchiver decodeObjectForKey:kBITCrashMetaAttachment]; + return attachment; + } + + return nil; +} + /** * 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. * @@ -474,7 +567,8 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; // if we have an identification from BITAuthenticator, use this as a default. if (( self.installationIdentificationType == BITAuthenticatorIdentificationTypeHockeyAppEmail || - self.installationIdentificationType == BITAuthenticatorIdentificationTypeHockeyAppUser + self.installationIdentificationType == BITAuthenticatorIdentificationTypeHockeyAppUser || + self.installationIdentificationType == BITAuthenticatorIdentificationTypeWebAuth ) && self.installationIdentification) { useremail = self.installationIdentification; @@ -494,12 +588,34 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; return useremail; } +- (NSString *)getCrashesDir { + return _crashesDir; +} #pragma mark - Public -- (void)setCrashCallbacks: (PLCrashReporterCallbacks *) callbacks { - _crashCallBacks = callbacks; +/** + * Set the callback for PLCrashReporter + * + * @param callbacks BITCrashManagerCallbacks instance + */ +- (void)setCrashCallbacks: (BITCrashManagerCallbacks *) callbacks { + if (!callbacks) return; + + // set our proxy callback struct + bitCrashCallbacks.context = callbacks->context; + bitCrashCallbacks.handleSignal = callbacks->handleSignal; + + // set the PLCrashReporterCallbacks struct + plCrashCallbacks.context = callbacks->context; + + _crashCallBacks = &plCrashCallbacks; +} + + +- (void)setAlertViewHandler:(CustomAlertViewHandler)alertViewHandler{ + _alertViewHandler = alertViewHandler; } /** @@ -567,6 +683,14 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; } [metaDict setObject:applicationLog forKey:kBITCrashMetaApplicationLog]; + if (self.delegate != nil && [self.delegate respondsToSelector:@selector(attachmentForCrashManager:)]) { + BITCrashAttachment *attachment = [self.delegate attachmentForCrashManager:self]; + + if (attachment) { + [self persistAttachment:attachment withFilename:[_crashesDir stringByAppendingPathComponent: filename]]; + } + } + NSData *plist = [NSPropertyListSerialization dataFromPropertyList:(id)metaDict format:NSPropertyListBinaryFormat_v1_0 errorDescription:&errorString]; @@ -577,6 +701,41 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; } } +- (BOOL)handleUserInput:(BITCrashManagerUserInput)userInput withUserProvidedCrashDescription:(NSString *)userProvidedCrashDescription{ + switch (userInput) { + case BITCrashManagerUserInputDontSend: + if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashManagerWillCancelSendingCrashReport:)]) { + [self.delegate crashManagerWillCancelSendingCrashReport:self]; + } + + [self cleanCrashReports]; + return YES; + + case BITCrashManagerUserInputSend: + [self persistUserProvidedCrashDescription:userProvidedCrashDescription]; + + [self sendCrashReports]; + return YES; + + case BITCrashManagerUserInputAlwaysSend: + _crashManagerStatus = BITCrashManagerStatusAutoSend; + [[NSUserDefaults standardUserDefaults] setInteger:_crashManagerStatus forKey:kBITCrashManagerStatus]; + [[NSUserDefaults standardUserDefaults] synchronize]; + if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashManagerWillSendCrashReportsAlways:)]) { + [self.delegate crashManagerWillSendCrashReportsAlways:self]; + } + + [self persistUserProvidedCrashDescription:userProvidedCrashDescription]; + + [self sendCrashReports]; + return YES; + + default: + return NO; + } + +} + #pragma mark - PLCrashReporter /** @@ -602,6 +761,7 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; NSData *crashData = [[NSData alloc] initWithData:[self.plCrashReporter loadPendingCrashReportDataAndReturnError: &error]]; NSString *cacheFilename = [NSString stringWithFormat: @"%.0f", [NSDate timeIntervalSinceReferenceDate]]; + _lastCrashFilename = cacheFilename; if (crashData == nil) { BITHockeyLog(@"ERROR: Could not load crash report: %@", error); @@ -676,7 +836,7 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; /** * 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 + * @return `YES` if there is at least one new crash report found, `NO` otherwise */ - (BOOL)hasPendingCrashReport { if (_crashManagerStatus == BITCrashManagerStatusDisabled) return NO; @@ -693,7 +853,9 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; ![file hasSuffix:@".DS_Store"] && ![file hasSuffix:@".analyzer"] && ![file hasSuffix:@".plist"] && - ![file hasSuffix:@".meta"]) { + ![file hasSuffix:@".data"] && + ![file hasSuffix:@".meta"] && + ![file hasSuffix:@".desc"]) { [_crashFiles addObject:[_crashesDir stringByAppendingPathComponent: file]]; } } @@ -771,17 +933,21 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; alertDescription = [NSString stringWithFormat:BITHockeyLocalizedString(@"CrashDataFoundDescription"), appName]; } - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:BITHockeyLocalizedString(@"CrashDataFoundTitle"), appName] - message:alertDescription - delegate:self - cancelButtonTitle:BITHockeyLocalizedString(@"CrashDontSendReport") - otherButtonTitles:BITHockeyLocalizedString(@"CrashSendReport"), nil]; - - if (self.shouldShowAlwaysButton) { - [alertView addButtonWithTitle:BITHockeyLocalizedString(@"CrashSendReportAlways")]; + if (_alertViewHandler) { + _alertViewHandler(); + } else { + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:BITHockeyLocalizedString(@"CrashDataFoundTitle"), appName] + message:alertDescription + delegate:self + cancelButtonTitle:BITHockeyLocalizedString(@"CrashDontSendReport") + otherButtonTitles:BITHockeyLocalizedString(@"CrashSendReport"), nil]; + + if (self.shouldShowAlwaysButton) { + [alertView addButtonWithTitle:BITHockeyLocalizedString(@"CrashSendReportAlways")]; + } + + [alertView show]; } - - [alertView show]; } else { [self sendCrashReports]; } @@ -1004,6 +1170,7 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; NSError *error = NULL; NSMutableString *crashes = nil; + NSMutableArray *attachments = [NSMutableArray array]; _crashIdenticalCurrentVersion = NO; for (NSUInteger i=0; i < [_crashFiles count]; i++) { @@ -1053,12 +1220,7 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; if (report == nil && crashLogString == nil) { BITHockeyLog(@"WARNING: Could not parse crash report"); // we cannot do anything with this report, so delete it - [_fileManager removeItemAtPath:filename error:&error]; - [_fileManager removeItemAtPath:[NSString stringWithFormat:@"%@.meta", metaFilename] error:&error]; - - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserName]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserEmail]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]]; + [self cleanFilesAndKeychainWithFileName:filename CacheFilename:cacheFilename Error:error]; continue; } @@ -1102,12 +1264,24 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; useremail = [self stringValueFromKeychainForKey:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserEmail]] ?: @""; userid = [self stringValueFromKeychainForKey:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]] ?: @""; applicationLog = [metaDict objectForKey:kBITCrashMetaApplicationLog] ?: @""; + description = [NSString stringWithContentsOfFile:[NSString stringWithFormat:@"%@.desc", [_crashesDir stringByAppendingPathComponent: cacheFilename]] encoding:NSUTF8StringEncoding error:&error]; + + BITCrashAttachment *attachment = [self attachmentForCrashReport:filename]; + if (attachment) { + NSDictionary *attachmentDict = @{KBITAttachmentDictIndex: @(i), + KBITAttachmentDictAttachment: attachment}; + [attachments addObject:attachmentDict]; + } } else { BITHockeyLog(@"ERROR: Reading crash meta data. %@", error); } if ([applicationLog length] > 0) { - description = [NSString stringWithFormat:@"%@", applicationLog]; + if ([description length] > 0) { + description = [NSString stringWithFormat:@"%@\n\nLog:\n%@", description, applicationLog]; + } else { + description = [NSString stringWithFormat:@"Log:\n%@", applicationLog]; + } } [crashes appendFormat:@"%s%@%@%@%@%@%@%@%@%@%@%@", @@ -1131,12 +1305,7 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; [_approvedCrashReports setObject:[NSNumber numberWithBool:YES] forKey:filename]; } else { // we cannot do anything with this report, so delete it - [_fileManager removeItemAtPath:filename error:&error]; - [_fileManager removeItemAtPath:[NSString stringWithFormat:@"%@.meta", filename] error:&error]; - - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserName]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserEmail]]; - [self removeKeyFromKeychain:[NSString stringWithFormat:@"%@.%@", cacheFilename, kBITCrashMetaUserID]]; + [self cleanFilesAndKeychainWithFileName:filename CacheFilename:cacheFilename Error:error]; } } @@ -1144,7 +1313,7 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; if (crashes != nil) { BITHockeyLog(@"INFO: Sending crash reports:\n%@", crashes); - [self postXML:[NSString stringWithFormat:@"%@", crashes]]; + [self postXML:[NSString stringWithFormat:@"%@", crashes] attachments:attachments]; } } @@ -1154,35 +1323,20 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { switch (buttonIndex) { case 0: - if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashManagerWillCancelSendingCrashReport:)]) { - [self.delegate crashManagerWillCancelSendingCrashReport:self]; - } - - _sendingInProgress = NO; - [self cleanCrashReports]; + [self handleUserInput:BITCrashManagerUserInputDontSend withUserProvidedCrashDescription:nil]; break; case 1: - [self sendCrashReports]; + [self handleUserInput:BITCrashManagerUserInputSend withUserProvidedCrashDescription:nil]; break; - case 2: { - _crashManagerStatus = BITCrashManagerStatusAutoSend; - [[NSUserDefaults standardUserDefaults] setInteger:_crashManagerStatus forKey:kBITCrashManagerStatus]; - [[NSUserDefaults standardUserDefaults] synchronize]; - if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashManagerWillSendCrashReportsAlways:)]) { - [self.delegate crashManagerWillSendCrashReportsAlways:self]; - } - - [self sendCrashReports]; - break; - } - default: - _sendingInProgress = NO; - [self cleanCrashReports]; + case 2: + [self handleUserInput:BITCrashManagerUserInputAlwaysSend withUserProvidedCrashDescription:nil]; break; } } + + #pragma mark - Networking /** @@ -1192,7 +1346,7 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; * * @param xml The XML data that needs to be send to the server */ -- (void)postXML:(NSString*)xml { +- (void)postXML:(NSString*)xml attachments:(NSArray *)attachments { NSMutableURLRequest *request = nil; NSString *boundary = @"----FOO"; @@ -1214,12 +1368,28 @@ NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString"; [request setValue:contentType forHTTPHeaderField:@"Content-type"]; NSMutableData *postBody = [NSMutableData data]; - [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; - [postBody appendData:[@"Content-Disposition: form-data; name=\"xml\"; filename=\"crash.xml\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; - [postBody appendData:[[NSString stringWithFormat:@"Content-Type: text/xml\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; - [postBody appendData:[xml dataUsingEncoding:NSUTF8StringEncoding]]; - [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + [postBody appendData:[BITHockeyAppClient dataWithPostValue:[xml dataUsingEncoding:NSUTF8StringEncoding] + forKey:@"xml" + contentType:@"text/xml" + boundary:boundary + filename:@"crash.xml"]]; + + for (NSDictionary *dict in attachments) { + NSInteger index = [(NSNumber *)dict[KBITAttachmentDictIndex] integerValue]; + NSString *key = [NSString stringWithFormat:@"attachment%ld", (long)index]; + + BITCrashAttachment *attachment = (BITCrashAttachment *)dict[KBITAttachmentDictAttachment]; + + [postBody appendData:[BITHockeyAppClient dataWithPostValue:attachment.attachmentData + forKey:key + contentType:attachment.contentType + boundary:boundary + filename:attachment.filename]]; + } + + [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + [request setHTTPBody:postBody]; _statusCode = 200; diff --git a/Classes/BITCrashManagerDelegate.h b/Classes/BITCrashManagerDelegate.h index 0c3174c5a1..09024a1743 100644 --- a/Classes/BITCrashManagerDelegate.h +++ b/Classes/BITCrashManagerDelegate.h @@ -29,6 +29,7 @@ #import @class BITCrashManager; +@class BITCrashAttachment; /** The `BITCrashManagerDelegate` formal protocol defines methods further configuring @@ -47,17 +48,43 @@ /** Return any log string based data the crash report being processed should contain @param crashManager The `BITCrashManager` instance invoking this delegate + @see attachmentForCrashManager: @see userNameForCrashManager: @see userEmailForCrashManager: */ -(NSString *)applicationLogForCrashManager:(BITCrashManager *)crashManager; +/** Return a BITCrashAttachment object providing an NSData object the crash report + being processed should contain + + Please limit your attachments to reasonable files to avoid high traffic costs for your users. + + Example implementation: + + - (BITCrashAttachment *)attachmentForCrashManager:(BITCrashManager *)crashManager { + NSData *data = [NSData dataWithContentsOfURL:@"mydatafile"]; + + BITCrashAttachment *attachment = [[BITCrashAttachment alloc] initWithFilename:@"myfile.data" + attachmentData:data + contentType:@"'application/octet-stream"]; + return attachment; + } + + @param crashManager The `BITCrashManager` instance invoking this delegate + @see applicationLogForCrashManager: + @see userNameForCrashManager: + @see userEmailForCrashManager: + */ +-(BITCrashAttachment *)attachmentForCrashManager:(BITCrashManager *)crashManager; + + /** Return the user name or userid that should be send along each crash report @param crashManager The `BITCrashManager` instance invoking this delegate @see applicationLogForCrashManager: + @see attachmentForCrashManager: @see userEmailForCrashManager: @deprecated Please use `BITHockeyManagerDelegate userNameForHockeyManager:componentManager:` instead @warning When returning a non nil value, crash reports are not anonymous any @@ -71,6 +98,7 @@ @param crashManager The `BITCrashManager` instance invoking this delegate @see applicationLogForCrashManager: + @see attachmentForCrashManager: @see userNameForCrashManager: @deprecated Please use `BITHockeyManagerDelegate userEmailForHockeyManager:componentManager:` instead @warning When returning a non nil value, crash reports are not anonymous any diff --git a/Classes/BITCrashManagerPrivate.h b/Classes/BITCrashManagerPrivate.h index f2231342f4..f63b998fb2 100644 --- a/Classes/BITCrashManagerPrivate.h +++ b/Classes/BITCrashManagerPrivate.h @@ -31,13 +31,19 @@ #if HOCKEYSDK_FEATURE_CRASH_REPORTER +#import + @interface BITCrashManager () { } @property (nonatomic) NSUncaughtExceptionHandler *exceptionHandler; +@property (nonatomic, strong) NSFileManager *fileManager; + @property (nonatomic, strong) BITPLCrashReporter *plCrashReporter; +@property (nonatomic) NSString *lastCrashFilename; + #if HOCKEYSDK_FEATURE_AUTHENTICATOR // Only set via BITAuthenticator @@ -61,9 +67,17 @@ - (BOOL)hasPendingCrashReport; - (BOOL)hasNonApprovedCrashReports; +- (void)persistUserProvidedCrashDescription:(NSString *)userProvidedCrashDescription; +- (void)persistAttachment:(BITCrashAttachment *)attachment withFilename:(NSString *)filename; + +- (BITCrashAttachment *)attachmentForCrashReport:(NSString *)filename; + - (void)invokeDelayedProcessing; - (void)sendCrashReports; +- (NSString *)getCrashesDir; +- (void)setLastCrashFilename:(NSString *)lastCrashFilename; + @end diff --git a/Classes/BITFeedbackManagerPrivate.h b/Classes/BITFeedbackManagerPrivate.h index dd5f03a13f..0da30ca52e 100644 --- a/Classes/BITFeedbackManagerPrivate.h +++ b/Classes/BITFeedbackManagerPrivate.h @@ -56,6 +56,11 @@ @property (nonatomic, copy) NSString *userEmail; +// Fetch user meta data +- (BOOL)updateUserIDUsingKeychainAndDelegate; +- (BOOL)updateUserNameUsingKeychainAndDelegate; +- (BOOL)updateUserEmailUsingKeychainAndDelegate; + // load new messages from the server - (void)updateMessagesList; diff --git a/Classes/BITHockeyAppClient.h b/Classes/BITHockeyAppClient.h index a8d5fdbd15..4de7fa24e7 100644 --- a/Classes/BITHockeyAppClient.h +++ b/Classes/BITHockeyAppClient.h @@ -118,8 +118,8 @@ #pragma mark - Helpers /** - * create a post body from the given value, key and boundary - * c/p from HockeyBaseManager + * create a post body from the given value, key and boundary. This is a convenience call to + * dataWithPostValue:forKey:contentType:boundary and aimed at NSString-content. * * @param value - * @param key - @@ -128,4 +128,18 @@ * @return NSData instance configured to be attached on a (post) URLRequest */ + (NSData *)dataWithPostValue:(NSString *)value forKey:(NSString *)key boundary:(NSString *) boundary; + +/** + * create a post body from the given value, key and boundary and content type. + * + * @param value - + * @param key - + *@param contentType - + * @param boundary - + * @param filename - + * + * @return NSData instance configured to be attached on a (post) URLRequest + */ ++ (NSData *)dataWithPostValue:(NSData *)value forKey:(NSString *)key contentType:(NSString *)contentType boundary:(NSString *) boundary filename:(NSString *)filename; + @end diff --git a/Classes/BITHockeyAppClient.m b/Classes/BITHockeyAppClient.m index 168162b47c..37a22b6407 100644 --- a/Classes/BITHockeyAppClient.m +++ b/Classes/BITHockeyAppClient.m @@ -85,12 +85,25 @@ } + (NSData *)dataWithPostValue:(NSString *)value forKey:(NSString *)key boundary:(NSString *) boundary { + return [self dataWithPostValue:[value dataUsingEncoding:NSUTF8StringEncoding] forKey:key contentType:@"text" boundary:boundary filename:nil]; +} + ++ (NSData *)dataWithPostValue:(NSData *)value forKey:(NSString *)key contentType:(NSString *)contentType boundary:(NSString *) boundary filename:(NSString *)filename { NSMutableData *postBody = [NSMutableData data]; [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; - [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\";\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; - [postBody appendData:[[NSString stringWithFormat:@"Content-Type: text\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; - [postBody appendData:[value dataUsingEncoding:NSUTF8StringEncoding]]; + + // There's certainly a better way to check if we are supposed to send binary data here. + if (filename){ + [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", key, filename] dataUsingEncoding:NSUTF8StringEncoding]]; + [postBody appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n", contentType] dataUsingEncoding:NSUTF8StringEncoding]]; + [postBody appendData:[[NSString stringWithFormat:@"Content-Transfer-Encoding: binary\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; + } else { + [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; + [postBody appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", contentType] dataUsingEncoding:NSUTF8StringEncoding]]; + } + + [postBody appendData:value]; [postBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; return postBody; diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index 434a596c85..a81f9cc373 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -38,9 +38,8 @@ #import "BITKeychainUtils.h" #import -#if !TARGET_IPHONE_SIMULATOR -#import -#endif +#import +#import #ifndef __IPHONE_6_1 #define __IPHONE_6_1 60100 @@ -134,29 +133,35 @@ } - (NSString *)executableUUID { - // This now requires the testing of this feature to be done on an actual device, since it returns always empty strings on the simulator - // Once there is a better solution to get unit test targets build without problems this should be changed again, so testing of this - // feature is also possible using the simulator - // See: http://support.hockeyapp.net/discussions/problems/2306-integrating-hockeyapp-with-test-bundle-target-i386-issues - // http://support.hockeyapp.net/discussions/problems/4113-linking-hockeysdk-to-test-bundle-target -#if !TARGET_IPHONE_SIMULATOR - const uint8_t *command = (const uint8_t *)(&_mh_execute_header + 1); - for (uint32_t idx = 0; idx < _mh_execute_header.ncmds; ++idx) { - const struct load_command *load_command = (const struct load_command *)command; - if (load_command->cmd == LC_UUID) { - const struct uuid_command *uuid_command = (const struct uuid_command *)command; - const uint8_t *uuid = uuid_command->uuid; + const struct mach_header *executableHeader = NULL; + for (uint32_t i = 0; i < _dyld_image_count(); i++) { + const struct mach_header *header = _dyld_get_image_header(i); + if (header->filetype == MH_EXECUTE) { + executableHeader = header; + break; + } + } + + if (!executableHeader) + return @""; + + BOOL is64bit = executableHeader->magic == MH_MAGIC_64 || executableHeader->magic == MH_CIGAM_64; + uintptr_t cursor = (uintptr_t)executableHeader + (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header)); + const struct segment_command *segmentCommand = NULL; + for (uint32_t i = 0; i < executableHeader->ncmds; i++, cursor += segmentCommand->cmdsize) { + segmentCommand = (struct segment_command *)cursor; + if (segmentCommand->cmd == LC_UUID) { + const struct uuid_command *uuidCommand = (const struct uuid_command *)segmentCommand; + const uint8_t *uuid = uuidCommand->uuid; return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]] lowercaseString]; - } else { - command += load_command->cmdsize; } } -#endif + return @""; } diff --git a/Classes/BITHockeyHelper.m b/Classes/BITHockeyHelper.m index 11b29ad849..4ea63f165d 100644 --- a/Classes/BITHockeyHelper.m +++ b/Classes/BITHockeyHelper.m @@ -458,10 +458,7 @@ UIImage *bit_newWithContentsOfResolutionIndependentFile(NSString * path) { UIImage *bit_imageWithContentsOfResolutionIndependentFile(NSString *path) { -#ifndef __clang_analyzer__ - // clang alayzer in 4.2b3 thinks here's a leak, which is not the case. return bit_newWithContentsOfResolutionIndependentFile(path); -#endif } diff --git a/Classes/BITHockeyManager.m b/Classes/BITHockeyManager.m index f72a907df1..baa1a7e81c 100644 --- a/Classes/BITHockeyManager.m +++ b/Classes/BITHockeyManager.m @@ -36,6 +36,20 @@ #import "BITHockeyAppClient.h" #import "BITKeychainUtils.h" +#include + +typedef struct { + uint8_t info_version; + const char hockey_version[16]; + const char hockey_build[16]; +} bitstadium_info_t; + +bitstadium_info_t bitstadium_library_info __attribute__((section("__TEXT,__bit_hockey,regular,no_dead_strip"))) = { + .info_version = 1, + .hockey_version = BITHOCKEY_C_VERSION, + .hockey_build = BITHOCKEY_C_BUILD +}; + #if HOCKEYSDK_FEATURE_CRASH_REPORTER #import "BITCrashManagerPrivate.h" @@ -417,11 +431,11 @@ - (NSString *)version { - return BITHOCKEY_VERSION; + return [NSString stringWithUTF8String:bitstadium_library_info.hockey_version]; } - (NSString *)build { - return BITHOCKEY_BUILD; + return [NSString stringWithUTF8String:bitstadium_library_info.hockey_build]; } diff --git a/Classes/BITStoreUpdateManager.m b/Classes/BITStoreUpdateManager.m index 0536f17830..78a0bcef1d 100644 --- a/Classes/BITStoreUpdateManager.m +++ b/Classes/BITStoreUpdateManager.m @@ -155,7 +155,7 @@ if ([self.userDefaults objectForKey:kBITStoreUpdateLastUUID]) { lastSavedUUID = [self.userDefaults objectForKey:kBITStoreUpdateLastUUID]; - if (lastSavedUUID && ![lastSavedUUID isEqualToString:_currentUUID]) { + if (lastSavedUUID && [lastSavedUUID length] > 0 && ![lastSavedUUID isEqualToString:_currentUUID]) { // the UUIDs don't match, store the new one [self.userDefaults setObject:_currentUUID forKey:kBITStoreUpdateLastUUID]; diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 3df6c72383..597e35a4eb 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -669,7 +669,7 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) { self.checkInProgress = YES; // do we need to update? - if (![self checkForTracker] && ![self shouldCheckForUpdates] && !_currentHockeyViewController) { + if (![self checkForTracker] && !_currentHockeyViewController && ![self shouldCheckForUpdates] && _updateSetting != BITUpdateCheckManually) { BITHockeyLog(@"INFO: Update not needed right now"); self.checkInProgress = NO; return; diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index fe9d7b9837..db47dec951 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -37,6 +37,7 @@ #if HOCKEYSDK_FEATURE_CRASH_REPORTER #import "BITCrashManager.h" +#import "BITCrashAttachment.h" #import "BITCrashManagerDelegate.h" #import "BITCrashDetails.h" #endif /* HOCKEYSDK_FEATURE_CRASH_REPORTER */ diff --git a/HockeySDK.podspec b/HockeySDK.podspec index 2d13ab5234..75107724fa 100644 --- a/HockeySDK.podspec +++ b/HockeySDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'HockeySDK' - s.version = '3.5.4' + s.version = '3.5.5' s.summary = 'Collect live crash reports, get feedback from your users, distribute your betas, and analyze your test coverage with HockeyApp.' s.description = <<-DESC @@ -12,19 +12,19 @@ Pod::Spec.new do |s| DESC s.homepage = 'http://hockeyapp.net/' - s.documentation_url = 'http://hockeyapp.net/help/sdk/ios/3.5.4/' + s.documentation_url = 'http://hockeyapp.net/help/sdk/ios/3.5.5/' s.license = 'MIT' s.author = { 'Andreas Linde' => 'mail@andreaslinde.de', 'Thomas Dohmke' => "thomas@dohmke.de" } s.source = { :git => 'https://github.com/bitstadium/HockeySDK-iOS.git', :tag => s.version.to_s } s.platform = :ios, '5.0' - s.source_files = 'Classes' + s.source_files = 'Classes', "Vendor/CrashReporter.framework/Versions/A/Headers/*.h" s.requires_arc = true s.frameworks = 'CoreText', 'QuartzCore', 'SystemConfiguration', 'CoreGraphics', 'UIKit', 'Security' s.ios.vendored_frameworks = 'Vendor/CrashReporter.framework' - s.xcconfig = {'GCC_PREPROCESSOR_DEFINITIONS' => %{$(inherited) BITHOCKEY_VERSION="@\\"#{s.version}\\"" BITHOCKEY_BUILD="@\\"27\\""} } + s.xcconfig = {'GCC_PREPROCESSOR_DEFINITIONS' => %{$(inherited) BITHOCKEY_VERSION="@\\"#{s.version}\\"" BITHOCKEY_C_VERSION="\\"#{s.version}\\"" BITHOCKEY_BUILD="@\\"28\\"" BITHOCKEY_C_BUILD="\\"28\\""} } s.resource_bundle = { 'HockeySDKResources' => ['Resources/*.png', 'Resources/*.lproj'] } s.preserve_paths = 'Resources', 'Support' diff --git a/LICENSE b/LICENSE old mode 100755 new mode 100644 diff --git a/README.md b/README.md index 1fc4f8f554..31833fb692 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -## Version 3.5.4 +## Version 3.5.5 -- [Changelog](http://www.hockeyapp.net/help/sdk/ios/3.5.4/docs/docs/Changelog.html) +- [Changelog](http://www.hockeyapp.net/help/sdk/ios/3.5.5/docs/docs/Changelog.html) ## Introduction @@ -31,10 +31,10 @@ The main SDK class is `BITHockeyManager`. It initializes all modules and provide ## Installation & Setup -- [Installation & Setup](http://www.hockeyapp.net/help/sdk/ios/3.5.4/docs/docs/Guide-Installation-Setup.html) (Recommended) -- [Installation & Setup Advanced](http://www.hockeyapp.net/help/sdk/ios/3.5.4/docs/docs/Guide-Installation-Setup-Advanced.html) (Using Git submodule and Xcode sub-project) -- [Identify and authenticate users of Ad-Hoc or Enterprise builds](http://www.hockeyapp.net/help/sdk/ios/3.5.4/docs/docs/HowTo-Authenticating-Users-on-iOS.html) -- [Migration from previous SDK Versions](http://www.hockeyapp.net/help/sdk/ios/3.5.4/docs/docs/Guide-Migration-Kits.html) +- [Installation & Setup](http://www.hockeyapp.net/help/sdk/ios/3.5.5/docs/docs/Guide-Installation-Setup.html) (Recommended) +- [Installation & Setup Advanced](http://www.hockeyapp.net/help/sdk/ios/3.5.5/docs/docs/Guide-Installation-Setup-Advanced.html) (Using Git submodule and Xcode sub-project) +- [Identify and authenticate users of Ad-Hoc or Enterprise builds](http://www.hockeyapp.net/help/sdk/ios/3.5.5/docs/docs/HowTo-Authenticating-Users-on-iOS.html) +- [Migration from previous SDK Versions](http://www.hockeyapp.net/help/sdk/ios/3.5.5/docs/docs/Guide-Migration-Kits.html) - [Mac Desktop Uploader](http://support.hockeyapp.net/kb/how-tos/how-to-upload-to-hockeyapp-on-a-mac) @@ -48,4 +48,4 @@ This documentation provides integrated help in Xcode for all public APIs and a s 3. Copy the content into ~`/Library/Developer/Shared/Documentation/DocSets` -The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.5.4/](http://hockeyapp.net/help/sdk/ios/3.5.4/) +The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.5.5/](http://hockeyapp.net/help/sdk/ios/3.5.5/) diff --git a/Resources/nl.lproj/HockeySDK.strings b/Resources/nl.lproj/HockeySDK.strings old mode 100755 new mode 100644 diff --git a/Resources/ro.lproj/HockeySDK.strings b/Resources/ro.lproj/HockeySDK.strings old mode 100755 new mode 100644 diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 8627e93a9f..13d4da6796 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -95,10 +95,10 @@ 1E5955D015B71C8600A03429 /* IconGradient@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C515B71C8600A03429 /* IconGradient@2x.png */; }; 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E5A459216F0DFC200B55C04 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E5A459116F0DFC200B55C04 /* SenTestingKit.framework */; }; - 1E5A459416F0DFC200B55C04 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E5A459316F0DFC200B55C04 /* UIKit.framework */; }; 1E5A459516F0DFC200B55C04 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E400561D148D79B500EB22B9 /* Foundation.framework */; }; 1E5A459B16F0DFC200B55C04 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1E5A459916F0DFC200B55C04 /* InfoPlist.strings */; }; 1E5A459E16F0DFC200B55C04 /* BITStoreUpdateManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E5A459D16F0DFC200B55C04 /* BITStoreUpdateManagerTests.m */; }; + 1E61CCAF18E0585A00A5E38E /* BITFeedbackManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E61CCAE18E0585A00A5E38E /* BITFeedbackManagerTests.m */; }; 1E70A23217F2F982001BB32D /* live_report_empty.plcrash in Resources */ = {isa = PBXBuildFile; fileRef = 1E70A22F17F2F982001BB32D /* live_report_empty.plcrash */; }; 1E70A23317F2F982001BB32D /* live_report_exception.plcrash in Resources */ = {isa = PBXBuildFile; fileRef = 1E70A23017F2F982001BB32D /* live_report_exception.plcrash */; }; 1E70A23417F2F982001BB32D /* live_report_signal.plcrash in Resources */ = {isa = PBXBuildFile; fileRef = 1E70A23117F2F982001BB32D /* live_report_signal.plcrash */; }; @@ -129,6 +129,8 @@ 1EAF20AA162DC0F600957B1D /* feedbackActiviy.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A6162DC0F600957B1D /* feedbackActiviy.png */; }; 1EAF20AB162DC0F600957B1D /* feedbackActiviy@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A7162DC0F600957B1D /* feedbackActiviy@2x.png */; }; 1EB52FD5167B766100C801D5 /* HockeySDK.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1E59555F15B6F80E00A03429 /* HockeySDK.strings */; }; + 1ED570C718BF878C00AB3350 /* BITCrashAttachment.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ED570C518BF878C00AB3350 /* BITCrashAttachment.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ED570C818BF878C00AB3350 /* BITCrashAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ED570C618BF878C00AB3350 /* BITCrashAttachment.m */; }; 1EF95CA6162CB037000AE3AD /* BITFeedbackActivity.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EF95CA4162CB036000AE3AD /* BITFeedbackActivity.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1EF95CA7162CB037000AE3AD /* BITFeedbackActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EF95CA5162CB036000AE3AD /* BITFeedbackActivity.m */; }; 1EF95CAA162CB314000AE3AD /* BITFeedbackComposeViewControllerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EF95CA9162CB313000AE3AD /* BITFeedbackComposeViewControllerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -248,11 +250,11 @@ 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManagerDelegate.h; sourceTree = ""; }; 1E5A459016F0DFC200B55C04 /* HockeySDKTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HockeySDKTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 1E5A459116F0DFC200B55C04 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; - 1E5A459316F0DFC200B55C04 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; 1E5A459816F0DFC200B55C04 /* HockeySDKTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HockeySDKTests-Info.plist"; sourceTree = ""; }; 1E5A459A16F0DFC200B55C04 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 1E5A459D16F0DFC200B55C04 /* BITStoreUpdateManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BITStoreUpdateManagerTests.m; sourceTree = ""; }; 1E5A459F16F0DFC200B55C04 /* HockeySDKTests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HockeySDKTests-Prefix.pch"; sourceTree = ""; }; + 1E61CCAE18E0585A00A5E38E /* BITFeedbackManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackManagerTests.m; sourceTree = ""; }; 1E66CA9115D4100500F35BED /* buildnumber.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = buildnumber.xcconfig; sourceTree = ""; }; 1E6DDCEE169E290C0076C65D /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/HockeySDK.strings; sourceTree = ""; }; 1E6F0450167B5E5600ED1C86 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/HockeySDK.strings"; sourceTree = ""; }; @@ -287,6 +289,8 @@ 1EAF20A6162DC0F600957B1D /* feedbackActiviy.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = feedbackActiviy.png; sourceTree = ""; }; 1EAF20A7162DC0F600957B1D /* feedbackActiviy@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "feedbackActiviy@2x.png"; sourceTree = ""; }; 1EB52FC3167B73D400C801D5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/HockeySDK.strings; sourceTree = ""; }; + 1ED570C518BF878C00AB3350 /* BITCrashAttachment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashAttachment.h; sourceTree = ""; }; + 1ED570C618BF878C00AB3350 /* BITCrashAttachment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashAttachment.m; sourceTree = ""; }; 1EDA60CF15C2C1450032D10B /* HockeySDK-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HockeySDK-Info.plist"; sourceTree = ""; }; 1EF95CA4162CB036000AE3AD /* BITFeedbackActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackActivity.h; sourceTree = ""; }; 1EF95CA5162CB036000AE3AD /* BITFeedbackActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackActivity.m; sourceTree = ""; }; @@ -336,7 +340,6 @@ files = ( 1EA1170016F4D32C001C015C /* libHockeySDK.a in Frameworks */, 1E5A459216F0DFC200B55C04 /* SenTestingKit.framework in Frameworks */, - 1E5A459416F0DFC200B55C04 /* UIKit.framework in Frameworks */, 1EA1170116F4D354001C015C /* CrashReporter.framework in Frameworks */, 1E5A459516F0DFC200B55C04 /* Foundation.framework in Frameworks */, 1E7A45FC16F54FB5005B08F1 /* OCHamcrestIOS.framework in Frameworks */, @@ -381,6 +384,7 @@ 1E5A459D16F0DFC200B55C04 /* BITStoreUpdateManagerTests.m */, E48A3DEE17B3EFF100924C3D /* BITAuthenticatorTests.m */, 1EFF03E417F2485500A5F13C /* BITCrashManagerTests.m */, + 1E61CCAE18E0585A00A5E38E /* BITFeedbackManagerTests.m */, E40E0B0817DA19DC005E38C1 /* BITHockeyAppClientTests.m */, E4507E4217F0658F00171A0D /* BITKeychainUtilsTests.m */, 1E70A23517F31B82001BB32D /* BITHockeyHelperTests.m */, @@ -486,6 +490,8 @@ 1E90FD7218EDB86400CF0417 /* BITCrashDetails.m */, 1EFF03D717F20F8300A5F13C /* BITCrashManagerPrivate.h */, 1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */, + 1ED570C518BF878C00AB3350 /* BITCrashAttachment.h */, + 1ED570C618BF878C00AB3350 /* BITCrashAttachment.m */, 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */, 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */, ); @@ -566,7 +572,6 @@ E41EB48B148D7C4E0015DEDC /* CrashReporter.framework */, E400561D148D79B500EB22B9 /* Foundation.framework */, 1E5A459116F0DFC200B55C04 /* SenTestingKit.framework */, - 1E5A459316F0DFC200B55C04 /* UIKit.framework */, ); name = Frameworks; sourceTree = ""; @@ -655,6 +660,7 @@ 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */, 1E49A4B8161222B900463151 /* BITHockeyBaseViewController.h in Headers */, 1E94F9E116E91330006570AD /* BITStoreUpdateManager.h in Headers */, + 1ED570C718BF878C00AB3350 /* BITCrashAttachment.h in Headers */, 1E0829001708F69A0073050E /* BITStoreUpdateManagerDelegate.h in Headers */, 1E49A4421612223B00463151 /* BITFeedbackListViewCell.h in Headers */, 1E49A4541612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */, @@ -744,7 +750,7 @@ E4005611148D79B500EB22B9 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0500; + LastUpgradeCheck = 0510; }; buildConfigurationList = E4005614148D79B500EB22B9 /* Build configuration list for PBXProject "HockeySDK" */; compatibilityVersion = "Xcode 3.2"; @@ -840,7 +846,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Sets the target folders and the final framework product.\nFMK_NAME=HockeySDK\nFMK_VERSION=A\nFMK_RESOURCE_BUNDLE=HockeySDKResources\n\n# Documentation\nHOCKEYSDK_DOCSET_VERSION_NAME=\"de.bitstadium.${HOCKEYSDK_DOCSET_NAME}-${VERSION_STRING}\"\n\n# Install dir will be the final output to the framework.\n# The following line create it in the root folder of the current project.\nPRODUCTS_DIR=${SRCROOT}/../Products\nPLCR_DIR=${SRCROOT}/../Vendor/CrashReporter.framework\nZIP_FOLDER=HockeySDK-iOS\nTEMP_DIR=${PRODUCTS_DIR}/${ZIP_FOLDER}\nINSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.framework\n\n# Working dir will be deleted after the framework creation.\nWRK_DIR=build\nDEVICE_DIR=${WRK_DIR}/Release-iphoneos\nSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator\nHEADERS_DIR=${WRK_DIR}/Release-iphoneos/usr/local/include\n\n# Building both architectures.\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphoneos\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphonesimulator\n\n# Cleaning the oldest.\nif [ -d \"${TEMP_DIR}\" ]\nthen\nrm -rf \"${TEMP_DIR}\"\nfi\n\n# Creates and renews the final product folder.\nmkdir -p \"${INSTALL_DIR}\"\nmkdir -p \"${INSTALL_DIR}/Versions\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers\"\n\n# Creates the internal links.\n# It MUST uses relative path, otherwise will not work when the folder is copied/moved.\nln -s \"${FMK_VERSION}\" \"${INSTALL_DIR}/Versions/Current\"\nln -s \"Versions/Current/Headers\" \"${INSTALL_DIR}/Headers\"\nln -s \"Versions/Current/Resources\" \"${INSTALL_DIR}/Resources\"\nln -s \"Versions/Current/${FMK_NAME}\" \"${INSTALL_DIR}/${FMK_NAME}\"\n\n# Copies the headers and resources files to the final product folder.\ncp -R \"${SRCROOT}/build/Release-iphoneos/include/HockeySDK/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${PLCR_DIR}/Versions/A/Headers/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${DEVICE_DIR}/${FMK_RESOURCE_BUNDLE}.bundle\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\ncp -f \"${SRCROOT}/${FMK_NAME}.xcconfig\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\n\n# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.\nlipo -create \"${DEVICE_DIR}/lib${FMK_NAME}.a\" \"${SIMULATOR_DIR}/lib${FMK_NAME}.a\" -output \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\nfi\n\nrm -r \"${WRK_DIR}\"\n\n# build embeddedframework folder and move framework into it\nmkdir \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework\"\nmv \"${INSTALL_DIR}\" \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework/${FMK_NAME}.framework\"\n\n# link Resources\nNEW_INSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.embeddedframework\nmkdir \"${NEW_INSTALL_DIR}/Resources\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_RESOURCE_BUNDLE}.bundle\" \"${NEW_INSTALL_DIR}/Resources/${FMK_RESOURCE_BUNDLE}.bundle\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_NAME}.xcconfig\" \"${NEW_INSTALL_DIR}/Resources/${FMK_NAME}.xcconfig\"\n\n# copy license, changelog, documentation, integration json\ncp -f \"${SRCROOT}/../Docs/Changelog-template.md\" \"${TEMP_DIR}/CHANGELOG\"\ncp -f \"${SRCROOT}/../Docs/Guide-Installation-Setup-template.md\" \"${TEMP_DIR}/README.md\"\ncp -f \"${SRCROOT}/../LICENSE\" \"${TEMP_DIR}\"\nmkdir \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\ncp -R \"${SRCROOT}/../documentation/docset/Contents\" \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\n\n# build zip\ncd \"${PRODUCTS_DIR}\"\nrm -f \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\nzip -yr \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"${ZIP_FOLDER}\" -x \\*/.*\n\n#copy to output dir on cisimple\nif [ $CISIMPLE ]; then\n if [ ! -d \"${CONFIGURATION_BUILD_DIR}\" ]; then\n mkdir \"${CONFIGURATION_BUILD_DIR}\"\n fi\n cd \"${PRODUCTS_DIR}\"\n cp \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"${CONFIGURATION_BUILD_DIR}/${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\nfi"; + shellScript = "# Sets the target folders and the final framework product.\nFMK_NAME=HockeySDK\nFMK_VERSION=A\nFMK_RESOURCE_BUNDLE=HockeySDKResources\n\n# Documentation\nHOCKEYSDK_DOCSET_VERSION_NAME=\"de.bitstadium.${HOCKEYSDK_DOCSET_NAME}-${VERSION_STRING}\"\n\n# Install dir will be the final output to the framework.\n# The following line create it in the root folder of the current project.\nPRODUCTS_DIR=${SRCROOT}/../Products\nZIP_FOLDER=HockeySDK-iOS\nTEMP_DIR=${PRODUCTS_DIR}/${ZIP_FOLDER}\nINSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.framework\n\n# Working dir will be deleted after the framework creation.\nWRK_DIR=build\nDEVICE_DIR=${WRK_DIR}/Release-iphoneos\nSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator\nHEADERS_DIR=${WRK_DIR}/Release-iphoneos/usr/local/include\n\n# Building both architectures.\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphoneos\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphonesimulator\n\n# Cleaning the oldest.\nif [ -d \"${TEMP_DIR}\" ]\nthen\nrm -rf \"${TEMP_DIR}\"\nfi\n\n# Creates and renews the final product folder.\nmkdir -p \"${INSTALL_DIR}\"\nmkdir -p \"${INSTALL_DIR}/Versions\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers\"\n\n# Creates the internal links.\n# It MUST uses relative path, otherwise will not work when the folder is copied/moved.\nln -s \"${FMK_VERSION}\" \"${INSTALL_DIR}/Versions/Current\"\nln -s \"Versions/Current/Headers\" \"${INSTALL_DIR}/Headers\"\nln -s \"Versions/Current/Resources\" \"${INSTALL_DIR}/Resources\"\nln -s \"Versions/Current/${FMK_NAME}\" \"${INSTALL_DIR}/${FMK_NAME}\"\n\n# Copies the headers and resources files to the final product folder.\ncp -R \"${SRCROOT}/build/Release-iphoneos/include/HockeySDK/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${DEVICE_DIR}/${FMK_RESOURCE_BUNDLE}.bundle\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\ncp -f \"${SRCROOT}/${FMK_NAME}.xcconfig\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\n\n# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.\nlipo -create \"${DEVICE_DIR}/lib${FMK_NAME}.a\" \"${SIMULATOR_DIR}/lib${FMK_NAME}.a\" -output \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\nfi\n\nrm -r \"${WRK_DIR}\"\n\n# build embeddedframework folder and move framework into it\nmkdir \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework\"\nmv \"${INSTALL_DIR}\" \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework/${FMK_NAME}.framework\"\n\n# link Resources\nNEW_INSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.embeddedframework\nmkdir \"${NEW_INSTALL_DIR}/Resources\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_RESOURCE_BUNDLE}.bundle\" \"${NEW_INSTALL_DIR}/Resources/${FMK_RESOURCE_BUNDLE}.bundle\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_NAME}.xcconfig\" \"${NEW_INSTALL_DIR}/Resources/${FMK_NAME}.xcconfig\"\n\n# copy license, changelog, documentation, integration json\ncp -f \"${SRCROOT}/../Docs/Changelog-template.md\" \"${TEMP_DIR}/CHANGELOG\"\ncp -f \"${SRCROOT}/../Docs/Guide-Installation-Setup-template.md\" \"${TEMP_DIR}/README.md\"\ncp -f \"${SRCROOT}/../LICENSE\" \"${TEMP_DIR}\"\nmkdir \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\ncp -R \"${SRCROOT}/../documentation/docset/Contents\" \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\n\n# build zip\ncd \"${PRODUCTS_DIR}\"\nrm -f \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\nzip -yr \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"${ZIP_FOLDER}\" -x \\*/.*\n"; }; 1E8E66B215BC3D8200632A2E /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -883,6 +889,7 @@ 1E49A4511612223B00463151 /* BITFeedbackManager.m in Sources */, E4933E8117B66CDA00B11ACC /* BITHTTPOperation.m in Sources */, 1E49A45A1612223B00463151 /* BITFeedbackMessage.m in Sources */, + 1ED570C818BF878C00AB3350 /* BITCrashAttachment.m in Sources */, 1E49A4601612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */, 1E49A4701612226D00463151 /* BITAppVersionMetaInfo.m in Sources */, 1E49A4761612226D00463151 /* BITUpdateManager.m in Sources */, @@ -923,6 +930,7 @@ 1E70A23617F31B82001BB32D /* BITHockeyHelperTests.m in Sources */, E48A3DEF17B3EFF100924C3D /* BITAuthenticatorTests.m in Sources */, 1EA1170716F53B91001C015C /* BITTestHelper.m in Sources */, + 1E61CCAF18E0585A00A5E38E /* BITFeedbackManagerTests.m in Sources */, E4507E4317F0658F00171A0D /* BITKeychainUtilsTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Documentation.xcscheme b/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Documentation.xcscheme index c339433201..6d2f03a55f 100644 --- a/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Documentation.xcscheme +++ b/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Documentation.xcscheme @@ -1,6 +1,6 @@ delegateMock = mockProtocol(@protocol(BITCrashManagerDelegate)); + _sut.delegate = delegateMock; + + assertThatBool([_sut handleUserInput:BITCrashManagerUserInputDontSend withUserProvidedCrashDescription:nil], equalToBool(YES)); + + [verify(delegateMock) crashManagerWillCancelSendingCrashReport:_sut]; + +} + +- (void)testHandleUserInputSend { + assertThatBool([_sut handleUserInput:BITCrashManagerUserInputSend withUserProvidedCrashDescription:nil], equalToBool(YES)); +} + +- (void)testHandleUserInputAlwaysSend { + id delegateMock = mockProtocol(@protocol(BITCrashManagerDelegate)); + _sut.delegate = delegateMock; + NSUserDefaults *mockUserDefaults = mock([NSUserDefaults class]); + + //Test if CrashManagerStatus is unset + [given([mockUserDefaults integerForKey:@"BITCrashManagerStatus"]) willReturn:nil]; + + //Test if method runs through + assertThatBool([_sut handleUserInput:BITCrashManagerUserInputAlwaysSend withUserProvidedCrashDescription:nil], equalToBool(YES)); + + //Test if correct CrashManagerStatus is now set + [given([mockUserDefaults integerForKey:@"BITCrashManagerStauts"]) willReturnInt:BITCrashManagerStatusAutoSend]; + + //Verify that delegate method has been called + [verify(delegateMock) crashManagerWillSendCrashReportsAlways:_sut]; + +} + +- (void)testHandleUserInputWithInvalidInput { + assertThatBool([_sut handleUserInput:3 withUserProvidedCrashDescription:nil], equalToBool(NO)); +} #pragma mark - Debugger @@ -201,6 +265,7 @@ [_sut handleCrashReport]; [verifyCount(delegateMock, times(1)) applicationLogForCrashManager:_sut]; + [verifyCount(delegateMock, times(1)) attachmentForCrashManager:_sut]; // we should have now 1 pending crash report assertThatBool([_sut hasPendingCrashReport], equalToBool(YES)); diff --git a/Support/HockeySDKTests/BITFeedbackManagerTests.m b/Support/HockeySDKTests/BITFeedbackManagerTests.m new file mode 100644 index 0000000000..838fdb56d7 --- /dev/null +++ b/Support/HockeySDKTests/BITFeedbackManagerTests.m @@ -0,0 +1,216 @@ +// +// BITFeedbackManagerTests.m +// HockeySDK +// +// Created by Andreas Linde on 24.03.14. +// +// + +#import + +#define HC_SHORTHAND +#import + +#define MOCKITO_SHORTHAND +#import + +#import "HockeySDK.h" +#import "HockeySDKPrivate.h" +#import "BITFeedbackManager.h" +#import "BITFeedbackManagerPrivate.h" +#import "BITHockeyBaseManager.h" +#import "BITHockeyBaseManagerPrivate.h" + +#import "BITTestHelper.h" + +@interface BITFeedbackManagerTests : SenTestCase + +@end + +@implementation BITFeedbackManagerTests { + BITFeedbackManager *_sut; +} + +- (void)setUp { + [super setUp]; + + BITHockeyManager *hm = [BITHockeyManager sharedHockeyManager]; + hm.delegate = nil; + _sut = [[BITFeedbackManager alloc] initWithAppIdentifier:nil isAppStoreEnvironment:NO]; + _sut.delegate = nil; +} + +- (void)tearDown { +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wimplicit" + __gcov_flush(); +# pragma clang diagnostic pop + + [_sut removeKeyFromKeychain:kBITHockeyMetaUserID]; + [_sut removeKeyFromKeychain:kBITHockeyMetaUserName]; + [_sut removeKeyFromKeychain:kBITHockeyMetaUserEmail]; + + _sut = nil; + + [super tearDown]; +} + +#pragma mark - Private + +- (void)startManager { + [_sut startManager]; +} + +#pragma mark - Setup Tests + + +#pragma mark - User Metadata + +- (void)testUpdateUserIDWithNoDataPresent { + BITHockeyManager *hm = [BITHockeyManager sharedHockeyManager]; + id delegateMock = mockProtocol(@protocol(BITHockeyManagerDelegate)); + hm.delegate = delegateMock; + _sut.delegate = delegateMock; + + BOOL dataAvailable = [_sut updateUserIDUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(NO)); + assertThat(_sut.userID, nilValue()); + + [verifyCount(delegateMock, times(1)) userIDForHockeyManager:hm componentManager:_sut]; +} + +- (void)testUpdateUserIDWithDelegateReturningData { + BITHockeyManager *hm = [BITHockeyManager sharedHockeyManager]; + NSObject *classMock = mockObjectAndProtocol([NSObject class], @protocol(BITHockeyManagerDelegate)); + [given([classMock userIDForHockeyManager:hm componentManager:_sut]) willReturn:@"test"]; + hm.delegate = classMock; + _sut.delegate = classMock; + + BOOL dataAvailable = [_sut updateUserIDUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(YES)); + assertThat(_sut.userID, equalTo(@"test")); + + [verifyCount(classMock, times(1)) userIDForHockeyManager:hm componentManager:_sut]; +} + +- (void)testUpdateUserIDWithValueInKeychain { + [_sut addStringValueToKeychain:@"test" forKey:kBITHockeyMetaUserID]; + + BOOL dataAvailable = [_sut updateUserIDUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(YES)); + assertThat(_sut.userID, equalTo(@"test")); +} + +- (void)testUpdateUserIDWithGlobalSetter { + BITHockeyManager *hm = [BITHockeyManager sharedHockeyManager]; + [hm setUserID:@"test"]; + + BOOL dataAvailable = [_sut updateUserIDUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(YES)); + assertThat(_sut.userID, equalTo(@"test")); +} + + +- (void)testUpdateUserNameWithNoDataPresent { + BITHockeyManager *hm = [BITHockeyManager sharedHockeyManager]; + id delegateMock = mockProtocol(@protocol(BITHockeyManagerDelegate)); + hm.delegate = delegateMock; + _sut.delegate = delegateMock; + + BOOL dataAvailable = [_sut updateUserNameUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(NO)); + assertThat(_sut.userName, nilValue()); + + [verifyCount(delegateMock, times(1)) userNameForHockeyManager:hm componentManager:_sut]; +} + +- (void)testUpdateUserNameWithDelegateReturningData { + BITHockeyManager *hm = [BITHockeyManager sharedHockeyManager]; + NSObject *classMock = mockObjectAndProtocol([NSObject class], @protocol(BITHockeyManagerDelegate)); + [given([classMock userNameForHockeyManager:hm componentManager:_sut]) willReturn:@"test"]; + hm.delegate = classMock; + _sut.delegate = classMock; + + BOOL dataAvailable = [_sut updateUserNameUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(YES)); + assertThat(_sut.userName, equalTo(@"test")); + + [verifyCount(classMock, times(1)) userNameForHockeyManager:hm componentManager:_sut]; +} + +- (void)testUpdateUserNameWithValueInKeychain { + [_sut addStringValueToKeychain:@"test" forKey:kBITHockeyMetaUserName]; + + BOOL dataAvailable = [_sut updateUserNameUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(YES)); + assertThat(_sut.userName, equalTo(@"test")); +} + +- (void)testUpdateUserNameWithGlobalSetter { + BITHockeyManager *hm = [BITHockeyManager sharedHockeyManager]; + [hm setUserName:@"test"]; + + BOOL dataAvailable = [_sut updateUserNameUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(YES)); + assertThat(_sut.userName, equalTo(@"test")); +} + + +- (void)testUpdateUserEmailWithNoDataPresent { + BITHockeyManager *hm = [BITHockeyManager sharedHockeyManager]; + id delegateMock = mockProtocol(@protocol(BITHockeyManagerDelegate)); + hm.delegate = delegateMock; + _sut.delegate = delegateMock; + + BOOL dataAvailable = [_sut updateUserEmailUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(NO)); + assertThat(_sut.userEmail, nilValue()); + + [verifyCount(delegateMock, times(1)) userEmailForHockeyManager:hm componentManager:_sut]; +} + +- (void)testUpdateUserEmailWithDelegateReturningData { + BITHockeyManager *hm = [BITHockeyManager sharedHockeyManager]; + NSObject *classMock = mockObjectAndProtocol([NSObject class], @protocol(BITHockeyManagerDelegate)); + [given([classMock userEmailForHockeyManager:hm componentManager:_sut]) willReturn:@"test"]; + hm.delegate = classMock; + _sut.delegate = classMock; + + BOOL dataAvailable = [_sut updateUserEmailUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(YES)); + assertThat(_sut.userEmail, equalTo(@"test")); + + [verifyCount(classMock, times(1)) userEmailForHockeyManager:hm componentManager:_sut]; +} + +- (void)testUpdateUserEmailWithValueInKeychain { + [_sut addStringValueToKeychain:@"test" forKey:kBITHockeyMetaUserEmail]; + + BOOL dataAvailable = [_sut updateUserEmailUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(YES)); + assertThat(_sut.userEmail, equalTo(@"test")); +} + +- (void)testUpdateUserEmailWithGlobalSetter { + BITHockeyManager *hm = [BITHockeyManager sharedHockeyManager]; + [hm setUserEmail:@"test"]; + + BOOL dataAvailable = [_sut updateUserEmailUsingKeychainAndDelegate]; + + assertThatBool(dataAvailable, equalToBool(YES)); + assertThat(_sut.userEmail, equalTo(@"test")); +} + + +@end diff --git a/Support/HockeySDKTests/BITHockeyHelperTests.m b/Support/HockeySDKTests/BITHockeyHelperTests.m index 9166d961cb..315a7c4238 100644 --- a/Support/HockeySDKTests/BITHockeyHelperTests.m +++ b/Support/HockeySDKTests/BITHockeyHelperTests.m @@ -32,7 +32,12 @@ } - (void)tearDown { - // Put teardown code here; it will be run once, after the last test case. + // Tear-down code here. +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wimplicit" + __gcov_flush(); +# pragma clang diagnostic pop + [super tearDown]; } diff --git a/Support/HockeySDKTests/BITStoreUpdateManagerTests.m b/Support/HockeySDKTests/BITStoreUpdateManagerTests.m index ffff07bfed..897ec761f1 100644 --- a/Support/HockeySDKTests/BITStoreUpdateManagerTests.m +++ b/Support/HockeySDKTests/BITStoreUpdateManagerTests.m @@ -300,7 +300,7 @@ STAssertFalse(result, @"The newer version is being ignored"); } -- (void)testReportedVersionIsNewerThanTHeIgnoredVersion { +- (void)testReportedVersionIsNewerThanTheIgnoredVersion { NSUserDefaults *mockUserDefaults = mock([NSUserDefaults class]); [given([mockUserDefaults objectForKey:@"BITStoreUpdateLastStoreVersion"]) willReturn:@"4.1.1"]; [given([mockUserDefaults objectForKey:@"BITStoreUpdateLastUUID"]) willReturn:@""]; diff --git a/Support/HockeySDKTests/OCHamcrestIOS.framework/Versions/A/Headers/HCInvocationMatcher.h b/Support/HockeySDKTests/OCHamcrestIOS.framework/Versions/A/Headers/HCInvocationMatcher.h old mode 100755 new mode 100644 diff --git a/Support/buildnumber.xcconfig b/Support/buildnumber.xcconfig index 39e6f651aa..b4f00c3b90 100644 --- a/Support/buildnumber.xcconfig +++ b/Support/buildnumber.xcconfig @@ -1,8 +1,8 @@ #include "HockeySDK.xcconfig" -BUILD_NUMBER = 27 -VERSION_STRING = 3.5.4 -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\""$(VERSION_STRING)"\"" BITHOCKEY_BUILD="@\""$(BUILD_NUMBER)"\"" +BUILD_NUMBER = 28 +VERSION_STRING = 3.5.5 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\""$(VERSION_STRING)"\"" BITHOCKEY_BUILD="@\""$(BUILD_NUMBER)"\"" BITHOCKEY_C_VERSION="\""$(VERSION_STRING)"\"" BITHOCKEY_C_BUILD="\""$(BUILD_NUMBER)"\"" BIT_ARM_ARCHS = armv7 armv7s arm64 BIT_SIM_ARCHS = x86_64 i386 ARCHS = $(BIT_ARM_ARCHS) diff --git a/Vendor/CrashReporter.framework/Versions/A/CrashReporter b/Vendor/CrashReporter.framework/Versions/A/CrashReporter index ef9fc8e724..3ee803a4c6 100644 Binary files a/Vendor/CrashReporter.framework/Versions/A/CrashReporter and b/Vendor/CrashReporter.framework/Versions/A/CrashReporter differ diff --git a/Vendor/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessInfo.h b/Vendor/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessInfo.h index f1bd05116d..ca683d50da 100644 --- a/Vendor/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessInfo.h +++ b/Vendor/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessInfo.h @@ -32,7 +32,7 @@ @interface PLCrashReportProcessInfo : NSObject { @private - /** Process name */ + /** Process name, or nil if unavailable. */ NSString *_processName; /** Process ID */ @@ -45,7 +45,7 @@ * will be nil. */ NSDate *_processStartTime; - /** Parent process name */ + /** Parent process name, or nil if unavailable. */ NSString *_parentProcessName; /** Parent process ID */ diff --git a/Vendor/CrashReporter.framework/Versions/A/Resources/Info.plist b/Vendor/CrashReporter.framework/Versions/A/Resources/Info.plist index c147c0f734..edca17c4d6 100644 --- a/Vendor/CrashReporter.framework/Versions/A/Resources/Info.plist +++ b/Vendor/CrashReporter.framework/Versions/A/Resources/Info.plist @@ -3,7 +3,7 @@ BuildMachineOSBuild - 13B42 + 13C64 CFBundleDevelopmentRegion English CFBundleExecutable @@ -23,16 +23,16 @@ DTCompiler com.apple.compilers.llvm.clang.1_0 DTPlatformBuild - 5A3005 + 5B1008 DTPlatformVersion GM DTSDKBuild - 13A595 + 13C64 DTSDKName macosx10.9 DTXcode - 0502 + 0511 DTXcodeBuild - 5A3005 + 5B1008 diff --git a/Vendor/XcodeCoverage/.gitignore b/Vendor/XcodeCoverage/.gitignore old mode 100755 new mode 100644 diff --git a/Vendor/XcodeCoverage/LICENSE.txt b/Vendor/XcodeCoverage/LICENSE.txt old mode 100755 new mode 100644 diff --git a/Vendor/XcodeCoverage/README.md b/Vendor/XcodeCoverage/README.md old mode 100755 new mode 100644 diff --git a/Vendor/XcodeCoverage/cleancov b/Vendor/XcodeCoverage/cleancov index 1130af9d13..948886b2a7 100755 --- a/Vendor/XcodeCoverage/cleancov +++ b/Vendor/XcodeCoverage/cleancov @@ -5,6 +5,7 @@ # Source: https://github.com/jonreid/XcodeCoverage # -source envcov.sh +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source ${DIR}/envcov.sh -"${LCOV}" --zerocounters -d "${OBJ_DIR}" +"${LCOV}" --zerocounters -d "${OBJ_DIR}" \ No newline at end of file diff --git a/Vendor/XcodeCoverage/envcov.sh b/Vendor/XcodeCoverage/envcov.sh index b48d4b7e01..3a7b48efa3 100755 --- a/Vendor/XcodeCoverage/envcov.sh +++ b/Vendor/XcodeCoverage/envcov.sh @@ -4,11 +4,12 @@ # Source: https://github.com/jonreid/XcodeCoverage # -source env.sh +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source ${DIR}/env.sh # Change the report name if you like: LCOV_INFO=Coverage.info LCOV_PATH=${SRCROOT}/../Vendor/XcodeCoverage/lcov-1.10/bin LCOV=${LCOV_PATH}/lcov -OBJ_DIR=${OBJECT_FILE_DIR_normal}/${CURRENT_ARCH} +OBJ_DIR=${OBJECT_FILE_DIR_normal}/${CURRENT_ARCH} \ No newline at end of file diff --git a/Vendor/XcodeCoverage/exportenv.sh b/Vendor/XcodeCoverage/exportenv.sh index 32455f9f48..bbde8108de 100755 --- a/Vendor/XcodeCoverage/exportenv.sh +++ b/Vendor/XcodeCoverage/exportenv.sh @@ -4,4 +4,5 @@ # Source: https://github.com/jonreid/XcodeCoverage # -export | egrep '( BUILT_PRODUCTS_DIR)|(CURRENT_ARCH)|(OBJECT_FILE_DIR_normal)|(SRCROOT)|(OBJROOT)' > ../Vendor/XcodeCoverage/env.sh +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +export | egrep '( BUILT_PRODUCTS_DIR)|(CURRENT_ARCH)|(OBJECT_FILE_DIR_normal)|(SRCROOT)|(OBJROOT)' > ${DIR}/env.sh \ No newline at end of file diff --git a/Vendor/XcodeCoverage/getcov b/Vendor/XcodeCoverage/getcov index 332aa8c053..e69e9e7ffd 100755 --- a/Vendor/XcodeCoverage/getcov +++ b/Vendor/XcodeCoverage/getcov @@ -5,7 +5,8 @@ # Source: https://github.com/jonreid/XcodeCoverage # -source envcov.sh +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source ${DIR}/envcov.sh remove_old_report() { @@ -45,4 +46,4 @@ remove_old_report enter_lcov_dir gather_coverage exclude_data -generate_report +generate_report \ No newline at end of file diff --git a/Vendor/XcodeCoverage/lcov-1.10/bin/geninfo b/Vendor/XcodeCoverage/lcov-1.10/bin/geninfo index 9325f9d68c..a553e21347 100755 --- a/Vendor/XcodeCoverage/lcov-1.10/bin/geninfo +++ b/Vendor/XcodeCoverage/lcov-1.10/bin/geninfo @@ -1017,7 +1017,7 @@ sub process_dafile($$) warn("WARNING: GCOV failed for $da_filename!\n"); return; } - die("ERROR: GCOV failed for $da_filename!\n"); + warn("WARNING: GCOV failed for $da_filename!\n"); } # Collect data from resulting .gcov files and create .info file @@ -1861,33 +1861,37 @@ sub read_gcov_file($) sub get_gcov_version() { - local *HANDLE; - my $version_string; - my $result; + local *HANDLE; + my $version_string; + my $result; - open(GCOV_PIPE, "-|", "$gcov_tool -v") - or die("ERROR: cannot retrieve gcov version!\n"); - $version_string = ; - close(GCOV_PIPE); + open(GCOV_PIPE, "-|", "$gcov_tool --version") + or die("ERROR: cannot retrieve gcov version!\n"); + $version_string = ; + close(GCOV_PIPE); - $result = 0; - if ($version_string =~ /(\d+)\.(\d+)(\.(\d+))?/) - { - if (defined($4)) - { - info("Found gcov version: $1.$2.$4\n"); - $result = $1 << 16 | $2 << 8 | $4; - } - else - { - info("Found gcov version: $1.$2\n"); - $result = $1 << 16 | $2 << 8; - } - } - return ($result, $version_string); + $result = 0; + if ($version_string =~ m/LLVM/) + { + info("Found llvm-cov\n"); + $result = 0x40201; + } + elsif ($version_string =~ /(\d+)\.(\d+)(\.(\d+))?/) + { + if (defined($4)) + { + info("Found gcov version: $1.$2.$4\n"); + $result = $1 << 16 | $2 << 8 | $4; + } + else + { + info("Found gcov version: $1.$2\n"); + $result = $1 << 16 | $2 << 8; + } + } + return ($result, $version_string); } - # # info(printf_parameter) # diff --git a/docs/Changelog-template.md b/docs/Changelog-template.md index 5b804fb123..5cc2d0a700 100644 --- a/docs/Changelog-template.md +++ b/docs/Changelog-template.md @@ -1,3 +1,14 @@ +## Version 3.5.5 + +- [NEW] `BITCrashManager`: Added support for adding a binary attachment to crash reports +- [NEW] `BITCrashManager`: Integrated PLCrashReporter 1.2 RC5 (with 2 more fixes) +- [BUGFIX] `BITUpdateManager`: Fixed problem with `checkForUpdate` when `updateSetting` is set to `BITUpdateCheckManually` +- [BUGFIX] `BITAuthenticator`: Fixed keychain warning alert showing app on launch if keychain is locked +- [BUGFIX] `BITAuthenticator`: Fixed a possible assertion problem with auto-authentication (when using custom SDK builds without assertions being disabled) +- [BUGFIX] `BITAuthenticator`: Added user email to crash report for beta builds if BITAuthenticator is set to BITAuthenticatorIdentificationTypeWebAuth +- [BUGFIX] Fixed more analyzer warnings +

+ ## Version 3.5.4 - [BUGFIX] Fix a possible crash before sending the crash report when the selector could not be found diff --git a/docs/Guide-Installation-Setup-Advanced-template.md b/docs/Guide-Installation-Setup-Advanced-template.md index 5b8e1ee2b4..19b54a67b3 100644 --- a/docs/Guide-Installation-Setup-Advanced-template.md +++ b/docs/Guide-Installation-Setup-Advanced-template.md @@ -1,6 +1,6 @@ -## Version 3.5.4 +## Version 3.5.5 -- [Changelog](http://www.hockeyapp.net/help/sdk/ios/3.5.4/docs/docs/Changelog.html) +- [Changelog](http://www.hockeyapp.net/help/sdk/ios/3.5.5/docs/docs/Changelog.html) ## Introduction @@ -116,7 +116,7 @@ This documentation provides integrated help in Xcode for all public APIs and a s 3. Copy the content into ~`/Library/Developer/Shared/Documentation/DocSets` -The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.5.4/](http://hockeyapp.net/help/sdk/ios/3.5.4/) +The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.5.5/](http://hockeyapp.net/help/sdk/ios/3.5.5/) ### Set up with xcconfig diff --git a/docs/Guide-Installation-Setup-template.md b/docs/Guide-Installation-Setup-template.md index 91a7a5e130..68d8356f0c 100644 --- a/docs/Guide-Installation-Setup-template.md +++ b/docs/Guide-Installation-Setup-template.md @@ -1,6 +1,6 @@ -## Version 3.5.4 +## Version 3.5.5 -- [Changelog](http://www.hockeyapp.net/help/sdk/ios/3.5.4/docs/docs/Changelog.html) +- [Changelog](http://www.hockeyapp.net/help/sdk/ios/3.5.5/docs/docs/Changelog.html) ## Introduction @@ -90,9 +90,9 @@ The Mac Desktop Uploader can provide easy uploading of your app versions to Hock This documentation provides integrated help in Xcode for all public APIs and a set of additional tutorials and how-tos. -1. Copy `de.bitstadium.HockeySDK-iOS-3.5.1.docset` into ~`/Library/Developer/Shared/Documentation/DocSets` +1. Copy `de.bitstadium.HockeySDK-iOS-3.5.5.docset` into ~`/Library/Developer/Shared/Documentation/DocSets` -The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.5.4/](http://hockeyapp.net/help/sdk/ios/3.5.4/) +The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.5.5/](http://hockeyapp.net/help/sdk/ios/3.5.5/) ### Set up with xcconfig