Refactoring

- Change Prefixes to BIT
- Make one shared instance and change the functionalities to modules
- One bundle for resources
- Targets for framework and static libs
- Other cleanup
This commit is contained in:
Andreas Linde 2012-07-19 17:17:19 +02:00
parent ddfc392a32
commit 671060929c
102 changed files with 5331 additions and 3585 deletions

View File

@ -0,0 +1,53 @@
/*
* Author: Peter Steinberger
*
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* Copyright (c) 2011 Andreas Linde, Peter Steinberger.
* 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>
@interface BITAppVersionMetaInfo : NSObject {
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *version;
@property (nonatomic, copy) NSString *shortVersion;
@property (nonatomic, copy) NSString *notes;
@property (nonatomic, copy) NSDate *date;
@property (nonatomic, copy) NSNumber *size;
@property (nonatomic, copy) NSNumber *mandatory;
- (NSString *)nameAndVersionString;
- (NSString *)versionString;
- (NSString *)dateString;
- (NSString *)sizeInMB;
- (NSString *)notesOrEmptyString;
- (void)setDateWithTimestamp:(NSTimeInterval)timestamp;
- (BOOL)isValid;
- (BOOL)isEqualToAppVersionMetaInfo:(BITAppVersionMetaInfo *)anAppVersionMetaInfo;
+ (BITAppVersionMetaInfo *)appVersionMetaInfoFromDict:(NSDictionary *)dict;
@end

View File

@ -0,0 +1,186 @@
/*
* Author: Peter Steinberger
*
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* Copyright (c) 2011 Andreas Linde, Peter Steinberger.
* 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 "BITAppVersionMetaInfo.h"
#import "HockeySDKPrivate.h"
@implementation BITAppVersionMetaInfo
@synthesize name = _name;
@synthesize version = _version;
@synthesize shortVersion = _shortVersion;
@synthesize notes = _notes;
@synthesize date = _date;
@synthesize size = _size;
@synthesize mandatory = _mandatory;
#pragma mark - Static
+ (BITAppVersionMetaInfo *)appVersionMetaInfoFromDict:(NSDictionary *)dict {
BITAppVersionMetaInfo *appVersionMetaInfo = [[[[self class] alloc] init] autorelease];
if ([dict isKindOfClass:[NSDictionary class]]) {
appVersionMetaInfo.name = [dict objectForKey:@"title"];
appVersionMetaInfo.version = [dict objectForKey:@"version"];
appVersionMetaInfo.shortVersion = [dict objectForKey:@"shortversion"];
[appVersionMetaInfo setDateWithTimestamp:[[dict objectForKey:@"timestamp"] doubleValue]];
appVersionMetaInfo.size = [dict objectForKey:@"appsize"];
appVersionMetaInfo.notes = [dict objectForKey:@"notes"];
appVersionMetaInfo.mandatory = [dict objectForKey:@"mandatory"];
}
return appVersionMetaInfo;
}
#pragma mark - NSObject
- (void)dealloc {
[_name release];
[_version release];
[_shortVersion release];
[_notes release];
[_date release];
[_size release];
[_mandatory release];
[super dealloc];
}
- (BOOL)isEqual:(id)other {
if (other == self)
return YES;
if (!other || ![other isKindOfClass:[self class]])
return NO;
return [self isEqualToAppVersionMetaInfo:other];
}
- (BOOL)isEqualToAppVersionMetaInfo:(BITAppVersionMetaInfo *)anAppVersionMetaInfo {
if (self == anAppVersionMetaInfo)
return YES;
if (self.name != anAppVersionMetaInfo.name && ![self.name isEqualToString:anAppVersionMetaInfo.name])
return NO;
if (self.version != anAppVersionMetaInfo.version && ![self.version isEqualToString:anAppVersionMetaInfo.version])
return NO;
if (self.shortVersion != anAppVersionMetaInfo.shortVersion && ![self.shortVersion isEqualToString:anAppVersionMetaInfo.shortVersion])
return NO;
if (self.notes != anAppVersionMetaInfo.notes && ![self.notes isEqualToString:anAppVersionMetaInfo.notes])
return NO;
if (self.date != anAppVersionMetaInfo.date && ![self.date isEqualToDate:anAppVersionMetaInfo.date])
return NO;
if (self.size != anAppVersionMetaInfo.size && ![self.size isEqualToNumber:anAppVersionMetaInfo.size])
return NO;
if (self.mandatory != anAppVersionMetaInfo.mandatory && ![self.mandatory isEqualToNumber:anAppVersionMetaInfo.mandatory])
return NO;
return YES;
}
#pragma mark - NSCoder
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeObject:self.version forKey:@"version"];
[encoder encodeObject:self.shortVersion forKey:@"shortVersion"];
[encoder encodeObject:self.notes forKey:@"notes"];
[encoder encodeObject:self.date forKey:@"date"];
[encoder encodeObject:self.size forKey:@"size"];
[encoder encodeObject:self.mandatory forKey:@"mandatory"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if ((self = [super init])) {
self.name = [decoder decodeObjectForKey:@"name"];
self.version = [decoder decodeObjectForKey:@"version"];
self.shortVersion = [decoder decodeObjectForKey:@"shortVersion"];
self.notes = [decoder decodeObjectForKey:@"notes"];
self.date = [decoder decodeObjectForKey:@"date"];
self.size = [decoder decodeObjectForKey:@"size"];
self.mandatory = [decoder decodeObjectForKey:@"mandatory"];
}
return self;
}
#pragma mark - Properties
- (NSString *)nameAndVersionString {
NSString *appNameAndVersion = [NSString stringWithFormat:@"%@ %@", self.name, [self versionString]];
return appNameAndVersion;
}
- (NSString *)versionString {
NSString *shortString = ([self.shortVersion respondsToSelector:@selector(length)] && [self.shortVersion length]) ? [NSString stringWithFormat:@"%@", self.shortVersion] : @"";
NSString *versionString = [shortString length] ? [NSString stringWithFormat:@" (%@)", self.version] : self.version;
return [NSString stringWithFormat:@"%@ %@%@", BITHockeySDKLocalizedString(@"UpdateVersion"), shortString, versionString];
}
- (NSString *)dateString {
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateStyle:NSDateFormatterMediumStyle];
return [formatter stringFromDate:self.date];
}
- (NSString *)sizeInMB {
if ([_size isKindOfClass: [NSNumber class]] && [_size doubleValue] > 0) {
double appSizeInMB = [_size doubleValue]/(1024*1024);
NSString *appSizeString = [NSString stringWithFormat:@"%.1f MB", appSizeInMB];
return appSizeString;
}
return @"0 MB";
}
- (void)setDateWithTimestamp:(NSTimeInterval)timestamp {
if (timestamp) {
NSDate *appDate = [NSDate dateWithTimeIntervalSince1970:timestamp];
self.date = appDate;
} else {
self.date = nil;
}
}
- (NSString *)notesOrEmptyString {
if (self.notes) {
return self.notes;
}else {
return [NSString string];
}
}
// a valid app needs at least following properties: name, version, date
- (BOOL)isValid {
BOOL valid = [self.name length] && [self.version length] && self.date;
return valid;
}
@end

116
Classes/BITCrashManager.h Normal file
View File

@ -0,0 +1,116 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
* Kent Sutherland
*
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* Copyright (c) 2011 Andreas Linde & Kent Sutherland.
* 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>
typedef enum BITCrashAlertType {
BITCrashAlertTypeSend = 0,
BITCrashAlertTypeFeedback = 1,
} BITCrashAlertType;
typedef enum BITCrashStatus {
BITCrashStatusQueued = -80,
BITCrashStatusUnknown = 0,
BITCrashStatusAssigned = 1,
BITCrashStatusSubmitted = 2,
BITCrashStatusAvailable = 3,
} BITCrashStatus;
@protocol BITCrashManagerDelegate;
@interface BITCrashManager : NSObject {
id <BITCrashManagerDelegate> _delegate;
NSString *_appIdentifier;
NSString *_feedbackRequestID;
float _feedbackDelayInterval;
NSMutableString *_contentOfProperty;
BITCrashStatus _serverResult;
int _analyzerStarted;
NSString *_crashesDir;
NSFileManager *_fileManager;
BOOL _crashIdenticalCurrentVersion;
BOOL _crashReportActivated;
NSMutableArray *_crashFiles;
NSMutableData *_responseData;
NSInteger _statusCode;
NSURLConnection *_urlConnection;
NSData *_crashData;
BOOL _sendingInProgress;
}
// delegate is optional
@property (nonatomic, assign) id <BITCrashManagerDelegate> delegate;
///////////////////////////////////////////////////////////////////////////////////////////////////
// settings
/** Define the users name or userid that should be send along each crash report
*/
@property (nonatomic, copy) NSString *userName;
/** Define the users email address that should be send along each crash report
*/
@property (nonatomic, copy) NSString *userEmail;
// if YES, the user will get the option to choose "Always" for sending crash reports. This will cause the dialog not to show the alert description text landscape mode! (default)
// if NO, the dialog will not show a "Always" button
@property (nonatomic, assign, getter=isShowingAlwaysButton) BOOL showAlwaysButton;
// if YES, the user will be presented with a status of the crash, if known
// if NO, the user will not see any feedback information (default)
@property (nonatomic, assign, getter=isFeedbackActivated) BOOL feedbackActivated;
// if YES, the crash report will be submitted without asking the user
// if NO, the user will be asked if the crash report can be submitted (default)
@property (nonatomic, assign, getter=isAutoSubmitCrashReport) BOOL autoSubmitCrashReport;
// will return YES if the last session crashed, to e.g. make sure a "rate my app" alert will not show up
@property (nonatomic, readonly) BOOL didCrashInLastSession;
// will return the timeinterval from startup to the crash in seconds, default is -1
@property (nonatomic, readonly) NSTimeInterval timeintervalCrashInLastSessionOccured;
- (id)initWithAppIdentifier:(NSString *)appIdentifier;
- (void)startManager;
@end

View File

@ -2,6 +2,7 @@
* Author: Andreas Linde <mail@andreaslinde.de> * Author: Andreas Linde <mail@andreaslinde.de>
* Kent Sutherland * Kent Sutherland
* *
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* Copyright (c) 2011 Andreas Linde & Kent Sutherland. * Copyright (c) 2011 Andreas Linde & Kent Sutherland.
* All rights reserved. * All rights reserved.
* *
@ -30,120 +31,60 @@
#import <CrashReporter/CrashReporter.h> #import <CrashReporter/CrashReporter.h>
#import <SystemConfiguration/SystemConfiguration.h> #import <SystemConfiguration/SystemConfiguration.h>
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "BWGlobal.h" #import "HockeySDK.h"
#import "BWQuincyManager.h" #import "HockeySDKPrivate.h"
#import "CNSCrashReportTextFormatter.h"
#import "BITCrashReportTextFormatter.h"
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <inttypes.h> //needed for PRIx64 macro
// hockey api error domain
typedef enum {
QuincyErrorUnknown,
QuincyAPIAppVersionRejected,
QuincyAPIReceivedEmptyResponse,
QuincyAPIErrorWithStatusCode
} HockeyErrorReason;
static NSString *kQuincyErrorDomain = @"QuincyErrorDomain";
NSBundle *quincyBundle(void) {
static NSBundle* bundle = nil;
if (!bundle) {
NSString* path = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:kQuincyBundleName];
bundle = [[NSBundle bundleWithPath:path] retain];
}
return bundle;
}
NSString *BWQuincyLocalize(NSString *stringToken) {
if ([BWQuincyManager sharedQuincyManager].languageStyle == nil)
return NSLocalizedStringFromTableInBundle(stringToken, @"Quincy", quincyBundle(), @"");
else {
NSString *alternate = [NSString stringWithFormat:@"Quincy%@", [BWQuincyManager sharedQuincyManager].languageStyle];
return NSLocalizedStringFromTableInBundle(stringToken, alternate, quincyBundle(), @"");
}
}
@interface BWQuincyManager () // flags if the crashlog analyzer is started. since this may theoretically crash we need to track it
#define kBITCrashAnalyzerStarted @"HockeySDKCrashAnalyzerStarted"
- (void)startManager; // stores the set of crashreports that have been approved but aren't sent yet
#define kBITCrashApprovedReports @"HockeySDKCrashApprovedReports"
- (void)showCrashStatusMessage; // stores the user name entered in the UI
#define kBITCrashUserName @"HockeySDKCrashUserName"
- (void)handleCrashReport; // stores the user email address entered in the UI
- (void)_cleanCrashReports; #define kBITCrashUserEmail @"HockeySDKCrashUserEmail"
- (void)_checkForFeedbackStatus;
- (void)_performSendingCrashReports; @interface BITCrashManager ()
- (void)_sendCrashReports;
- (void)_postXML:(NSString*)xml toURL:(NSURL*)url;
- (NSString *)_getDevicePlatform;
- (BOOL)hasNonApprovedCrashReports;
- (BOOL)hasPendingCrashReport;
@property (nonatomic, retain) NSFileManager *fileManager; @property (nonatomic, retain) NSFileManager *fileManager;
@end @end
@implementation BWQuincyManager @implementation BITCrashManager
@synthesize delegate = _delegate; @synthesize delegate = _delegate;
@synthesize submissionURL = _submissionURL;
@synthesize showAlwaysButton = _showAlwaysButton; @synthesize showAlwaysButton = _showAlwaysButton;
@synthesize feedbackActivated = _feedbackActivated; @synthesize feedbackActivated = _feedbackActivated;
@synthesize autoSubmitCrashReport = _autoSubmitCrashReport; @synthesize autoSubmitCrashReport = _autoSubmitCrashReport;
@synthesize languageStyle = _languageStyle;
@synthesize didCrashInLastSession = _didCrashInLastSession; @synthesize didCrashInLastSession = _didCrashInLastSession;
@synthesize timeintervalCrashInLastSessionOccured = _timeintervalCrashInLastSessionOccured; @synthesize timeintervalCrashInLastSessionOccured = _timeintervalCrashInLastSessionOccured;
@synthesize loggingEnabled = _loggingEnabled;
@synthesize appIdentifier = _appIdentifier;
@synthesize fileManager = _fileManager; @synthesize fileManager = _fileManager;
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
+(BWQuincyManager *)sharedQuincyManager {
static BWQuincyManager *sharedInstance = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{ - (id)initWithAppIdentifier:(NSString *)appIdentifier {
sharedInstance = [BWQuincyManager alloc];
sharedInstance = [sharedInstance init];
});
return sharedInstance;
}
#else
+ (BWQuincyManager *)sharedQuincyManager {
static BWQuincyManager *quincyManager = nil;
if (quincyManager == nil) {
quincyManager = [[BWQuincyManager alloc] init];
}
return quincyManager;
}
#endif
- (id) init {
if ((self = [super init])) { if ((self = [super init])) {
_serverResult = CrashReportStatusUnknown; BITHockeySDKLog(@"Initializing CrashReporter");
_appIdentifier = appIdentifier;
_delegate = nil;
_serverResult = BITCrashStatusUnknown;
_crashIdenticalCurrentVersion = YES; _crashIdenticalCurrentVersion = YES;
_crashData = nil; _crashData = nil;
_urlConnection = nil; _urlConnection = nil;
_submissionURL = nil;
_responseData = nil; _responseData = nil;
_appIdentifier = nil;
_sendingInProgress = NO; _sendingInProgress = NO;
_languageStyle = nil;
_didCrashInLastSession = NO; _didCrashInLastSession = NO;
_timeintervalCrashInLastSessionOccured = -1; _timeintervalCrashInLastSessionOccured = -1;
_loggingEnabled = NO;
_fileManager = [[NSFileManager alloc] init]; _fileManager = [[NSFileManager alloc] init];
self.delegate = nil; self.delegate = nil;
@ -151,20 +92,20 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
self.showAlwaysButton = NO; self.showAlwaysButton = NO;
self.autoSubmitCrashReport = NO; self.autoSubmitCrashReport = NO;
NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kQuincyKitAnalyzerStarted]; NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kBITCrashAnalyzerStarted];
if (testValue) { if (testValue) {
_analyzerStarted = [[NSUserDefaults standardUserDefaults] integerForKey:kQuincyKitAnalyzerStarted]; _analyzerStarted = [[NSUserDefaults standardUserDefaults] integerForKey:kBITCrashAnalyzerStarted];
} else { } else {
_analyzerStarted = 0; _analyzerStarted = 0;
} }
testValue = nil; testValue = nil;
testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kQuincyKitActivated]; testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kBITCrashActivated];
if (testValue) { if (testValue) {
_crashReportActivated = [[NSUserDefaults standardUserDefaults] boolForKey:kQuincyKitActivated]; _crashReportActivated = [[NSUserDefaults standardUserDefaults] boolForKey:kBITCrashActivated];
} else { } else {
_crashReportActivated = YES; _crashReportActivated = YES;
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:YES] forKey:kQuincyKitActivated]; [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:YES] forKey:kBITCrashActivated];
} }
if (_crashReportActivated) { if (_crashReportActivated) {
@ -192,10 +133,10 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
if (![crashReporter enableCrashReporterAndReturnError: &error]) if (![crashReporter enableCrashReporterAndReturnError: &error])
NSLog(@"WARNING: Could not enable crash reporter: %@", error); NSLog(@"WARNING: Could not enable crash reporter: %@", error);
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startManager) name:BWQuincyNetworkBecomeReachable object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startManager) name:BITHockeyNetworkDidBecomeReachableNotification object:nil];
} }
if (!quincyBundle()) { if (!BITHockeySDKBundle()) {
NSLog(@"WARNING: Quincy.bundle is missing, will send reports automatically!"); NSLog(@"WARNING: Quincy.bundle is missing, will send reports automatically!");
} }
} }
@ -205,12 +146,7 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
- (void) dealloc { - (void) dealloc {
self.delegate = nil; self.delegate = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:BWQuincyNetworkBecomeReachable object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyNetworkDidBecomeReachableNotification object:nil];
[_languageStyle release];
[_submissionURL release];
_submissionURL = nil;
[_appIdentifier release]; [_appIdentifier release];
_appIdentifier = nil; _appIdentifier = nil;
@ -231,35 +167,13 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
} }
#pragma mark - #pragma mark - private methods
#pragma mark setter
- (void)setSubmissionURL:(NSString *)anSubmissionURL {
if (_submissionURL != anSubmissionURL) {
[_submissionURL release];
_submissionURL = [anSubmissionURL copy];
}
[self performSelector:@selector(startManager) withObject:nil afterDelay:1.0f];
}
- (void)setAppIdentifier:(NSString *)anAppIdentifier {
if (_appIdentifier != anAppIdentifier) {
[_appIdentifier release];
_appIdentifier = [anAppIdentifier copy];
}
[self setSubmissionURL:@"https://sdk.hockeyapp.net/"];
}
#pragma mark -
#pragma mark private methods
- (BOOL)autoSendCrashReports { - (BOOL)autoSendCrashReports {
BOOL result = NO; BOOL result = NO;
if (!self.autoSubmitCrashReport) { if (!self.autoSubmitCrashReport) {
if (self.isShowingAlwaysButton && [[NSUserDefaults standardUserDefaults] boolForKey: kAutomaticallySendCrashReports]) { if (self.isShowingAlwaysButton && [[NSUserDefaults standardUserDefaults] boolForKey: kBITCrashAutomaticallySendReports]) {
result = YES; result = YES;
} }
} else { } else {
@ -273,38 +187,84 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
- (void)startManager { - (void)startManager {
if (!_sendingInProgress && [self hasPendingCrashReport]) { if (!_sendingInProgress && [self hasPendingCrashReport]) {
_sendingInProgress = YES; _sendingInProgress = YES;
if (!quincyBundle()) { if (!BITHockeySDKBundle()) {
NSLog(@"WARNING: Quincy.bundle is missing, sending reports automatically!"); NSLog(@"WARNING: HockeySDKResource.bundle is missing, sending reports automatically!");
[self _sendCrashReports]; [self sendCrashReports];
} else if (![self autoSendCrashReports] && [self hasNonApprovedCrashReports]) { } else if (![self autoSendCrashReports] && [self hasNonApprovedCrashReports]) {
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(willShowSubmitCrashReportAlert)]) { if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporterWillShowSubmitCrashReportAlert:)]) {
[self.delegate willShowSubmitCrashReportAlert]; [self.delegate crashReporterWillShowSubmitCrashReportAlert:self];
} }
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:BWQuincyLocalize(@"CrashDataFoundTitle"), appName] UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashDataFoundTitle"), appName]
message:[NSString stringWithFormat:BWQuincyLocalize(@"CrashDataFoundDescription"), appName] message:[NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashDataFoundDescription"), appName]
delegate:self delegate:self
cancelButtonTitle:BWQuincyLocalize(@"CrashDontSendReport") cancelButtonTitle:BITHockeySDKLocalizedString(@"CrashDontSendReport")
otherButtonTitles:BWQuincyLocalize(@"CrashSendReport"), nil]; otherButtonTitles:BITHockeySDKLocalizedString(@"CrashSendReport"), nil];
if ([self isShowingAlwaysButton]) { if ([self isShowingAlwaysButton]) {
[alertView addButtonWithTitle:BWQuincyLocalize(@"CrashSendReportAlways")]; [alertView addButtonWithTitle:BITHockeySDKLocalizedString(@"CrashSendReportAlways")];
} }
[alertView setTag: QuincyKitAlertTypeSend]; [alertView setTag: BITCrashAlertTypeSend];
[alertView show]; [alertView show];
[alertView release]; [alertView release];
} else { } else {
[self _sendCrashReports]; [self sendCrashReports];
} }
} }
} }
#pragma mark - PLCrashReporter
//
// Called to handle a pending crash report.
//
- (void) handleCrashReport {
PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
NSError *error = NULL;
// check if the next call ran successfully the last time
if (_analyzerStarted == 0) {
// mark the start of the routine
_analyzerStarted = 1;
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_analyzerStarted] forKey:kBITCrashAnalyzerStarted];
[[NSUserDefaults standardUserDefaults] synchronize];
// Try loading the crash report
_crashData = [[NSData alloc] initWithData:[crashReporter loadPendingCrashReportDataAndReturnError: &error]];
NSString *cacheFilename = [NSString stringWithFormat: @"%.0f", [NSDate timeIntervalSinceReferenceDate]];
if (_crashData == nil) {
NSLog(@"Could not load crash report: %@", error);
} else {
[_crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES];
// get the startup timestamp from the crash report, and the file timestamp to calculate the timeinterval when the crash happened after startup
PLCrashReport *report = [[[PLCrashReport alloc] initWithData:_crashData error:&error] autorelease];
if (report.systemInfo.timestamp && report.applicationInfo.applicationStartupTimestamp) {
_timeintervalCrashInLastSessionOccured = [report.systemInfo.timestamp timeIntervalSinceDate:report.applicationInfo.applicationStartupTimestamp];
}
}
}
// Purge the report
// mark the end of the routine
_analyzerStarted = 0;
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_analyzerStarted] forKey:kBITCrashAnalyzerStarted];
[[NSUserDefaults standardUserDefaults] synchronize];
[crashReporter purgePendingCrashReport];
return;
}
- (BOOL)hasNonApprovedCrashReports { - (BOOL)hasNonApprovedCrashReports {
NSDictionary *approvedCrashReports = [[NSUserDefaults standardUserDefaults] dictionaryForKey: kApprovedCrashReports]; NSDictionary *approvedCrashReports = [[NSUserDefaults standardUserDefaults] dictionaryForKey: kBITCrashApprovedReports];
if (!approvedCrashReports || [approvedCrashReports count] == 0) return YES; if (!approvedCrashReports || [approvedCrashReports count] == 0) return YES;
@ -334,7 +294,7 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
} }
if ([_crashFiles count] > 0) { if ([_crashFiles count] > 0) {
BWQuincyLog(@"Pending crash reports found."); BITHockeySDKLog(@"Pending crash reports found.");
return YES; return YES;
} else } else
return NO; return NO;
@ -346,31 +306,31 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
- (void) showCrashStatusMessage { - (void) showCrashStatusMessage {
UIAlertView *alertView = nil; UIAlertView *alertView = nil;
if (_serverResult >= CrashReportStatusAssigned && if (_serverResult >= BITCrashStatusAssigned &&
_crashIdenticalCurrentVersion && _crashIdenticalCurrentVersion &&
quincyBundle()) { BITHockeySDKBundle()) {
// show some feedback to the user about the crash status // show some feedback to the user about the crash status
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
switch (_serverResult) { switch (_serverResult) {
case CrashReportStatusAssigned: case BITCrashStatusAssigned:
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ] alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseTitle"), appName ]
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseNextRelease"), appName] message: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseNextRelease"), appName]
delegate: self delegate: self
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK") cancelButtonTitle: BITHockeySDKLocalizedString(@"HockeyOK")
otherButtonTitles: nil]; otherButtonTitles: nil];
break; break;
case CrashReportStatusSubmitted: case BITCrashStatusSubmitted:
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ] alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseTitle"), appName ]
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseWaitingApple"), appName] message: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseWaitingApple"), appName]
delegate: self delegate: self
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK") cancelButtonTitle: BITHockeySDKLocalizedString(@"HockeyOK")
otherButtonTitles: nil]; otherButtonTitles: nil];
break; break;
case CrashReportStatusAvailable: case BITCrashStatusAvailable:
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ] alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseTitle"), appName ]
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseAvailable"), appName] message: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseAvailable"), appName]
delegate: self delegate: self
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK") cancelButtonTitle: BITHockeySDKLocalizedString(@"HockeyOK")
otherButtonTitles: nil]; otherButtonTitles: nil];
break; break;
default: default:
@ -379,7 +339,7 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
} }
if (alertView) { if (alertView) {
[alertView setTag: QuincyKitAlertTypeFeedback]; [alertView setTag: BITCrashAlertTypeFeedback];
[alertView show]; [alertView show];
[alertView release]; [alertView release];
} }
@ -391,89 +351,47 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
#pragma mark UIAlertView Delegate #pragma mark UIAlertView Delegate
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
if ([alertView tag] == QuincyKitAlertTypeSend) { if ([alertView tag] == BITCrashAlertTypeSend) {
switch (buttonIndex) { switch (buttonIndex) {
case 0: case 0:
_sendingInProgress = NO; _sendingInProgress = NO;
[self _cleanCrashReports]; [self cleanCrashReports];
break; break;
case 1: case 1:
[self _sendCrashReports]; [self sendCrashReports];
break; break;
case 2: { case 2: {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:kAutomaticallySendCrashReports]; [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kBITCrashAutomaticallySendReports];
[[NSUserDefaults standardUserDefaults] synchronize]; [[NSUserDefaults standardUserDefaults] synchronize];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(userDidChooseSendAlways)]) { if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporterWillSendCrashReportsAlways:)]) {
[self.delegate userDidChooseSendAlways]; [self.delegate crashReporterWillSendCrashReportsAlways:self];
} }
[self _sendCrashReports]; [self sendCrashReports];
break; break;
} }
default: default:
_sendingInProgress = NO; _sendingInProgress = NO;
[self _cleanCrashReports]; [self cleanCrashReports];
break; break;
} }
} }
} }
#pragma mark -
#pragma mark NSXMLParser Delegate
#pragma mark NSXMLParser #pragma mark - Private
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if (qName) {
elementName = qName;
}
if ([elementName isEqualToString:@"result"]) {
_contentOfProperty = [NSMutableString string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if (qName) {
elementName = qName;
}
// open source implementation
if ([elementName isEqualToString: @"result"]) {
if ([_contentOfProperty intValue] > _serverResult) {
_serverResult = (CrashReportStatus)[_contentOfProperty intValue];
} else {
CrashReportStatus errorcode = (CrashReportStatus)[_contentOfProperty intValue];
NSLog(@"CrashReporter ended in error code: %i", errorcode);
}
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (_contentOfProperty) {
// If the current element is one whose content we care about, append 'string'
// to the property that holds the content of the current element.
if (string != nil) {
[_contentOfProperty appendString:string];
}
}
}
#pragma mark -
#pragma mark Private
- (NSString *) extractAppUUIDs:(PLCrashReport *)report { - (NSString *) extractAppUUIDs:(PLCrashReport *)report {
NSMutableString *uuidString = [NSMutableString string]; NSMutableString *uuidString = [NSMutableString string];
NSArray *uuidArray = [CNSCrashReportTextFormatter arrayOfAppUUIDsForCrashReport:report]; NSArray *uuidArray = [BITCrashReportTextFormatter arrayOfAppUUIDsForCrashReport:report];
for (NSDictionary *element in uuidArray) { for (NSDictionary *element in uuidArray) {
if ([element objectForKey:kCNSBinaryImageKeyUUID] && [element objectForKey:kCNSBinaryImageKeyArch] && [element objectForKey:kCNSBinaryImageKeyUUID]) { if ([element objectForKey:kBITBinaryImageKeyUUID] && [element objectForKey:kBITBinaryImageKeyArch] && [element objectForKey:kBITBinaryImageKeyUUID]) {
[uuidString appendFormat:@"<uuid type=\"%@\" arch=\"%@\">%@</uuid>", [uuidString appendFormat:@"<uuid type=\"%@\" arch=\"%@\">%@</uuid>",
[element objectForKey:kCNSBinaryImageKeyType], [element objectForKey:kBITBinaryImageKeyType],
[element objectForKey:kCNSBinaryImageKeyArch], [element objectForKey:kBITBinaryImageKeyArch],
[element objectForKey:kCNSBinaryImageKeyUUID] [element objectForKey:kBITBinaryImageKeyUUID]
]; ];
} }
} }
@ -482,7 +400,7 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
} }
- (NSString *)_getDevicePlatform { - (NSString *)getDevicePlatform {
size_t size = 0; size_t size = 0;
sysctlbyname("hw.machine", NULL, &size, NULL, 0); sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *answer = (char*)malloc(size); char *answer = (char*)malloc(size);
@ -493,25 +411,17 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
} }
- (void)_performSendingCrashReports { - (void)performSendingCrashReports {
NSMutableDictionary *approvedCrashReports = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey: kApprovedCrashReports]]; NSMutableDictionary *approvedCrashReports = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey: kBITCrashApprovedReports]];
NSError *error = NULL; NSError *error = NULL;
NSString *userid = @""; NSString *username = _userName ?: @"";
NSString *contact = @""; NSString *email = _userEmail ?: @"";
NSString *description = @""; NSString *applicationLog = @"";
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReportUserID)]) { if (self.delegate != nil && [self.delegate respondsToSelector:@selector(applicationLogForCrashReporter:)]) {
userid = [self.delegate crashReportUserID] ?: @""; applicationLog = [self.delegate applicationLogForCrashReporter:self] ?: @"";
}
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReportContact)]) {
contact = [self.delegate crashReportContact] ?: @"";
}
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReportDescription)]) {
description = [self.delegate crashReportDescription] ?: @"";
} }
NSMutableString *crashes = nil; NSMutableString *crashes = nil;
@ -526,11 +436,13 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
if (report == nil) { if (report == nil) {
NSLog(@"Could not parse crash report"); NSLog(@"Could not parse crash report");
// we cannot do anything with this report, so delete it
[self.fileManager removeItemAtPath:filename error:&error];
continue; continue;
} }
NSString *crashUUID = report.reportInfo.reportGUID ?: @""; NSString *crashUUID = report.reportInfo.reportGUID ?: @"";
NSString *crashLogString = [CNSCrashReportTextFormatter stringValueForCrashReport:report withTextFormat:PLCrashReportTextFormatiOS]; NSString *crashLogString = [BITCrashReportTextFormatter stringValueForCrashReport:report];
if ([report.applicationInfo.applicationVersion compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] == NSOrderedSame) { if ([report.applicationInfo.applicationVersion compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] == NSOrderedSame) {
_crashIdenticalCurrentVersion = YES; _crashIdenticalCurrentVersion = YES;
@ -545,14 +457,14 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
[self extractAppUUIDs:report], [self extractAppUUIDs:report],
report.applicationInfo.applicationIdentifier, report.applicationInfo.applicationIdentifier,
report.systemInfo.operatingSystemVersion, report.systemInfo.operatingSystemVersion,
[self _getDevicePlatform], [self getDevicePlatform],
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"], [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
report.applicationInfo.applicationVersion, report.applicationInfo.applicationVersion,
crashUUID, crashUUID,
[crashLogString stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,crashLogString.length)], [crashLogString stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,crashLogString.length)],
userid, username,
contact, email,
[description stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,description.length)]]; [applicationLog stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,applicationLog.length)]];
// store this crash report as user approved, so if it fails it will retry automatically // store this crash report as user approved, so if it fails it will retry automatically
@ -563,18 +475,18 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
} }
} }
[[NSUserDefaults standardUserDefaults] setObject:approvedCrashReports forKey:kApprovedCrashReports]; [[NSUserDefaults standardUserDefaults] setObject:approvedCrashReports forKey:kBITCrashApprovedReports];
[[NSUserDefaults standardUserDefaults] synchronize]; [[NSUserDefaults standardUserDefaults] synchronize];
if (crashes != nil) { if (crashes != nil) {
BWQuincyLog(@"Sending crash reports:\n%@", crashes); BITHockeySDKLog(@"Sending crash reports:\n%@", crashes);
[self _postXML:[NSString stringWithFormat:@"<crashes>%@</crashes>", crashes] [self postXML:[NSString stringWithFormat:@"<crashes>%@</crashes>", crashes]
toURL:[NSURL URLWithString:self.submissionURL]]; toURL:[NSURL URLWithString:BITHOCKEYSDK_URL]];
} }
} }
- (void)_cleanCrashReports { - (void)cleanCrashReports {
NSError *error = NULL; NSError *error = NULL;
for (NSUInteger i=0; i < [_crashFiles count]; i++) { for (NSUInteger i=0; i < [_crashFiles count]; i++) {
@ -582,22 +494,22 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
} }
[_crashFiles removeAllObjects]; [_crashFiles removeAllObjects];
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:kApprovedCrashReports]; [[NSUserDefaults standardUserDefaults] setObject:nil forKey:kBITCrashApprovedReports];
[[NSUserDefaults standardUserDefaults] synchronize]; [[NSUserDefaults standardUserDefaults] synchronize];
} }
- (void)_sendCrashReports { - (void)sendCrashReports {
// send it to the next runloop // send it to the next runloop
[self performSelector:@selector(_performSendingCrashReports) withObject:nil afterDelay:0.0f]; [self performSelector:@selector(performSendingCrashReports) withObject:nil afterDelay:0.0f];
} }
- (void)_checkForFeedbackStatus { - (void)checkForFeedbackStatus {
NSMutableURLRequest *request = nil; NSMutableURLRequest *request = nil;
request = [NSMutableURLRequest requestWithURL: request = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes/%@", [NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes/%@",
self.submissionURL, BITHOCKEYSDK_URL,
[self.appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], [_appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
_feedbackRequestID _feedbackRequestID
] ]
]]; ]];
@ -608,26 +520,25 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
[request setTimeoutInterval: 15]; [request setTimeoutInterval: 15];
[request setHTTPMethod:@"GET"]; [request setHTTPMethod:@"GET"];
_serverResult = CrashReportStatusUnknown; _serverResult = BITCrashStatusUnknown;
_statusCode = 200; _statusCode = 200;
// Release when done in the delegate method // Release when done in the delegate method
_responseData = [[NSMutableData alloc] init]; _responseData = [[NSMutableData alloc] init];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(connectionOpened)]) {
[self.delegate connectionOpened];
}
_urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; _urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
BWQuincyLog(@"Requesting feedback status."); if (!_urlConnection) {
BITHockeySDKLog(@"Requesting feedback status could not start!");
} else {
BITHockeySDKLog(@"Requesting feedback status.");
}
} }
- (void)_postXML:(NSString*)xml toURL:(NSURL*)url { - (void)postXML:(NSString*)xml toURL:(NSURL*)url {
NSMutableURLRequest *request = nil; NSMutableURLRequest *request = nil;
NSString *boundary = @"----FOO"; NSString *boundary = @"----FOO";
if (self.appIdentifier) {
NSString *feedbackEnabled = @"&feedbackEnabled=no"; NSString *feedbackEnabled = @"&feedbackEnabled=no";
if ([self isFeedbackActivated]) { if ([self isFeedbackActivated]) {
@ -636,16 +547,13 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
request = [NSMutableURLRequest requestWithURL: request = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes?sdk=%@&sdk_version=%@%@", [NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes?sdk=%@&sdk_version=%@%@",
self.submissionURL, BITHOCKEYSDK_URL,
[self.appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], [_appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
SDK_NAME, BITHOCKEYSDK_NAME,
SDK_VERSION, BITHOCKEYSDK_VERSION,
feedbackEnabled feedbackEnabled
] ]
]]; ]];
} else {
request = [NSMutableURLRequest requestWithURL:url];
}
[request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData]; [request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData];
[request setValue:@"Quincy/iOS" forHTTPHeaderField:@"User-Agent"]; [request setValue:@"Quincy/iOS" forHTTPHeaderField:@"User-Agent"];
@ -657,18 +565,14 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
NSMutableData *postBody = [NSMutableData data]; NSMutableData *postBody = [NSMutableData data];
[postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
if (self.appIdentifier) {
[postBody appendData:[@"Content-Disposition: form-data; name=\"xml\"; filename=\"crash.xml\"\r\n" 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:[[NSString stringWithFormat:@"Content-Type: text/xml\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
} else {
[postBody appendData:[@"Content-Disposition: form-data; name=\"xmlstring\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
}
[postBody appendData:[xml dataUsingEncoding:NSUTF8StringEncoding]]; [postBody appendData:[xml dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:postBody]; [request setHTTPBody:postBody];
_serverResult = CrashReportStatusUnknown; _serverResult = BITCrashStatusUnknown;
_statusCode = 200; _statusCode = 200;
//Release when done in the delegate method //Release when done in the delegate method
@ -677,22 +581,18 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
_urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; _urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (!_urlConnection) { if (!_urlConnection) {
BWQuincyLog(@"Sending crash reports could not start!"); BITHockeySDKLog(@"Sending crash reports could not start!");
_sendingInProgress = NO; _sendingInProgress = NO;
} else { } else {
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(connectionOpened)]) { if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporterWillSendCrashReport:)]) {
[self.delegate connectionOpened]; [self.delegate crashReporterWillSendCrashReport:self];
} }
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(sendingCrashReportsDidStart)]) { BITHockeySDKLog(@"Sending crash reports started.");
[self.delegate sendingCrashReportsDidStart];
}
BWQuincyLog(@"Sending crash reports started.");
} }
} }
#pragma mark NSURLConnection Delegate #pragma mark - NSURLConnection Delegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) { if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
@ -705,15 +605,11 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
} }
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(connectionClosed)]) { if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporter:didFailWithError:)]) {
[self.delegate connectionClosed]; [self.delegate crashReporter:self didFailWithError:error];
} }
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(sendingCrashReportsDidFailWithError:)]) { BITHockeySDKLog(@"ERROR: %@", [error localizedDescription]);
[self.delegate sendingCrashReportsDidFailWithError:error];
}
BWQuincyLog(@"ERROR: %@", [error localizedDescription]);
_sendingInProgress = NO; _sendingInProgress = NO;
@ -727,85 +623,68 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
NSError *error = nil; NSError *error = nil;
if (_statusCode >= 200 && _statusCode < 400 && _responseData != nil && [_responseData length] > 0) { if (_statusCode >= 200 && _statusCode < 400 && _responseData != nil && [_responseData length] > 0) {
[self _cleanCrashReports]; [self cleanCrashReports];
_feedbackRequestID = nil; _feedbackRequestID = nil;
if (self.appIdentifier) {
// HockeyApp uses PList XML format // HockeyApp uses PList XML format
NSMutableDictionary *response = [NSPropertyListSerialization propertyListFromData:_responseData NSMutableDictionary *response = [NSPropertyListSerialization propertyListFromData:_responseData
mutabilityOption:NSPropertyListMutableContainersAndLeaves mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:nil format:nil
errorDescription:NULL]; errorDescription:NULL];
BWQuincyLog(@"Received API response: %@", response); BITHockeySDKLog(@"Received API response: %@", response);
_serverResult = (CrashReportStatus)[[response objectForKey:@"status"] intValue]; _serverResult = (BITCrashStatus)[[response objectForKey:@"status"] intValue];
if ([response objectForKey:@"id"]) { if ([response objectForKey:@"id"]) {
_feedbackRequestID = [[NSString alloc] initWithString:[response objectForKey:@"id"]]; _feedbackRequestID = [[NSString alloc] initWithString:[response objectForKey:@"id"]];
_feedbackDelayInterval = [[response objectForKey:@"delay"] floatValue]; _feedbackDelayInterval = [[response objectForKey:@"delay"] floatValue];
if (_feedbackDelayInterval > 0) if (_feedbackDelayInterval > 0)
_feedbackDelayInterval *= 0.01; _feedbackDelayInterval *= 0.01;
} }
} else {
BWQuincyLog(@"Received API response: %@", [[[NSString alloc] initWithBytes:[_responseData bytes] length:[_responseData length] encoding: NSUTF8StringEncoding] autorelease]);
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:_responseData];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
[parser setDelegate:self];
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
[parser release];
}
if ([self isFeedbackActivated]) { if ([self isFeedbackActivated]) {
// only proceed if the server did not report any problem // only proceed if the server did not report any problem
if ((self.appIdentifier) && (_serverResult == CrashReportStatusQueued)) { if (_serverResult == BITCrashStatusQueued) {
// the report is still in the queue // the report is still in the queue
if (_feedbackRequestID) { if (_feedbackRequestID) {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_checkForFeedbackStatus) object:nil]; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(checkForFeedbackStatus) object:nil];
[self performSelector:@selector(_checkForFeedbackStatus) withObject:nil afterDelay:_feedbackDelayInterval]; [self performSelector:@selector(checkForFeedbackStatus) withObject:nil afterDelay:_feedbackDelayInterval];
} }
} else { } else {
[self showCrashStatusMessage]; [self showCrashStatusMessage];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(sendingCrashReportsDidFinish)]) {
[self.delegate sendingCrashReportsDidFinish];
} }
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporterDidFinishSendingCrashReport:)]) {
[self.delegate crashReporterDidFinishSendingCrashReport:self];
} }
} }
} else if (_statusCode == 400 && self.appIdentifier) { } else if (_statusCode == 400) {
[self _cleanCrashReports]; [self cleanCrashReports];
error = [NSError errorWithDomain:kQuincyErrorDomain error = [NSError errorWithDomain:kBITCrashErrorDomain
code:QuincyAPIAppVersionRejected code:BITCrashAPIAppVersionRejected
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The server rejected receiving crash reports for this app version!", NSLocalizedDescriptionKey, nil]]; userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The server rejected receiving crash reports for this app version!", NSLocalizedDescriptionKey, nil]];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(sendingCrashReportsDidFailWithError:)]) { if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporter:didFailWithError:)]) {
[self.delegate sendingCrashReportsDidFailWithError:error]; [self.delegate crashReporter:self didFailWithError:error];
} }
BWQuincyLog(@"ERROR: %@", [error localizedDescription]); BITHockeySDKLog(@"ERROR: %@", [error localizedDescription]);
} else { } else {
if (_responseData == nil || [_responseData length] == 0) { if (_responseData == nil || [_responseData length] == 0) {
error = [NSError errorWithDomain:kQuincyErrorDomain error = [NSError errorWithDomain:kBITCrashErrorDomain
code:QuincyAPIReceivedEmptyResponse code:BITCrashAPIReceivedEmptyResponse
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Sending failed with an empty response!", NSLocalizedDescriptionKey, nil]]; userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Sending failed with an empty response!", NSLocalizedDescriptionKey, nil]];
} else { } else {
error = [NSError errorWithDomain:kQuincyErrorDomain error = [NSError errorWithDomain:kBITCrashErrorDomain
code:QuincyAPIErrorWithStatusCode code:BITCrashAPIErrorWithStatusCode
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Sending failed with status code: %i", _statusCode], NSLocalizedDescriptionKey, nil]]; userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Sending failed with status code: %i", _statusCode], NSLocalizedDescriptionKey, nil]];
} }
BWQuincyLog(@"ERROR: %@", [error localizedDescription]); if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporter:didFailWithError:)]) {
[self.delegate crashReporter:self didFailWithError:error];
} }
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(connectionClosed)]) { BITHockeySDKLog(@"ERROR: %@", [error localizedDescription]);
[self.delegate connectionClosed];
} }
_sendingInProgress = NO; _sendingInProgress = NO;
@ -816,50 +695,5 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
_urlConnection = nil; _urlConnection = nil;
} }
#pragma mark PLCrashReporter
//
// Called to handle a pending crash report.
//
- (void) handleCrashReport {
PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
NSError *error = NULL;
// check if the next call ran successfully the last time
if (_analyzerStarted == 0) {
// mark the start of the routine
_analyzerStarted = 1;
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_analyzerStarted] forKey:kQuincyKitAnalyzerStarted];
[[NSUserDefaults standardUserDefaults] synchronize];
// Try loading the crash report
_crashData = [[NSData alloc] initWithData:[crashReporter loadPendingCrashReportDataAndReturnError: &error]];
NSString *cacheFilename = [NSString stringWithFormat: @"%.0f", [NSDate timeIntervalSinceReferenceDate]];
if (_crashData == nil) {
NSLog(@"Could not load crash report: %@", error);
} else {
[_crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES];
// get the startup timestamp from the crash report, and the file timestamp to calculate the timeinterval when the crash happened after startup
PLCrashReport *report = [[[PLCrashReport alloc] initWithData:_crashData error:&error] autorelease];
if (report.systemInfo.timestamp && report.applicationInfo.applicationStartupTimestamp) {
_timeintervalCrashInLastSessionOccured = [report.systemInfo.timestamp timeIntervalSinceDate:report.applicationInfo.applicationStartupTimestamp];
}
}
}
// Purge the report
// mark the end of the routine
_analyzerStarted = 0;
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_analyzerStarted] forKey:kQuincyKitAnalyzerStarted];
[[NSUserDefaults standardUserDefaults] synchronize];
[crashReporter purgePendingCrashReport];
return;
}
@end @end

View File

@ -0,0 +1,60 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
*
* Copyright (c) 2012 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 <Foundation/Foundation.h>
@protocol BITCrashManagerDelegate <NSObject>
@optional
/** Return any log string based data the crash report being processed should contain
*/
-(NSString *)applicationLogForCrashReporter:(BITCrashManager *)crashReporter;
/** Invoked before the user is asked to send a crash report, so you can do additional actions.
E.g. to make sure not to ask the user for an app rating :)
*/
-(void)crashReporterWillShowSubmitCrashReportAlert:(BITCrashManager *)crashReporter;
/** Invoked after the user did choose to send crashes always in the alert
*/
-(void)crashReporterWillSendCrashReportsAlways:(BITCrashManager *)crashReporter;
/** Invoked right before sending crash reports will start
*/
- (void)crashReporterWillSendCrashReport:(BITCrashManager *)crashReporter;
/** Invoked after sending crash reports failed
*/
- (void)crashReporter:(BITCrashManager *)crashReporter didFailWithError:(NSError *)error;
/** Invoked after sending crash reports succeeded
*/
- (void)crashReporterDidFinishSendingCrashReport:(BITCrashManager *)crashReporter;
@end

View File

@ -6,7 +6,7 @@
* *
* Copyright (c) 2008-2012 Plausible Labs Cooperative, Inc. * Copyright (c) 2008-2012 Plausible Labs Cooperative, Inc.
* Copyright (c) 2010 MOSO Corporation, Pty Ltd. * Copyright (c) 2010 MOSO Corporation, Pty Ltd.
* Copyright (c) 2012 Codenauts UG (haftungsbeschränkt) * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* 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
@ -34,38 +34,20 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "CrashReporter/PLCrashReportFormatter.h" #import <CrashReporter/PLCrashReport.h>
/**
* Supported text output formats.
*
* @ingroup enums
*/
typedef enum {
/** An iOS-compatible crash log text format. Compatible with the crash logs generated by the device and available
* through iTunes Connect. */
CNSCrashReportTextFormatiOS = 0
} CNSCrashReportTextFormat;
// Dictionary keys for array elements returned by arrayOfAppUUIDsForCrashReport: // Dictionary keys for array elements returned by arrayOfAppUUIDsForCrashReport:
#define kCNSBinaryImageKeyUUID @"uuid" #ifndef kBITBinaryImageKeyUUID
#define kCNSBinaryImageKeyArch @"arch" #define kBITBinaryImageKeyUUID @"uuid"
#define kCNSBinaryImageKeyType @"type" #define kBITBinaryImageKeyArch @"arch"
#define kBITBinaryImageKeyType @"type"
#endif
@interface CNSCrashReportTextFormatter : NSObject <PLCrashReportFormatter> { @interface BITCrashReportTextFormatter : NSObject {
@private
/** Text output format. */
CNSCrashReportTextFormat _textFormat;
/** Encoding to use for string output. */
NSStringEncoding _stringEncoding;
} }
+ (NSString *) stringValueForCrashReport: (PLCrashReport *) report withTextFormat: (CNSCrashReportTextFormat) textFormat; + (NSString *)stringValueForCrashReport:(PLCrashReport *)report;
+ (NSArray *)arrayOfAppUUIDsForCrashReport:(PLCrashReport *)report; + (NSArray *)arrayOfAppUUIDsForCrashReport:(PLCrashReport *)report;
- (id) initWithTextFormat: (CNSCrashReportTextFormat) textFormat stringEncoding: (NSStringEncoding) stringEncoding;
@end @end

View File

@ -6,7 +6,7 @@
* *
* Copyright (c) 2008-2012 Plausible Labs Cooperative, Inc. * Copyright (c) 2008-2012 Plausible Labs Cooperative, Inc.
* Copyright (c) 2010 MOSO Corporation, Pty Ltd. * Copyright (c) 2010 MOSO Corporation, Pty Ltd.
* Copyright (c) 2012 Codenauts UG (haftungsbeschränkt) * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* 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
@ -31,11 +31,11 @@
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
#import "CrashReporter/CrashReporter.h" #import <CrashReporter/CrashReporter.h>
#import "CNSCrashReportTextFormatter.h" #import "BITCrashReportTextFormatter.h"
@interface CNSCrashReportTextFormatter (PrivateAPI) @interface BITCrashReportTextFormatter (PrivateAPI)
NSInteger binaryImageSort(id binary1, id binary2, void *context); NSInteger binaryImageSort(id binary1, id binary2, void *context);
+ (NSString *)formatStackFrame:(PLCrashReportStackFrameInfo *)frameInfo + (NSString *)formatStackFrame:(PLCrashReportStackFrameInfo *)frameInfo
frameIndex:(NSUInteger)frameIndex frameIndex:(NSUInteger)frameIndex
@ -46,7 +46,7 @@ NSInteger binaryImageSort(id binary1, id binary2, void *context);
/** /**
* Formats PLCrashReport data as human-readable text. * Formats PLCrashReport data as human-readable text.
*/ */
@implementation CNSCrashReportTextFormatter @implementation BITCrashReportTextFormatter
/** /**
@ -58,7 +58,7 @@ NSInteger binaryImageSort(id binary1, id binary2, void *context);
* *
* @return Returns the formatted result on success, or nil if an error occurs. * @return Returns the formatted result on success, or nil if an error occurs.
*/ */
+ (NSString *) stringValueForCrashReport: (PLCrashReport *) report withTextFormat: (CNSCrashReportTextFormat) textFormat { + (NSString *)stringValueForCrashReport:(PLCrashReport *)report {
NSMutableString* text = [NSMutableString string]; NSMutableString* text = [NSMutableString string];
boolean_t lp64 = true; // quiesce GCC uninitialized value warning boolean_t lp64 = true; // quiesce GCC uninitialized value warning
@ -498,7 +498,7 @@ NSInteger binaryImageSort(id binary1, id binary2, void *context);
} }
if ([imagePath isEqual: report.processInfo.processPath] || [imagePath hasPrefix:appBundleContentsPath]) { if ([imagePath isEqual: report.processInfo.processPath] || [imagePath hasPrefix:appBundleContentsPath]) {
[appUUIDs addObject:[NSDictionary dictionaryWithObjectsAndKeys:uuid, kCNSBinaryImageKeyUUID, archName, kCNSBinaryImageKeyArch, imageType, kCNSBinaryImageKeyType, nil]]; [appUUIDs addObject:[NSDictionary dictionaryWithObjectsAndKeys:uuid, kBITBinaryImageKeyUUID, archName, kBITBinaryImageKeyArch, imageType, kBITBinaryImageKeyType, nil]];
} }
} }
@ -506,32 +506,10 @@ NSInteger binaryImageSort(id binary1, id binary2, void *context);
return appUUIDs; return appUUIDs;
} }
/**
* Initialize with the request string encoding and output format.
*
* @param textFormat Format to use for the generated text crash report.
* @param stringEncoding Encoding to use when writing to the output stream.
*/
- (id) initWithTextFormat: (CNSCrashReportTextFormat) textFormat stringEncoding: (NSStringEncoding) stringEncoding {
if ((self = [super init]) == nil)
return nil;
_textFormat = textFormat;
_stringEncoding = stringEncoding;
return self;
}
// from PLCrashReportFormatter protocol
- (NSData *) formatReport: (PLCrashReport *) report error: (NSError **) outError {
NSString *text = [PLCrashReportTextFormatter stringValueForCrashReport: report withTextFormat: _textFormat];
return [text dataUsingEncoding: _stringEncoding allowLossyConversion: YES];
}
@end @end
@implementation CNSCrashReportTextFormatter (PrivateAPI) @implementation BITCrashReportTextFormatter (PrivateAPI)
/** /**

View File

@ -0,0 +1,81 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
* Kent Sutherland
*
* Copyright (c) 2012 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 "BITUpdateManager.h"
@protocol BITHockeyManagerDelegate;
@class BITCrashManager;
@interface BITHockeyManager : NSObject {
@private
id<BITHockeyManagerDelegate> delegate;
NSString *_appIdentifier;
BOOL _validAppIdentifier;
BOOL _startManagerIsInvoked;
}
#pragma mark - Public Properties
@property (nonatomic, retain) BITCrashManager *crashManager;
@property (nonatomic, retain) BITUpdateManager *updateManager;
// if YES the app is installed from the app store
// if NO the app is installed via ad-hoc or enterprise distribution
@property (nonatomic, readonly) BOOL isAppStoreEnvironment;
// Enable debug logging; ONLY ENABLE THIS FOR DEBUGGING!
//
// Default: NO
@property (nonatomic, assign, getter=isLoggingEnabled) BOOL loggingEnabled;
#pragma mark - Public Methods
// Returns the shared manager object
+ (BITHockeyManager *)sharedHockeyManager;
// Configure HockeyApp with a single app identifier and delegate; use this
// only for debug or beta versions of your app!
- (void)configureWithIdentifier:(NSString *)appIdentifier delegate:(id<BITHockeyManagerDelegate>)delegate;
// Configure HockeyApp with different app identifiers for beta and live versions
// of the app; the update alert will only be shown for the beta identifier
- (void)configureWithBetaIdentifier:(NSString *)betaIdentifier liveIdentifier:(NSString *)liveIdentifier delegate:(id<BITHockeyManagerDelegate>)delegate;
// Initialize all submodules and start them
- (void)startManager;
@end

296
Classes/BITHockeyManager.m Normal file
View File

@ -0,0 +1,296 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
* Kent Sutherland
*
* Copyright (c) 2012 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 "HockeySDK.h"
#import "HockeySDKPrivate.h"
#import "BITUpdateManager.h"
@interface BITHockeyManager ()
- (BOOL)shouldUseLiveIdenfitier;
- (void)configureJMC;
@end
@implementation BITHockeyManager
@synthesize crashManager = _crashManager;
@synthesize updateManager = _updateManager;
@synthesize isAppStoreEnvironment = _isAppStoreEnvironment;
#pragma mark - Public Class Methods
+ (BITHockeyManager *)sharedHockeyManager {
static BITHockeyManager *sharedInstance = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
sharedInstance = [BITHockeyManager alloc];
sharedInstance = [sharedInstance init];
});
return sharedInstance;
}
- (id) init {
if ((self = [super init])) {
_isAppStoreEnvironment = NO;
_startManagerIsInvoked = NO;
[self performSelector:@selector(validateStartManagerIsInvoked) withObject:nil afterDelay:0.0f];
}
return self;
}
- (void)dealloc {
[_appIdentifier release], _appIdentifier = nil;
[_crashManager release], _crashManager = nil;
[_updateManager release], _updateManager = nil;
delegate = nil;
[super dealloc];
}
#pragma mark - Public Instance Methods (Configuration)
- (void)configureWithIdentifier:(NSString *)newAppIdentifier delegate:(id)newDelegate {
delegate = newDelegate;
[_appIdentifier release];
_appIdentifier = [newAppIdentifier copy];
[self initializeModules];
}
- (void)configureWithBetaIdentifier:(NSString *)betaIdentifier liveIdentifier:(NSString *)liveIdentifier delegate:(id)newDelegate {
delegate = newDelegate;
[_appIdentifier release];
if ([self shouldUseLiveIdenfitier]) {
_appIdentifier = [liveIdentifier copy];
}
else {
_appIdentifier = [betaIdentifier copy];
}
[self initializeModules];
}
- (void)startManager {
BITHockeySDKLog(@"Starting HockeyManager");
_startManagerIsInvoked = YES;
// start CrashManager
BITHockeySDKLog(@"Start crashManager");
[_crashManager performSelector:@selector(startManager) withObject:nil afterDelay:1.0f];
// Setup UpdateManager
BITHockeySDKLog(@"Start UpdateManager");
[_updateManager performSelector:@selector(startManager) withObject:nil afterDelay:0.0f];
}
- (void)validateStartManagerIsInvoked {
if (_validAppIdentifier && !_isAppStoreEnvironment) {
if (!_startManagerIsInvoked) {
NSLog(@"ERROR: You did not call [[BITHockeyManager sharedHockeyManager] startManager] to startup the HockeySDK! Please do so after setting up all properties. The SDK is NOT running.");
}
}
}
#pragma mark - Private Instance Methods
- (BOOL)shouldUseLiveIdenfitier {
BOOL delegateResult = NO;
if ([delegate respondsToSelector:@selector(shouldUseLiveIdenfitier)]) {
delegateResult = [(NSObject <BITHockeyManagerDelegate>*)delegate shouldUseLiveIdenfitier];
}
return (delegateResult) || (_isAppStoreEnvironment);
}
- (void)initializeModules {
NSCharacterSet *hexSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789abcdef"];
NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:_appIdentifier];
_validAppIdentifier = ([_appIdentifier length] == 32) && ([hexSet isSupersetOfSet:inStringSet]);
// check if we are really not in an app store environment
if ([[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]) {
_isAppStoreEnvironment = NO;
} else {
_isAppStoreEnvironment = YES;
}
#if TARGET_IPHONE_SIMULATOR
_isAppStoreEnvironment = NO;
#endif
_startManagerIsInvoked = NO;
if (_validAppIdentifier) {
BITHockeySDKLog(@"Setup CrashManager");
self.crashManager = [[[BITCrashManager alloc] initWithAppIdentifier:_appIdentifier] autorelease];
BITHockeySDKLog(@"Setup UpdateManager");
self.updateManager = [[[BITUpdateManager alloc] initWithAppIdentifier:_appIdentifier isAppStoreEnvironemt:_isAppStoreEnvironment] autorelease];
// Only if JMC is part of the project
if ([[self class] isJMCPresent]) {
BITHockeySDKLog(@"Setup JMC");
[_updateManager setCheckForTracker:YES];
[_updateManager addObserver:self forKeyPath:@"trackerConfig" options:0 context:nil];
[[self class] disableJMCCrashReporter];
[self performSelector:@selector(configureJMC) withObject:nil afterDelay:0];
}
} else {
NSLog(@"ERROR: The app identifier is invalid! Please use the HockeyApp app identifier you find on the apps website on HockeyApp! The SDK is disabled!");
}
}
#pragma mark - JMC
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
+ (id)jmcInstance {
id jmcClass = NSClassFromString(@"JMC");
if ((jmcClass) && ([jmcClass respondsToSelector:@selector(sharedInstance)])) {
return [jmcClass performSelector:@selector(sharedInstance)];
}
#ifdef JMC_LEGACY
else if ((jmcClass) && ([jmcClass respondsToSelector:@selector(instance)])) {
return [jmcClass performSelector:@selector(instance)]; // legacy pre (JMC 1.0.11) support
}
#endif
return nil;
}
#pragma clang diagnostic pop
+ (BOOL)isJMCActive {
id jmcInstance = [self jmcInstance];
return (jmcInstance) && ([jmcInstance performSelector:@selector(url)]);
}
+ (BOOL)isJMCPresent {
return [self jmcInstance] != nil;
}
#pragma mark - Private Class Methods
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
+ (void)disableJMCCrashReporter {
id jmcInstance = [self jmcInstance];
id jmcOptions = [jmcInstance performSelector:@selector(options)];
SEL crashReporterSelector = @selector(setCrashReportingEnabled:);
BOOL value = NO;
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[jmcOptions methodSignatureForSelector:crashReporterSelector]];
invocation.target = jmcOptions;
invocation.selector = crashReporterSelector;
[invocation setArgument:&value atIndex:2];
[invocation invoke];
}
#pragma clang diagnostic pop
+ (BOOL)checkJMCConfiguration:(NSDictionary *)configuration {
return (([configuration isKindOfClass:[NSDictionary class]]) &&
([[configuration valueForKey:@"enabled"] boolValue]) &&
([[configuration valueForKey:@"url"] length] > 0) &&
([[configuration valueForKey:@"key"] length] > 0) &&
([[configuration valueForKey:@"project"] length] > 0));
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
+ (void)applyJMCConfiguration:(NSDictionary *)configuration {
id jmcInstance = [self jmcInstance];
SEL configureSelector = @selector(configureJiraConnect:projectKey:apiKey:);
NSString *url = [configuration valueForKey:@"url"];
NSString *project = [configuration valueForKey:@"project"];
NSString *key = [configuration valueForKey:@"key"];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[jmcInstance methodSignatureForSelector:configureSelector]];
invocation.target = jmcInstance;
invocation.selector = configureSelector;
[invocation setArgument:&url atIndex:2];
[invocation setArgument:&project atIndex:3];
[invocation setArgument:&key atIndex:4];
[invocation invoke];
if ([jmcInstance respondsToSelector:@selector(ping)]) {
[jmcInstance performSelector:@selector(ping)];
}
}
#pragma clang diagnostic pop
- (void)configureJMC {
// Return if JMC is already configured
if ([[self class] isJMCActive]) {
return;
}
// Configure JMC from user defaults
NSDictionary *configurations = [[NSUserDefaults standardUserDefaults] valueForKey:@"BITTrackerConfigurations"];
NSDictionary *configuration = [configurations valueForKey:_appIdentifier];
if ([[self class] checkJMCConfiguration:configuration]) {
[[self class] applyJMCConfiguration:configuration];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (([object trackerConfig]) && ([[object trackerConfig] isKindOfClass:[NSDictionary class]])) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *trackerConfig = [[defaults valueForKey:@"BITTrackerConfigurations"] mutableCopy];
if (!trackerConfig) {
trackerConfig = [[NSMutableDictionary dictionaryWithCapacity:1] retain];
}
[trackerConfig setValue:[object trackerConfig] forKey:_appIdentifier];
[defaults setValue:trackerConfig forKey:@"BITTrackerConfigurations"];
[trackerConfig release];
[defaults synchronize];
[self configureJMC];
}
}
@end

View File

@ -0,0 +1,41 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
*
* Copyright (c) 2012 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 <Foundation/Foundation.h>
@protocol BITHockeyManagerDelegate <NSObject>
@optional
// Invoked when the manager is configured
//
// Implement to force the usage of the live identifier, e.g. for enterprise apps
// which are distributed inside your company
- (BOOL)shouldUseLiveIdenfitier;
@end

194
Classes/BITUpdateManager.h Normal file
View File

@ -0,0 +1,194 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
* Peter Steinberger
*
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* Copyright (c) 2011 Andreas Linde.
* 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 <UIKit/UIKit.h>
typedef enum {
BITUpdateComparisonResultDifferent,
BITUpdateComparisonResultGreater
} BITUpdateComparisonResult;
typedef enum {
BITUpdateAuthorizationDenied,
BITUpdateAuthorizationAllowed,
BITUpdateAuthorizationPending
} BITUpdateAuthorizationState;
typedef enum {
BITUpdateCheckStartup = 0,
BITUpdateCheckDaily = 1,
BITUpdateCheckManually = 2
} BITUpdateSetting;
@protocol BITUpdateManagerDelegate;
@class BITAppVersionMetaInfo;
@class BITUpdateViewController;
@interface BITUpdateManager : NSObject <UIAlertViewDelegate> {
NSString *_appIdentifier;
NSString *_currentAppVersion;
UINavigationController *_navController;
BITUpdateViewController *_currentHockeyViewController;
BOOL _dataFound;
BOOL _showFeedback;
BOOL _updateURLOffline;
BOOL _updateAlertShowing;
BOOL _lastCheckFailed;
BOOL _isAppStoreEnvironment;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Setting Properties
// delegate is optional
@property (nonatomic, assign) id <BITUpdateManagerDelegate> delegate;
// hockey secret is required if authentication is used
@property (nonatomic, retain) NSString *authenticationSecret;
// if YES, the current user data is send: device type, iOS version, app version, UDID (default)
// if NO, no such data is send to the server
@property (nonatomic, assign, getter=shouldSendUserData) BOOL sendUserData;
// if YES, the the users usage time of the app to the service, only in 1 minute granularity! (default)
// if NO, no such data is send to the server
@property (nonatomic, assign, getter=shouldSendUsageTime) BOOL sendUsageTime;
// if YES, the user agrees to send the usage data, user can change it if the developer shows the settings (default)
// if NO, the user overwrites the developer setting and no such data is sent
@property (nonatomic, assign, getter=isAllowUserToDisableSendData) BOOL allowUserToDisableSendData;
// if YES, the user allowed to send user data (default)
// if NO, the user denied to send user data
@property (nonatomic, assign, getter=doesUserAllowsSendUserData) BOOL userAllowsSendUserData;
// if YES, the user allowed to send usage data (default)
// if NO, the user denied to send usage data
@property (nonatomic, assign, getter=doesUserAllowsSendUsageTime) BOOL userAllowsSendUsageTime;
// if YES, the new version alert will be displayed always if the current version is outdated (default)
// if NO, the alert will be displayed only once for each new update
@property (nonatomic, assign) BOOL alwaysShowUpdateReminder;
// if YES, the user can change the HockeyUpdateSetting value (default)
// if NO, the user can not change it, and the default or developer defined value will be used
@property (nonatomic, assign, getter=shouldShowUserSettings) BOOL showUserSettings;
// set bar style of navigation controller
@property (nonatomic, assign) UIBarStyle barStyle;
// set modal presentation style of update view
@property (nonatomic, assign) UIModalPresentationStyle modalPresentationStyle;
// if YES, then an update check will be performed after the application becomes active (default)
// if NO, then the update check will not happen unless invoked explicitly
@property (nonatomic, assign, getter=isCheckForUpdateOnLaunch) BOOL checkForUpdateOnLaunch;
// if YES, the alert notifying about an new update also shows a button to install the update directly
// if NO, the alert notifying about an new update only shows ignore and show update button
@property (nonatomic, assign, getter=isShowingDirectInstallOption) BOOL showDirectInstallOption;
// if YES, each app version needs to be authorized by the server to run on this device
// if NO, each app version does not need to be authorized (default)
@property (nonatomic, assign, getter=isRequireAuthorization) BOOL requireAuthorization;
// HockeyComparisonResultDifferent: alerts if the version on the server is different (default)
// HockeyComparisonResultGreater: alerts if the version on the server is greater
@property (nonatomic, assign) BITUpdateComparisonResult compareVersionType;
// see HockeyUpdateSetting-enum. Will be saved in user defaults.
// default value: HockeyUpdateCheckStartup
@property (nonatomic, assign) BITUpdateSetting updateSetting;
///////////////////////////////////////////////////////////////////////////////////////////////////
// Private Properties
// if YES, the API will return an existing JMC config
// if NO, the API will return only version information
@property (nonatomic, assign) BOOL checkForTracker;
// Contains the tracker config if received from server
@property (nonatomic, retain, readonly) NSDictionary *trackerConfig;
- (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment;
- (void)startManager;
// is an update available?
- (BOOL)isUpdateAvailable;
// are we currently checking for updates?
- (BOOL)isCheckInProgress;
// open update info view
- (void)showUpdateView;
// manually start an update check
- (void)checkForUpdate;
// checks for update, informs the user (error, no update found, etc)
- (void)checkForUpdateShowFeedback:(BOOL)feedback;
// initiates app-download call. displays an system UIAlertView
- (BOOL)initiateAppDownload;
// checks wether this app version is authorized
- (BOOL)appVersionIsAuthorized;
// start checking for an authorization key
- (void)checkForAuthorization;
// convenience methode to create hockey view controller
- (BITUpdateViewController *)hockeyViewController:(BOOL)modal;
// get/set current active hockey view controller
@property (nonatomic, retain) BITUpdateViewController *currentHockeyViewController;
// convenience method to get current running version string
- (NSString *)currentAppVersion;
// get newest app version
- (BITAppVersionMetaInfo *)newestAppVersion;
// get array of all available versions
- (NSArray *)appVersions;
// check if there is any newer version mandatory
- (BOOL)hasNewerMandatoryVersion;
@end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
*
* Copyright (c) 2012 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 <Foundation/Foundation.h>
@protocol BITUpdateManagerDelegate <NSObject>
/*
Return the device UDID which is required for beta testing, should return nil for app store configuration!
Example implementation if your configuration for the App Store is called "AppStore":
#ifndef (CONFIGURATION_AppStore)
if ([[UIDevice currentDevice] respondsToSelector:@selector(uniqueIdentifier)])
return [[UIDevice currentDevice] performSelector:@selector(uniqueIdentifier)];
#endif
return nil;
*/
- (NSString *)customDeviceIdentifierForUpdateManager:(BITUpdateManager *)updateManager;
@optional
// optional parent view controller for the update screen when invoked via the alert view, default is the root UIWindow instance
- (UIViewController *)viewControllerForUpdateManager:(BITUpdateManager *)updateManager;
@end

View File

@ -0,0 +1,42 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
*
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* Copyright (c) 2011 Andreas Linde.
* 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 <UIKit/UIKit.h>
@class BITUpdateManager;
@interface BITUpdateSettingsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
}
@property (nonatomic, retain) BITUpdateManager *updateManager;
- (id)init:(BITUpdateManager *)newUpdateManager;
- (id)init;
@end

View File

@ -1,32 +1,54 @@
// /*
// BWHockeySettingsViewController.m * Author: Andreas Linde <mail@andreaslinde.de>
// HockeyDemo *
// * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
// Created by Andreas Linde on 3/8/11. * Copyright (c) 2011 Andreas Linde.
// Copyright 2011 Andreas Linde. All rights reserved. * 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 "BITUpdateSettingsViewController.h"
#import "HockeySDK.h"
#import "HockeySDKPrivate.h"
#import "BWHockeySettingsViewController.h"
#import "BWHockeyManager.h"
#import "BWGlobal.h"
#define BW_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] #define BW_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
@implementation BWHockeySettingsViewController @implementation BITUpdateSettingsViewController
@synthesize hockeyManager = hockeyManager_; @synthesize updateManager = _updateManager;
- (void)dismissSettings { - (void)dismissSettings {
[self.navigationController dismissModalViewControllerAnimated:YES]; [self.navigationController dismissModalViewControllerAnimated:YES];
} }
#pragma mark - #pragma mark - Initialization
#pragma mark Initialization
- (id)init:(BWHockeyManager *)newHockeyManager { - (id)init:(BITUpdateManager *)newUpdateManager {
if ((self = [super init])) { if ((self = [super init])) {
self.hockeyManager = newHockeyManager; self.updateManager = newUpdateManager;
self.title = BWHockeyLocalize(@"HockeySettingsTitle"); self.title = BITHockeySDKLocalizedString(@"UpdateSettingsTitle");
CGRect frame = self.view.frame; CGRect frame = self.view.frame;
frame.origin = CGPointZero; frame.origin = CGPointZero;
@ -34,7 +56,6 @@
UITableView *tableView_ = [[[UITableView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 260, self.view.frame.size.width, 260) style:UITableViewStyleGrouped] autorelease]; UITableView *tableView_ = [[[UITableView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 260, self.view.frame.size.width, 260) style:UITableViewStyleGrouped] autorelease];
tableView_.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth; tableView_.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
BW_IF_3_2_OR_GREATER(
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
self.view.backgroundColor = BW_RGBCOLOR(200, 202, 204); self.view.backgroundColor = BW_RGBCOLOR(200, 202, 204);
tableView_.backgroundColor = BW_RGBCOLOR(200, 202, 204); tableView_.backgroundColor = BW_RGBCOLOR(200, 202, 204);
@ -42,14 +63,6 @@
tableView_.frame = frame; tableView_.frame = frame;
tableView_.autoresizingMask = tableView_.autoresizingMask | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; tableView_.autoresizingMask = tableView_.autoresizingMask | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
} }
)
BW_IF_PRE_3_2(
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(dismissSettings)] autorelease];
tableView_.frame = frame;
tableView_.autoresizingMask = tableView_.autoresizingMask | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
)
tableView_.delegate = self; tableView_.delegate = self;
tableView_.dataSource = self; tableView_.dataSource = self;
@ -62,18 +75,18 @@
} }
- (id)init { - (id)init {
return [self init:[BWHockeyManager sharedHockeyManager]]; return [self init:[BITHockeyManager sharedHockeyManager].updateManager];
} }
#pragma mark -
#pragma mark Table view data source #pragma mark - Table view data source
- (int)numberOfSections { - (int)numberOfSections {
int numberOfSections = 1; int numberOfSections = 1;
if ([self.hockeyManager isAllowUserToDisableSendData]) { if ([_updateManager isAllowUserToDisableSendData]) {
if ([self.hockeyManager shouldSendUserData]) numberOfSections++; if ([_updateManager shouldSendUserData]) numberOfSections++;
if ([self.hockeyManager shouldSendUsageTime]) numberOfSections++; if ([_updateManager shouldSendUsageTime]) numberOfSections++;
} }
return numberOfSections; return numberOfSections;
@ -82,7 +95,7 @@
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (section == [self numberOfSections] - 1) { if (section == [self numberOfSections] - 1) {
return BWHockeyLocalize(@"HockeySectionCheckTitle"); return BITHockeySDKLocalizedString(@"UpdateSectionCheckTitle");
} else { } else {
return nil; return nil;
} }
@ -106,10 +119,10 @@
footer.textColor = [UIColor grayColor]; footer.textColor = [UIColor grayColor];
footer.font = [UIFont systemFontOfSize:13]; footer.font = [UIFont systemFontOfSize:13];
if (section == 0 && [self.hockeyManager isAllowUserToDisableSendData] && [self.hockeyManager shouldSendUserData]) { if (section == 0 && [_updateManager isAllowUserToDisableSendData] && [_updateManager shouldSendUserData]) {
footer.text = BWHockeyLocalize(@"HockeySettingsUserDataDescription"); footer.text = BITHockeySDKLocalizedString(@"UpdateSettingsUserDataDescription");
} else if ([self.hockeyManager isAllowUserToDisableSendData] && section < [self numberOfSections]) { } else if ([_updateManager isAllowUserToDisableSendData] && section < [self numberOfSections]) {
footer.text = BWHockeyLocalize(@"HockeySettingsUsageDataDescription"); footer.text = BITHockeySDKLocalizedString(@"UpdateSettingsUsageDataDescription");
} }
UIView* view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 285, footer.frame.size.height + 6 + 11)] autorelease]; UIView* view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 285, footer.frame.size.height + 6 + 11)] autorelease];
@ -147,11 +160,11 @@
- (void)sendUserData:(UISwitch *)switcher { - (void)sendUserData:(UISwitch *)switcher {
[self.hockeyManager setUserAllowsSendUserData:switcher.on]; [_updateManager setUserAllowsSendUserData:switcher.on];
} }
- (void)sendUsageData:(UISwitch *)switcher { - (void)sendUsageData:(UISwitch *)switcher {
[self.hockeyManager setUserAllowsSendUsageTime:switcher.on]; [_updateManager setUserAllowsSendUsageTime:switcher.on];
} }
@ -185,42 +198,42 @@
cell.selectionStyle = UITableViewCellSelectionStyleBlue; cell.selectionStyle = UITableViewCellSelectionStyleBlue;
// update check selection // update check selection
HockeyUpdateSetting hockeyAutoUpdateSetting = [[BWHockeyManager sharedHockeyManager] updateSetting]; BITUpdateSetting hockeyAutoUpdateSetting = [_updateManager updateSetting];
if (indexPath.row == 0) { if (indexPath.row == 0) {
// on startup // on startup
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckStartup"); cell.textLabel.text = BITHockeySDKLocalizedString(@"UpdateSectionCheckStartup");
if (hockeyAutoUpdateSetting == HockeyUpdateCheckStartup) { if (hockeyAutoUpdateSetting == BITUpdateCheckStartup) {
cell.accessoryType = UITableViewCellAccessoryCheckmark; cell.accessoryType = UITableViewCellAccessoryCheckmark;
} }
} else if (indexPath.row == 1) { } else if (indexPath.row == 1) {
// daily // daily
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckDaily"); cell.textLabel.text = BITHockeySDKLocalizedString(@"UpdateSectionCheckDaily");
if (hockeyAutoUpdateSetting == HockeyUpdateCheckDaily) { if (hockeyAutoUpdateSetting == BITUpdateCheckDaily) {
cell.accessoryType = UITableViewCellAccessoryCheckmark; cell.accessoryType = UITableViewCellAccessoryCheckmark;
} }
} else { } else {
// manually // manually
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckManually"); cell.textLabel.text = BITHockeySDKLocalizedString(@"UpdateSectionCheckManually");
if (hockeyAutoUpdateSetting == HockeyUpdateCheckManually) { if (hockeyAutoUpdateSetting == BITUpdateCheckManually) {
cell.accessoryType = UITableViewCellAccessoryCheckmark; cell.accessoryType = UITableViewCellAccessoryCheckmark;
} }
} }
} else { } else {
UISwitch *toggleSwitch = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease]; UISwitch *toggleSwitch = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
if (indexPath.section == 0 && [self.hockeyManager shouldSendUserData] && [self.hockeyManager isAllowUserToDisableSendData]) { if (indexPath.section == 0 && [_updateManager shouldSendUserData] && [_updateManager isAllowUserToDisableSendData]) {
// send user data // send user data
cell.textLabel.text = BWHockeyLocalize(@"HockeySettingsUserData"); cell.textLabel.text = BITHockeySDKLocalizedString(@"UpdateSettingsUserData");
[toggleSwitch addTarget:self action:@selector(sendUserData:) [toggleSwitch addTarget:self action:@selector(sendUserData:)
forControlEvents:UIControlEventValueChanged]; forControlEvents:UIControlEventValueChanged];
[toggleSwitch setOn:[self.hockeyManager doesUserAllowsSendUserData]]; [toggleSwitch setOn:[_updateManager doesUserAllowsSendUserData]];
} else if ([self.hockeyManager shouldSendUsageTime] && [self.hockeyManager isAllowUserToDisableSendData]) { } else if ([_updateManager shouldSendUsageTime] && [_updateManager isAllowUserToDisableSendData]) {
// send usage time // send usage time
cell.textLabel.text = BWHockeyLocalize(@"HockeySettingsUsageData"); cell.textLabel.text = BITHockeySDKLocalizedString(@"UpdateSettingsUsageData");
[toggleSwitch addTarget:self action:@selector(sendUsageData:) [toggleSwitch addTarget:self action:@selector(sendUsageData:)
forControlEvents:UIControlEventValueChanged]; forControlEvents:UIControlEventValueChanged];
[toggleSwitch setOn:[self.hockeyManager doesUserAllowsSendUsageTime]]; [toggleSwitch setOn:[_updateManager doesUserAllowsSendUsageTime]];
} }
cell.accessoryView = toggleSwitch; cell.accessoryView = toggleSwitch;
@ -231,8 +244,7 @@
} }
#pragma mark - #pragma mark - Table view delegate
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES];
@ -240,43 +252,29 @@
// update check interval selection // update check interval selection
if (indexPath.row == 0) { if (indexPath.row == 0) {
// on startup // on startup
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckStartup; _updateManager.updateSetting = BITUpdateCheckStartup;
} else if (indexPath.row == 1) { } else if (indexPath.row == 1) {
// daily // daily
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckDaily; _updateManager.updateSetting = BITUpdateCheckDaily;
} else { } else {
// manually // manually
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckManually; _updateManager.updateSetting = BITUpdateCheckManually;
} }
[tableView reloadData]; [tableView reloadData];
} }
#pragma mark - #pragma mark - Memory management
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc { - (void)dealloc {
[_updateManager release];
[super dealloc]; [super dealloc];
} }
/////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - Rotation
#pragma mark -
#pragma mark Rotation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
BOOL shouldAutorotate; BOOL shouldAutorotate;

View File

@ -0,0 +1,66 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
* Peter Steinberger
*
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* Copyright (c) 2011 Andreas Linde, Peter Steinberger.
* 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 <UIKit/UIKit.h>
@class PSStoreButton;
@class PSAppStoreHeader;
@class BITUpdateManager;
typedef enum {
AppStoreButtonStateOffline,
AppStoreButtonStateCheck,
AppStoreButtonStateSearching,
AppStoreButtonStateUpdate,
AppStoreButtonStateInstalling
} AppStoreButtonState;
@interface BITUpdateViewController : UITableViewController {
BOOL _kvoRegistered;
BOOL _showAllVersions;
UIStatusBarStyle _statusBarStyle;
PSAppStoreHeader *_appStoreHeader;
PSStoreButton *_appStoreButton;
id _popOverController;
NSMutableArray *_cells;
BOOL _isAppStoreEnvironment;
}
@property (nonatomic, retain) BITUpdateManager *updateManager;
@property (nonatomic, readwrite) BOOL modal;
@property (nonatomic, readwrite) BOOL modalAnimated;
- (id)init:(BITUpdateManager *)newUpdateManager modal:(BOOL)newModal;
- (id)init;
@end

View File

@ -1,42 +1,51 @@
// /*
// BWHockeyViewController.m * Author: Andreas Linde <mail@andreaslinde.de>
// * Peter Steinberger
// Created by Andreas Linde on 8/17/10. *
// Copyright 2010-2011 Andreas Linde, Peter Steinberger. All rights reserved. * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
// * Copyright (c) 2011 Andreas Linde, Peter Steinberger.
// Permission is hereby granted, free of charge, to any person obtaining a copy * All rights reserved.
// of this software and associated documentation files (the "Software"), to deal *
// in the Software without restriction, including without limitation the rights * Permission is hereby granted, free of charge, to any person
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * obtaining a copy of this software and associated documentation
// copies of the Software, and to permit persons to whom the Software is * files (the "Software"), to deal in the Software without
// furnished to do so, subject to the following conditions: * restriction, including without limitation the rights to use,
// * copy, modify, merge, publish, distribute, sublicense, and/or sell
// The above copyright notice and this permission notice shall be included in * copies of the Software, and to permit persons to whom the
// all copies or substantial portions of the Software. * Software is furnished to do so, subject to the following
// * conditions:
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * The above copyright notice and this permission notice shall be
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * included in all copies or substantial portions of the Software.
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// THE SOFTWARE. * 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 <QuartzCore/QuartzCore.h> #import <QuartzCore/QuartzCore.h>
#import "NSString+HockeyAdditions.h" #import "NSString+BITHockeyAdditions.h"
#import "BWHockeyViewController.h" #import "BITAppVersionMetaInfo.h"
#import "BWHockeyManager.h" #import "UIImage+BITHockeyAdditions.h"
#import "BWGlobal.h"
#import "UIImage+HockeyAdditions.h"
#import "PSAppStoreHeader.h" #import "PSAppStoreHeader.h"
#import "PSWebTableViewCell.h" #import "PSWebTableViewCell.h"
#import "BWHockeySettingsViewController.h" #import "BITUpdateSettingsViewController.h"
#import "PSStoreButton.h"
#define BW_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] #import "HockeySDK.h"
#import "HockeySDKPrivate.h"
#define BIT_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
#define kWebCellIdentifier @"PSWebTableViewCell" #define kWebCellIdentifier @"PSWebTableViewCell"
#define kAppStoreViewHeight 90 #define kAppStoreViewHeight 90
@interface BWHockeyViewController () @interface BITUpdateViewController()<PSStoreButtonDelegate>
// updates the whole view // updates the whole view
- (void)showPreviousVersionAction; - (void)showPreviousVersionAction;
- (void)redrawTableView; - (void)redrawTableView;
@ -45,89 +54,78 @@
@end @end
@implementation BWHockeyViewController @implementation BITUpdateViewController
@synthesize appStoreButtonState = appStoreButtonState_; @synthesize appStoreButtonState = appStoreButtonState_;
@synthesize hockeyManager = hockeyManager_; @synthesize modal = _modal;
@synthesize modal = modal_; @synthesize modalAnimated = _modalAnimated;
@synthesize modalAnimated = modalAnimated_;
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark private
- (void)restoreStoreButtonStateAnimated_:(BOOL)animated { #pragma mark - Private
if ([self.hockeyManager isAppStoreEnvironment]) {
- (void)restoreStoreButtonStateAnimated:(BOOL)animated {
if (_isAppStoreEnvironment) {
[self setAppStoreButtonState:AppStoreButtonStateOffline animated:animated]; [self setAppStoreButtonState:AppStoreButtonStateOffline animated:animated];
} else if ([self.hockeyManager isUpdateAvailable]) { } else if ([_updateManager isUpdateAvailable]) {
[self setAppStoreButtonState:AppStoreButtonStateUpdate animated:animated]; [self setAppStoreButtonState:AppStoreButtonStateUpdate animated:animated];
} else { } else {
[self setAppStoreButtonState:AppStoreButtonStateCheck animated:animated]; [self setAppStoreButtonState:AppStoreButtonStateCheck animated:animated];
} }
} }
- (void)updateAppStoreHeader_ { - (void)updateAppStoreHeader {
BWApp *app = self.hockeyManager.app; BITAppVersionMetaInfo *appVersion = _updateManager.newestAppVersion;
appStoreHeader_.headerLabel = app.name; _appStoreHeader.headerLabel = appVersion.name;
appStoreHeader_.middleHeaderLabel = [app versionString]; _appStoreHeader.middleHeaderLabel = [appVersion versionString];
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease]; NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateStyle:NSDateFormatterMediumStyle]; [formatter setDateStyle:NSDateFormatterMediumStyle];
NSMutableString *subHeaderString = [NSMutableString string]; NSMutableString *subHeaderString = [NSMutableString string];
if (app.date) { if (appVersion.date) {
[subHeaderString appendString:[formatter stringFromDate:app.date]]; [subHeaderString appendString:[formatter stringFromDate:appVersion.date]];
} }
if (app.size) { if (appVersion.size) {
if ([subHeaderString length]) { if ([subHeaderString length]) {
[subHeaderString appendString:@" - "]; [subHeaderString appendString:@" - "];
} }
[subHeaderString appendString:app.sizeInMB]; [subHeaderString appendString:appVersion.sizeInMB];
} }
appStoreHeader_.subHeaderLabel = subHeaderString; _appStoreHeader.subHeaderLabel = subHeaderString;
} }
- (void)appDidBecomeActive_ { - (void)appDidBecomeActive_ {
if (self.appStoreButtonState == AppStoreButtonStateInstalling) { if (self.appStoreButtonState == AppStoreButtonStateInstalling) {
[self setAppStoreButtonState:AppStoreButtonStateUpdate animated:YES]; [self setAppStoreButtonState:AppStoreButtonStateUpdate animated:YES];
} else if (![self.hockeyManager isCheckInProgress]) { } else if (![_updateManager isCheckInProgress]) {
[self restoreStoreButtonStateAnimated_:YES]; [self restoreStoreButtonStateAnimated:YES];
} }
} }
- (void)openSettings:(id)sender { - (void)openSettings:(id)sender {
BWHockeySettingsViewController *settings = [[[BWHockeySettingsViewController alloc] init] autorelease]; BITUpdateSettingsViewController *settings = [[[BITUpdateSettingsViewController alloc] init] autorelease];
Class popoverControllerClass = NSClassFromString(@"UIPopoverController"); Class popoverControllerClass = NSClassFromString(@"UIPopoverController");
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && popoverControllerClass) { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && popoverControllerClass) {
if (popOverController_ == nil) { if (_popOverController == nil) {
popOverController_ = [[popoverControllerClass alloc] initWithContentViewController:settings]; _popOverController = [[popoverControllerClass alloc] initWithContentViewController:settings];
} }
if ([popOverController_ contentViewController].view.window) { if ([_popOverController contentViewController].view.window) {
[popOverController_ dismissPopoverAnimated:YES]; [_popOverController dismissPopoverAnimated:YES];
}else { }else {
[popOverController_ setPopoverContentSize: CGSizeMake(320, 440)]; [_popOverController setPopoverContentSize: CGSizeMake(320, 440)];
[popOverController_ presentPopoverFromBarButtonItem:self.navigationItem.rightBarButtonItem [_popOverController presentPopoverFromBarButtonItem:self.navigationItem.rightBarButtonItem
permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES]; permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
} }
} else { } else {
BW_IF_3_2_OR_GREATER(
settings.modalTransitionStyle = UIModalTransitionStylePartialCurl; settings.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentModalViewController:settings animated:YES]; [self presentModalViewController:settings animated:YES];
)
BW_IF_PRE_3_2(
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:settings] autorelease];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:navController animated:YES];
)
} }
} }
- (UIImage *)addGlossToImage_:(UIImage *)image { - (UIImage *)addGlossToImage:(UIImage *)image {
BW_IF_IOS4_OR_GREATER(UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);) UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
BW_IF_PRE_IOS4(UIGraphicsBeginImageContext(image.size);)
[image drawAtPoint:CGPointZero]; [image drawAtPoint:CGPointZero];
UIImage *iconGradient = [UIImage bw_imageNamed:@"IconGradient.png" bundle:kHockeyBundleName]; UIImage *iconGradient = [UIImage bit_imageNamed:@"IconGradient.png" bundle:BITHOCKEYSDK_BUNDLE];
[iconGradient drawInRect:CGRectMake(0, 0, image.size.width, image.size.height) blendMode:kCGBlendModeNormal alpha:0.5]; [iconGradient drawInRect:CGRectMake(0, 0, image.size.width, image.size.height) blendMode:kCGBlendModeNormal alpha:0.5];
UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
@ -161,64 +159,62 @@
} }
- (void)changePreviousVersionButtonBackground:(id)sender { - (void)changePreviousVersionButtonBackground:(id)sender {
[(UIButton *)sender setBackgroundColor:BW_RGBCOLOR(183,183,183)]; [(UIButton *)sender setBackgroundColor:BIT_RGBCOLOR(183,183,183)];
} }
- (void)changePreviousVersionButtonBackgroundHighlighted:(id)sender { - (void)changePreviousVersionButtonBackgroundHighlighted:(id)sender {
[(UIButton *)sender setBackgroundColor:BW_RGBCOLOR(183,183,183)]; [(UIButton *)sender setBackgroundColor:BIT_RGBCOLOR(183,183,183)];
} }
- (void)showHidePreviousVersionsButton { - (void)showHidePreviousVersionsButton {
BOOL multipleVersionButtonNeeded = [self.hockeyManager.apps count] > 1 && !showAllVersions_; BOOL multipleVersionButtonNeeded = [_updateManager.appVersions count] > 1 && !_showAllVersions;
if(multipleVersionButtonNeeded) { if(multipleVersionButtonNeeded) {
// align at the bottom if tableview is small // align at the bottom if tableview is small
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kMinPreviousVersionButtonHeight)]; UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kMinPreviousVersionButtonHeight)];
footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth; footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
footerView.backgroundColor = BW_RGBCOLOR(200, 202, 204); footerView.backgroundColor = BIT_RGBCOLOR(200, 202, 204);
UIButton *footerButton = [UIButton buttonWithType:UIButtonTypeCustom]; UIButton *footerButton = [UIButton buttonWithType:UIButtonTypeCustom];
BW_IF_IOS4_OR_GREATER(
//footerButton.layer.shadowOffset = CGSizeMake(-2, 2); //footerButton.layer.shadowOffset = CGSizeMake(-2, 2);
footerButton.layer.shadowColor = [[UIColor blackColor] CGColor]; footerButton.layer.shadowColor = [[UIColor blackColor] CGColor];
footerButton.layer.shadowRadius = 2.0f; footerButton.layer.shadowRadius = 2.0f;
)
footerButton.titleLabel.font = [UIFont boldSystemFontOfSize:14]; footerButton.titleLabel.font = [UIFont boldSystemFontOfSize:14];
[footerButton setTitle:BWHockeyLocalize(@"HockeyShowPreviousVersions") forState:UIControlStateNormal]; [footerButton setTitle:BITHockeySDKLocalizedString(@"UpdateShowPreviousVersions") forState:UIControlStateNormal];
[footerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [footerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[footerButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; [footerButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
[footerButton setBackgroundImage:[UIImage bw_imageNamed:@"buttonHighlight.png" bundle:kHockeyBundleName] forState:UIControlStateHighlighted]; [footerButton setBackgroundImage:[UIImage bit_imageNamed:@"buttonHighlight.png" bundle:BITHOCKEYSDK_BUNDLE] forState:UIControlStateHighlighted];
footerButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; footerButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
[footerButton addTarget:self action:@selector(showPreviousVersionAction) forControlEvents:UIControlEventTouchUpInside]; [footerButton addTarget:self action:@selector(showPreviousVersionAction) forControlEvents:UIControlEventTouchUpInside];
footerButton.frame = CGRectMake(0, kMinPreviousVersionButtonHeight-44, self.view.frame.size.width, 44); footerButton.frame = CGRectMake(0, kMinPreviousVersionButtonHeight-44, self.view.frame.size.width, 44);
footerButton.backgroundColor = BW_RGBCOLOR(183,183,183); footerButton.backgroundColor = BIT_RGBCOLOR(183,183,183);
[footerView addSubview:footerButton]; [footerView addSubview:footerButton];
self.tableView.tableFooterView = footerView; self.tableView.tableFooterView = footerView;
[self realignPreviousVersionButton]; [self realignPreviousVersionButton];
[footerView release]; [footerView release];
} else { } else {
self.tableView.tableFooterView = nil; self.tableView.tableFooterView = nil;
self.tableView.backgroundColor = BW_RGBCOLOR(200, 202, 204); self.tableView.backgroundColor = BIT_RGBCOLOR(200, 202, 204);
} }
} }
- (void)configureWebCell:(PSWebTableViewCell *)cell forApp_:(BWApp *)app { - (void)configureWebCell:(PSWebTableViewCell *)cell forAppVersion:(BITAppVersionMetaInfo *)appVersion {
// create web view for a version // create web view for a version
NSString *installed = @""; NSString *installed = @"";
if ([app.version isEqualToString:[self.hockeyManager currentAppVersion]]) { if ([appVersion.version isEqualToString:[_updateManager currentAppVersion]]) {
installed = [NSString stringWithFormat:@"<span style=\"float:%@;text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\"><b>%@</b></span>", [app isEqual:self.hockeyManager.app] ? @"left" : @"right", BWHockeyLocalize(@"HockeyInstalled")]; installed = [NSString stringWithFormat:@"<span style=\"float:%@;text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\"><b>%@</b></span>", [appVersion isEqual:_updateManager.newestAppVersion] ? @"left" : @"right", BITHockeySDKLocalizedString(@"UpdateInstalled")];
} }
if ([app isEqual:self.hockeyManager.app]) { if ([appVersion isEqual:_updateManager.newestAppVersion]) {
if ([app.notes length] > 0) { if ([appVersion.notes length] > 0) {
installed = [NSString stringWithFormat:@"<p>&nbsp;%@</p>", installed]; installed = [NSString stringWithFormat:@"<p>&nbsp;%@</p>", installed];
cell.webViewContent = [NSString stringWithFormat:@"%@%@", installed, app.notes]; cell.webViewContent = [NSString stringWithFormat:@"%@%@", installed, appVersion.notes];
} else { } else {
cell.webViewContent = [NSString stringWithFormat:@"<div style=\"min-height:200px;vertical-align:middle;text-align:center;text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\">%@</div>", BWHockeyLocalize(@"HockeyNoReleaseNotesAvailable")]; cell.webViewContent = [NSString stringWithFormat:@"<div style=\"min-height:200px;vertical-align:middle;text-align:center;text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\">%@</div>", BITHockeySDKLocalizedString(@"UpdateNoReleaseNotesAvailable")];
} }
} else { } else {
cell.webViewContent = [NSString stringWithFormat:@"<p><b style=\"text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\">%@</b>%@<br/><small>%@</small></p><p>%@</p>", [app versionString], installed, [app dateString], [app notesOrEmptyString]]; cell.webViewContent = [NSString stringWithFormat:@"<p><b style=\"text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\">%@</b>%@<br/><small>%@</small></p><p>%@</p>", [appVersion versionString], installed, [appVersion dateString], [appVersion notesOrEmptyString]];
} }
cell.cellBackgroundColor = BW_RGBCOLOR(200, 202, 204); cell.cellBackgroundColor = BIT_RGBCOLOR(200, 202, 204);
[cell addWebView]; [cell addWebView];
// hack // hack
@ -227,47 +223,46 @@
[cell addObserver:self forKeyPath:@"webViewSize" options:0 context:nil]; [cell addObserver:self forKeyPath:@"webViewSize" options:0 context:nil];
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark NSObject
- (id)init:(BWHockeyManager *)newHockeyManager modal:(BOOL)newModal { #pragma mark - Init
- (id)init:(BITUpdateManager *)newUpdateManager modal:(BOOL)newModal {
if ((self = [super initWithStyle:UITableViewStylePlain])) { if ((self = [super initWithStyle:UITableViewStylePlain])) {
self.hockeyManager = newHockeyManager; self.updateManager = newUpdateManager;
self.modal = newModal; self.modal = newModal;
self.modalAnimated = YES; self.modalAnimated = YES;
self.title = BWHockeyLocalize(@"HockeyUpdateScreenTitle"); self.title = BITHockeySDKLocalizedString(@"UpdateScreenTitle");
if ([self.hockeyManager shouldShowUserSettings]) { _isAppStoreEnvironment = [BITHockeyManager sharedHockeyManager].isAppStoreEnvironment;
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithImage:[UIImage bw_imageNamed:@"gear.png" bundle:kHockeyBundleName]
if ([_updateManager shouldShowUserSettings]) {
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithImage:[UIImage bit_imageNamed:@"gear.png" bundle:BITHOCKEYSDK_BUNDLE]
style:UIBarButtonItemStyleBordered style:UIBarButtonItemStyleBordered
target:self target:self
action:@selector(openSettings:)] autorelease]; action:@selector(openSettings:)] autorelease];
} }
cells_ = [[NSMutableArray alloc] initWithCapacity:5]; _cells = [[NSMutableArray alloc] initWithCapacity:5];
popOverController_ = nil; _popOverController = nil;
} }
return self; return self;
} }
- (id)init { - (id)init {
return [self init:[BWHockeyManager sharedHockeyManager] modal:NO]; return [self init:[BITHockeyManager sharedHockeyManager].updateManager modal:NO];
} }
- (void)dealloc { - (void)dealloc {
[self viewDidUnload]; [self viewDidUnload];
for (UITableViewCell *cell in cells_) { for (UITableViewCell *cell in _cells) {
[cell removeObserver:self forKeyPath:@"webViewSize"]; [cell removeObserver:self forKeyPath:@"webViewSize"];
} }
[cells_ release]; [_cells release];
[super dealloc]; [super dealloc];
} }
/////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - View lifecycle
#pragma mark -
#pragma mark View lifecycle
- (void)onAction:(id)sender { - (void)onAction:(id)sender {
if (self.modal) { if (self.modal) {
@ -293,7 +288,7 @@
[self.navigationController popViewControllerAnimated:YES]; [self.navigationController popViewControllerAnimated:YES];
} }
[[UIApplication sharedApplication] setStatusBarStyle:statusBarStyle_]; [[UIApplication sharedApplication] setStatusBarStyle:_statusBarStyle];
} }
- (CAGradientLayer *)backgroundLayer { - (CAGradientLayer *)backgroundLayer {
@ -327,22 +322,22 @@
[dnc addObserver:self selector:@selector(appDidBecomeActive_) name:UIApplicationDidBecomeActiveNotification object:nil]; [dnc addObserver:self selector:@selector(appDidBecomeActive_) name:UIApplicationDidBecomeActiveNotification object:nil];
// hook into manager with kvo! // hook into manager with kvo!
[self.hockeyManager addObserver:self forKeyPath:@"checkInProgress" options:0 context:nil]; [_updateManager addObserver:self forKeyPath:@"checkInProgress" options:0 context:nil];
[self.hockeyManager addObserver:self forKeyPath:@"isUpdateURLOffline" options:0 context:nil]; [_updateManager addObserver:self forKeyPath:@"isUpdateURLOffline" options:0 context:nil];
[self.hockeyManager addObserver:self forKeyPath:@"updateAvailable" options:0 context:nil]; [_updateManager addObserver:self forKeyPath:@"updateAvailable" options:0 context:nil];
[self.hockeyManager addObserver:self forKeyPath:@"apps" options:0 context:nil]; [_updateManager addObserver:self forKeyPath:@"apps" options:0 context:nil];
kvoRegistered_ = YES; _kvoRegistered = YES;
self.tableView.backgroundColor = BW_RGBCOLOR(200, 202, 204); self.tableView.backgroundColor = BIT_RGBCOLOR(200, 202, 204);
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
UIView *topView = [[[UIView alloc] initWithFrame:CGRectMake(0, -(600-kAppStoreViewHeight), self.view.frame.size.width, 600)] autorelease]; UIView *topView = [[[UIView alloc] initWithFrame:CGRectMake(0, -(600-kAppStoreViewHeight), self.view.frame.size.width, 600)] autorelease];
topView.autoresizingMask = UIViewAutoresizingFlexibleWidth; topView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
topView.backgroundColor = BW_RGBCOLOR(140, 141, 142); topView.backgroundColor = BIT_RGBCOLOR(140, 141, 142);
[self.tableView addSubview:topView]; [self.tableView addSubview:topView];
appStoreHeader_ = [[PSAppStoreHeader alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kAppStoreViewHeight)]; _appStoreHeader = [[PSAppStoreHeader alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kAppStoreViewHeight)];
[self updateAppStoreHeader_]; [self updateAppStoreHeader];
NSString *iconString = nil; NSString *iconString = nil;
NSArray *icons = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFiles"]; NSArray *icons = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFiles"];
@ -362,7 +357,7 @@
if (icons) { if (icons) {
BOOL useHighResIcon = NO; BOOL useHighResIcon = NO;
BW_IF_IOS4_OR_GREATER(if ([UIScreen mainScreen].scale == 2.0f) useHighResIcon = YES;) if ([UIScreen mainScreen].scale == 2.0f) useHighResIcon = YES;
for(NSString *icon in icons) { for(NSString *icon in icons) {
iconString = icon; iconString = icon;
@ -386,12 +381,12 @@
} }
if (addGloss) { if (addGloss) {
appStoreHeader_.iconImage = [self addGlossToImage_:[UIImage imageNamed:iconString]]; _appStoreHeader.iconImage = [self addGlossToImage:[UIImage imageNamed:iconString]];
} else { } else {
appStoreHeader_.iconImage = [UIImage imageNamed:iconString]; _appStoreHeader.iconImage = [UIImage imageNamed:iconString];
} }
self.tableView.tableHeaderView = appStoreHeader_; self.tableView.tableHeaderView = _appStoreHeader;
if (self.modal) { if (self.modal) {
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
@ -406,47 +401,47 @@
storeButton.buttonData = [PSStoreButtonData dataWithLabel:@"" colors:[PSStoreButton appStoreGrayColor] enabled:NO]; storeButton.buttonData = [PSStoreButtonData dataWithLabel:@"" colors:[PSStoreButton appStoreGrayColor] enabled:NO];
self.appStoreButtonState = AppStoreButtonStateCheck; self.appStoreButtonState = AppStoreButtonStateCheck;
[storeButton alignToSuperview]; [storeButton alignToSuperview];
appStoreButton_ = [storeButton retain]; _appStoreButton = [storeButton retain];
} }
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
if ([self.hockeyManager isAppStoreEnvironment]) if (_isAppStoreEnvironment)
self.appStoreButtonState = AppStoreButtonStateOffline; self.appStoreButtonState = AppStoreButtonStateOffline;
self.hockeyManager.currentHockeyViewController = self; _updateManager.currentHockeyViewController = self;
[super viewWillAppear:animated]; [super viewWillAppear:animated];
statusBarStyle_ = [[UIApplication sharedApplication] statusBarStyle]; _statusBarStyle = [[UIApplication sharedApplication] statusBarStyle];
[[UIApplication sharedApplication] setStatusBarStyle:(self.navigationController.navigationBar.barStyle == UIBarStyleDefault) ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque]; [[UIApplication sharedApplication] setStatusBarStyle:(self.navigationController.navigationBar.barStyle == UIBarStyleDefault) ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque];
[self redrawTableView]; [self redrawTableView];
} }
- (void)viewWillDisappear:(BOOL)animated { - (void)viewWillDisappear:(BOOL)animated {
self.hockeyManager.currentHockeyViewController = nil; _updateManager.currentHockeyViewController = nil;
//if the popover is still visible, dismiss it //if the popover is still visible, dismiss it
[popOverController_ dismissPopoverAnimated:YES]; [_popOverController dismissPopoverAnimated:YES];
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
[[UIApplication sharedApplication] setStatusBarStyle:statusBarStyle_]; [[UIApplication sharedApplication] setStatusBarStyle:_statusBarStyle];
} }
- (void)redrawTableView { - (void)redrawTableView {
[self restoreStoreButtonStateAnimated_:NO]; [self restoreStoreButtonStateAnimated:NO];
[self updateAppStoreHeader_]; [self updateAppStoreHeader];
// clean up and remove any pending overservers // clean up and remove any pending overservers
for (UITableViewCell *cell in cells_) { for (UITableViewCell *cell in _cells) {
[cell removeObserver:self forKeyPath:@"webViewSize"]; [cell removeObserver:self forKeyPath:@"webViewSize"];
} }
[cells_ removeAllObjects]; [_cells removeAllObjects];
int i = 0; int i = 0;
BOOL breakAfterThisApp = NO; BOOL breakAfterThisAppVersion = NO;
for (BWApp *app in self.hockeyManager.apps) { for (BITAppVersionMetaInfo *appVersion in _updateManager.appVersions) {
i++; i++;
// only show the newer version of the app by default, if we don't show all versions // only show the newer version of the app by default, if we don't show all versions
if (!showAllVersions_) { if (!_showAllVersions) {
if ([app.version isEqualToString:[self.hockeyManager currentAppVersion]]) { if ([appVersion.version isEqualToString:[_updateManager currentAppVersion]]) {
if (i == 1) { if (i == 1) {
breakAfterThisApp = YES; breakAfterThisAppVersion = YES;
} else { } else {
break; break;
} }
@ -454,10 +449,10 @@
} }
PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease]; PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease];
[self configureWebCell:cell forApp_:app]; [self configureWebCell:cell forAppVersion:appVersion];
[cells_ addObject:cell]; [_cells addObject:cell];
if (breakAfterThisApp) break; if (breakAfterThisAppVersion) break;
} }
[self.tableView reloadData]; [self.tableView reloadData];
@ -465,14 +460,14 @@
} }
- (void)showPreviousVersionAction { - (void)showPreviousVersionAction {
showAllVersions_ = YES; _showAllVersions = YES;
BOOL showAllPending = NO; BOOL showAllPending = NO;
for (BWApp *app in self.hockeyManager.apps) { for (BITAppVersionMetaInfo *appVersion in _updateManager.appVersions) {
if (!showAllPending) { if (!showAllPending) {
if ([app.version isEqualToString:[self.hockeyManager currentAppVersion]]) { if ([appVersion.version isEqualToString:[_updateManager currentAppVersion]]) {
showAllPending = YES; showAllPending = YES;
if (app == self.hockeyManager.app) { if (appVersion == _updateManager.newestAppVersion) {
continue; // skip this version already if it the latest version is the installed one continue; // skip this version already if it the latest version is the installed one
} }
} else { } else {
@ -481,33 +476,32 @@
} }
PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease]; PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease];
[self configureWebCell:cell forApp_:app]; [self configureWebCell:cell forAppVersion:appVersion];
[cells_ addObject:cell]; [_cells addObject:cell];
} }
[self.tableView reloadData]; [self.tableView reloadData];
[self showHidePreviousVersionsButton]; [self showHidePreviousVersionsButton];
} }
- (void)viewDidUnload { - (void)viewDidUnload {
[appStoreHeader_ release]; appStoreHeader_ = nil; [_appStoreHeader release]; _appStoreHeader = nil;
[popOverController_ release], popOverController_ = nil; [_popOverController release], _popOverController = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self];
// test if KVO's are registered. if class is destroyed before it was shown(viewDidLoad) no KVOs are registered. // test if KVO's are registered. if class is destroyed before it was shown(viewDidLoad) no KVOs are registered.
if (kvoRegistered_) { if (_kvoRegistered) {
[self.hockeyManager removeObserver:self forKeyPath:@"checkInProgress"]; [_updateManager removeObserver:self forKeyPath:@"checkInProgress"];
[self.hockeyManager removeObserver:self forKeyPath:@"isUpdateURLOffline"]; [_updateManager removeObserver:self forKeyPath:@"isUpdateURLOffline"];
[self.hockeyManager removeObserver:self forKeyPath:@"updateAvailable"]; [_updateManager removeObserver:self forKeyPath:@"updateAvailable"];
[self.hockeyManager removeObserver:self forKeyPath:@"apps"]; [_updateManager removeObserver:self forKeyPath:@"apps"];
kvoRegistered_ = NO; _kvoRegistered = NO;
} }
[super viewDidUnload]; [super viewDidUnload];
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - Table view data source
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1; return 1;
@ -516,31 +510,30 @@
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat rowHeight = 0; CGFloat rowHeight = 0;
if ([cells_ count] > (NSUInteger)indexPath.row) { if ([_cells count] > (NSUInteger)indexPath.row) {
PSWebTableViewCell *cell = [cells_ objectAtIndex:indexPath.row]; PSWebTableViewCell *cell = [_cells objectAtIndex:indexPath.row];
rowHeight = cell.webViewSize.height; rowHeight = cell.webViewSize.height;
} }
if ([self.hockeyManager.apps count] > 1 && !showAllVersions_) { if ([_updateManager.appVersions count] > 1 && !_showAllVersions) {
self.tableView.backgroundColor = BW_RGBCOLOR(183, 183, 183); self.tableView.backgroundColor = BIT_RGBCOLOR(183, 183, 183);
} }
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 = BW_RGBCOLOR(200, 202, 204); self.tableView.backgroundColor = BIT_RGBCOLOR(200, 202, 204);
} }
return rowHeight; return rowHeight;
} }
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger cellCount = [cells_ count]; NSInteger cellCount = [_cells count];
return cellCount; return cellCount;
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - KVO
#pragma mark KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
// only make changes if we are visible // only make changes if we are visible
@ -549,15 +542,15 @@
[self.tableView reloadData]; [self.tableView reloadData];
[self realignPreviousVersionButton]; [self realignPreviousVersionButton];
} else if ([keyPath isEqualToString:@"checkInProgress"]) { } else if ([keyPath isEqualToString:@"checkInProgress"]) {
if (self.hockeyManager.isCheckInProgress) { if (_updateManager.isCheckInProgress) {
[self setAppStoreButtonState:AppStoreButtonStateSearching animated:YES]; [self setAppStoreButtonState:AppStoreButtonStateSearching animated:YES];
}else { }else {
[self restoreStoreButtonStateAnimated_:YES]; [self restoreStoreButtonStateAnimated:YES];
} }
} else if ([keyPath isEqualToString:@"isUpdateURLOffline"]) { } else if ([keyPath isEqualToString:@"isUpdateURLOffline"]) {
[self restoreStoreButtonStateAnimated_:YES]; [self restoreStoreButtonStateAnimated:YES];
} else if ([keyPath isEqualToString:@"updateAvailable"]) { } else if ([keyPath isEqualToString:@"updateAvailable"]) {
[self restoreStoreButtonStateAnimated_:YES]; [self restoreStoreButtonStateAnimated:YES];
} else if ([keyPath isEqualToString:@"apps"]) { } else if ([keyPath isEqualToString:@"apps"]) {
[self redrawTableView]; [self redrawTableView];
} }
@ -566,18 +559,16 @@
// Customize the appearance of table view cells. // Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([cells_ count] > (NSUInteger)indexPath.row) { if ([_cells count] > (NSUInteger)indexPath.row) {
return [cells_ objectAtIndex:indexPath.row]; return [_cells objectAtIndex:indexPath.row];
} else { } else {
BWHockeyLog(@"Warning: cells_ and indexPath do not match? forgot calling redrawTableView?"); BITHockeySDKLog(@"Warning: cells_ and indexPath do not match? forgot calling redrawTableView?");
} }
return nil; return nil;
} }
/////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - Rotation
#pragma mark -
#pragma mark Rotation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
BOOL shouldAutorotate; BOOL shouldAutorotate;
@ -595,12 +586,11 @@
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
// update all cells // update all cells
[cells_ makeObjectsPerformSelector:@selector(addWebView)]; [_cells makeObjectsPerformSelector:@selector(addWebView)];
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - PSAppStoreHeaderDelegate
#pragma mark PSAppStoreHeaderDelegate
- (void)setAppStoreButtonState:(AppStoreButtonState)anAppStoreButtonState { - (void)setAppStoreButtonState:(AppStoreButtonState)anAppStoreButtonState {
[self setAppStoreButtonState:anAppStoreButtonState animated:NO]; [self setAppStoreButtonState:anAppStoreButtonState animated:NO];
@ -611,19 +601,19 @@
switch (anAppStoreButtonState) { switch (anAppStoreButtonState) {
case AppStoreButtonStateOffline: case AppStoreButtonStateOffline:
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonOffline") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated]; [_appStoreButton setButtonData:[PSStoreButtonData dataWithLabel:BITHockeySDKLocalizedString(@"UpdateButtonOffline") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated];
break; break;
case AppStoreButtonStateCheck: case AppStoreButtonStateCheck:
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonCheck") colors:[PSStoreButton appStoreGreenColor] enabled:YES] animated:animated]; [_appStoreButton setButtonData:[PSStoreButtonData dataWithLabel:BITHockeySDKLocalizedString(@"UpdateButtonCheck") colors:[PSStoreButton appStoreGreenColor] enabled:YES] animated:animated];
break; break;
case AppStoreButtonStateSearching: case AppStoreButtonStateSearching:
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonSearching") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated]; [_appStoreButton setButtonData:[PSStoreButtonData dataWithLabel:BITHockeySDKLocalizedString(@"UpdateButtonSearching") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated];
break; break;
case AppStoreButtonStateUpdate: case AppStoreButtonStateUpdate:
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonUpdate") colors:[PSStoreButton appStoreBlueColor] enabled:YES] animated:animated]; [_appStoreButton setButtonData:[PSStoreButtonData dataWithLabel:BITHockeySDKLocalizedString(@"UpdateButtonUpdate") colors:[PSStoreButton appStoreBlueColor] enabled:YES] animated:animated];
break; break;
case AppStoreButtonStateInstalling: case AppStoreButtonStateInstalling:
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonInstalling") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated]; [_appStoreButton setButtonData:[PSStoreButtonData dataWithLabel:BITHockeySDKLocalizedString(@"UpdateButtonInstalling") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated];
break; break;
default: default:
break; break;
@ -633,10 +623,10 @@
- (void)storeButtonFired:(PSStoreButton *)button { - (void)storeButtonFired:(PSStoreButton *)button {
switch (appStoreButtonState_) { switch (appStoreButtonState_) {
case AppStoreButtonStateCheck: case AppStoreButtonStateCheck:
[self.hockeyManager checkForUpdateShowFeedback:YES]; [_updateManager checkForUpdateShowFeedback:YES];
break; break;
case AppStoreButtonStateUpdate: case AppStoreButtonStateUpdate:
if ([self.hockeyManager initiateAppDownload]) { if ([_updateManager initiateAppDownload]) {
[self setAppStoreButtonState:AppStoreButtonStateInstalling animated:YES]; [self setAppStoreButtonState:AppStoreButtonStateInstalling animated:YES];
}; };
break; break;

View File

@ -1,56 +0,0 @@
//
// BWApp.h
// HockeyDemo
//
// Created by Peter Steinberger on 04.02.11.
// Copyright 2011 Buzzworks. 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>
@interface BWApp : NSObject {
NSString *name_;
NSString *version_;
NSString *shortVersion_;
NSString *notes_;
NSDate *date_;
NSNumber *size_;
NSNumber *mandatory_;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *version;
@property (nonatomic, copy) NSString *shortVersion;
@property (nonatomic, copy) NSString *notes;
@property (nonatomic, copy) NSDate *date;
@property (nonatomic, copy) NSNumber *size;
@property (nonatomic, copy) NSNumber *mandatory;
- (NSString *)nameAndVersionString;
- (NSString *)versionString;
- (NSString *)dateString;
- (NSString *)sizeInMB;
- (NSString *)notesOrEmptyString;
- (void)setDateWithTimestamp:(NSTimeInterval)timestamp;
- (BOOL)isValid;
- (BOOL)isEqualToBWApp:(BWApp *)anApp;
+ (BWApp *)appFromDict:(NSDictionary *)dict;
@end

View File

@ -1,186 +0,0 @@
//
// BWApp.m
// HockeyDemo
//
// Created by Peter Steinberger on 04.02.11.
// Copyright 2011 Buzzworks. 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 "BWApp.h"
#import "BWGlobal.h"
@implementation BWApp
@synthesize name = name_;
@synthesize version = version_;
@synthesize shortVersion = shortVersion_;
@synthesize notes = notes_;
@synthesize date = date_;
@synthesize size = size_;
@synthesize mandatory = mandatory_;
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark static
+ (BWApp *)appFromDict:(NSDictionary *)dict {
BWApp *app = [[[[self class] alloc] init] autorelease];
// NSParameterAssert([dict isKindOfClass:[NSDictionary class]]);
if ([dict isKindOfClass:[NSDictionary class]]) {
app.name = [dict objectForKey:@"title"];
app.version = [dict objectForKey:@"version"];
app.shortVersion = [dict objectForKey:@"shortversion"];
[app setDateWithTimestamp:[[dict objectForKey:@"timestamp"] doubleValue]];
app.size = [dict objectForKey:@"appsize"];
app.notes = [dict objectForKey:@"notes"];
app.mandatory = [dict objectForKey:@"mandatory"];
}
return app;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark NSObject
- (void)dealloc {
[name_ release];
[version_ release];
[shortVersion_ release];
[notes_ release];
[date_ release];
[size_ release];
[mandatory_ release];
[super dealloc];
}
- (BOOL)isEqual:(id)other {
if (other == self)
return YES;
if (!other || ![other isKindOfClass:[self class]])
return NO;
return [self isEqualToBWApp:other];
}
- (BOOL)isEqualToBWApp:(BWApp *)anApp {
if (self == anApp)
return YES;
if (self.name != anApp.name && ![self.name isEqualToString:anApp.name])
return NO;
if (self.version != anApp.version && ![self.version isEqualToString:anApp.version])
return NO;
if (self.shortVersion != anApp.shortVersion && ![self.shortVersion isEqualToString:anApp.shortVersion])
return NO;
if (self.notes != anApp.notes && ![self.notes isEqualToString:anApp.notes])
return NO;
if (self.date != anApp.date && ![self.date isEqualToDate:anApp.date])
return NO;
if (self.size != anApp.size && ![self.size isEqualToNumber:anApp.size])
return NO;
if (self.mandatory != anApp.mandatory && ![self.mandatory isEqualToNumber:anApp.mandatory])
return NO;
return YES;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark NSCoder
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeObject:self.version forKey:@"version"];
[encoder encodeObject:self.shortVersion forKey:@"shortVersion"];
[encoder encodeObject:self.notes forKey:@"notes"];
[encoder encodeObject:self.date forKey:@"date"];
[encoder encodeObject:self.size forKey:@"size"];
[encoder encodeObject:self.mandatory forKey:@"mandatory"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if ((self = [super init])) {
self.name = [decoder decodeObjectForKey:@"name"];
self.version = [decoder decodeObjectForKey:@"version"];
self.shortVersion = [decoder decodeObjectForKey:@"shortVersion"];
self.notes = [decoder decodeObjectForKey:@"notes"];
self.date = [decoder decodeObjectForKey:@"date"];
self.size = [decoder decodeObjectForKey:@"size"];
self.mandatory = [decoder decodeObjectForKey:@"mandatory"];
}
return self;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Properties
- (NSString *)nameAndVersionString {
NSString *appNameAndVersion = [NSString stringWithFormat:@"%@ %@", self.name, [self versionString]];
return appNameAndVersion;
}
- (NSString *)versionString {
NSString *shortString = ([self.shortVersion respondsToSelector:@selector(length)] && [self.shortVersion length]) ? [NSString stringWithFormat:@"%@", self.shortVersion] : @"";
NSString *versionString = [shortString length] ? [NSString stringWithFormat:@" (%@)", self.version] : self.version;
return [NSString stringWithFormat:@"%@ %@%@", BWHockeyLocalize(@"HockeyVersion"), shortString, versionString];
}
- (NSString *)dateString {
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateStyle:NSDateFormatterMediumStyle];
return [formatter stringFromDate:self.date];
}
- (NSString *)sizeInMB {
if ([size_ isKindOfClass: [NSNumber class]] && [size_ doubleValue] > 0) {
double appSizeInMB = [size_ doubleValue]/(1024*1024);
NSString *appSizeString = [NSString stringWithFormat:@"%.1f MB", appSizeInMB];
return appSizeString;
}
return @"0 MB";
}
- (void)setDateWithTimestamp:(NSTimeInterval)timestamp {
if (timestamp) {
NSDate *appDate = [NSDate dateWithTimeIntervalSince1970:timestamp];
self.date = appDate;
} else {
self.date = nil;
}
}
- (NSString *)notesOrEmptyString {
if (self.notes) {
return self.notes;
}else {
return [NSString string];
}
}
// a valid app needs at least following properties: name, version, date
- (BOOL)isValid {
BOOL valid = [self.name length] && [self.version length] && self.date;
return valid;
}
@end

View File

@ -1,127 +0,0 @@
//
// BWGlobal.h
//
// Created by Andreas Linde on 08/17/10.
// Copyright 2010-2011 Andreas Linde, Peter Steinberger. 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 "BWHockeyManager.h"
#import "BWApp.h"
#define SDK_NAME @"HockeySDK"
#define SDK_VERSION @"2.2.6"
#ifndef HOCKEY_BLOCK_UDID
#define HOCKEY_BLOCK_UDID 1
#endif
// uncomment this line to enable NSLog-debugging output
//#define kHockeyDebugEnabled
#define kArrayOfLastHockeyCheck @"ArrayOfLastHockeyCheck"
#define kDateOfLastHockeyCheck @"DateOfLastHockeyCheck"
#define kDateOfVersionInstallation @"DateOfVersionInstallation"
#define kUsageTimeOfCurrentVersion @"UsageTimeOfCurrentVersion"
#define kUsageTimeForVersionString @"kUsageTimeForVersionString"
#define kHockeyAutoUpdateSetting @"HockeyAutoUpdateSetting"
#define kHockeyAllowUserSetting @"HockeyAllowUserSetting"
#define kHockeyAllowUsageSetting @"HockeyAllowUsageSetting"
#define kHockeyAutoUpdateSetting @"HockeyAutoUpdateSetting"
#define kHockeyAuthorizedVersion @"HockeyAuthorizedVersion"
#define kHockeyAuthorizedToken @"HockeyAuthorizedToken"
#define kHockeyBundleName @"Hockey.bundle"
// Notification message which HockeyManager is listening to, to retry requesting updated from the server
#define BWHockeyNetworkBecomeReachable @"NetworkDidBecomeReachable"
#define BWHockeyLog(fmt, ...) do { if([BWHockeyManager sharedHockeyManager].isLoggingEnabled) { NSLog((@"[HockeyLib] %s/%d " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); }} while(0)
NSBundle *hockeyBundle(void);
NSString *BWmd5(NSString *str);
NSString *BWHockeyLocalize(NSString *stringToken);
// compatibility helper
#ifdef HOCKEYLIB_STATIC_LIBRARY
// If HockeyLib is built as a static library and linked into the project
// we can't use this project's deployment target to statically decide if
// native JSON is available
#define BW_NATIVE_JSON_AVAILABLE 0
#else
#define BW_NATIVE_JSON_AVAILABLE __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000
#endif
#ifndef kCFCoreFoundationVersionNumber_iPhoneOS_3_2
#define kCFCoreFoundationVersionNumber_iPhoneOS_3_2 478.61
#endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 32000
#define BW_IF_3_2_OR_GREATER(...) \
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_3_2) \
{ \
__VA_ARGS__ \
}
#else
#define BW_IF_3_2_OR_GREATER(...)
#endif
#define BW_IF_PRE_3_2(...) \
if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_3_2) \
{ \
__VA_ARGS__ \
}
#ifndef kCFCoreFoundationVersionNumber_iPhoneOS_4_0
#define kCFCoreFoundationVersionNumber_iPhoneOS_4_0 550.32
#endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
#define BW_IF_IOS4_OR_GREATER(...) \
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_4_0) \
{ \
__VA_ARGS__ \
}
#else
#define BW_IF_IOS4_OR_GREATER(...)
#endif
#define BW_IF_PRE_IOS4(...) \
if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_4_0) \
{ \
__VA_ARGS__ \
}
#ifndef kCFCoreFoundationVersionNumber_iPhoneOS_5_0
#define kCFCoreFoundationVersionNumber_iPhoneOS_5_0 674.0
#endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 50000
#define BW_IF_IOS5_OR_GREATER(...) \
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_5_0) \
{ \
__VA_ARGS__ \
}
#else
#define BW_IF_IOS5_OR_GREATER(...)
#endif
#define BW_IF_PRE_IOS5(...) \
if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_5_0) \
{ \
__VA_ARGS__ \
}

View File

@ -1,61 +0,0 @@
//
// BWGlobal.h
//
// Created by Andreas Linde on 08/17/10.
// Copyright 2010-2011 Andreas Linde, Peter Steinberger. 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 "BWGlobal.h"
#include <CommonCrypto/CommonDigest.h>
NSBundle *hockeyBundle(void) {
static NSBundle* bundle = nil;
if (!bundle) {
NSString* path = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:kHockeyBundleName];
bundle = [[NSBundle bundleWithPath:path] retain];
}
return bundle;
}
NSString *BWmd5(NSString *str) {
const char *cStr = [str UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5( cStr, strlen(cStr), result );
return [NSString
stringWithFormat: @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1],
result[2], result[3],
result[4], result[5],
result[6], result[7],
result[8], result[9],
result[10], result[11],
result[12], result[13],
result[14], result[15]
];
}
NSString *BWHockeyLocalize(NSString *stringToken) {
if (hockeyBundle()) {
return NSLocalizedStringFromTableInBundle(stringToken, @"Hockey", hockeyBundle(), @"");
} else {
return stringToken;
}
}

View File

@ -1,266 +0,0 @@
//
// BWHockeyManager.h
//
// Created by Andreas Linde on 8/17/10.
// Copyright 2010-2011 Andreas Linde. 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 <UIKit/UIKit.h>
#import "BWHockeyViewController.h"
#import "BWGlobal.h"
typedef enum {
HockeyComparisonResultDifferent,
HockeyComparisonResultGreater
} HockeyComparisonResult;
typedef enum {
HockeyAuthorizationDenied,
HockeyAuthorizationAllowed,
HockeyAuthorizationPending
} HockeyAuthorizationState;
typedef enum {
HockeyUpdateCheckStartup = 0,
HockeyUpdateCheckDaily = 1,
HockeyUpdateCheckManually = 2
} HockeyUpdateSetting;
@protocol BWHockeyManagerDelegate;
@class BWApp;
@interface BWHockeyManager : NSObject <UIAlertViewDelegate> {
id <BWHockeyManagerDelegate> delegate_;
NSArray *apps_;
NSString *updateURL_;
NSString *appIdentifier_;
NSString *currentAppVersion_;
UINavigationController *navController_;
BWHockeyViewController *currentHockeyViewController_;
UIView *authorizeView_;
NSMutableData *receivedData_;
BOOL loggingEnabled_;
BOOL checkInProgress_;
BOOL dataFound;
BOOL updateAvailable_;
BOOL showFeedback_;
BOOL updateURLOffline_;
BOOL updateAlertShowing_;
BOOL lastCheckFailed_;
BOOL isAppStoreEnvironment_;
NSURLConnection *urlConnection_;
NSDate *lastCheck_;
NSDate *usageStartTimestamp_;
BOOL sendUserData_;
BOOL sendUsageTime_;
BOOL allowUserToDisableSendData_;
BOOL userAllowsSendUserData_;
BOOL userAllowsSendUsageTime_;
BOOL showUpdateReminder_;
BOOL checkForUpdateOnLaunch_;
HockeyComparisonResult compareVersionType_;
HockeyUpdateSetting updateSetting_;
BOOL showUserSettings_;
BOOL showDirectInstallOption_;
BOOL requireAuthorization_;
NSString *authenticationSecret_;
BOOL checkForTracker_;
NSDictionary *trackerConfig_;
UIBarStyle barStyle_;
UIModalPresentationStyle modalPresentationStyle_;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// this is a singleton
+ (BWHockeyManager *)sharedHockeyManager;
// update url needs to be set
@property (nonatomic, retain) NSString *updateURL;
// private app identifier (optional)
@property (nonatomic, retain) NSString *appIdentifier;
// delegate is optional
@property (nonatomic, assign) id <BWHockeyManagerDelegate> delegate;
// hockey secret is required if authentication is used
@property (nonatomic, retain) NSString *authenticationSecret;
///////////////////////////////////////////////////////////////////////////////////////////////////
// Setting Properties
// if YES, states will be logged using NSLog. Only enable this for debugging!
// if NO, nothing will be logged. (default)
@property (nonatomic, assign, getter=isLoggingEnabled) BOOL loggingEnabled;
// if YES, the current user data is send: device type, iOS version, app version, UDID (default)
// if NO, no such data is send to the server
@property (nonatomic, assign, getter=shouldSendUserData) BOOL sendUserData;
// if YES, the the users usage time of the app to the service, only in 1 minute granularity! (default)
// if NO, no such data is send to the server
@property (nonatomic, assign, getter=shouldSendUsageTime) BOOL sendUsageTime;
// if YES, the user agrees to send the usage data, user can change it if the developer shows the settings (default)
// if NO, the user overwrites the developer setting and no such data is sent
@property (nonatomic, assign, getter=isAllowUserToDisableSendData) BOOL allowUserToDisableSendData;
// if YES, the user allowed to send user data (default)
// if NO, the user denied to send user data
@property (nonatomic, assign, getter=doesUserAllowsSendUserData) BOOL userAllowsSendUserData;
// if YES, the user allowed to send usage data (default)
// if NO, the user denied to send usage data
@property (nonatomic, assign, getter=doesUserAllowsSendUsageTime) BOOL userAllowsSendUsageTime;
// if YES, the new version alert will be displayed always if the current version is outdated (default)
// if NO, the alert will be displayed only once for each new update
@property (nonatomic, assign) BOOL alwaysShowUpdateReminder;
// if YES, the user can change the HockeyUpdateSetting value (default)
// if NO, the user can not change it, and the default or developer defined value will be used
@property (nonatomic, assign, getter=shouldShowUserSettings) BOOL showUserSettings;
// set bar style of navigation controller
@property (nonatomic, assign) UIBarStyle barStyle;
// set modal presentation style of update view
@property (nonatomic, assign) UIModalPresentationStyle modalPresentationStyle;
// if YES, then an update check will be performed after the application becomes active (default)
// if NO, then the update check will not happen unless invoked explicitly
@property (nonatomic, assign, getter=isCheckForUpdateOnLaunch) BOOL checkForUpdateOnLaunch;
// if YES, the alert notifying about an new update also shows a button to install the update directly
// if NO, the alert notifying about an new update only shows ignore and show update button
@property (nonatomic, assign, getter=isShowingDirectInstallOption) BOOL showDirectInstallOption;
// if YES, each app version needs to be authorized by the server to run on this device
// if NO, each app version does not need to be authorized (default)
@property (nonatomic, assign, getter=isRequireAuthorization) BOOL requireAuthorization;
// HockeyComparisonResultDifferent: alerts if the version on the server is different (default)
// HockeyComparisonResultGreater: alerts if the version on the server is greater
@property (nonatomic, assign) HockeyComparisonResult compareVersionType;
// see HockeyUpdateSetting-enum. Will be saved in user defaults.
// default value: HockeyUpdateCheckStartup
@property (nonatomic, assign) HockeyUpdateSetting updateSetting;
///////////////////////////////////////////////////////////////////////////////////////////////////
// Private Properties
// if YES, the API will return an existing JMC config
// if NO, the API will return only version information
@property (nonatomic, assign) BOOL checkForTracker;
// Contains the tracker config if received from server
@property (nonatomic, retain, readonly) NSDictionary *trackerConfig;
// if YES the app is installed from the app store
// if NO the app is installed via ad-hoc or enterprise distribution
@property (nonatomic, readonly) BOOL isAppStoreEnvironment;
// is an update available?
- (BOOL)isUpdateAvailable;
// are we currently checking for updates?
- (BOOL)isCheckInProgress;
// open update info view
- (void)showUpdateView;
// manually start an update check
- (void)checkForUpdate;
// checks for update, informs the user (error, no update found, etc)
- (void)checkForUpdateShowFeedback:(BOOL)feedback;
// initiates app-download call. displays an system UIAlertView
- (BOOL)initiateAppDownload;
// checks wether this app version is authorized
- (BOOL)appVersionIsAuthorized;
// start checking for an authorization key
- (void)checkForAuthorization;
// convenience methode to create hockey view controller
- (BWHockeyViewController *)hockeyViewController:(BOOL)modal;
// get/set current active hockey view controller
@property (nonatomic, retain) BWHockeyViewController *currentHockeyViewController;
// convenience method to get current running version string
- (NSString *)currentAppVersion;
// get newest app or array of all available versions
- (BWApp *)app;
- (NSArray *)apps;
// check if there is any newer version mandatory
- (BOOL)hasNewerMandatoryVersion;
@end
///////////////////////////////////////////////////////////////////////////////////////////////////
@protocol BWHockeyManagerDelegate <NSObject>
/*
Return the device UDID which is required for beta testing, should return nil for app store configuration!
Example implementation if your configuration for the App Store is called "AppStore":
#ifndef (CONFIGURATION_AppStore)
if ([[UIDevice currentDevice] respondsToSelector:@selector(uniqueIdentifier)])
return [[UIDevice currentDevice] performSelector:@selector(uniqueIdentifier)];
#endif
return nil;
*/
- (NSString *)customDeviceIdentifier;
@optional
// Invoked when the internet connection is started, to let the app enable the activity indicator
- (void)connectionOpened;
// Invoked when the internet connection is closed, to let the app disable the activity indicator
- (void)connectionClosed;
// optional parent view controller for the update screen when invoked via the alert view, default is the root UIWindow instance
- (UIViewController *)viewControllerForHockeyController:(BWHockeyManager *)hockeyController;
@end

View File

@ -1,22 +0,0 @@
//
// BWHockeySettingsViewController.h
// HockeyDemo
//
// Created by Andreas Linde on 3/8/11.
// Copyright 2011 Andreas Linde. All rights reserved.
//
#import <UIKit/UIKit.h>
@class BWHockeyManager;
@interface BWHockeySettingsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
BWHockeyManager *hockeyManager_;
}
@property (nonatomic, retain) BWHockeyManager *hockeyManager;
- (id)init:(BWHockeyManager *)newHockeyManager;
- (id)init;
@end

View File

@ -1,68 +0,0 @@
//
// BWHockeyViewController.h
//
// Created by Andreas Linde on 8/17/10.
// Copyright 2010-2011 Andreas Linde. 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 <UIKit/UIKit.h>
#import "PSStoreButton.h"
@class PSAppStoreHeader;
typedef enum {
AppStoreButtonStateOffline,
AppStoreButtonStateCheck,
AppStoreButtonStateSearching,
AppStoreButtonStateUpdate,
AppStoreButtonStateInstalling
} AppStoreButtonState;
@class BWHockeyManager;
@interface BWHockeyViewController : UITableViewController <PSStoreButtonDelegate> {
BWHockeyManager *hockeyManager_;
NSDictionary *cellLayout;
BOOL modal_;
BOOL modalAnimated_;
BOOL kvoRegistered_;
BOOL showAllVersions_;
UIStatusBarStyle statusBarStyle_;
PSAppStoreHeader *appStoreHeader_;
PSStoreButton *appStoreButton_;
id popOverController_;
AppStoreButtonState appStoreButtonState_;
NSMutableArray *cells_;
}
@property (nonatomic, retain) BWHockeyManager *hockeyManager;
@property (nonatomic, readwrite) BOOL modal;
@property (nonatomic, readwrite) BOOL modalAnimated;
- (id)init:(BWHockeyManager *)newHockeyManager modal:(BOOL)newModal;
- (id)init;
@end

View File

@ -1,201 +0,0 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
* Kent Sutherland
*
* Copyright (c) 2011 Andreas Linde & Kent Sutherland.
* 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 "BWQuincyManagerDelegate.h"
#define BWQuincyLog(fmt, ...) do { if([BWQuincyManager sharedQuincyManager].isLoggingEnabled) { NSLog((@"[QuincyLib] %s/%d " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); }} while(0)
#define kQuincyBundleName @"Quincy.bundle"
NSBundle *quincyBundle(void);
NSString *BWQuincyLocalize(NSString *stringToken);
//#define BWQuincyLocalize(StringToken) NSLocalizedStringFromTableInBundle(StringToken, @"Quincy", quincyBundle(), @"")
// flags if the crashlog analyzer is started. since this may theoretically crash we need to track it
#define kQuincyKitAnalyzerStarted @"QuincyKitAnalyzerStarted"
// flags if the QuincyKit is activated at all
#define kQuincyKitActivated @"QuincyKitActivated"
// flags if the crashreporter should automatically send crashes without asking the user again
#define kAutomaticallySendCrashReports @"AutomaticallySendCrashReports"
// stores the set of crashreports that have been approved but aren't sent yet
#define kApprovedCrashReports @"ApprovedCrashReports"
// Notification message which QuincyManager is listening to, to retry sending pending crash reports to the server
#define BWQuincyNetworkBecomeReachable @"NetworkDidBecomeReachable"
typedef enum QuincyKitAlertType {
QuincyKitAlertTypeSend = 0,
QuincyKitAlertTypeFeedback = 1,
} CrashAlertType;
typedef enum CrashReportStatus {
// The status of the crash is queued, need to check later (HockeyApp)
CrashReportStatusQueued = -80,
// This app version is set to discontinued, no new crash reports accepted by the server
CrashReportStatusFailureVersionDiscontinued = -30,
// XML: Sender version string contains not allowed characters, only alphanumberical including space and . are allowed
CrashReportStatusFailureXMLSenderVersionNotAllowed = -21,
// XML: Version string contains not allowed characters, only alphanumberical including space and . are allowed
CrashReportStatusFailureXMLVersionNotAllowed = -20,
// SQL for adding a symoblicate todo entry in the database failed
CrashReportStatusFailureSQLAddSymbolicateTodo = -18,
// SQL for adding crash log in the database failed
CrashReportStatusFailureSQLAddCrashlog = -17,
// SQL for adding a new version in the database failed
CrashReportStatusFailureSQLAddVersion = -16,
// SQL for checking if the version is already added in the database failed
CrashReportStatusFailureSQLCheckVersionExists = -15,
// SQL for creating a new pattern for this bug and set amount of occurrances to 1 in the database failed
CrashReportStatusFailureSQLAddPattern = -14,
// SQL for checking the status of the bugfix version in the database failed
CrashReportStatusFailureSQLCheckBugfixStatus = -13,
// SQL for updating the occurances of this pattern in the database failed
CrashReportStatusFailureSQLUpdatePatternOccurances = -12,
// SQL for getting all the known bug patterns for the current app version in the database failed
CrashReportStatusFailureSQLFindKnownPatterns = -11,
// SQL for finding the bundle identifier in the database failed
CrashReportStatusFailureSQLSearchAppName = -10,
// the post request didn't contain valid data
CrashReportStatusFailureInvalidPostData = -3,
// incoming data may not be added, because e.g. bundle identifier wasn't found
CrashReportStatusFailureInvalidIncomingData = -2,
// database cannot be accessed, check hostname, username, password and database name settings in config.php
CrashReportStatusFailureDatabaseNotAvailable = -1,
CrashReportStatusUnknown = 0,
CrashReportStatusAssigned = 1,
CrashReportStatusSubmitted = 2,
CrashReportStatusAvailable = 3,
} CrashReportStatus;
@interface BWQuincyManager : NSObject <NSXMLParserDelegate> {
NSString *_submissionURL;
id <BWQuincyManagerDelegate> _delegate;
BOOL _loggingEnabled;
BOOL _showAlwaysButton;
BOOL _feedbackActivated;
BOOL _autoSubmitCrashReport;
BOOL _didCrashInLastSession;
NSTimeInterval _timeintervalCrashInLastSessionOccured;
NSString *_appIdentifier;
NSString *_feedbackRequestID;
float _feedbackDelayInterval;
NSMutableString *_contentOfProperty;
CrashReportStatus _serverResult;
int _analyzerStarted;
NSString *_crashesDir;
NSFileManager *_fileManager;
BOOL _crashIdenticalCurrentVersion;
BOOL _crashReportActivated;
NSMutableArray *_crashFiles;
NSMutableData *_responseData;
NSInteger _statusCode;
NSURLConnection *_urlConnection;
NSData *_crashData;
NSString *_languageStyle;
BOOL _sendingInProgress;
}
+ (BWQuincyManager *)sharedQuincyManager;
// submission URL defines where to send the crash reports to (required)
@property (nonatomic, retain) NSString *submissionURL;
// delegate is optional
@property (nonatomic, assign) id <BWQuincyManagerDelegate> delegate;
///////////////////////////////////////////////////////////////////////////////////////////////////
// settings
// if YES, states will be logged using NSLog. Only enable this for debugging!
// if NO, nothing will be logged. (default)
@property (nonatomic, assign, getter=isLoggingEnabled) BOOL loggingEnabled;
// nil, using the default localization files (Default)
// set to another string which will be appended to the Quincy localization file name, "Alternate" is another provided text set
@property (nonatomic, retain) NSString *languageStyle;
// if YES, the user will get the option to choose "Always" for sending crash reports. This will cause the dialog not to show the alert description text landscape mode! (default)
// if NO, the dialog will not show a "Always" button
@property (nonatomic, assign, getter=isShowingAlwaysButton) BOOL showAlwaysButton;
// if YES, the user will be presented with a status of the crash, if known
// if NO, the user will not see any feedback information (default)
@property (nonatomic, assign, getter=isFeedbackActivated) BOOL feedbackActivated;
// if YES, the crash report will be submitted without asking the user
// if NO, the user will be asked if the crash report can be submitted (default)
@property (nonatomic, assign, getter=isAutoSubmitCrashReport) BOOL autoSubmitCrashReport;
// will return YES if the last session crashed, to e.g. make sure a "rate my app" alert will not show up
@property (nonatomic, readonly) BOOL didCrashInLastSession;
// will return the timeinterval from startup to the crash in seconds, default is -1
@property (nonatomic, readonly) NSTimeInterval timeintervalCrashInLastSessionOccured;
// If you want to use HockeyApp instead of your own server, this is required
@property (nonatomic, retain) NSString *appIdentifier;
@end

View File

@ -1,46 +0,0 @@
//
// CNSCrashReportManagerDelegate.h
// HockeySDK
//
// Created by Andreas Linde on 29.03.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
// This protocol is used to send the image updates
@protocol BWQuincyManagerDelegate <NSObject>
@optional
// Return the userid the crashreport should contain, empty by default
-(NSString *) crashReportUserID;
// Return the contact value (e.g. email) the crashreport should contain, empty by default
-(NSString *) crashReportContact;
// Return the description the crashreport should contain, empty by default. The string will automatically be wrapped into <[DATA[ ]]>, so make sure you don't do that in your string.
-(NSString *) crashReportDescription;
// Invoked when the internet connection is started, to let the app enable the activity indicator
-(void) connectionOpened;
// Invoked when the internet connection is closed, to let the app disable the activity indicator
-(void) connectionClosed;
// Invoked before the user is asked to send a crash report, so you can do additional actions. E.g. to make sure not to ask the user for an app rating :)
-(void) willShowSubmitCrashReportAlert;
// Invoked after the user did choose to send crashes always in the alert
-(void) userDidChooseSendAlways;
// Invoked right before sending crash reports to the server succeeded
-(void) sendingCrashReportsDidStart;
// Invoked after sending crash reports to the server failed
-(void) sendingCrashReportsDidFailWithError:(NSError *)error;
// Invoked after sending crash reports to the server succeeded
-(void) sendingCrashReportsDidFinish;
@end

View File

@ -1,25 +0,0 @@
//
// CNSFixCategoryBug.h
// HockeySDK
//
// Created by Andreas Linde on 12/7/11.
// Copyright (c) 2011 Andreas Linde. All rights reserved.
//
#ifndef HockeySDK_CNSFixCategoryBug_h
#define HockeySDK_CNSFixCategoryBug_h
/**
Add this macro before each category implementation, so we don't have to use
-all_load or -force_load to load object files from static libraries that only contain
categories and no classes.
See http://developer.apple.com/library/mac/#qa/qa2006/qa1490.html for more info.
Shamelessly borrowed from Three20
*/
#define CNS_FIX_CATEGORY_BUG(name) @interface CNS_FIX_CATEGORY_BUG##name @end \
@implementation CNS_FIX_CATEGORY_BUG##name @end
#endif

View File

@ -1,261 +0,0 @@
// Copyright 2011 Codenauts UG (haftungsbeschränkt). All rights reserved.
// See LICENSE.txt for author information.
//
// 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 "BWHockeyManager.h"
#pragma mark - Delegate
@protocol CNSHockeyManagerDelegate <NSObject>
/*
Return the device UDID which is required for beta testing, should return nil for app store configuration!
Example implementation if your configuration for the App Store is called "AppStore":
#ifndef (CONFIGURATION_AppStore)
if ([[UIDevice currentDevice] respondsToSelector:@selector(uniqueIdentifier)])
return [[UIDevice currentDevice] performSelector:@selector(uniqueIdentifier)];
#endif
return nil;
*/
- (NSString *)customDeviceIdentifier;
@optional
// Invoked when the manager is configured
//
// Implement to force the usage of the live identifier, e.g. for enterprise apps
// which are distributed inside your company
- (BOOL)shouldUseLiveIdenfitier;
// Invoked when the internet connection is started
//
// Implement to let the delegate enable the activity indicator
- (void)connectionOpened;
// Invoked when the internet connection is closed
//
// Implement to let the delegate disable the activity indicator
- (void)connectionClosed;
// Invoked via the alert view to define the presenting view controller
//
// Default is the root view controller of the main window instance
- (UIViewController *)viewControllerForHockeyController:(BWHockeyManager *)hockeyController;
// Invoked before a crash report will be sent
//
// Return a userid or similar which the crashreport should contain
//
// Maximum length: 255 chars
//
// Default: empty
- (NSString *)crashReportUserID;
// Invoked before a crash report will be sent
//
// Return contact data, e.g. an email address, for the crash report
// Maximum length: 255 chars
//
// Default: empty
-(NSString *)crashReportContact;
// Invoked before a crash report will be sent
//
// Return a the description for the crashreport should contain; the string
// will automatically be wrapped into <[DATA[ ]]>, so make sure you don't do
// that in your string.
//
// Default: empty
-(NSString *)crashReportDescription;
// Invoked before the user is asked to send a crash report
//
// Implement to do additional actions, e.g. to make sure to not to ask the
// user for an app rating :)
- (void)willShowSubmitCrashReportAlert;
// Invoked after the user did choose to send crashes always in the alert
-(void) userDidChooseSendAlways;
@end
@interface CNSHockeyManager : NSObject {
@private
id<CNSHockeyManagerDelegate> delegate;
NSString *appIdentifier;
}
#pragma mark - Public Properties
// Custom language style; set to a string which will be appended to
// to the localization file name; the Hockey SDK includes an alternative
// file, to use this, set to @"Alternate"
//
// Default: nil
@property (nonatomic, retain) NSString *languageStyle;
// Enable debug logging; ONLY ENABLE THIS FOR DEBUGGING!
//
// Default: NO
@property (nonatomic, assign, getter=isLoggingEnabled) BOOL loggingEnabled;
// Show button "Always" in crash alert; this will cause the dialog not to
// show the alert description text landscape mode! (default)
//
// Default: NO
@property (nonatomic, assign, getter=isShowingAlwaysButton) BOOL showAlwaysButton;
// Show feedback from server with status of the crash; if you set a crash
// to resolved on HockeyApp and assign a fixed version, this version will
// be reported to the user
//
// Default: NO
@property (nonatomic, assign, getter=isFeedbackActivated) BOOL feedbackActivated;
// Submit crash report without asking the user
//
// Default: NO
@property (nonatomic, assign, getter=isAutoSubmitCrashReport) BOOL autoSubmitCrashReport;
// Send user data to HockeyApp when checking for a new version; works only
// for beta apps and should not be activated for live apps. User data includes
// the device type, OS version, app version and device UDID.
//
// Default: YES
@property (nonatomic, assign, getter=shouldSendUserData) BOOL sendUserData;
// Send usage time to HockeyApp when checking for a new version; works only
// for beta apps and should not be activated for live apps.
//
// Default: YES
@property (nonatomic, assign, getter=shouldSendUsageTime) BOOL sendUsageTime;
// Enable to allow the user to change the settings from the update view
//
// Default: YES
@property (nonatomic, assign, getter=shouldShowUserSettings) BOOL showUserSettings;
// Set bar style of navigation controller
//
// Default: UIBarStyleDefault
@property (nonatomic, assign) UIBarStyle barStyle;
// Set modal presentation style of update view
//
// Default: UIModalPresentationStyleFormSheet
@property (nonatomic, assign) UIModalPresentationStyle modalPresentationStyle;
// Allow the user to disable the sending of user data; this settings should
// only be set if showUserSettings is enabled.
//
// Default: YES
@property (nonatomic, assign, getter=isUserAllowedToDisableSendData) BOOL allowUserToDisableSendData;
// Enable to show the new version alert every time the app becomes active and
// the current version is outdated
//
// Default: YES
@property (nonatomic, assign) BOOL alwaysShowUpdateReminder;
// Enable to check for a new version every time the app becomes active; if
// disabled you need to trigger the update mechanism manually
//
// Default: YES
@property (nonatomic, assign, getter=shouldCheckForUpdateOnLaunch) BOOL checkForUpdateOnLaunch;
// Show a button "Install" in the update alert to let the user directly start
// the update; note that the user will not see the release notes.
//
// Default: NO
@property (nonatomic, assign, getter=isShowingDirectInstallOption) BOOL showDirectInstallOption;
// Enable to check on the server that the app is authorized to run on this
// device; the check is based on the UDID and the authentication secret which
// is shown on the app page on HockeyApp
//
// Default: NO
@property (nonatomic, assign, getter=shouldRequireAuthorization) BOOL requireAuthorization;
// Set to the authentication secret which is shown on the app page on HockeyApp;
// must be set if requireAuthorization is enabled; leave empty otherwise
//
// Default: nil
@property (nonatomic, retain) NSString *authenticationSecret;
// Define how the client determines if a new version is available.
//
// Values:
// HockeyComparisonResultDifferent - the version on the server is different
// HockeyComparisonResultGreate - the version on the server is greater
//
// Default: HockeyComparisonResultGreater
@property (nonatomic, assign) HockeyComparisonResult compareVersionType;
// if YES the app is installed from the app store
// if NO the app is installed via ad-hoc or enterprise distribution
@property (nonatomic, readonly) BOOL isAppStoreEnvironment;
#pragma mark - Public Methods
// Returns the shared manager object
+ (CNSHockeyManager *)sharedHockeyManager;
// Configure HockeyApp with a single app identifier and delegate; use this
// only for debug or beta versions of your app!
- (void)configureWithIdentifier:(NSString *)appIdentifier delegate:(id<CNSHockeyManagerDelegate>)delegate;
// Configure HockeyApp with different app identifiers for beta and live versions
// of the app; the update alert will only be shown for the beta identifier
- (void)configureWithBetaIdentifier:(NSString *)betaIdentifier liveIdentifier:(NSString *)liveIdentifier delegate:(id<CNSHockeyManagerDelegate>)delegate;
// Returns true if the app crashes in the last session
- (BOOL)didCrashInLastSession;
// Returns true if an update is available
- (BOOL)isUpdateAvailable;
// Returns true if update check is running
- (BOOL)isCheckInProgress;
// Show update info view
- (void)showUpdateView;
// Manually start an update check
- (void)checkForUpdate;
// Checks for update and informs the user if an update was found or an
// error occurred
- (void)checkForUpdateShowFeedback:(BOOL)feedback;
// Initiates app-download call; this displays an alert view of the OS
- (BOOL)initiateAppDownload;
// Returns true if this app version was authorized with the server
- (BOOL)appVersionIsAuthorized;
// Manually check if the device is authorized to run this version
- (void)checkForAuthorization;
// Return a new instance of BWHockeyViewController
- (BWHockeyViewController *)hockeyViewController:(BOOL)modal;
@end

View File

@ -1,427 +0,0 @@
// Copyright 2011 Codenauts UG (haftungsbeschränkt). All rights reserved.
// See LICENSE.txt for author information.
//
// 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 "CNSHockeyManager.h"
#import "BWQuincyManager.h"
#import "BWHockeyManager.h"
@interface CNSHockeyManager ()
- (BOOL)shouldUseLiveIdenfitier;
- (void)configureJMC;
- (void)configureHockeyManager;
- (void)configureQuincyManager;
@end
@implementation CNSHockeyManager
#pragma mark - Public Class Methods
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
+ (CNSHockeyManager *)sharedHockeyManager {
static CNSHockeyManager *sharedInstance = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
sharedInstance = [CNSHockeyManager alloc];
sharedInstance = [sharedInstance init];
});
return sharedInstance;
}
#else
+ (CNSHockeyManager *)sharedHockeyManager {
static CNSHockeyManager *hockeyManager = nil;
if (hockeyManager == nil) {
hockeyManager = [[CNSHockeyManager alloc] init];
}
return hockeyManager;
}
#endif
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
+ (id)jmcInstance {
id jmcClass = NSClassFromString(@"JMC");
if ((jmcClass) && ([jmcClass respondsToSelector:@selector(sharedInstance)])) {
return [jmcClass performSelector:@selector(sharedInstance)];
}
#ifdef JMC_LEGACY
else if ((jmcClass) && ([jmcClass respondsToSelector:@selector(instance)])) {
return [jmcClass performSelector:@selector(instance)]; // legacy pre (JMC 1.0.11) support
}
#endif
return nil;
}
#pragma clang diagnostic pop
+ (BOOL)isJMCActive {
id jmcInstance = [self jmcInstance];
return (jmcInstance) && ([jmcInstance performSelector:@selector(url)]);
}
+ (BOOL)isJMCPresent {
return [self jmcInstance] != nil;
}
#pragma mark - Private Class Methods
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
+ (void)disableJMCCrashReporter {
id jmcInstance = [self jmcInstance];
id jmcOptions = [jmcInstance performSelector:@selector(options)];
SEL crashReporterSelector = @selector(setCrashReportingEnabled:);
BOOL value = NO;
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[jmcOptions methodSignatureForSelector:crashReporterSelector]];
invocation.target = jmcOptions;
invocation.selector = crashReporterSelector;
[invocation setArgument:&value atIndex:2];
[invocation invoke];
}
#pragma clang diagnostic pop
+ (BOOL)checkJMCConfiguration:(NSDictionary *)configuration {
return (([configuration isKindOfClass:[NSDictionary class]]) &&
([[configuration valueForKey:@"enabled"] boolValue]) &&
([[configuration valueForKey:@"url"] length] > 0) &&
([[configuration valueForKey:@"key"] length] > 0) &&
([[configuration valueForKey:@"project"] length] > 0));
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
+ (void)applyJMCConfiguration:(NSDictionary *)configuration {
id jmcInstance = [self jmcInstance];
SEL configureSelector = @selector(configureJiraConnect:projectKey:apiKey:);
NSString *url = [configuration valueForKey:@"url"];
NSString *project = [configuration valueForKey:@"project"];
NSString *key = [configuration valueForKey:@"key"];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[jmcInstance methodSignatureForSelector:configureSelector]];
invocation.target = jmcInstance;
invocation.selector = configureSelector;
[invocation setArgument:&url atIndex:2];
[invocation setArgument:&project atIndex:3];
[invocation setArgument:&key atIndex:4];
[invocation invoke];
if ([jmcInstance respondsToSelector:@selector(ping)]) {
[jmcInstance performSelector:@selector(ping)];
}
}
#pragma clang diagnostic pop
#pragma mark - Public Instance Methods (Configuration)
- (void)configureWithIdentifier:(NSString *)newAppIdentifier delegate:(id)newDelegate {
delegate = newDelegate;
[appIdentifier release];
appIdentifier = [newAppIdentifier copy];
[self configureQuincyManager];
[self configureHockeyManager];
}
- (void)configureWithBetaIdentifier:(NSString *)betaIdentifier liveIdentifier:(NSString *)liveIdentifier delegate:(id)newDelegate {
delegate = newDelegate;
[appIdentifier release];
if ([self shouldUseLiveIdenfitier]) {
appIdentifier = [liveIdentifier copy];
}
else {
appIdentifier = [betaIdentifier copy];
}
if (appIdentifier) {
[self configureQuincyManager];
[self configureHockeyManager];
}
}
- (BOOL)isLoggingEnabled {
return [[BWHockeyManager sharedHockeyManager] isLoggingEnabled];
return [[BWQuincyManager sharedQuincyManager] isLoggingEnabled];
}
- (void)setLoggingEnabled:(BOOL)loggingEnabled {
return [[BWHockeyManager sharedHockeyManager] setLoggingEnabled:loggingEnabled];
return [[BWQuincyManager sharedQuincyManager] setLoggingEnabled:loggingEnabled];
}
#pragma mark - Public Instance Methods (Crash Reporting)
- (NSString *)languageStyle {
return [[BWQuincyManager sharedQuincyManager] languageStyle];
}
- (void)setLanguageStyle:(NSString *)languageStyle {
[[BWQuincyManager sharedQuincyManager] setLanguageStyle:languageStyle];
}
- (BOOL)isShowingAlwaysButton {
return [[BWQuincyManager sharedQuincyManager] isShowingAlwaysButton];
}
- (void)setShowAlwaysButton:(BOOL)showAlwaysButton {
[[BWQuincyManager sharedQuincyManager] setShowAlwaysButton:showAlwaysButton];
}
- (BOOL)isFeedbackActivated {
return [[BWQuincyManager sharedQuincyManager] isFeedbackActivated];
}
- (void)setFeedbackActivated:(BOOL)setFeedbackActivated {
[[BWQuincyManager sharedQuincyManager] setFeedbackActivated:setFeedbackActivated];
}
- (BOOL)isAutoSubmitCrashReport {
return [[BWQuincyManager sharedQuincyManager] isAutoSubmitCrashReport];
}
- (void)setAutoSubmitCrashReport:(BOOL)autoSubmitCrashReport {
[[BWQuincyManager sharedQuincyManager] setAutoSubmitCrashReport:autoSubmitCrashReport];
}
- (BOOL)didCrashInLastSession {
return [[BWQuincyManager sharedQuincyManager] didCrashInLastSession];
}
#pragma mark - Public Instance Methods (Distribution)
- (BOOL)shouldSendUserData {
return [[BWHockeyManager sharedHockeyManager] shouldSendUserData];
}
- (void)setSendUserData:(BOOL)sendUserData {
[[BWHockeyManager sharedHockeyManager] setSendUserData:sendUserData];
}
- (BOOL)shouldSendUsageTime {
return [[BWHockeyManager sharedHockeyManager] shouldSendUsageTime];
}
- (void)setSendUsageTime:(BOOL)sendUsageTime {
[[BWHockeyManager sharedHockeyManager] setSendUsageTime:sendUsageTime];
}
- (BOOL)shouldShowUserSettings {
return [[BWHockeyManager sharedHockeyManager] shouldShowUserSettings];
}
- (void)setShowUserSettings:(BOOL)showUserSettings {
[[BWHockeyManager sharedHockeyManager] setShowUserSettings:showUserSettings];
}
- (UIBarStyle)barStyle {
return [[BWHockeyManager sharedHockeyManager] barStyle];
}
- (void)setBarStyle:(UIBarStyle)barStyle {
[[BWHockeyManager sharedHockeyManager] setBarStyle:barStyle];
}
- (UIModalPresentationStyle)modalPresentationStyle {
return [[BWHockeyManager sharedHockeyManager] modalPresentationStyle];
}
- (void)setModalPresentationStyle:(UIModalPresentationStyle)modalPresentationStyle {
[[BWHockeyManager sharedHockeyManager] setModalPresentationStyle:modalPresentationStyle];
}
- (BOOL)isUserAllowedToDisableSendData {
return [[BWHockeyManager sharedHockeyManager] isAllowUserToDisableSendData];
}
- (void)setAllowUserToDisableSendData:(BOOL)allowUserToDisableSendData {
[[BWHockeyManager sharedHockeyManager] setAllowUserToDisableSendData:allowUserToDisableSendData];
}
- (BOOL)alwaysShowUpdateReminder {
return [[BWHockeyManager sharedHockeyManager] alwaysShowUpdateReminder];
}
- (void)setAlwaysShowUpdateReminder:(BOOL)alwaysShowUpdateReminder {
[[BWHockeyManager sharedHockeyManager] setAlwaysShowUpdateReminder:alwaysShowUpdateReminder];
}
- (BOOL)shouldCheckForUpdateOnLaunch {
return [[BWHockeyManager sharedHockeyManager] isCheckForUpdateOnLaunch];
}
- (void)setCheckForUpdateOnLaunch:(BOOL)checkForUpdateOnLaunch {
[[BWHockeyManager sharedHockeyManager] setCheckForUpdateOnLaunch:checkForUpdateOnLaunch];
}
- (BOOL)isShowingDirectInstallOption {
return [[BWHockeyManager sharedHockeyManager] isShowingDirectInstallOption];
}
- (void)setShowDirectInstallOption:(BOOL)showDirectInstallOption {
[[BWHockeyManager sharedHockeyManager] setShowDirectInstallOption:showDirectInstallOption];
}
- (BOOL)shouldRequireAuthorization {
return [[BWHockeyManager sharedHockeyManager] isRequireAuthorization];
}
- (void)setRequireAuthorization:(BOOL)requireAuthorization {
[[BWHockeyManager sharedHockeyManager] setRequireAuthorization:requireAuthorization];
}
- (NSString *)authenticationSecret {
return [[BWHockeyManager sharedHockeyManager] authenticationSecret];
}
- (void)setAuthenticationSecret:(NSString *)authenticationSecret {
[[BWHockeyManager sharedHockeyManager] setAuthenticationSecret:authenticationSecret];
}
- (HockeyComparisonResult)compareVersionType {
return [[BWHockeyManager sharedHockeyManager] compareVersionType];
}
- (void)setCompareVersionType:(HockeyComparisonResult)compareVersionType {
[[BWHockeyManager sharedHockeyManager] setCompareVersionType:compareVersionType];
}
- (BOOL)isAppStoreEnvironment {
return [[BWHockeyManager sharedHockeyManager] isAppStoreEnvironment];
}
- (BOOL)isUpdateAvailable {
return [[BWHockeyManager sharedHockeyManager] isUpdateAvailable];
}
- (BOOL)isCheckInProgress {
return [[BWHockeyManager sharedHockeyManager] isCheckInProgress];
}
- (void)showUpdateView {
[[BWHockeyManager sharedHockeyManager] showUpdateView];
}
- (void)checkForUpdate {
[[BWHockeyManager sharedHockeyManager] checkForUpdate];
}
- (void)checkForUpdateShowFeedback:(BOOL)feedback {
[[BWHockeyManager sharedHockeyManager] checkForUpdateShowFeedback:feedback];
}
- (BOOL)initiateAppDownload {
return [[BWHockeyManager sharedHockeyManager] initiateAppDownload];
}
- (BOOL)appVersionIsAuthorized {
return [[BWHockeyManager sharedHockeyManager] appVersionIsAuthorized];
}
- (void)checkForAuthorization {
[[BWHockeyManager sharedHockeyManager] checkForAuthorization];
}
- (BWHockeyViewController *)hockeyViewController:(BOOL)modal {
return [[BWHockeyManager sharedHockeyManager] hockeyViewController:modal];
}
#pragma mark - Private Instance Methods
- (BOOL)shouldUseLiveIdenfitier {
BOOL delegateResult = NO;
if ([delegate respondsToSelector:@selector(shouldUseLiveIdenfitier)]) {
delegateResult = [(NSObject <CNSHockeyManagerDelegate>*)delegate shouldUseLiveIdenfitier];
}
return (delegateResult) || ([[BWHockeyManager sharedHockeyManager] isAppStoreEnvironment]);
}
- (void)configureQuincyManager {
[[BWQuincyManager sharedQuincyManager] setAppIdentifier:appIdentifier];
[[BWQuincyManager sharedQuincyManager] setDelegate:(id)delegate];
}
- (void)configureHockeyManager {
[[BWHockeyManager sharedHockeyManager] setAppIdentifier:appIdentifier];
[[BWHockeyManager sharedHockeyManager] setCheckForTracker:YES];
[[BWHockeyManager sharedHockeyManager] setDelegate:(id)delegate];
// Only if JMC is part of the project
if ([[self class] isJMCPresent]) {
[[BWHockeyManager sharedHockeyManager] addObserver:self forKeyPath:@"trackerConfig" options:0 context:nil];
[[self class] disableJMCCrashReporter];
[self performSelector:@selector(configureJMC) withObject:nil afterDelay:0];
}
}
- (void)configureJMC {
// Return if JMC is already configured
if ([[self class] isJMCActive]) {
return;
}
// Return if app id is nil
if (!appIdentifier) {
return;
}
// Configure JMC from user defaults
NSDictionary *configurations = [[NSUserDefaults standardUserDefaults] valueForKey:@"CNSTrackerConfigurations"];
NSDictionary *configuration = [configurations valueForKey:appIdentifier];
if ([[self class] checkJMCConfiguration:configuration]) {
[[self class] applyJMCConfiguration:configuration];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (([object trackerConfig]) && ([[object trackerConfig] isKindOfClass:[NSDictionary class]])) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *trackerConfig = [[defaults valueForKey:@"CNSTrackerConfigurations"] mutableCopy];
if (!trackerConfig) {
trackerConfig = [[NSMutableDictionary dictionaryWithCapacity:1] retain];
}
[trackerConfig setValue:[object trackerConfig] forKey:appIdentifier];
[defaults setValue:trackerConfig forKey:@"CNSTrackerConfigurations"];
[trackerConfig release];
[defaults synchronize];
[self configureJMC];
}
}
- (void)dealloc {
[appIdentifier release], appIdentifier = nil;
delegate = nil;
[super dealloc];
}
@end

82
Classes/HockeySDK.h Normal file
View File

@ -0,0 +1,82 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
*
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* Copyright (c) 2011 Andreas Linde.
* 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 HockeySDK_h
#define HockeySDK_h
#import "BITHockeyManager.h"
#import "BITHockeyManagerDelegate.h"
#import "BITCrashManager.h"
#import "BITCrashManagerDelegate.h"
#import "BITUpdateManager.h"
#import "BITUpdateManagerDelegate.h"
#import "BITUpdateViewController.h"
#import "BITUpdateSettingsViewController.h"
// Notification message which HockeyManager is listening to, to retry requesting updated from the server
#define BITHockeyNetworkDidBecomeReachableNotification @"BITHockeyNetworkDidBecomeReachable"
// Crash Reporting
// flags if the crashreporter is activated at all
// set this as bool in user defaults e.g. in the settings, if you want to let the user be able to deactivate it
#define kBITCrashActivated @"BITCrashActivated"
// flags if the crashreporter should automatically send crashes without asking the user again
// set this as bool in user defaults e.g. in the settings, if you want to let the user be able to set this on or off
#define kBITCrashAutomaticallySendReports @"BITCrashAutomaticallySendReports"
// hockey api error domain
typedef enum {
BITCrashErrorUnknown,
BITCrashAPIAppVersionRejected,
BITCrashAPIReceivedEmptyResponse,
BITCrashAPIErrorWithStatusCode
} BITCrashErrorReason;
static NSString *kBITCrashErrorDomain = @"BITCrashReporterErrorDomain";
// Update App Versions
// hockey api error domain
typedef enum {
BITUpdateErrorUnknown,
BITUpdateAPIServerReturnedInvalidStatus,
BITUpdateAPIServerReturnedInvalidData,
BITUpdateAPIServerReturnedEmptyResponse,
BITUpdateAPIClientAuthorizationMissingSecret,
BITUpdateAPIClientCannotCreateConnection
} BITUpdateErrorReason;
static NSString *kBITUpdateErrorDomain = @"BITUpdaterErrorDomain";
#endif

View File

@ -0,0 +1,94 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
* Kent Sutherland
*
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* Copyright (c) 2011 Andreas Linde & Kent Sutherland.
* 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>
#ifndef HockeySDK_HockeySDKPrivate_h
#define HockeySDK_HockeySDKPrivate_h
#define BITHOCKEYSDK_NAME @"HockeySDK"
#define BITHOCKEYSDK_VERSION @"2.3.0-dev"
#define kBITUpdateArrayOfLastCheck @"BITUpdateArrayOfLastCheck"
#define kBITUpdateDateOfLastCheck @"BITUpdateDateOfLastCheck"
#define kBITUpdateDateOfVersionInstallation @"BITUpdateDateOfVersionInstallation"
#define kBITUpdateUsageTimeOfCurrentVersion @"BITUpdateUsageTimeOfCurrentVersion"
#define kBITUpdateUsageTimeForVersionString @"BITUpdateUsageTimeForVersionString"
#define kBITUpdateAutoUpdateSetting @"BITUpdateAutoUpdateSetting"
#define kBITUpdateAllowUserSetting @"BITUpdateAllowUserSetting"
#define kBITUpdateAllowUsageSetting @"BITUpdateAllowUsageSetting"
#define kBITUpdateAutoUpdateSetting @"BITUpdateAutoUpdateSetting"
#define kBITUpdateAuthorizedVersion @"BITUpdateAuthorizedVersion"
#define kBITUpdateAuthorizedToken @"BITUpdateAuthorizedToken"
#define BITHOCKEYSDK_BUNDLE @"HockeySDKResources"
#define BITHOCKEYSDK_URL @"https://sdk.hockeyapp.net/"
#define BITHockeySDKLog(fmt, ...) do { if([BITHockeyManager sharedHockeyManager].isLoggingEnabled) { NSLog((@"[HockeySDK] %s/%d " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); }} while(0)
NSBundle *BITHockeySDKBundle(void);
NSString *BITHockeySDKLocalizedString(NSString *stringToken);
NSString *BITHockeySDKMD5(NSString *str);
// compatibility helper
#ifdef BITHOCKEYSDK_STATIC_LIBRARY
// If HockeySDK is built as a static library and linked into the project
// we can't use this project's deployment target to statically decide if
// native JSON is available
#define BITHOCKEYSDK_NATIVE_JSON_AVAILABLE 0
#else
#define BITHOCKEYSDK_NATIVE_JSON_AVAILABLE __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000
#endif
#ifndef kCFCoreFoundationVersionNumber_iPhoneOS_5_0
#define kCFCoreFoundationVersionNumber_iPhoneOS_5_0 674.0
#endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 50000
#define BITHOCKEYSDK_IF_IOS5_OR_GREATER(...) \
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_5_0) \
{ \
__VA_ARGS__ \
}
#else
#define BITHOCKEYSDK_IF_IOS5_OR_GREATER(...)
#endif
#define BITHOCKEYSDK_IF_PRE_IOS5(...) \
if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_5_0) \
{ \
__VA_ARGS__ \
}
#endif

View File

@ -0,0 +1,69 @@
/*
* Author: Andreas Linde <mail@andreaslinde.de>
*
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* Copyright (c) 2011 Andreas Linde.
* 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 "HockeySDKPrivate.h"
#include <CommonCrypto/CommonDigest.h>
// Load the framework bundle.
NSBundle *BITHockeySDKBundle(void) {
static NSBundle *bundle = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
NSString* mainBundlePath = [[NSBundle mainBundle] resourcePath];
NSString* frameworkBundlePath = [mainBundlePath stringByAppendingPathComponent:BITHOCKEYSDK_BUNDLE];
bundle = [[NSBundle bundleWithPath:frameworkBundlePath] retain];
});
return bundle;
}
NSString *BITHockeySDKLocalizedString(NSString *stringToken) {
if (BITHockeySDKBundle()) {
return NSLocalizedStringFromTableInBundle(stringToken, @"HockeySDK", BITHockeySDKBundle(), @"");
} else {
return stringToken;
}
}
NSString *BITHockeySDKMD5(NSString *str) {
const char *cStr = [str UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5( cStr, strlen(cStr), result );
return [NSString
stringWithFormat: @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1],
result[2], result[3],
result[4], result[5],
result[6], result[7],
result[8], result[9],
result[10], result[11],
result[12], result[13],
result[14], result[15]
];
}

View File

@ -1,8 +1,7 @@
// //
// NSString+HockeyAdditions.h
//
// Created by Jon Crosby on 10/19/07. // Created by Jon Crosby on 10/19/07.
// Copyright 2007 Kaboomerang LLC. All rights reserved. // Copyright 2007 Kaboomerang LLC. All rights reserved.
// Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -25,11 +24,11 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@interface NSString (HockeyAdditions) @interface NSString (BITHockeyAdditions)
- (NSString *)bw_URLEncodedString; - (NSString *)bit_URLEncodedString;
- (NSString *)bw_URLDecodedString; - (NSString *)bit_URLDecodedString;
- (NSComparisonResult)versionCompare:(NSString *)other; - (NSComparisonResult)bit_versionCompare:(NSString *)other;
@end @end

View File

@ -1,8 +1,7 @@
// //
// NSString+HockeyAdditions.m
//
// Created by Jon Crosby on 10/19/07. // Created by Jon Crosby on 10/19/07.
// Copyright 2007 Kaboomerang LLC. All rights reserved. // Copyright 2007 Kaboomerang LLC. All rights reserved.
// Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -23,16 +22,11 @@
// THE SOFTWARE. // THE SOFTWARE.
#import "NSString+HockeyAdditions.h" #import "NSString+BITHockeyAdditions.h"
#ifdef HOCKEYLIB_STATIC_LIBRARY @implementation NSString (BITHockeyAdditions)
#import "CNSFixCategoryBug.h"
CNS_FIX_CATEGORY_BUG(NSString_HockeyAdditions)
#endif
@implementation NSString (HockeyAdditions) - (NSString *)bit_URLEncodedString {
- (NSString *)bw_URLEncodedString {
NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)self, (CFStringRef)self,
NULL, NULL,
@ -42,7 +36,7 @@ CNS_FIX_CATEGORY_BUG(NSString_HockeyAdditions)
return result; return result;
} }
- (NSString*)bw_URLDecodedString { - (NSString*)bit_URLDecodedString {
NSString *result = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, NSString *result = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
(CFStringRef)self, (CFStringRef)self,
CFSTR(""), CFSTR(""),
@ -51,7 +45,7 @@ CNS_FIX_CATEGORY_BUG(NSString_HockeyAdditions)
return result; return result;
} }
- (NSComparisonResult)versionCompare:(NSString *)other { - (NSComparisonResult)bit_versionCompare:(NSString *)other {
// Extract plain version number from self // Extract plain version number from self
NSString *plainSelf = self; NSString *plainSelf = self;
NSRange letterRange = [plainSelf rangeOfCharacterFromSet: [NSCharacterSet letterCharacterSet]]; NSRange letterRange = [plainSelf rangeOfCharacterFromSet: [NSCharacterSet letterCharacterSet]];

View File

@ -1,9 +1,6 @@
// //
// PSAppStoreHeader.h
// HockeyDemo
//
// Created by Peter Steinberger on 09.01.11. // Created by Peter Steinberger on 09.01.11.
// Copyright 2011 Peter Steinberger. All rights reserved. // Copyright (c) 2011-2012 Peter Steinberger. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal

View File

@ -1,9 +1,6 @@
// //
// PSAppStoreHeader.m
// HockeyDemo
//
// Created by Peter Steinberger on 09.01.11. // Created by Peter Steinberger on 09.01.11.
// Copyright 2011 Peter Steinberger. All rights reserved. // Copyright (c) 2011-2012 Peter Steinberger. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -24,13 +21,14 @@
// THE SOFTWARE. // THE SOFTWARE.
#import "PSAppStoreHeader.h" #import "PSAppStoreHeader.h"
#import "UIImage+HockeyAdditions.h" #import "UIImage+BITHockeyAdditions.h"
#import "BWGlobal.h" #import "HockeySDKPrivate.h"
#define BW_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
#define kLightGrayColor BW_RGBCOLOR(200, 202, 204) #define BIT_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
#define kDarkGrayColor BW_RGBCOLOR(140, 141, 142)
#define kLightGrayColor BIT_RGBCOLOR(200, 202, 204)
#define kDarkGrayColor BIT_RGBCOLOR(140, 141, 142)
#define kImageHeight 57 #define kImageHeight 57
#define kReflectionHeight 20 #define kReflectionHeight 20
@ -45,9 +43,8 @@
@synthesize subHeaderLabel; @synthesize subHeaderLabel;
@synthesize iconImage = iconImage_; @synthesize iconImage = iconImage_;
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - NSObject
#pragma mark NSObject
- (id)initWithFrame:(CGRect)frame { - (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) { if ((self = [super initWithFrame:frame])) {
@ -67,9 +64,7 @@
} }
/////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - UIView
#pragma mark -
#pragma mark UIView
- (void)drawRect:(CGRect)rect { - (void)drawRect:(CGRect)rect {
CGRect bounds = self.bounds; CGRect bounds = self.bounds;
@ -85,8 +80,8 @@
CGGradientRelease(gradient); CGGradientRelease(gradient);
// draw header name // draw header name
UIColor *mainTextColor = BW_RGBCOLOR(0,0,0); UIColor *mainTextColor = BIT_RGBCOLOR(0,0,0);
UIColor *secondaryTextColor = BW_RGBCOLOR(48,48,48); UIColor *secondaryTextColor = BIT_RGBCOLOR(48,48,48);
UIFont *mainFont = [UIFont boldSystemFontOfSize:20]; UIFont *mainFont = [UIFont boldSystemFontOfSize:20];
UIFont *secondaryFont = [UIFont boldSystemFontOfSize:12]; UIFont *secondaryFont = [UIFont boldSystemFontOfSize:12];
UIFont *smallFont = [UIFont systemFontOfSize:12]; UIFont *smallFont = [UIFont systemFontOfSize:12];
@ -101,12 +96,10 @@
// shadows are a beast // shadows are a beast
NSInteger shadowOffset = 2; NSInteger shadowOffset = 2;
BW_IF_IOS4_OR_GREATER(if([[UIScreen mainScreen] scale] == 2) shadowOffset = 1;) if([[UIScreen mainScreen] scale] == 2) shadowOffset = 1;
BW_IF_IOS5_OR_GREATER(shadowOffset = 1;) // iOS5 changes this - again! BITHOCKEYSDK_IF_IOS5_OR_GREATER(shadowOffset = 1;) // iOS5 changes this - again!
BW_IF_3_2_OR_GREATER(CGContextSetShadowWithColor(context, CGSizeMake(shadowOffset, shadowOffset), 0, myColor);)
BW_IF_PRE_3_2(shadowOffset=1;CGContextSetShadowWithColor(context, CGSizeMake(shadowOffset, -shadowOffset), 0, myColor);)
CGContextSetShadowWithColor(context, CGSizeMake(shadowOffset, shadowOffset), 0, myColor);
[mainTextColor set]; [mainTextColor set];
[headerLabel_ drawInRect:CGRectMake(kTextRow, kImageMargin, globalWidth-kTextRow, 20) withFont:mainFont lineBreakMode:UILineBreakModeTailTruncation]; [headerLabel_ drawInRect:CGRectMake(kTextRow, kImageMargin, globalWidth-kTextRow, 20) withFont:mainFont lineBreakMode:UILineBreakModeTailTruncation];
@ -124,9 +117,8 @@
CGColorSpaceRelease(myColorSpace); CGColorSpaceRelease(myColorSpace);
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - Properties
#pragma mark Properties
- (void)setHeaderLabel:(NSString *)anHeaderLabel { - (void)setHeaderLabel:(NSString *)anHeaderLabel {
if (headerLabel_ != anHeaderLabel) { if (headerLabel_ != anHeaderLabel) {
@ -157,14 +149,14 @@
[iconImage_ release]; [iconImage_ release];
// scale, make borders and reflection // scale, make borders and reflection
iconImage_ = [anIconImage bw_imageToFitSize:CGSizeMake(kImageHeight, kImageHeight) honorScaleFactor:YES]; iconImage_ = [anIconImage bit_imageToFitSize:CGSizeMake(kImageHeight, kImageHeight) honorScaleFactor:YES];
iconImage_ = [[iconImage_ bw_roundedCornerImage:kImageBorderRadius borderSize:0.0] retain]; iconImage_ = [[iconImage_ bit_roundedCornerImage:kImageBorderRadius borderSize:0.0] retain];
// create reflected image // create reflected image
[reflectedImage_ release]; [reflectedImage_ release];
reflectedImage_ = nil; reflectedImage_ = nil;
if (anIconImage) { if (anIconImage) {
reflectedImage_ = [[iconImage_ bw_reflectedImageWithHeight:kReflectionHeight fromAlpha:0.5 toAlpha:0.0] retain]; reflectedImage_ = [[iconImage_ bit_reflectedImageWithHeight:kReflectionHeight fromAlpha:0.5 toAlpha:0.0] retain];
} }
[self setNeedsDisplay]; [self setNeedsDisplay];
} }

View File

@ -1,9 +1,6 @@
// //
// PSStoreButton.h
// HockeyDemo
//
// Created by Peter Steinberger on 09.01.11. // Created by Peter Steinberger on 09.01.11.
// Copyright 2011 Peter Steinberger. All rights reserved. // Copyright 2011-2012 Peter Steinberger. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal

View File

@ -1,9 +1,6 @@
// //
// PSStoreButton.m
// HockeyDemo
//
// Created by Peter Steinberger on 09.01.11. // Created by Peter Steinberger on 09.01.11.
// Copyright 2011 Peter Steinberger. All rights reserved. // Copyright 2011-2012 Peter Steinberger. All rights reserved.
// //
// This code was inspired by https://github.com/dhmspector/ZIStoreButton // This code was inspired by https://github.com/dhmspector/ZIStoreButton
// //
@ -39,9 +36,8 @@
@synthesize colors = colors_; @synthesize colors = colors_;
@synthesize enabled = enabled_; @synthesize enabled = enabled_;
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - NSObject
#pragma mark NSObject
- (id)initWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag { - (id)initWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag {
if ((self = [super init])) { if ((self = [super init])) {
@ -77,9 +73,8 @@
@synthesize buttonDelegate = buttonDelegate_; @synthesize buttonDelegate = buttonDelegate_;
@synthesize customPadding = customPadding_; @synthesize customPadding = customPadding_;
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - private
#pragma mark private
- (void)buttonPressed:(id)sender { - (void)buttonPressed:(id)sender {
[buttonDelegate_ storeButtonFired:self]; [buttonDelegate_ storeButtonFired:self];
@ -159,9 +154,8 @@
} }
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - NSObject
#pragma mark NSObject
- (id)initWithFrame:(CGRect)frame { - (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) { if ((self = [super initWithFrame:frame])) {
@ -214,9 +208,8 @@
[super dealloc]; [super dealloc];
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - UIView
#pragma mark UIView
- (CGSize)sizeThatFits:(CGSize)size { - (CGSize)sizeThatFits:(CGSize)size {
CGSize constr = (CGSize){.height = self.frame.size.height, .width = PS_MAX_WIDTH}; CGSize constr = (CGSize){.height = self.frame.size.height, .width = PS_MAX_WIDTH};
@ -241,9 +234,8 @@
} }
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - Properties
#pragma mark Properties
- (void)setButtonData:(PSStoreButtonData *)aButtonData { - (void)setButtonData:(PSStoreButtonData *)aButtonData {
[self setButtonData:aButtonData animated:NO]; [self setButtonData:aButtonData animated:NO];
@ -258,9 +250,8 @@
[self updateButtonAnimated:animated]; [self updateButtonAnimated:animated];
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - Static
#pragma mark Static
+ (NSArray *)appStoreGreenColor { + (NSArray *)appStoreGreenColor {
return [NSArray arrayWithObjects:(id) return [NSArray arrayWithObjects:(id)

View File

@ -1,9 +1,6 @@
// //
// PSWebTableViewCell.h
// HockeyDemo
//
// Created by Peter Steinberger on 04.02.11. // Created by Peter Steinberger on 04.02.11.
// Copyright 2011 Peter Steinberger. All rights reserved. // Copyright 2011-2012 Peter Steinberger. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal

View File

@ -1,9 +1,6 @@
// //
// PSWebTableViewCell.m
// HockeyDemo
//
// Created by Peter Steinberger on 04.02.11. // Created by Peter Steinberger on 04.02.11.
// Copyright 2011 Peter Steinberger. All rights reserved. // Copyright 2011-2012 Peter Steinberger. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -24,7 +21,7 @@
// THE SOFTWARE. // THE SOFTWARE.
#import "PSWebTableViewCell.h" #import "PSWebTableViewCell.h"
#import "BWGlobal.h"
@implementation PSWebTableViewCell @implementation PSWebTableViewCell
@ -47,9 +44,8 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
@synthesize webViewSize = webViewSize_; @synthesize webViewSize = webViewSize_;
@synthesize cellBackgroundColor = cellBackgroundColor_; @synthesize cellBackgroundColor = cellBackgroundColor_;
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - private
#pragma mark private
- (void)addWebView { - (void)addWebView {
if(webViewContent_) { if(webViewContent_) {
@ -83,7 +79,7 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
webView_.frame = webViewRect; webView_.frame = webViewRect;
NSString *deviceWidth = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? [NSString stringWithFormat:@"%.0f", CGRectGetWidth(self.bounds)] : @"device-width"; NSString *deviceWidth = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? [NSString stringWithFormat:@"%.0f", CGRectGetWidth(self.bounds)] : @"device-width";
//BWHockeyLog(@"%@\n%@\%@", PSWebTableViewCellHtmlTemplate, deviceWidth, self.webViewContent); //HockeySDKLog(@"%@\n%@\%@", PSWebTableViewCellHtmlTemplate, deviceWidth, self.webViewContent);
NSString *contentHtml = [NSString stringWithFormat:PSWebTableViewCellHtmlTemplate, deviceWidth, self.webViewContent]; NSString *contentHtml = [NSString stringWithFormat:PSWebTableViewCellHtmlTemplate, deviceWidth, self.webViewContent];
[webView_ loadHTMLString:contentHtml baseURL:nil]; [webView_ loadHTMLString:contentHtml baseURL:nil];
} }
@ -118,9 +114,8 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
} }
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - NSObject
#pragma mark NSObject
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) { if((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
@ -135,9 +130,8 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
[super dealloc]; [super dealloc];
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - UIView
#pragma mark UIView
- (void)setFrame:(CGRect)aFrame { - (void)setFrame:(CGRect)aFrame {
BOOL needChange = !CGRectEqualToRect(aFrame, self.frame); BOOL needChange = !CGRectEqualToRect(aFrame, self.frame);
@ -148,9 +142,8 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
} }
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - UITableViewCell
#pragma mark UITableViewCell
- (void)prepareForReuse { - (void)prepareForReuse {
[self removeWebView]; [self removeWebView];
@ -158,9 +151,8 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
[super prepareForReuse]; [super prepareForReuse];
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - #pragma mark - UIWebView
#pragma mark UIWebView
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if(navigationType == UIWebViewNavigationTypeOther) if(navigationType == UIWebViewNavigationTypeOther)

View File

@ -1,9 +1,10 @@
// //
// UIImage+HockeyAdditions.h // UIImage+BITHockeySDKAdditions.h
// HockeyDemo
// //
// Created by Peter Steinberger on 10.01.11. // Created by Peter Steinberger on 10.01.11.
// Copyright 2011 Peter Steinberger. All rights reserved. // Copyright (c) 2011-2012 Peter Steinberger.
// Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
// All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -25,14 +26,14 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
@interface UIImage (HockeyAdditions) @interface UIImage (BITHockeySDKAdditions)
- (UIImage *)bw_roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize; - (UIImage *)bit_roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize;
- (UIImage *)bw_imageToFitSize:(CGSize)fitSize honorScaleFactor:(BOOL)honorScaleFactor; - (UIImage *)bit_imageToFitSize:(CGSize)fitSize honorScaleFactor:(BOOL)honorScaleFactor;
- (UIImage *)bw_reflectedImageWithHeight:(NSUInteger)height fromAlpha:(float)fromAlpha toAlpha:(float)toAlpha; - (UIImage *)bit_reflectedImageWithHeight:(NSUInteger)height fromAlpha:(float)fromAlpha toAlpha:(float)toAlpha;
- (id)bw_initWithContentsOfResolutionIndependentFile:(NSString *)path NS_RETURNS_RETAINED; - (id)bit_initWithContentsOfResolutionIndependentFile:(NSString *)path NS_RETURNS_RETAINED;
+ (UIImage*)bw_imageWithContentsOfResolutionIndependentFile:(NSString *)path; + (UIImage *)bit_imageWithContentsOfResolutionIndependentFile:(NSString *)path;
+ (UIImage *)bw_imageNamed:(NSString *)imageName bundle:(NSString *)bundleName; + (UIImage *)bit_imageNamed:(NSString *)imageName bundle:(NSString *)bundleName;
@end @end

View File

@ -1,9 +1,10 @@
// //
// UIImage+HockeyAdditions.m // UIImage+BITHockeySDKAdditions.m
// HockeyDemo
// //
// Created by Peter Steinberger on 10.01.11. // Created by Peter Steinberger on 10.01.11.
// Copyright 2011 Peter Steinberger. All rights reserved. // Copyright (c) 2011-2012 Peter Steinberger.
// Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
// All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -23,20 +24,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#import "UIImage+HockeyAdditions.h" #import "UIImage+BITHockeyAdditions.h"
#import "BWGlobal.h"
#ifdef HOCKEYLIB_STATIC_LIBRARY
#import "CNSFixCategoryBug.h"
CNS_FIX_CATEGORY_BUG(UIImage_HockeyAdditionsPrivate)
#endif
// Private helper methods // Private helper methods
@interface UIImage (HockeyAdditionsPrivate) @interface UIImage (BITHockeyAdditionsPrivate)
- (void)addRoundedRectToPath:(CGRect)rect context:(CGContextRef)context ovalWidth:(CGFloat)ovalWidth ovalHeight:(CGFloat)ovalHeight; - (void)bit_addRoundedRectToPath:(CGRect)rect context:(CGContextRef)context ovalWidth:(CGFloat)ovalWidth ovalHeight:(CGFloat)ovalHeight;
@end @end
@implementation UIImage (HockeyAdditions) @implementation UIImage (BITHockeyAdditions)
CGContextRef MyOpenBitmapContext(int pixelsWide, int pixelsHigh); CGContextRef MyOpenBitmapContext(int pixelsWide, int pixelsHigh);
CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha, float toAlpha); CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha, float toAlpha);
@ -84,12 +79,10 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
// Creates a copy of this image with rounded corners // Creates a copy of this image with rounded corners
// If borderSize is non-zero, a transparent border of the given size will also be added // If borderSize is non-zero, a transparent border of the given size will also be added
// Original author: Björn Sållarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/ // Original author: Björn Sållarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/
- (UIImage *)bw_roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize { - (UIImage *)bit_roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize {
// If the image does not have an alpha layer, add one // If the image does not have an alpha layer, add one
UIImage *roundedImage = nil; UIImage *roundedImage = nil;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
BW_IF_IOS4_OR_GREATER(
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0); // 0.0 for scale means "correct scale for device's main screen". UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0); // 0.0 for scale means "correct scale for device's main screen".
CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], CGRectMake(0, 0, self.size.width * self.scale, self.size.height * self.scale)); // cropping happens here. CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], CGRectMake(0, 0, self.size.width * self.scale, self.size.height * self.scale)); // cropping happens here.
@ -108,8 +101,7 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
CGImageRelease(sourceImg); CGImageRelease(sourceImg);
roundedImage = UIGraphicsGetImageFromCurrentImageContext(); roundedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext(); UIGraphicsEndImageContext();
)
#endif
if (!roundedImage) { if (!roundedImage) {
// Try older method. // Try older method.
UIImage *image = [self imageWithAlpha]; UIImage *image = [self imageWithAlpha];
@ -146,8 +138,7 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
return roundedImage; return roundedImage;
} }
#pragma mark - #pragma mark - Private helper methods
#pragma mark Private helper methods
// Adds a rectangular path to the given context and rounds its corners by the given extents // Adds a rectangular path to the given context and rounds its corners by the given extents
// Original author: Björn Sållarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/ // Original author: Björn Sållarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/
@ -170,16 +161,14 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
CGContextRestoreGState(context); CGContextRestoreGState(context);
} }
- (UIImage *)bw_imageToFitSize:(CGSize)fitSize honorScaleFactor:(BOOL)honorScaleFactor - (UIImage *)bit_imageToFitSize:(CGSize)fitSize honorScaleFactor:(BOOL)honorScaleFactor
{ {
float imageScaleFactor = 1.0; float imageScaleFactor = 1.0;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
if (honorScaleFactor) { if (honorScaleFactor) {
if ([self respondsToSelector:@selector(scale)]) { if ([self respondsToSelector:@selector(scale)]) {
imageScaleFactor = [self scale]; imageScaleFactor = [self scale];
} }
} }
#endif
float sourceWidth = [self size].width * imageScaleFactor; float sourceWidth = [self size].width * imageScaleFactor;
float sourceHeight = [self size].height * imageScaleFactor; float sourceHeight = [self size].height * imageScaleFactor;
@ -214,8 +203,6 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
// Create appropriately modified image. // Create appropriately modified image.
UIImage *image = nil; UIImage *image = nil;
BW_IF_IOS4_OR_GREATER
(
UIGraphicsBeginImageContextWithOptions(destRect.size, NO, honorScaleFactor ? 0.0 : 1.0); // 0.0 for scale means "correct scale for device's main screen". UIGraphicsBeginImageContextWithOptions(destRect.size, NO, honorScaleFactor ? 0.0 : 1.0); // 0.0 for scale means "correct scale for device's main screen".
CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], sourceRect); // cropping happens here. CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], sourceRect); // cropping happens here.
image = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage. image = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage.
@ -223,7 +210,6 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
CGImageRelease(sourceImg); CGImageRelease(sourceImg);
image = UIGraphicsGetImageFromCurrentImageContext(); image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext(); UIGraphicsEndImageContext();
)
if (!image) { if (!image) {
// Try older method. // Try older method.
@ -292,7 +278,7 @@ CGContextRef MyOpenBitmapContext(int pixelsWide, int pixelsHigh) {
return UIGraphicsGetCurrentContext(); return UIGraphicsGetCurrentContext();
} }
- (UIImage *)bw_reflectedImageWithHeight:(NSUInteger)height fromAlpha:(float)fromAlpha toAlpha:(float)toAlpha { - (UIImage *)bit_reflectedImageWithHeight:(NSUInteger)height fromAlpha:(float)fromAlpha toAlpha:(float)toAlpha {
if(height == 0) if(height == 0)
return nil; return nil;
@ -319,7 +305,7 @@ CGContextRef MyOpenBitmapContext(int pixelsWide, int pixelsHigh) {
return theImage; return theImage;
} }
- (id)bw_initWithContentsOfResolutionIndependentFile:(NSString *)path { - (id)bit_initWithContentsOfResolutionIndependentFile:(NSString *)path {
if ([UIScreen instancesRespondToSelector:@selector(scale)] && (int)[[UIScreen mainScreen] scale] == 2.0) { if ([UIScreen instancesRespondToSelector:@selector(scale)] && (int)[[UIScreen mainScreen] scale] == 2.0) {
NSString *path2x = [[path stringByDeletingLastPathComponent] NSString *path2x = [[path stringByDeletingLastPathComponent]
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@@2x.%@", stringByAppendingPathComponent:[NSString stringWithFormat:@"%@@2x.%@",
@ -334,19 +320,19 @@ CGContextRef MyOpenBitmapContext(int pixelsWide, int pixelsHigh) {
return [self initWithContentsOfFile:path]; return [self initWithContentsOfFile:path];
} }
+ (UIImage*)bw_imageWithContentsOfResolutionIndependentFile:(NSString *)path { + (UIImage*)bit_imageWithContentsOfResolutionIndependentFile:(NSString *)path {
#ifndef __clang_analyzer__ #ifndef __clang_analyzer__
// clang alayzer in 4.2b3 thinks here's a leak, which is not the case. // clang alayzer in 4.2b3 thinks here's a leak, which is not the case.
return [[[UIImage alloc] bw_initWithContentsOfResolutionIndependentFile:path] autorelease]; return [[[UIImage alloc] bit_initWithContentsOfResolutionIndependentFile:path] autorelease];
#endif #endif
} }
+ (UIImage *)bw_imageNamed:(NSString *)imageName bundle:(NSString *)bundleName { + (UIImage *)bit_imageNamed:(NSString *)imageName bundle:(NSString *)bundleName {
NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *bundlePath = [resourcePath stringByAppendingPathComponent:bundleName]; NSString *bundlePath = [resourcePath stringByAppendingPathComponent:bundleName];
NSString *imagePath = [bundlePath stringByAppendingPathComponent:imageName]; NSString *imagePath = [bundlePath stringByAppendingPathComponent:imageName];
return [UIImage bw_imageWithContentsOfResolutionIndependentFile:imagePath]; return [UIImage bit_imageWithContentsOfResolutionIndependentFile:imagePath];
} }
@end @end

View File

@ -1,12 +1,12 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'HockeySDK' s.name = 'HockeySDK'
s.version = '2.2.6' s.version = '2.3.0'
s.license = 'MIT' s.license = 'MIT'
s.platform = :ios s.platform = :ios
s.summary = 'Distribute beta apps and collect crash reports with HockeyApp.' s.summary = 'Distribute beta apps and collect crash reports with HockeyApp.'
s.homepage = 'http://hockeyapp.net/' s.homepage = 'http://hockeyapp.net/'
s.author = { 'Andreas Linde' => 'mail@andreaslinde.de', 'Thomas Dohmke' => "thomas@dohmke.de" } s.author = { 'Andreas Linde' => 'mail@andreaslinde.de', 'Thomas Dohmke' => "thomas@dohmke.de" }
s.source = { :git => 'https://github.com/codenauts/HockeySDK-iOS', :tag => '2.2.3' } s.source = { :git => 'https://github.com/bitstadium/HockeySDK-iOS', :tag => '2.3.0' }
s.description = 'HockeyApp is a server to distribute beta apps and collect crash reports. ' \ s.description = 'HockeyApp is a server to distribute beta apps and collect crash reports. ' \
'It improves the testing process dramatically and can be used for both beta ' \ 'It improves the testing process dramatically and can be used for both beta ' \
@ -17,7 +17,7 @@ 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.resources = 'Resources/Hockey.bundle', 'Resources/Quincy.bundle' s.resources = 'Resources/HockeySDKResources.bundle'
s.frameworks = 'QuartzCore', 'SystemConfiguration', 'CrashReporter' s.frameworks = 'QuartzCore', 'SystemConfiguration', 'CrashReporter'
s.xcconfig = { 'FRAMEWORK_SEARCH_PATHS' => '"$(BUILT_PRODUCTS_DIR)/Pods/Frameworks"' } s.xcconfig = { 'FRAMEWORK_SEARCH_PATHS' => '"$(BUILT_PRODUCTS_DIR)/Pods/Frameworks"' }

View File

@ -1,20 +1,10 @@
## Authors
Andreas Linde <andy@buzzworks.de>
Stanley Rost <soryu2@gmail.com>
Fabian Kreiser <fabian@fabian-kreiser.com>
Tobias Höhmann
FutureTap
Kent Sutherland
Peter Steinberger <me@petersteinberger.com>
Thomas Dohmke <thomas@dohmke.de>
## Licenses ## Licenses
The Hockey SDK is provided under the following license: The Hockey SDK is provided under the following license:
The MIT License The MIT License
Copyright (c) 2011-2012 Codenauts UG (haftungsbeschränkt). All rights reserved. Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
All rights reserved.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation
@ -41,6 +31,7 @@ Except as noted below, PLCrashReporter
is provided under the following license: is provided under the following license:
Copyright (c) 2008 - 2012 Plausible Labs Cooperative, Inc. Copyright (c) 2008 - 2012 Plausible Labs Cooperative, Inc.
Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
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

View File

@ -1,87 +0,0 @@
/*
Hockey.strings
Hockey
Created by Andreas Linde on 11/15/10.
Copyright 2010 buzzworks.de. All rights reserved.
*/
/* Alert view */
/* For dialogs yes buttons */
"HockeyYes" = "Ja";
/* For dialogs no buttons */
"HockeyNo" = "Nein";
/* Update available */
"HockeyUpdateAvailable" = "Aktualisierung verfügbar";
/* Would you like to check out the new update? You can do this later on at any time in the In-App settings. */
"HockeyUpdateAlertText" = "Möchten Sie sich weitere Informationen zu der Aktualisierung ansehen?";
/* Update details screen */
/* Update Details */
"HockeyUpdateScreenTitle" = "Aktualisierung";
/* Settings */
/* Screen title for settings view */
"HockeySettingsTitle" = "Einstellungen";
/* Text asking the user to send user data (on/off switch) */
"HockeySettingsUserData" = "Daten senden";
/* Description text for turning on/off sending user data */
"HockeySettingsUserDataDescription" = "Daten senden liefert dem Entwickler die folgenden Daten: Programmversion, Sprache, Gerätetyp und iOS Version.";
/* Text asking the user to send usage data (on/off switch) */
"HockeySettingsUsageData" = "Testzeit senden";
/* Description text for turning on/off sending usage data */
"HockeySettingsUsageDataDescription" = "Testzeit senden informiert den Entwickler über die Summe der Testzeit, in einer Genauigkeit von 1 Minute.";
/* Title for defining when update checks may be made */
"HockeySectionCheckTitle" = "Nach Aktualisierung Prüfen";
/* On Startup */
"HockeySectionCheckStartup" = "Beim Start";
/* Daily */
"HockeySectionCheckDaily" = "Täglich";
/* Manually */
"HockeySectionCheckManually" = "Manuell";
"HockeyVersion" = "Version";
"HockeyShowPreviousVersions" = "Zeige frühere Versionen...";
"HockeyNoUpdateNeededTitle" = "Kein Update Verfügbar";
"HockeyNoUpdateNeededMessage" = "%@ ist bereits die aktuellste Version.";
"HockeyUpdateAlertTextWithAppVersion" = "%@ ist verfügbar.";
"HockeyUpdateAlertMandatoryTextWithAppVersion" = "%@ ist verfügbar und muss installiert werden!";
"HockeyIgnore" = "Ignorieren";
"HockeyShowUpdate" = "Anzeigen";
"HockeyInstallUpdate" = "Installieren";
"HockeyError" = "Fehler";
"HockeyOK" = "OK";
"HockeyWarning" = "Warnung";
"HockeyNoReleaseNotesAvailable" = "Keine Release Notes verfügbar.";
"HockeyAuthorizationProgress" = "Autorisierung...";
"HockeyAuthorizationOffline" = "Internet Verbindung wird benötigt!";
"HockeyAuthorizationDenied" = "Autorisierung verweigert. Bitte kontaktieren Sie den Entwickler.";
"HockeyiOS3Message" = "In-App download benötigt iOS 4 oder höher. Sie können die Applikation manuell updaten, indem sie das IPA von %@ laden und es via iTunes syncen.";
"HockeySimulatorMessage" = "Hockey funktioniert nicht im Simulator.";
"HockeyButtonCheck" = "PRÜFE";
"HockeyButtonSearching" = "PRÜFEN";
"HockeyButtonUpdate" = "UPDATE";
"HockeyButtonInstalling" = "INSTALLIEREN";
"HockeyButtonOffline" = "OFFLINE";
"HockeyInstalled" = "INSTALLIERT";

View File

@ -1,87 +0,0 @@
/*
Hockey.strings
Hockey
Created by Andreas Linde on 11/15/10.
Copyright 2010 buzzworks.de. All rights reserved.
*/
/* Alert view */
/* For dialogs yes buttons */
"HockeyYes" = "Yes";
/* For dialogs no buttons */
"HockeyNo" = "No";
/* Update available */
"HockeyUpdateAvailable" = "Update available";
/* Would you like to check out the new update? You can do this later on at any time in the In-App settings. */
"HockeyUpdateAlertText" = "Would you like to check out the new update?";
/* Update details screen */
/* Update Details */
"HockeyUpdateScreenTitle" = "Update";
/* Settings */
/* Screen title for settings view */
"HockeySettingsTitle" = "Settings";
/* Text asking the user to send user data (on/off switch) */
"HockeySettingsUserData" = "Send User Data";
/* Description text for turning on/off sending user data */
"HockeySettingsUserDataDescription" = "Send User Data will send the following data to the developer: app version, language, device type and iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"HockeySettingsUsageData" = "Send Usage Data";
/* Description text for turning on/off sending usage data */
"HockeySettingsUsageDataDescription" = "Send Usage Data will send the amount of test time to the developer, in a granularity of 1 minute.";
/* Title for defining when update checks may be made */
"HockeySectionCheckTitle" = "Check For Update";
/* On Startup */
"HockeySectionCheckStartup" = "On Startup";
/* Daily */
"HockeySectionCheckDaily" = "Daily";
/* Manually */
"HockeySectionCheckManually" = "Manually";
"HockeyVersion" = "Version";
"HockeyShowPreviousVersions" = "Show previous versions...";
"HockeyNoUpdateNeededTitle" = "No Update Available";
"HockeyNoUpdateNeededMessage" = "%@ is already the latest version.";
"HockeyUpdateAlertTextWithAppVersion" = "%@ is available.";
"HockeyUpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"HockeyIgnore" = "Ignore";
"HockeyShowUpdate" = "Show";
"HockeyInstallUpdate" = "Install";
"HockeyError" = "Error";
"HockeyOK" = "OK";
"HockeyWarning" = "Warning";
"HockeyNoReleaseNotesAvailable" = "No release notes available.";
"HockeyAuthorizationProgress" = "Authorizing...";
"HockeyAuthorizationOffline" = "Internet connection required!";
"HockeyAuthorizationDenied" = "Authorizing denied. Please contact the developer.";
"HockeyiOS3Message" = "In-App download requires iOS 4 or higher. You can update this application via downloading the IPA from %@ and syncing it with iTunes.";
"HockeySimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
"HockeyButtonCheck" = "CHECK";
"HockeyButtonSearching" = "CHECKING";
"HockeyButtonUpdate" = "UPDATE";
"HockeyButtonInstalling" = "INSTALLING";
"HockeyButtonOffline" = "OFFLINE";
"HockeyInstalled" = "INSTALLED";

View File

@ -1,87 +0,0 @@
/*
Hockey.strings
Hockey
Created by Andreas Linde on 11/15/10.
Copyright 2010 buzzworks.de. All rights reserved.
*/
/* Alert view */
/* For dialogs yes buttons */
"HockeyYes" = "Si";
/* For dialogs no buttons */
"HockeyNo" = "No";
/* Update available */
"HockeyUpdateAvailable" = "Aggiornamento disponibile";
/* Would you like to check out the new update? You can do this later on at any time in the In-App settings. */
"HockeyUpdateAlertText" = "Vuoi scaricare il nuovo aggiornamento ?";
/* Update details screen */
/* Update Details */
"HockeyUpdateScreenTitle" = "Aggiorna";
/* Settings */
/* Screen title for settings view */
"HockeySettingsTitle" = "Impostazioni";
/* Text asking the user to send user data (on/off switch) */
"HockeySettingsUserData" = "Invia dati di sistema";
/* Description text for turning on/off sending user data */
"HockeySettingsUserDataDescription" = "Invia le seguenti informazioni allo sviluppatore: versione app, lingua, tipo dispositivo e versione iOS.";
/* Text asking the user to send usage data (on/off switch) */
"HockeySettingsUsageData" = "Invia dati di utilizzo";
/* Description text for turning on/off sending usage data */
"HockeySettingsUsageDataDescription" = "Invia il tempo di utilizzo allo svilupatore, con un dettaglio di 1 minuto.";
/* Title for defining when update checks may be made */
"HockeySectionCheckTitle" = "Controlla gli aggiornamenti";
/* On Startup */
"HockeySectionCheckStartup" = "All'avvio";
/* Daily */
"HockeySectionCheckDaily" = "Ogni giorno";
/* Manually */
"HockeySectionCheckManually" = "Manualmente";
"HockeyVersion" = "Versione";
"HockeyShowPreviousVersions" = "Mostra le versioni precedenti...";
"HockeyNoUpdateNeededTitle" = "Nessun aggiornamento disponibile";
"HockeyNoUpdateNeededMessage" = "%@ <20> aggiornata all'ultima versione.";
"HockeyUpdateAlertTextWithAppVersion" = "%@ <20> disponibile.";
"HockeyUpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"HockeyIgnore" = "Ignora";
"HockeyShowUpdate" = "Mostra";
"HockeyInstallUpdate" = "Installa";
"HockeyError" = "Errore";
"HockeyOK" = "OK";
"HockeyWarning" = "Avviso";
"HockeyNoReleaseNotesAvailable" = "Non sono disponibili note di rilascio.";
"HockeyAuthorizationProgress" = "Attendo autorizzazione...";
"HockeyAuthorizationOffline" = "E' richiesta la connessione internet!";
"HockeyAuthorizationDenied" = "Autorizzazione negata, contattare lo sviluppatore.";
"HockeyiOS3Message" = "L'aggioranento dall'applicazione <20> possibile con iOS 4 o superiore. Puoi aggiornare questa applicazione scaricandola da %@.";
"HockeySimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
"HockeyButtonCheck" = "CONTROLLA";
"HockeyButtonSearching" = "CONTROLLO";
"HockeyButtonUpdate" = "AGGIORNA";
"HockeyButtonInstalling" = "INSTALLO";
"HockeyButtonOffline" = "OFFLINE";
"HockeyInstalled" = "INSTALLATA";

View File

@ -1,88 +0,0 @@
/*
Hockey.strings
Hockey
Created by Andreas Linde on 11/15/10.
Copyright 2010 buzzworks.de. All rights reserved.
Swedish translation by Joakim Ramer.
*/
/* Alert view */
/* For dialogs yes buttons */
"HockeyYes" = "Ja";
/* For dialogs no buttons */
"HockeyNo" = "Nej";
/* Update available */
"HockeyUpdateAvailable" = "Uppdatering tillgänglig";
/* Would you like to check out the new update? You can do this later on at any time in the In-App settings. */
"HockeyUpdateAlertText" = "Vill du hämta den nya uppdateringen?";
/* Update details screen */
/* Update Details */
"HockeyUpdateScreenTitle" = "Uppdatera";
/* Settings */
/* Screen title for settings view */
"HockeySettingsTitle" = "Inställningar";
/* Text asking the user to send user data (on/off switch) */
"HockeySettingsUserData" = "Skicka användardata";
/* Description text for turning on/off sending user data */
"HockeySettingsUserDataDescription" = "Skicka användardata skickar följande till utvecklaren: app version, språk, enhetstyp och iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"HockeySettingsUsageData" = "Skicka användn.data";
/* Description text for turning on/off sending usage data */
"HockeySettingsUsageDataDescription" = "Skicka användningsdata skickar information om hur länge appen testats (i antal minuter), till utvecklaren.";
/* Title for defining when update checks may be made */
"HockeySectionCheckTitle" = "Leta efter uppdateringar";
/* On Startup */
"HockeySectionCheckStartup" = "Vid uppstart";
/* Daily */
"HockeySectionCheckDaily" = "Dagligen";
/* Manually */
"HockeySectionCheckManually" = "Manuellt";
"HockeyVersion" = "Version";
"HockeyShowPreviousVersions" = "Se tidigare versioner...";
"HockeyNoUpdateNeededTitle" = "Ingen uppdatering tillgänglig";
"HockeyNoUpdateNeededMessage" = "%@ är den senaste versionen.";
"HockeyUpdateAlertTextWithAppVersion" = "%@ finns.";
"HockeyUpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"HockeyIgnore" = "Ignorera";
"HockeyShowUpdate" = "Visa";
"HockeyInstallUpdate" = "Installera";
"HockeyError" = "Error";
"HockeyOK" = "OK";
"HockeyWarning" = "Varning";
"HockeyNoReleaseNotesAvailable" = "Inga releasenoteringar tillgängliga.";
"HockeyAuthorizationProgress" = "Auktoriserar...";
"HockeyAuthorizationOffline" = "Internetuppkoppling krävs!";
"HockeyAuthorizationDenied" = "Auktoriseringen nekades. Kontakta utvecklaren.";
"HockeyiOS3Message" = "In-App nedladdning kräver iOS 4 eller högre. Du kan uppdatera applikationen genoma att ladda ner IPA-filen från %@ och synka in den i iTunes.";
"HockeySimulatorMessage" = "Hockey Update fungerar inte i Simulatorn.\nitms-services:// url schemat är implementerat men fungerar ej.";
"HockeyButtonCheck" = "FRÅGA";
"HockeyButtonSearching" = "FRÅGAR";
"HockeyButtonUpdate" = "UPPDATERA";
"HockeyButtonInstalling" = "INSTALLERAR";
"HockeyButtonOffline" = "OFFLINE";
"HockeyInstalled" = "INSTALLERAD";

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1021 B

After

Width:  |  Height:  |  Size: 1021 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,144 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Ja";
/* For dialogs no buttons */
"HockeyNo" = "Nein";
/* For dialogs ok buttons */
"HockeyOK" = "OK";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "%@ unerwartet beendet";
/* Description explaining that crash data has been found and ask the user if the data might be uplaoded to the developers server */
"CrashDataFoundDescription" = "Möchten Sie einen anonymen Absturzbericht senden, damit wir das Problem beheben können?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "Immer senden";
/* Alert box button to send the crash report once */
"CrashSendReport" = "Bericht senden";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "Nicht senden";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "Senden…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "Zuvor auf %@";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "%@ wurde unerwartet beendet. Die gute Nachricht? Die Absturzursache wurde gefunden und wird für eine zukünftige Aktualisierung behoben. Bleiben Sie dran.";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "%@ wurde unerwartet beendet. Die gute Nachricht? Wir haben den Fehler bereits behoben und eine Aktualisierung an Apple gesendet. Gedulden Sie sich noch etwas, während sie geprüft wird.";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "%@ wurde unerwartet beendet. Die gute Nachricht? Wir haben den Fehler bereits behoben! Aktualisieren Sie auf die neueste Version.";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Aktualisierung verfügbar";
"UpdateAlertTextWithAppVersion" = "%@ ist verfügbar.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ ist verfügbar und muss installiert werden!";
"UpdateIgnore" = "Ignorieren";
"UpdateShow" = "Anzeigen";
"UpdateInstall" = "Installieren";
/* Update Details */
"UpdateScreenTitle" = "Aktualisierung";
"UpdateButtonCheck" = "PRÜFE";
"UpdateButtonSearching" = "PRÜFEN";
"UpdateButtonUpdate" = "UPDATE";
"UpdateButtonInstalling" = "INSTALLIEREN";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLIERT";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Zeige frühere Versionen...";
"UpdateNoUpdateAvailableTitle" = "Kein Update Verfügbar";
"UpdateNoUpdateAvailableMessage" = "%@ ist bereits die aktuellste Version.";
"UpdateError" = "Fehler";
"UpdateWarning" = "Warnung";
"UpdateNoReleaseNotesAvailable" = "Keine Release Notes verfügbar.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Autorisierung...";
"UpdateAuthorizationOffline" = "Internet Verbindung wird benötigt!";
"UpdateAuthorizationDenied" = "Autorisierung verweigert. Bitte kontaktieren Sie den Entwickler.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey funktioniert nicht im Simulator.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Einstellungen";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Daten senden";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Daten senden liefert dem Entwickler die folgenden Daten: Programmversion, Sprache, Gerätetyp und iOS Version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Testzeit senden";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Testzeit senden informiert den Entwickler über die Summe der Testzeit, in einer Genauigkeit von 1 Minute.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Nach Aktualisierung Prüfen";
/* On Startup */
"UpdateSectionCheckStartup" = "Beim Start";
/* Daily */
"UpdateSectionCheckDaily" = "Täglich";
/* Manually */
"UpdateSectionCheckManually" = "Manuell";

View File

@ -0,0 +1,143 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Yes";
/* For dialogs no buttons */
"HockeyNo" = "No";
/* For dialogs ok buttons */
"HockeyOK" = "OK";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "%@ Unexpectedly Quit";
/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */
"CrashDataFoundDescription" = "Would you like to send an anonymous report so we can fix the problem?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "Always Send";
/* Alert box button to send the crash report once */
"CrashSendReport" = "Send Report";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "Don't Send";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "Sending…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "Previously on %@";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "The bug has been fixed for a future update. Stay tuned.";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "The bug has been fixed, and we submitted an update to Apple. Hang tight while its in review!";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "The bug has been fixed. Update to the latest version in the App Store.";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Update available";
"UpdateAlertTextWithAppVersion" = "%@ is available.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignore";
"UpdateShow" = "Show";
"UpdateInstall" = "Install";
/* Update Details */
"UpdateScreenTitle" = "Update";
"UpdateButtonCheck" = "CHECK";
"UpdateButtonSearching" = "CHECKING";
"UpdateButtonUpdate" = "UPDATE";
"UpdateButtonInstalling" = "INSTALLING";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLED";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Show previous versions...";
"UpdateNoUpdateAvailableTitle" = "No Update Available";
"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version.";
"UpdateError" = "Error";
"UpdateWarning" = "Warning";
"UpdateNoReleaseNotesAvailable" = "No release notes available.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Authorizing...";
"UpdateAuthorizationOffline" = "Internet connection required!";
"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Settings";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Send User Data";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Send User Data will send the following data to the developer: app version, language, device type and iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Send Usage Data";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Send Usage Data will send the amount of test time to the developer, in a granularity of 1 minute.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Check For Update";
/* On Startup */
"UpdateSectionCheckStartup" = "On Startup";
/* Daily */
"UpdateSectionCheckDaily" = "Daily";
/* Manually */
"UpdateSectionCheckManually" = "Manually";

View File

@ -0,0 +1,143 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Yes";
/* For dialogs no buttons */
"HockeyNo" = "No";
/* For dialogs ok buttons */
"HockeyOK" = "OK";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "Conflicto de datos detectado";
/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */
"CrashDataFoundDescription" = "La aplicación fallo previamente. ¿Le gustaría proporcionar de manera anonima información relacionado con el fallo al programador para que este pueda solucionar el problema?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "Siempre";
/* Alert box button to send the crash report once */
"CrashSendReport" = "Sí";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "No";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "Enviando…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "Estado de la falla";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "El error que causo la falla ha sido solucionado y la corrección estará disponible en la siguiente versión de %@";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "El error que causo la falla ha sido solucionado, la nueva versión de %@ esta en espera de la aprobación de Apple";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "El error que causo la falla ha sido solucionado, una nueva versión de %@ esta disponible. ¡Por favor actaulice!";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Update available";
"UpdateAlertTextWithAppVersion" = "%@ is available.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignore";
"UpdateShow" = "Show";
"UpdateInstall" = "Install";
/* Update Details */
"UpdateScreenTitle" = "Update";
"UpdateButtonCheck" = "CHECK";
"UpdateButtonSearching" = "CHECKING";
"UpdateButtonUpdate" = "UPDATE";
"UpdateButtonInstalling" = "INSTALLING";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLED";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Show previous versions...";
"UpdateNoUpdateAvailableTitle" = "No Update Available";
"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version.";
"UpdateError" = "Error";
"UpdateWarning" = "Warning";
"UpdateNoReleaseNotesAvailable" = "No release notes available.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Authorizing...";
"UpdateAuthorizationOffline" = "Internet connection required!";
"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Settings";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Send User Data";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Send User Data will send the following data to the developer: app version, language, device type and iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Send Usage Data";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Send Usage Data will send the amount of test time to the developer, in a granularity of 1 minute.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Check For Update";
/* On Startup */
"UpdateSectionCheckStartup" = "On Startup";
/* Daily */
"UpdateSectionCheckDaily" = "Daily";
/* Manually */
"UpdateSectionCheckManually" = "Manually";

View File

@ -0,0 +1,143 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Oui";
/* For dialogs no buttons */
"HockeyNo" = "Non";
/* For dialogs ok buttons */
"HockeyOK" = "OK";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "Rapport de plantage";
/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */
"CrashDataFoundDescription" = "%@ sest fermé de façon inattendue. Souhaitez-vous envoyer un rapport dincident anonyme pour nous aider à corriger le problème ?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "Toujours";
/* Alert box button to send the crash report once */
"CrashSendReport" = "Oui";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "Non";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "Envoyer…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "Précédemment dans %@";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "%@ sest fermé de façon inattendue. La bonne nouvelle ? La cause du problème a été détectée et une solution a été trouvée pour les versions ultérieures. Restez à lécoute.";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "%@ sest fermé de façon inattendue. La bonne nouvelle ? Nous avons déjà corrigé le problème et soumis une mise à jour à Apple. Veuillez patienter durant lexamen de cette mise à jour !";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "%@ sest fermé de façon inattendue. La bonne nouvelle ? Nous avons déjà réglé le problème ! Veuillez installer la mise à jour la plus récente.";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Update available";
"UpdateAlertTextWithAppVersion" = "%@ is available.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignore";
"UpdateShow" = "Show";
"UpdateInstall" = "Install";
/* Update Details */
"UpdateScreenTitle" = "Update";
"UpdateButtonCheck" = "CHECK";
"UpdateButtonSearching" = "CHECKING";
"UpdateButtonUpdate" = "UPDATE";
"UpdateButtonInstalling" = "INSTALLING";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLED";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Show previous versions...";
"UpdateNoUpdateAvailableTitle" = "No Update Available";
"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version.";
"UpdateError" = "Error";
"UpdateWarning" = "Warning";
"UpdateNoReleaseNotesAvailable" = "No release notes available.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Authorizing...";
"UpdateAuthorizationOffline" = "Internet connection required!";
"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Settings";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Send User Data";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Send User Data will send the following data to the developer: app version, language, device type and iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Send Usage Data";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Send Usage Data will send the amount of test time to the developer, in a granularity of 1 minute.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Check For Update";
/* On Startup */
"UpdateSectionCheckStartup" = "On Startup";
/* Daily */
"UpdateSectionCheckDaily" = "Daily";
/* Manually */
"UpdateSectionCheckManually" = "Manually";

View File

Before

Width:  |  Height:  |  Size: 521 B

After

Width:  |  Height:  |  Size: 521 B

View File

Before

Width:  |  Height:  |  Size: 911 B

After

Width:  |  Height:  |  Size: 911 B

View File

@ -0,0 +1,143 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Si";
/* For dialogs no buttons */
"HockeyNo" = "No";
/* For dialogs ok buttons */
"HockeyOK" = "OK";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "Dati del crash trovati";
/* Description explaining that crash data has been found and ask the user if the data might be uplaoded to the developers server */
"CrashDataFoundDescription" = "L'applicazione precedentemente ha avuto un crash. Vuoi inviare allo sviluppatore i dati anonimi del crash in modo che possa provare a sistemare il problema?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "Sempre";
/* Alert box button to send the crash report once */
"CrashSendReport" = "Si";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "No";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "Invio…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "Stato del bug";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "Il bug che ha causato il tuo problema è già stato risolto e sarà incluso nella prossima versione di %@.";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "Il bug che ha causato il tuo problema è già stato risolto e la nuova versione di %@ è in attesa di approvazione da parte della Apple.";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "Il bug che ha causato il tuo problema è già stato risolto e la nuova versione di %@ è disponibile. Ti preghiamo di effettuare un aggiornamento!";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Aggiornamento disponibile";
"UpdateAlertTextWithAppVersion" = "%@ è disponibile.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignora";
"UpdateShow" = "Mostra";
"UpdateInstall" = "Installa";
/* Update Details */
"UpdateScreenTitle" = "Aggiorna";
"UpdateButtonCheck" = "CONTROLLA";
"UpdateButtonSearching" = "CONTROLLO";
"UpdateButtonUpdate" = "AGGIORNA";
"UpdateButtonInstalling" = "INSTALLO";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLATA";
"UpdateVersion" = "Versione";
"UpdateShowPreviousVersions" = "Mostra le versioni precedenti...";
"UpdateNoUpdateAvailableTitle" = "Nessun aggiornamento disponibile";
"UpdateNoUpdateAvailableMessage" = "%@ è aggiornata all'ultima versione.";
"UpdateError" = "Errore";
"UpdateWarning" = "Avviso";
"UpdateNoReleaseNotesAvailable" = "Non sono disponibili note di rilascio.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Attendo autorizzazione...";
"UpdateAuthorizationOffline" = "E' richiesta la connessione internet!";
"UpdateAuthorizationDenied" = "Autorizzazione negata, contattare lo sviluppatore.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Impostazioni";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Invia dati di sistema";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Invia le seguenti informazioni allo sviluppatore: versione app, lingua, tipo dispositivo e versione iOS.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Invia dati di utilizzo";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Invia il tempo di utilizzo allo svilupatore, con un dettaglio di 1 minuto.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Controlla gli aggiornamenti";
/* On Startup */
"UpdateSectionCheckStartup" = "All'avvio";
/* Daily */
"UpdateSectionCheckDaily" = "Ogni giorno";
/* Manually */
"UpdateSectionCheckManually" = "Manualmente";

View File

@ -0,0 +1,143 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Yes";
/* For dialogs no buttons */
"HockeyNo" = "No";
/* For dialogs ok buttons */
"HockeyOK" = "保存";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "クラッシュ時のデータを検知";
/* Description explaining that crash data has been found and ask the user if the data might be uplaoded to the developers server */
"CrashDataFoundDescription" = "%@ は不正に終了しました。問題の修正のため、匿名でクラッシュレポートを送信しますか?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "いつも";
/* Alert box button to send the crash report once */
"CrashSendReport" = "はい";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "いいえ";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "送信中…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "%@、前回までは";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "%@ は不正に終了しました。幸い、クラッシュの原因は既に特定され、将来のバージョンで修正されます。今しばらくお待ちください。";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "%@ は不正に終了しました。幸い、クラッシュの原因を既に修正したアップデートを Apple に提出しました。公開まで今しばらくお待ちください!";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "%@ は不正に終了しました。幸い、クラッシュの原因を既に修正したアップデートが配布されています!最新版にアップデートしてください。";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Update available";
"UpdateAlertTextWithAppVersion" = "%@ is available.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignore";
"UpdateShow" = "Show";
"UpdateInstall" = "Install";
/* Update Details */
"UpdateScreenTitle" = "Update";
"UpdateButtonCheck" = "CHECK";
"UpdateButtonSearching" = "CHECKING";
"UpdateButtonUpdate" = "UPDATE";
"UpdateButtonInstalling" = "INSTALLING";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLED";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Show previous versions...";
"UpdateNoUpdateAvailableTitle" = "No Update Available";
"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version.";
"UpdateError" = "Error";
"UpdateWarning" = "Warning";
"UpdateNoReleaseNotesAvailable" = "No release notes available.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Authorizing...";
"UpdateAuthorizationOffline" = "Internet connection required!";
"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Settings";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Send User Data";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Send User Data will send the following data to the developer: app version, language, device type and iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Send Usage Data";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Send Usage Data will send the amount of test time to the developer, in a granularity of 1 minute.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Check For Update";
/* On Startup */
"UpdateSectionCheckStartup" = "On Startup";
/* Daily */
"UpdateSectionCheckDaily" = "Daily";
/* Manually */
"UpdateSectionCheckManually" = "Manually";

View File

@ -0,0 +1,143 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Ja";
/* For dialogs no buttons */
"HockeyNo" = "Nee";
/* For dialogs ok buttons */
"HockeyOK" = "OK";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "Crashdata gevonden";
/* Description explaining that crash data has been found and ask the user if the data might be uplaoded to the developers server */
"CrashDataFoundDescription" = "De applicatie is gecrasht. Wilt u de ontwikkelaars anonieme data sturen zodat zij kunnen proberen de problemen op te lossen?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "Altijd";
/* Alert box button to send the crash report once */
"CrashSendReport" = "Ja";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "Nee";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "Zenden…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "Bugstatus";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "De bug die uw probleem heeft veroorzaakt is reeds opgelost en de oplossing zal in een volgende versie van %@ worden toegevoegd.";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "De bug die uw probleem heeft veroorzaakt is reeds opgelost en een nieuwe versie %@ wacht op goedkeuring door Apple.";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "De bug die uw probleem heeft veroorzaakt is reeds opgelost en een nieuwe versie van %@ is beschikbaar. Update a.u.b.!";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Update available";
"UpdateAlertTextWithAppVersion" = "%@ is available.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignore";
"UpdateShow" = "Show";
"UpdateInstall" = "Install";
/* Update Details */
"UpdateScreenTitle" = "Update";
"UpdateButtonCheck" = "CHECK";
"UpdateButtonSearching" = "CHECKING";
"UpdateButtonUpdate" = "UPDATE";
"UpdateButtonInstalling" = "INSTALLING";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLED";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Show previous versions...";
"UpdateNoUpdateAvailableTitle" = "No Update Available";
"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version.";
"UpdateError" = "Error";
"UpdateWarning" = "Warning";
"UpdateNoReleaseNotesAvailable" = "No release notes available.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Authorizing...";
"UpdateAuthorizationOffline" = "Internet connection required!";
"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Settings";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Send User Data";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Send User Data will send the following data to the developer: app version, language, device type and iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Send Usage Data";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Send Usage Data will send the amount of test time to the developer, in a granularity of 1 minute.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Check For Update";
/* On Startup */
"UpdateSectionCheckStartup" = "On Startup";
/* Daily */
"UpdateSectionCheckDaily" = "Daily";
/* Manually */
"UpdateSectionCheckManually" = "Manually";

View File

@ -0,0 +1,143 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Sim";
/* For dialogs no buttons */
"HockeyNo" = "Não";
/* For dialogs ok buttons */
"HockeyOK" = "OK";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "Informação de falha encontrada";
/* Description explaining that crash data has been found and ask the user if the data might be uplaoded to the developers server */
"CrashDataFoundDescription" = "A aplicação falhou anteriormente. Gostaria de enviar informação anónima ao programador acerca da falha de forma a poderem resolver o problema?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "Sempre";
/* Alert box button to send the crash report once */
"CrashSendReport" = "Sim";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "Não";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "Enviando…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "Estado do bug";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "O bug que causou o problema já se encontra resolvido e a solução será incluída na próxima versão do %@.";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "O bug que causou o problema já se encontra resolvido e a nova versão do %@ está aguardando aprovação da Apple.";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "O bug que causou o problema já se encontra resolvido e a nova versão do %@ está disponível. Por favor actualize!";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Update available";
"UpdateAlertTextWithAppVersion" = "%@ is available.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignore";
"UpdateShow" = "Show";
"UpdateInstall" = "Install";
/* Update Details */
"UpdateScreenTitle" = "Update";
"UpdateButtonCheck" = "CHECK";
"UpdateButtonSearching" = "CHECKING";
"UpdateButtonUpdate" = "UPDATE";
"UpdateButtonInstalling" = "INSTALLING";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLED";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Show previous versions...";
"UpdateNoUpdateAvailableTitle" = "No Update Available";
"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version.";
"UpdateError" = "Error";
"UpdateWarning" = "Warning";
"UpdateNoReleaseNotesAvailable" = "No release notes available.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Authorizing...";
"UpdateAuthorizationOffline" = "Internet connection required!";
"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Settings";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Send User Data";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Send User Data will send the following data to the developer: app version, language, device type and iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Send Usage Data";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Send Usage Data will send the amount of test time to the developer, in a granularity of 1 minute.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Check For Update";
/* On Startup */
"UpdateSectionCheckStartup" = "On Startup";
/* Daily */
"UpdateSectionCheckDaily" = "Daily";
/* Manually */
"UpdateSectionCheckManually" = "Manually";

View File

@ -0,0 +1,143 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Sim";
/* For dialogs no buttons */
"HockeyNo" = "Não";
/* For dialogs ok buttons */
"HockeyOK" = "OK";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "Dados de falha encontrados";
/* Description explaining that crash data has been found and ask the user if the data might be uplaoded to the developers server */
"CrashDataFoundDescription" = "O aplicativo falhou anteriormente. Você gostaria de enviar ao desenvolvedor os dados sobre a falha do sistema, para que ele resolva o problema?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "Sempre";
/* Alert box button to send the crash report once */
"CrashSendReport" = "Sim";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "Não";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "Enviando…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "Status do bug";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "O bug que causou o problema já está resolvido e a solução será incluída na próxima versão do %@.";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "O bug que causou o problema já está resolvido e uma nova versão do %@ está aguardando aprovação da Apple.";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "O bug que causou o problema já está resolvido e uma nova versão do %@ está disponível. Por favor, atualize!";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Update available";
"UpdateAlertTextWithAppVersion" = "%@ is available.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignore";
"UpdateShow" = "Show";
"UpdateInstall" = "Install";
/* Update Details */
"UpdateScreenTitle" = "Update";
"UpdateButtonCheck" = "CHECK";
"UpdateButtonSearching" = "CHECKING";
"UpdateButtonUpdate" = "UPDATE";
"UpdateButtonInstalling" = "INSTALLING";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLED";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Show previous versions...";
"UpdateNoUpdateAvailableTitle" = "No Update Available";
"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version.";
"UpdateError" = "Error";
"UpdateWarning" = "Warning";
"UpdateNoReleaseNotesAvailable" = "No release notes available.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Authorizing...";
"UpdateAuthorizationOffline" = "Internet connection required!";
"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Settings";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Send User Data";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Send User Data will send the following data to the developer: app version, language, device type and iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Send Usage Data";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Send Usage Data will send the amount of test time to the developer, in a granularity of 1 minute.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Check For Update";
/* On Startup */
"UpdateSectionCheckStartup" = "On Startup";
/* Daily */
"UpdateSectionCheckDaily" = "Daily";
/* Manually */
"UpdateSectionCheckManually" = "Manually";

View File

@ -0,0 +1,140 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Да";
/* For dialogs no buttons */
"HockeyNo" = "Нет";
/* For dialogs ok buttons */
"HockeyOK" = "OK";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "Обнаружена проблема";
/* Description explaining that crash data has been found and ask the user if the data might be uplaoded to the developers server */
"CrashDataFoundDescription" = "%@ программа неожиданно завершена. Хотите ли Вы отправить нам анонимное сообщение о неполадках, чтобы мы могли устранить проблему?";
/* Alert box button if the users wants to send crash data always automatically */
"Always" = "Всегда";
/* Alert box button to send the crash report once */
"Send Report" = "Да";
/* Alert box button to decline sending the report */
"Don't Send" = "Нет";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"Sending" = "Отправить";
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "Обнаружена проблема %@";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "%@ неожиданно завершен. Причина неполадки будет найдена и исправлена ​​в следующем обновлении. Оставайтесь с нами.";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "%@ неожиданно завершен. Мы исправили ошибку и отправили обновление в Apple.";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "%@ неожиданно завершен. Ошибка исправлена​​! Обновите программу в App Store.";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Update available";
"UpdateAlertTextWithAppVersion" = "%@ is available.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignore";
"UpdateShow" = "Show";
"UpdateInstall" = "Install";
/* Update Details */
"UpdateScreenTitle" = "Update";
"UpdateButtonCheck" = "CHECK";
"UpdateButtonSearching" = "CHECKING";
"UpdateButtonUpdate" = "UPDATE";
"UpdateButtonInstalling" = "INSTALLING";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLED";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Show previous versions...";
"UpdateNoUpdateAvailableTitle" = "No Update Available";
"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version.";
"UpdateError" = "Error";
"UpdateWarning" = "Warning";
"UpdateNoReleaseNotesAvailable" = "No release notes available.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Authorizing...";
"UpdateAuthorizationOffline" = "Internet connection required!";
"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Settings";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Send User Data";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Send User Data will send the following data to the developer: app version, language, device type and iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Send Usage Data";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Send Usage Data will send the amount of test time to the developer, in a granularity of 1 minute.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Check For Update";
/* On Startup */
"UpdateSectionCheckStartup" = "On Startup";
/* Daily */
"UpdateSectionCheckDaily" = "Daily";
/* Manually */
"UpdateSectionCheckManually" = "Manually";

View File

@ -0,0 +1,144 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Ja";
/* For dialogs no buttons */
"HockeyNo" = "Nej";
/* For dialogs ok buttons */
"HockeyOK" = "OK";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "%@ kraschade";
/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */
"CrashDataFoundDescription" = "Vill du skicka en anonym kraschrapport så att vi kan lösa felet?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "Skicka alltid";
/* Alert box button to send the crash report once */
"CrashSendReport" = "Skicka rapport";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "Skicka inte";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "Skickar…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "Tidigare %@ krasch";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "Buggen har lösts och är borttagen i nästa release som kommer snart.";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "Buggen har lösts, en ny version har skickats till Apple. Håll i dig medans de testar!";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "Buggen har lösts. Updatera till senaste versionen i App Store.";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Uppdatering tillgänglig";
"UpdateAlertTextWithAppVersion" = "%@ finns.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignorera";
"UpdateShow" = "Visa";
"UpdateInstall" = "Installera";
/* Update Details */
"UpdateScreenTitle" = "Uppdatera";
"UpdateButtonCheck" = "FRÅGA";
"UpdateButtonSearching" = "FRÅGAR";
"UpdateButtonUpdate" = "UPPDATERA";
"UpdateButtonInstalling" = "INSTALLERAR";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLERAD";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Se tidigare versioner...";
"UpdateNoUpdateAvailableTitle" = "Ingen uppdatering tillgänglig";
"UpdateNoUpdateAvailableMessage" = "%@ är den senaste versionen.";
"UpdateError" = "Error";
"UpdateWarning" = "Varning";
"UpdateNoReleaseNotesAvailable" = "Inga releasenoteringar tillgängliga.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Auktoriserar...";
"UpdateAuthorizationOffline" = "Internetuppkoppling krävs!";
"UpdateAuthorizationDenied" = "Auktoriseringen nekades. Kontakta utvecklaren.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update fungerar inte i Simulatorn.\nitms-services:// url schemat är implementerat men fungerar ej.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Inställningar";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Skicka användardata";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Skicka användardata skickar följande till utvecklaren: app version, språk, enhetstyp och iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Skicka användn.data";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Skicka användningsdata skickar information om hur länge appen testats (i antal minuter), till utvecklaren.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Leta efter uppdateringar";
/* On Startup */
"UpdateSectionCheckStartup" = "Vid uppstart";
/* Daily */
"UpdateSectionCheckDaily" = "Dagligen";
/* Manually */
"UpdateSectionCheckManually" = "Manuellt";

View File

@ -0,0 +1,142 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Evet";
/* For dialogs no buttons */
"HockeyNo" = "Yok";
/* For dialogs ok buttons */
"HockeyOK" = "Tamam";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "Hata raporu bulundu";
/* Description explaining that crash data has been found and ask the user if the data might be uplaoded to the developers server */
"CrashDataFoundDescription" = "%@ beklenmeyen bir şekilde kapanmış. Bu hatayı gidermemizi kolaylaştırmak için anonim bir hata raporu göndermek ister misiniz?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "Her seferinde gönder!";
/* Alert box button to send the crash report once */
"CrashSendReport" = "Gönder!";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "Hayır";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "Gönderiliyor…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "Hata raporu bulundu";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "%@ beklenmeyen bir şekilde kapanmış. Sorunun sebebi bulundu ve en kısa zamanda bir güncelleme ile giderilecek.";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "%@ beklenmeyen bir şekilde kapanmış. Hata giderildi ve yeni sunum Apple'a gönderildi. Birkaç gün içerisinde iTunes'tan indirebilirsiniz.";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "%@ beklenmeyen bir şekilde kapanmış. Bu hatayı gideren yeni sunumu iTunes'tan indirebilirsiniz.";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Update available";
"UpdateAlertTextWithAppVersion" = "%@ is available.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignore";
"UpdateShow" = "Show";
"UpdateInstall" = "Install";
/* Update Details */
"UpdateScreenTitle" = "Update";
"UpdateButtonCheck" = "CHECK";
"UpdateButtonSearching" = "CHECKING";
"UpdateButtonUpdate" = "UPDATE";
"UpdateButtonInstalling" = "INSTALLING";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLED";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Show previous versions...";
"UpdateNoUpdateAvailableTitle" = "No Update Available";
"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version.";
"UpdateError" = "Error";
"UpdateWarning" = "Warning";
"UpdateNoReleaseNotesAvailable" = "No release notes available.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Authorizing...";
"UpdateAuthorizationOffline" = "Internet connection required!";
"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Settings";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Send User Data";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Send User Data will send the following data to the developer: app version, language, device type and iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Send Usage Data";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Send Usage Data will send the amount of test time to the developer, in a granularity of 1 minute.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Check For Update";
/* On Startup */
"UpdateSectionCheckStartup" = "On Startup";
/* Daily */
"UpdateSectionCheckDaily" = "Daily";
/* Manually */
"UpdateSectionCheckManually" = "Manually";

View File

@ -0,0 +1,143 @@
/* General */
/* For dialogs yes buttons */
"HockeyYes" = "Yes";
/* For dialogs no buttons */
"HockeyNo" = "No";
/* For dialogs ok buttons */
"HockeyOK" = "确定";
/* Crash */
/* Crash dialog */
/* Title showing in the alert box when crash report data has been found */
"CrashDataFoundTitle" = "发现崩溃数据";
/* Description explaining that crash data has been found and ask the user if the data might be uplaoded to the developers server */
"CrashDataFoundDescription" = "%@ 不正常退出。您能否匿名提供崩溃记录以帮助我们解决问题?";
/* Alert box button if the users wants to send crash data always automatically */
"CrashSendReportAlways" = "总是";
/* Alert box button to send the crash report once */
"CrashSendReport" = "是";
/* Alert box button to decline sending the report */
"CrashDontSendReport" = "否";
/* Text showing in a processing box that the crash data is being uploaded to the server */
"CrashReportSending" = "发送中…";
/* Crash status dialog */
/* Title for the alertview giving feedback about the crash */
"CrashResponseTitle" = "之前在 %@";
/* Full text telling the bug is fixed and will be available in the next release */
"CrashResponseNextRelease" = "%@ 不正常退出。好消息?造成崩溃的原因已被发现,并将在后续版本中修正。请耐心等待。";
/* Full text telling the bug is fixed and the new release is waiting at Apple */
"CrashResponseWaitingApple" = "%@ 不正常。好消息?我们已经解决了这个问题,并已将新版本提交到苹果审核。请在审核期间耐心等待。";
/* Full text telling the bug is fixed and an update is available in the AppStore */
"CrashResponseAvailable" = "%@ 不正常退出。好消息?我们已经解决了这个问题。请更新到最新版本。";
/* Update */
/* Update Alert view */
/* Update available */
"UpdateAvailable" = "Update available";
"UpdateAlertTextWithAppVersion" = "%@ is available.";
"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!";
"UpdateIgnore" = "Ignore";
"UpdateShow" = "Show";
"UpdateInstall" = "Install";
/* Update Details */
"UpdateScreenTitle" = "Update";
"UpdateButtonCheck" = "CHECK";
"UpdateButtonSearching" = "CHECKING";
"UpdateButtonUpdate" = "UPDATE";
"UpdateButtonInstalling" = "INSTALLING";
"UpdateButtonOffline" = "OFFLINE";
"UpdateInstalled" = "INSTALLED";
"UpdateVersion" = "Version";
"UpdateShowPreviousVersions" = "Show previous versions...";
"UpdateNoUpdateAvailableTitle" = "No Update Available";
"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version.";
"UpdateError" = "Error";
"UpdateWarning" = "Warning";
"UpdateNoReleaseNotesAvailable" = "No release notes available.";
/* Update Authorization */
"UpdateAuthorizationProgress" = "Authorizing...";
"UpdateAuthorizationOffline" = "Internet connection required!";
"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer.";
/* Update Simulator Warning */
"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional.";
/* Update Settings */
/* Screen title for settings view */
"UpdateSettingsTitle" = "Settings";
/* Text asking the user to send user data (on/off switch) */
"UpdateSettingsUserData" = "Send User Data";
/* Description text for turning on/off sending user data */
"UpdateSettingsUserDataDescription" = "Send User Data will send the following data to the developer: app version, language, device type and iOS version.";
/* Text asking the user to send usage data (on/off switch) */
"UpdateSettingsUsageData" = "Send Usage Data";
/* Description text for turning on/off sending usage data */
"UpdateSettingsUsageDataDescription" = "Send Usage Data will send the amount of test time to the developer, in a granularity of 1 minute.";
/* Title for defining when update checks may be made */
"UpdateSectionCheckTitle" = "Check For Update";
/* On Startup */
"UpdateSectionCheckStartup" = "On Startup";
/* Daily */
"UpdateSectionCheckDaily" = "Daily";
/* Manually */
"UpdateSectionCheckManually" = "Manually";

Some files were not shown because too many files have changed in this diff Show More