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>
* Kent Sutherland
*
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* Copyright (c) 2011 Andreas Linde & Kent Sutherland.
* All rights reserved.
*
@ -30,120 +31,60 @@
#import <CrashReporter/CrashReporter.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <UIKit/UIKit.h>
#import "BWGlobal.h"
#import "BWQuincyManager.h"
#import "CNSCrashReportTextFormatter.h"
#import "HockeySDK.h"
#import "HockeySDKPrivate.h"
#import "BITCrashReportTextFormatter.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;
- (void)_cleanCrashReports;
// stores the user email address entered in the UI
#define kBITCrashUserEmail @"HockeySDKCrashUserEmail"
- (void)_checkForFeedbackStatus;
- (void)_performSendingCrashReports;
- (void)_sendCrashReports;
- (void)_postXML:(NSString*)xml toURL:(NSURL*)url;
- (NSString *)_getDevicePlatform;
- (BOOL)hasNonApprovedCrashReports;
- (BOOL)hasPendingCrashReport;
@interface BITCrashManager ()
@property (nonatomic, retain) NSFileManager *fileManager;
@end
@implementation BWQuincyManager
@implementation BITCrashManager
@synthesize delegate = _delegate;
@synthesize submissionURL = _submissionURL;
@synthesize showAlwaysButton = _showAlwaysButton;
@synthesize feedbackActivated = _feedbackActivated;
@synthesize autoSubmitCrashReport = _autoSubmitCrashReport;
@synthesize languageStyle = _languageStyle;
@synthesize didCrashInLastSession = _didCrashInLastSession;
@synthesize timeintervalCrashInLastSessionOccured = _timeintervalCrashInLastSessionOccured;
@synthesize loggingEnabled = _loggingEnabled;
@synthesize appIdentifier = _appIdentifier;
@synthesize fileManager = _fileManager;
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
+(BWQuincyManager *)sharedQuincyManager {
static BWQuincyManager *sharedInstance = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
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 {
- (id)initWithAppIdentifier:(NSString *)appIdentifier {
if ((self = [super init])) {
_serverResult = CrashReportStatusUnknown;
BITHockeySDKLog(@"Initializing CrashReporter");
_appIdentifier = appIdentifier;
_delegate = nil;
_serverResult = BITCrashStatusUnknown;
_crashIdenticalCurrentVersion = YES;
_crashData = nil;
_urlConnection = nil;
_submissionURL = nil;
_responseData = nil;
_appIdentifier = nil;
_sendingInProgress = NO;
_languageStyle = nil;
_didCrashInLastSession = NO;
_timeintervalCrashInLastSessionOccured = -1;
_loggingEnabled = NO;
_fileManager = [[NSFileManager alloc] init];
self.delegate = nil;
@ -151,20 +92,20 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
self.showAlwaysButton = NO;
self.autoSubmitCrashReport = NO;
NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kQuincyKitAnalyzerStarted];
NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kBITCrashAnalyzerStarted];
if (testValue) {
_analyzerStarted = [[NSUserDefaults standardUserDefaults] integerForKey:kQuincyKitAnalyzerStarted];
_analyzerStarted = [[NSUserDefaults standardUserDefaults] integerForKey:kBITCrashAnalyzerStarted];
} else {
_analyzerStarted = 0;
}
testValue = nil;
testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kQuincyKitActivated];
testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kBITCrashActivated];
if (testValue) {
_crashReportActivated = [[NSUserDefaults standardUserDefaults] boolForKey:kQuincyKitActivated];
_crashReportActivated = [[NSUserDefaults standardUserDefaults] boolForKey:kBITCrashActivated];
} else {
_crashReportActivated = YES;
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:YES] forKey:kQuincyKitActivated];
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:YES] forKey:kBITCrashActivated];
}
if (_crashReportActivated) {
@ -192,10 +133,10 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
if (![crashReporter enableCrashReporterAndReturnError: &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!");
}
}
@ -205,12 +146,7 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
- (void) dealloc {
self.delegate = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:BWQuincyNetworkBecomeReachable object:nil];
[_languageStyle release];
[_submissionURL release];
_submissionURL = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyNetworkDidBecomeReachableNotification object:nil];
[_appIdentifier release];
_appIdentifier = nil;
@ -231,35 +167,13 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
}
#pragma mark -
#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
#pragma mark - private methods
- (BOOL)autoSendCrashReports {
BOOL result = NO;
if (!self.autoSubmitCrashReport) {
if (self.isShowingAlwaysButton && [[NSUserDefaults standardUserDefaults] boolForKey: kAutomaticallySendCrashReports]) {
if (self.isShowingAlwaysButton && [[NSUserDefaults standardUserDefaults] boolForKey: kBITCrashAutomaticallySendReports]) {
result = YES;
}
} else {
@ -273,38 +187,84 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
- (void)startManager {
if (!_sendingInProgress && [self hasPendingCrashReport]) {
_sendingInProgress = YES;
if (!quincyBundle()) {
NSLog(@"WARNING: Quincy.bundle is missing, sending reports automatically!");
[self _sendCrashReports];
if (!BITHockeySDKBundle()) {
NSLog(@"WARNING: HockeySDKResource.bundle is missing, sending reports automatically!");
[self sendCrashReports];
} else if (![self autoSendCrashReports] && [self hasNonApprovedCrashReports]) {
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(willShowSubmitCrashReportAlert)]) {
[self.delegate willShowSubmitCrashReportAlert];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporterWillShowSubmitCrashReportAlert:)]) {
[self.delegate crashReporterWillShowSubmitCrashReportAlert:self];
}
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:BWQuincyLocalize(@"CrashDataFoundTitle"), appName]
message:[NSString stringWithFormat:BWQuincyLocalize(@"CrashDataFoundDescription"), appName]
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashDataFoundTitle"), appName]
message:[NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashDataFoundDescription"), appName]
delegate:self
cancelButtonTitle:BWQuincyLocalize(@"CrashDontSendReport")
otherButtonTitles:BWQuincyLocalize(@"CrashSendReport"), nil];
cancelButtonTitle:BITHockeySDKLocalizedString(@"CrashDontSendReport")
otherButtonTitles:BITHockeySDKLocalizedString(@"CrashSendReport"), nil];
if ([self isShowingAlwaysButton]) {
[alertView addButtonWithTitle:BWQuincyLocalize(@"CrashSendReportAlways")];
[alertView addButtonWithTitle:BITHockeySDKLocalizedString(@"CrashSendReportAlways")];
}
[alertView setTag: QuincyKitAlertTypeSend];
[alertView setTag: BITCrashAlertTypeSend];
[alertView show];
[alertView release];
} 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 {
NSDictionary *approvedCrashReports = [[NSUserDefaults standardUserDefaults] dictionaryForKey: kApprovedCrashReports];
NSDictionary *approvedCrashReports = [[NSUserDefaults standardUserDefaults] dictionaryForKey: kBITCrashApprovedReports];
if (!approvedCrashReports || [approvedCrashReports count] == 0) return YES;
@ -334,7 +294,7 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
}
if ([_crashFiles count] > 0) {
BWQuincyLog(@"Pending crash reports found.");
BITHockeySDKLog(@"Pending crash reports found.");
return YES;
} else
return NO;
@ -346,31 +306,31 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
- (void) showCrashStatusMessage {
UIAlertView *alertView = nil;
if (_serverResult >= CrashReportStatusAssigned &&
if (_serverResult >= BITCrashStatusAssigned &&
_crashIdenticalCurrentVersion &&
quincyBundle()) {
BITHockeySDKBundle()) {
// show some feedback to the user about the crash status
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
switch (_serverResult) {
case CrashReportStatusAssigned:
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ]
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseNextRelease"), appName]
case BITCrashStatusAssigned:
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseTitle"), appName ]
message: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseNextRelease"), appName]
delegate: self
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK")
cancelButtonTitle: BITHockeySDKLocalizedString(@"HockeyOK")
otherButtonTitles: nil];
break;
case CrashReportStatusSubmitted:
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ]
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseWaitingApple"), appName]
case BITCrashStatusSubmitted:
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseTitle"), appName ]
message: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseWaitingApple"), appName]
delegate: self
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK")
cancelButtonTitle: BITHockeySDKLocalizedString(@"HockeyOK")
otherButtonTitles: nil];
break;
case CrashReportStatusAvailable:
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ]
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseAvailable"), appName]
case BITCrashStatusAvailable:
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseTitle"), appName ]
message: [NSString stringWithFormat:BITHockeySDKLocalizedString(@"CrashResponseAvailable"), appName]
delegate: self
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK")
cancelButtonTitle: BITHockeySDKLocalizedString(@"HockeyOK")
otherButtonTitles: nil];
break;
default:
@ -379,7 +339,7 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
}
if (alertView) {
[alertView setTag: QuincyKitAlertTypeFeedback];
[alertView setTag: BITCrashAlertTypeFeedback];
[alertView show];
[alertView release];
}
@ -391,89 +351,47 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
#pragma mark UIAlertView Delegate
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
if ([alertView tag] == QuincyKitAlertTypeSend) {
if ([alertView tag] == BITCrashAlertTypeSend) {
switch (buttonIndex) {
case 0:
_sendingInProgress = NO;
[self _cleanCrashReports];
[self cleanCrashReports];
break;
case 1:
[self _sendCrashReports];
[self sendCrashReports];
break;
case 2: {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:kAutomaticallySendCrashReports];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:kBITCrashAutomaticallySendReports];
[[NSUserDefaults standardUserDefaults] synchronize];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(userDidChooseSendAlways)]) {
[self.delegate userDidChooseSendAlways];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporterWillSendCrashReportsAlways:)]) {
[self.delegate crashReporterWillSendCrashReportsAlways:self];
}
[self _sendCrashReports];
[self sendCrashReports];
break;
}
default:
_sendingInProgress = NO;
[self _cleanCrashReports];
[self cleanCrashReports];
break;
}
}
}
#pragma mark -
#pragma mark NSXMLParser Delegate
#pragma mark NSXMLParser
- (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
#pragma mark - Private
- (NSString *) extractAppUUIDs:(PLCrashReport *)report {
NSMutableString *uuidString = [NSMutableString string];
NSArray *uuidArray = [CNSCrashReportTextFormatter arrayOfAppUUIDsForCrashReport:report];
NSArray *uuidArray = [BITCrashReportTextFormatter arrayOfAppUUIDsForCrashReport:report];
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>",
[element objectForKey:kCNSBinaryImageKeyType],
[element objectForKey:kCNSBinaryImageKeyArch],
[element objectForKey:kCNSBinaryImageKeyUUID]
[element objectForKey:kBITBinaryImageKeyType],
[element objectForKey:kBITBinaryImageKeyArch],
[element objectForKey:kBITBinaryImageKeyUUID]
];
}
}
@ -482,7 +400,7 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
}
- (NSString *)_getDevicePlatform {
- (NSString *)getDevicePlatform {
size_t size = 0;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *answer = (char*)malloc(size);
@ -493,25 +411,17 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
}
- (void)_performSendingCrashReports {
NSMutableDictionary *approvedCrashReports = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey: kApprovedCrashReports]];
- (void)performSendingCrashReports {
NSMutableDictionary *approvedCrashReports = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey: kBITCrashApprovedReports]];
NSError *error = NULL;
NSString *userid = @"";
NSString *contact = @"";
NSString *description = @"";
NSString *username = _userName ?: @"";
NSString *email = _userEmail ?: @"";
NSString *applicationLog = @"";
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReportUserID)]) {
userid = [self.delegate crashReportUserID] ?: @"";
}
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] ?: @"";
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(applicationLogForCrashReporter:)]) {
applicationLog = [self.delegate applicationLogForCrashReporter:self] ?: @"";
}
NSMutableString *crashes = nil;
@ -526,11 +436,13 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
if (report == nil) {
NSLog(@"Could not parse crash report");
// we cannot do anything with this report, so delete it
[self.fileManager removeItemAtPath:filename error:&error];
continue;
}
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) {
_crashIdenticalCurrentVersion = YES;
@ -545,14 +457,14 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
[self extractAppUUIDs:report],
report.applicationInfo.applicationIdentifier,
report.systemInfo.operatingSystemVersion,
[self _getDevicePlatform],
[self getDevicePlatform],
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
report.applicationInfo.applicationVersion,
crashUUID,
[crashLogString stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,crashLogString.length)],
userid,
contact,
[description stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,description.length)]];
username,
email,
[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
@ -563,18 +475,18 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
}
}
[[NSUserDefaults standardUserDefaults] setObject:approvedCrashReports forKey:kApprovedCrashReports];
[[NSUserDefaults standardUserDefaults] setObject:approvedCrashReports forKey:kBITCrashApprovedReports];
[[NSUserDefaults standardUserDefaults] synchronize];
if (crashes != nil) {
BWQuincyLog(@"Sending crash reports:\n%@", crashes);
[self _postXML:[NSString stringWithFormat:@"<crashes>%@</crashes>", crashes]
toURL:[NSURL URLWithString:self.submissionURL]];
BITHockeySDKLog(@"Sending crash reports:\n%@", crashes);
[self postXML:[NSString stringWithFormat:@"<crashes>%@</crashes>", crashes]
toURL:[NSURL URLWithString:BITHOCKEYSDK_URL]];
}
}
- (void)_cleanCrashReports {
- (void)cleanCrashReports {
NSError *error = NULL;
for (NSUInteger i=0; i < [_crashFiles count]; i++) {
@ -582,22 +494,22 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
}
[_crashFiles removeAllObjects];
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:kApprovedCrashReports];
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:kBITCrashApprovedReports];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void)_sendCrashReports {
- (void)sendCrashReports {
// 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;
request = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes/%@",
self.submissionURL,
[self.appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
BITHOCKEYSDK_URL,
[_appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
_feedbackRequestID
]
]];
@ -608,45 +520,41 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
[request setTimeoutInterval: 15];
[request setHTTPMethod:@"GET"];
_serverResult = CrashReportStatusUnknown;
_serverResult = BITCrashStatusUnknown;
_statusCode = 200;
// Release when done in the delegate method
_responseData = [[NSMutableData alloc] init];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(connectionOpened)]) {
[self.delegate connectionOpened];
}
_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;
NSString *boundary = @"----FOO";
if (self.appIdentifier) {
NSString *feedbackEnabled = @"&feedbackEnabled=no";
if ([self isFeedbackActivated]) {
feedbackEnabled = @"&feedbackEnabled=yes";
}
request = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes?sdk=%@&sdk_version=%@%@",
self.submissionURL,
[self.appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
SDK_NAME,
SDK_VERSION,
feedbackEnabled
]
]];
} else {
request = [NSMutableURLRequest requestWithURL:url];
NSString *feedbackEnabled = @"&feedbackEnabled=no";
if ([self isFeedbackActivated]) {
feedbackEnabled = @"&feedbackEnabled=yes";
}
request = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes?sdk=%@&sdk_version=%@%@",
BITHOCKEYSDK_URL,
[_appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
BITHOCKEYSDK_NAME,
BITHOCKEYSDK_VERSION,
feedbackEnabled
]
]];
[request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData];
[request setValue:@"Quincy/iOS" forHTTPHeaderField:@"User-Agent"];
[request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
@ -657,18 +565,14 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
NSMutableData *postBody = [NSMutableData data];
[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:[[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:[@"Content-Disposition: form-data; name=\"xml\"; filename=\"crash.xml\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithFormat:@"Content-Type: text/xml\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[xml dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:postBody];
_serverResult = CrashReportStatusUnknown;
_serverResult = BITCrashStatusUnknown;
_statusCode = 200;
//Release when done in the delegate method
@ -677,22 +581,18 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
_urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (!_urlConnection) {
BWQuincyLog(@"Sending crash reports could not start!");
BITHockeySDKLog(@"Sending crash reports could not start!");
_sendingInProgress = NO;
} else {
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(connectionOpened)]) {
[self.delegate connectionOpened];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporterWillSendCrashReport:)]) {
[self.delegate crashReporterWillSendCrashReport:self];
}
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(sendingCrashReportsDidStart)]) {
[self.delegate sendingCrashReportsDidStart];
}
BWQuincyLog(@"Sending crash reports started.");
BITHockeySDKLog(@"Sending crash reports started.");
}
}
#pragma mark NSURLConnection Delegate
#pragma mark - NSURLConnection Delegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
@ -705,15 +605,11 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(connectionClosed)]) {
[self.delegate connectionClosed];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporter:didFailWithError:)]) {
[self.delegate crashReporter:self didFailWithError:error];
}
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(sendingCrashReportsDidFailWithError:)]) {
[self.delegate sendingCrashReportsDidFailWithError:error];
}
BWQuincyLog(@"ERROR: %@", [error localizedDescription]);
BITHockeySDKLog(@"ERROR: %@", [error localizedDescription]);
_sendingInProgress = NO;
@ -727,85 +623,68 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
NSError *error = nil;
if (_statusCode >= 200 && _statusCode < 400 && _responseData != nil && [_responseData length] > 0) {
[self _cleanCrashReports];
[self cleanCrashReports];
_feedbackRequestID = nil;
if (self.appIdentifier) {
// HockeyApp uses PList XML format
NSMutableDictionary *response = [NSPropertyListSerialization propertyListFromData:_responseData
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:nil
errorDescription:NULL];
BWQuincyLog(@"Received API response: %@", response);
_serverResult = (CrashReportStatus)[[response objectForKey:@"status"] intValue];
if ([response objectForKey:@"id"]) {
_feedbackRequestID = [[NSString alloc] initWithString:[response objectForKey:@"id"]];
_feedbackDelayInterval = [[response objectForKey:@"delay"] floatValue];
if (_feedbackDelayInterval > 0)
_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];
// HockeyApp uses PList XML format
NSMutableDictionary *response = [NSPropertyListSerialization propertyListFromData:_responseData
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:nil
errorDescription:NULL];
BITHockeySDKLog(@"Received API response: %@", response);
_serverResult = (BITCrashStatus)[[response objectForKey:@"status"] intValue];
if ([response objectForKey:@"id"]) {
_feedbackRequestID = [[NSString alloc] initWithString:[response objectForKey:@"id"]];
_feedbackDelayInterval = [[response objectForKey:@"delay"] floatValue];
if (_feedbackDelayInterval > 0)
_feedbackDelayInterval *= 0.01;
}
if ([self isFeedbackActivated]) {
// 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
if (_feedbackRequestID) {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_checkForFeedbackStatus) object:nil];
[self performSelector:@selector(_checkForFeedbackStatus) withObject:nil afterDelay:_feedbackDelayInterval];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(checkForFeedbackStatus) object:nil];
[self performSelector:@selector(checkForFeedbackStatus) withObject:nil afterDelay:_feedbackDelayInterval];
}
} else {
[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) {
[self _cleanCrashReports];
} else if (_statusCode == 400) {
[self cleanCrashReports];
error = [NSError errorWithDomain:kQuincyErrorDomain
code:QuincyAPIAppVersionRejected
error = [NSError errorWithDomain:kBITCrashErrorDomain
code:BITCrashAPIAppVersionRejected
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The server rejected receiving crash reports for this app version!", NSLocalizedDescriptionKey, nil]];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(sendingCrashReportsDidFailWithError:)]) {
[self.delegate sendingCrashReportsDidFailWithError:error];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporter:didFailWithError:)]) {
[self.delegate crashReporter:self didFailWithError:error];
}
BWQuincyLog(@"ERROR: %@", [error localizedDescription]);
BITHockeySDKLog(@"ERROR: %@", [error localizedDescription]);
} else {
if (_responseData == nil || [_responseData length] == 0) {
error = [NSError errorWithDomain:kQuincyErrorDomain
code:QuincyAPIReceivedEmptyResponse
error = [NSError errorWithDomain:kBITCrashErrorDomain
code:BITCrashAPIReceivedEmptyResponse
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Sending failed with an empty response!", NSLocalizedDescriptionKey, nil]];
} else {
error = [NSError errorWithDomain:kQuincyErrorDomain
code:QuincyAPIErrorWithStatusCode
error = [NSError errorWithDomain:kBITCrashErrorDomain
code:BITCrashAPIErrorWithStatusCode
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(connectionClosed)]) {
[self.delegate connectionClosed];
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReporter:didFailWithError:)]) {
[self.delegate crashReporter:self didFailWithError:error];
}
BITHockeySDKLog(@"ERROR: %@", [error localizedDescription]);
}
_sendingInProgress = NO;
@ -816,50 +695,5 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
_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

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) 2010 MOSO Corporation, Pty Ltd.
* Copyright (c) 2012 Codenauts UG (haftungsbeschränkt)
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
@ -34,38 +34,20 @@
#import <Foundation/Foundation.h>
#import "CrashReporter/PLCrashReportFormatter.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;
#import <CrashReporter/PLCrashReport.h>
// Dictionary keys for array elements returned by arrayOfAppUUIDsForCrashReport:
#define kCNSBinaryImageKeyUUID @"uuid"
#define kCNSBinaryImageKeyArch @"arch"
#define kCNSBinaryImageKeyType @"type"
#ifndef kBITBinaryImageKeyUUID
#define kBITBinaryImageKeyUUID @"uuid"
#define kBITBinaryImageKeyArch @"arch"
#define kBITBinaryImageKeyType @"type"
#endif
@interface CNSCrashReportTextFormatter : NSObject <PLCrashReportFormatter> {
@private
/** Text output format. */
CNSCrashReportTextFormat _textFormat;
/** Encoding to use for string output. */
NSStringEncoding _stringEncoding;
@interface BITCrashReportTextFormatter : NSObject {
}
+ (NSString *) stringValueForCrashReport: (PLCrashReport *) report withTextFormat: (CNSCrashReportTextFormat) textFormat;
+ (NSArray *) arrayOfAppUUIDsForCrashReport: (PLCrashReport *) report;
- (id) initWithTextFormat: (CNSCrashReportTextFormat) textFormat stringEncoding: (NSStringEncoding) stringEncoding;
+ (NSString *)stringValueForCrashReport:(PLCrashReport *)report;
+ (NSArray *)arrayOfAppUUIDsForCrashReport:(PLCrashReport *)report;
@end

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2008-2012 Plausible Labs Cooperative, Inc.
* Copyright (c) 2010 MOSO Corporation, Pty Ltd.
* Copyright (c) 2012 Codenauts UG (haftungsbeschränkt)
* Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
@ -31,22 +31,22 @@
* 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);
+ (NSString *) formatStackFrame: (PLCrashReportStackFrameInfo *) frameInfo
frameIndex: (NSUInteger) frameIndex
report: (PLCrashReport *) report;
+ (NSString *)formatStackFrame:(PLCrashReportStackFrameInfo *)frameInfo
frameIndex:(NSUInteger)frameIndex
report:(PLCrashReport *)report;
@end
/**
* 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.
*/
+ (NSString *) stringValueForCrashReport: (PLCrashReport *) report withTextFormat: (CNSCrashReportTextFormat) textFormat {
+ (NSString *)stringValueForCrashReport:(PLCrashReport *)report {
NSMutableString* text = [NSMutableString string];
boolean_t lp64 = true; // quiesce GCC uninitialized value warning
@ -435,7 +435,7 @@ NSInteger binaryImageSort(id binary1, id binary2, void *context);
*
* @return Returns the formatted result on success, or nil if an error occurs.
*/
+ (NSArray *) arrayOfAppUUIDsForCrashReport: (PLCrashReport *) report {
+ (NSArray *)arrayOfAppUUIDsForCrashReport:(PLCrashReport *)report {
NSMutableArray* appUUIDs = [NSMutableArray array];
/* Images. The iPhone crash report format sorts these in ascending order, by the base address */
@ -498,40 +498,18 @@ NSInteger binaryImageSort(id binary1, id binary2, void *context);
}
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]];
}
}
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
@implementation CNSCrashReportTextFormatter (PrivateAPI)
@implementation BITCrashReportTextFormatter (PrivateAPI)
/**
@ -543,9 +521,9 @@ NSInteger binaryImageSort(id binary1, id binary2, void *context);
*
* @return Returns a formatted frame line.
*/
+ (NSString *) formatStackFrame: (PLCrashReportStackFrameInfo *) frameInfo
frameIndex: (NSUInteger) frameIndex
report: (PLCrashReport *) report
+ (NSString *)formatStackFrame: (PLCrashReportStackFrameInfo *) frameInfo
frameIndex: (NSUInteger) frameIndex
report: (PLCrashReport *) report
{
/* Base image address containing instrumention pointer, offset of the IP from that base
* address, and the associated image name */

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
// HockeyDemo
//
// Created by Andreas Linde on 3/8/11.
// Copyright 2011 Andreas Linde. All rights reserved.
//
/*
* 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 "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]
@implementation BWHockeySettingsViewController
@implementation BITUpdateSettingsViewController
@synthesize hockeyManager = hockeyManager_;
@synthesize updateManager = _updateManager;
- (void)dismissSettings {
[self.navigationController dismissModalViewControllerAnimated:YES];
}
#pragma mark -
#pragma mark Initialization
#pragma mark - Initialization
- (id)init:(BWHockeyManager *)newHockeyManager {
- (id)init:(BITUpdateManager *)newUpdateManager {
if ((self = [super init])) {
self.hockeyManager = newHockeyManager;
self.title = BWHockeyLocalize(@"HockeySettingsTitle");
self.updateManager = newUpdateManager;
self.title = BITHockeySDKLocalizedString(@"UpdateSettingsTitle");
CGRect frame = self.view.frame;
frame.origin = CGPointZero;
@ -34,22 +56,13 @@
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;
BW_IF_3_2_OR_GREATER(
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
self.view.backgroundColor = BW_RGBCOLOR(200, 202, 204);
tableView_.backgroundColor = BW_RGBCOLOR(200, 202, 204);
} else {
tableView_.frame = frame;
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;
)
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
self.view.backgroundColor = BW_RGBCOLOR(200, 202, 204);
tableView_.backgroundColor = BW_RGBCOLOR(200, 202, 204);
} else {
tableView_.frame = frame;
tableView_.autoresizingMask = tableView_.autoresizingMask | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
}
tableView_.delegate = self;
tableView_.dataSource = self;
@ -62,18 +75,18 @@
}
- (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 = 1;
if ([self.hockeyManager isAllowUserToDisableSendData]) {
if ([self.hockeyManager shouldSendUserData]) numberOfSections++;
if ([self.hockeyManager shouldSendUsageTime]) numberOfSections++;
if ([_updateManager isAllowUserToDisableSendData]) {
if ([_updateManager shouldSendUserData]) numberOfSections++;
if ([_updateManager shouldSendUsageTime]) numberOfSections++;
}
return numberOfSections;
@ -82,7 +95,7 @@
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (section == [self numberOfSections] - 1) {
return BWHockeyLocalize(@"HockeySectionCheckTitle");
return BITHockeySDKLocalizedString(@"UpdateSectionCheckTitle");
} else {
return nil;
}
@ -106,10 +119,10 @@
footer.textColor = [UIColor grayColor];
footer.font = [UIFont systemFontOfSize:13];
if (section == 0 && [self.hockeyManager isAllowUserToDisableSendData] && [self.hockeyManager shouldSendUserData]) {
footer.text = BWHockeyLocalize(@"HockeySettingsUserDataDescription");
} else if ([self.hockeyManager isAllowUserToDisableSendData] && section < [self numberOfSections]) {
footer.text = BWHockeyLocalize(@"HockeySettingsUsageDataDescription");
if (section == 0 && [_updateManager isAllowUserToDisableSendData] && [_updateManager shouldSendUserData]) {
footer.text = BITHockeySDKLocalizedString(@"UpdateSettingsUserDataDescription");
} else if ([_updateManager isAllowUserToDisableSendData] && section < [self numberOfSections]) {
footer.text = BITHockeySDKLocalizedString(@"UpdateSettingsUsageDataDescription");
}
UIView* view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 285, footer.frame.size.height + 6 + 11)] autorelease];
@ -147,11 +160,11 @@
- (void)sendUserData:(UISwitch *)switcher {
[self.hockeyManager setUserAllowsSendUserData:switcher.on];
[_updateManager setUserAllowsSendUserData:switcher.on];
}
- (void)sendUsageData:(UISwitch *)switcher {
[self.hockeyManager setUserAllowsSendUsageTime:switcher.on];
[_updateManager setUserAllowsSendUsageTime:switcher.on];
}
@ -185,42 +198,42 @@
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
// update check selection
HockeyUpdateSetting hockeyAutoUpdateSetting = [[BWHockeyManager sharedHockeyManager] updateSetting];
BITUpdateSetting hockeyAutoUpdateSetting = [_updateManager updateSetting];
if (indexPath.row == 0) {
// on startup
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckStartup");
if (hockeyAutoUpdateSetting == HockeyUpdateCheckStartup) {
cell.textLabel.text = BITHockeySDKLocalizedString(@"UpdateSectionCheckStartup");
if (hockeyAutoUpdateSetting == BITUpdateCheckStartup) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
} else if (indexPath.row == 1) {
// daily
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckDaily");
if (hockeyAutoUpdateSetting == HockeyUpdateCheckDaily) {
cell.textLabel.text = BITHockeySDKLocalizedString(@"UpdateSectionCheckDaily");
if (hockeyAutoUpdateSetting == BITUpdateCheckDaily) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
} else {
// manually
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckManually");
if (hockeyAutoUpdateSetting == HockeyUpdateCheckManually) {
cell.textLabel.text = BITHockeySDKLocalizedString(@"UpdateSectionCheckManually");
if (hockeyAutoUpdateSetting == BITUpdateCheckManually) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
} else {
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
cell.textLabel.text = BWHockeyLocalize(@"HockeySettingsUserData");
cell.textLabel.text = BITHockeySDKLocalizedString(@"UpdateSettingsUserData");
[toggleSwitch addTarget:self action:@selector(sendUserData:)
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
cell.textLabel.text = BWHockeyLocalize(@"HockeySettingsUsageData");
cell.textLabel.text = BITHockeySDKLocalizedString(@"UpdateSettingsUsageData");
[toggleSwitch addTarget:self action:@selector(sendUsageData:)
forControlEvents:UIControlEventValueChanged];
[toggleSwitch setOn:[self.hockeyManager doesUserAllowsSendUsageTime]];
[toggleSwitch setOn:[_updateManager doesUserAllowsSendUsageTime]];
}
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 {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
@ -240,43 +252,29 @@
// update check interval selection
if (indexPath.row == 0) {
// on startup
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckStartup;
_updateManager.updateSetting = BITUpdateCheckStartup;
} else if (indexPath.row == 1) {
// daily
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckDaily;
_updateManager.updateSetting = BITUpdateCheckDaily;
} else {
// manually
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckManually;
_updateManager.updateSetting = BITUpdateCheckManually;
}
[tableView reloadData];
}
#pragma mark -
#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;
}
#pragma mark - Memory management
- (void)dealloc {
[_updateManager release];
[super dealloc];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Rotation
#pragma mark - Rotation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
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
//
// Created by Andreas Linde on 8/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.
/*
* 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 <QuartzCore/QuartzCore.h>
#import "NSString+HockeyAdditions.h"
#import "BWHockeyViewController.h"
#import "BWHockeyManager.h"
#import "BWGlobal.h"
#import "UIImage+HockeyAdditions.h"
#import "NSString+BITHockeyAdditions.h"
#import "BITAppVersionMetaInfo.h"
#import "UIImage+BITHockeyAdditions.h"
#import "PSAppStoreHeader.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 kAppStoreViewHeight 90
@interface BWHockeyViewController ()
@interface BITUpdateViewController()<PSStoreButtonDelegate>
// updates the whole view
- (void)showPreviousVersionAction;
- (void)redrawTableView;
@ -45,89 +54,78 @@
@end
@implementation BWHockeyViewController
@implementation BITUpdateViewController
@synthesize appStoreButtonState = appStoreButtonState_;
@synthesize hockeyManager = hockeyManager_;
@synthesize modal = modal_;
@synthesize modalAnimated = modalAnimated_;
@synthesize modal = _modal;
@synthesize modalAnimated = _modalAnimated;
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark private
- (void)restoreStoreButtonStateAnimated_:(BOOL)animated {
if ([self.hockeyManager isAppStoreEnvironment]) {
#pragma mark - Private
- (void)restoreStoreButtonStateAnimated:(BOOL)animated {
if (_isAppStoreEnvironment) {
[self setAppStoreButtonState:AppStoreButtonStateOffline animated:animated];
} else if ([self.hockeyManager isUpdateAvailable]) {
} else if ([_updateManager isUpdateAvailable]) {
[self setAppStoreButtonState:AppStoreButtonStateUpdate animated:animated];
} else {
[self setAppStoreButtonState:AppStoreButtonStateCheck animated:animated];
}
}
- (void)updateAppStoreHeader_ {
BWApp *app = self.hockeyManager.app;
appStoreHeader_.headerLabel = app.name;
appStoreHeader_.middleHeaderLabel = [app versionString];
- (void)updateAppStoreHeader {
BITAppVersionMetaInfo *appVersion = _updateManager.newestAppVersion;
_appStoreHeader.headerLabel = appVersion.name;
_appStoreHeader.middleHeaderLabel = [appVersion versionString];
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateStyle:NSDateFormatterMediumStyle];
NSMutableString *subHeaderString = [NSMutableString string];
if (app.date) {
[subHeaderString appendString:[formatter stringFromDate:app.date]];
if (appVersion.date) {
[subHeaderString appendString:[formatter stringFromDate:appVersion.date]];
}
if (app.size) {
if (appVersion.size) {
if ([subHeaderString length]) {
[subHeaderString appendString:@" - "];
}
[subHeaderString appendString:app.sizeInMB];
[subHeaderString appendString:appVersion.sizeInMB];
}
appStoreHeader_.subHeaderLabel = subHeaderString;
_appStoreHeader.subHeaderLabel = subHeaderString;
}
- (void)appDidBecomeActive_ {
if (self.appStoreButtonState == AppStoreButtonStateInstalling) {
[self setAppStoreButtonState:AppStoreButtonStateUpdate animated:YES];
} else if (![self.hockeyManager isCheckInProgress]) {
[self restoreStoreButtonStateAnimated_:YES];
} else if (![_updateManager isCheckInProgress]) {
[self restoreStoreButtonStateAnimated:YES];
}
}
- (void)openSettings:(id)sender {
BWHockeySettingsViewController *settings = [[[BWHockeySettingsViewController alloc] init] autorelease];
BITUpdateSettingsViewController *settings = [[[BITUpdateSettingsViewController alloc] init] autorelease];
Class popoverControllerClass = NSClassFromString(@"UIPopoverController");
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && popoverControllerClass) {
if (popOverController_ == nil) {
popOverController_ = [[popoverControllerClass alloc] initWithContentViewController:settings];
if (_popOverController == nil) {
_popOverController = [[popoverControllerClass alloc] initWithContentViewController:settings];
}
if ([popOverController_ contentViewController].view.window) {
[popOverController_ dismissPopoverAnimated:YES];
if ([_popOverController contentViewController].view.window) {
[_popOverController dismissPopoverAnimated:YES];
}else {
[popOverController_ setPopoverContentSize: CGSizeMake(320, 440)];
[popOverController_ presentPopoverFromBarButtonItem:self.navigationItem.rightBarButtonItem
[_popOverController setPopoverContentSize: CGSizeMake(320, 440)];
[_popOverController presentPopoverFromBarButtonItem:self.navigationItem.rightBarButtonItem
permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
} else {
BW_IF_3_2_OR_GREATER(
settings.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[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];
)
settings.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentModalViewController:settings animated:YES];
}
}
- (UIImage *)addGlossToImage_:(UIImage *)image {
BW_IF_IOS4_OR_GREATER(UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);)
BW_IF_PRE_IOS4(UIGraphicsBeginImageContext(image.size);)
- (UIImage *)addGlossToImage:(UIImage *)image {
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
[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];
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
@ -161,64 +159,62 @@
}
- (void)changePreviousVersionButtonBackground:(id)sender {
[(UIButton *)sender setBackgroundColor:BW_RGBCOLOR(183,183,183)];
[(UIButton *)sender setBackgroundColor:BIT_RGBCOLOR(183,183,183)];
}
- (void)changePreviousVersionButtonBackgroundHighlighted:(id)sender {
[(UIButton *)sender setBackgroundColor:BW_RGBCOLOR(183,183,183)];
[(UIButton *)sender setBackgroundColor:BIT_RGBCOLOR(183,183,183)];
}
- (void)showHidePreviousVersionsButton {
BOOL multipleVersionButtonNeeded = [self.hockeyManager.apps count] > 1 && !showAllVersions_;
BOOL multipleVersionButtonNeeded = [_updateManager.appVersions count] > 1 && !_showAllVersions;
if(multipleVersionButtonNeeded) {
// align at the bottom if tableview is small
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kMinPreviousVersionButtonHeight)];
footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
footerView.backgroundColor = BW_RGBCOLOR(200, 202, 204);
footerView.backgroundColor = BIT_RGBCOLOR(200, 202, 204);
UIButton *footerButton = [UIButton buttonWithType:UIButtonTypeCustom];
BW_IF_IOS4_OR_GREATER(
//footerButton.layer.shadowOffset = CGSizeMake(-2, 2);
footerButton.layer.shadowColor = [[UIColor blackColor] CGColor];
footerButton.layer.shadowRadius = 2.0f;
)
//footerButton.layer.shadowOffset = CGSizeMake(-2, 2);
footerButton.layer.shadowColor = [[UIColor blackColor] CGColor];
footerButton.layer.shadowRadius = 2.0f;
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 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 addTarget:self action:@selector(showPreviousVersionAction) forControlEvents:UIControlEventTouchUpInside];
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];
self.tableView.tableFooterView = footerView;
[self realignPreviousVersionButton];
[footerView release];
} else {
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
NSString *installed = @"";
if ([app.version isEqualToString:[self.hockeyManager 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")];
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>", [appVersion isEqual:_updateManager.newestAppVersion] ? @"left" : @"right", BITHockeySDKLocalizedString(@"UpdateInstalled")];
}
if ([app isEqual:self.hockeyManager.app]) {
if ([app.notes length] > 0) {
if ([appVersion isEqual:_updateManager.newestAppVersion]) {
if ([appVersion.notes length] > 0) {
installed = [NSString stringWithFormat:@"<p>&nbsp;%@</p>", installed];
cell.webViewContent = [NSString stringWithFormat:@"%@%@", installed, app.notes];
cell.webViewContent = [NSString stringWithFormat:@"%@%@", installed, appVersion.notes];
} 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 {
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];
// hack
@ -227,47 +223,46 @@
[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])) {
self.hockeyManager = newHockeyManager;
self.updateManager = newUpdateManager;
self.modal = newModal;
self.modalAnimated = YES;
self.title = BWHockeyLocalize(@"HockeyUpdateScreenTitle");
self.title = BITHockeySDKLocalizedString(@"UpdateScreenTitle");
if ([self.hockeyManager shouldShowUserSettings]) {
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithImage:[UIImage bw_imageNamed:@"gear.png" bundle:kHockeyBundleName]
_isAppStoreEnvironment = [BITHockeyManager sharedHockeyManager].isAppStoreEnvironment;
if ([_updateManager shouldShowUserSettings]) {
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithImage:[UIImage bit_imageNamed:@"gear.png" bundle:BITHOCKEYSDK_BUNDLE]
style:UIBarButtonItemStyleBordered
target:self
action:@selector(openSettings:)] autorelease];
}
cells_ = [[NSMutableArray alloc] initWithCapacity:5];
popOverController_ = nil;
_cells = [[NSMutableArray alloc] initWithCapacity:5];
_popOverController = nil;
}
return self;
}
- (id)init {
return [self init:[BWHockeyManager sharedHockeyManager] modal:NO];
return [self init:[BITHockeyManager sharedHockeyManager].updateManager modal:NO];
}
- (void)dealloc {
[self viewDidUnload];
for (UITableViewCell *cell in cells_) {
for (UITableViewCell *cell in _cells) {
[cell removeObserver:self forKeyPath:@"webViewSize"];
}
[cells_ release];
[_cells release];
[super dealloc];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark View lifecycle
#pragma mark - View lifecycle
- (void)onAction:(id)sender {
if (self.modal) {
@ -293,7 +288,7 @@
[self.navigationController popViewControllerAnimated:YES];
}
[[UIApplication sharedApplication] setStatusBarStyle:statusBarStyle_];
[[UIApplication sharedApplication] setStatusBarStyle:_statusBarStyle];
}
- (CAGradientLayer *)backgroundLayer {
@ -327,22 +322,22 @@
[dnc addObserver:self selector:@selector(appDidBecomeActive_) name:UIApplicationDidBecomeActiveNotification object:nil];
// hook into manager with kvo!
[self.hockeyManager addObserver:self forKeyPath:@"checkInProgress" options:0 context:nil];
[self.hockeyManager addObserver:self forKeyPath:@"isUpdateURLOffline" options:0 context:nil];
[self.hockeyManager addObserver:self forKeyPath:@"updateAvailable" options:0 context:nil];
[self.hockeyManager addObserver:self forKeyPath:@"apps" options:0 context:nil];
kvoRegistered_ = YES;
[_updateManager addObserver:self forKeyPath:@"checkInProgress" options:0 context:nil];
[_updateManager addObserver:self forKeyPath:@"isUpdateURLOffline" options:0 context:nil];
[_updateManager addObserver:self forKeyPath:@"updateAvailable" options:0 context:nil];
[_updateManager addObserver:self forKeyPath:@"apps" options:0 context:nil];
_kvoRegistered = YES;
self.tableView.backgroundColor = BW_RGBCOLOR(200, 202, 204);
self.tableView.backgroundColor = BIT_RGBCOLOR(200, 202, 204);
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
UIView *topView = [[[UIView alloc] initWithFrame:CGRectMake(0, -(600-kAppStoreViewHeight), self.view.frame.size.width, 600)] autorelease];
topView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
topView.backgroundColor = BW_RGBCOLOR(140, 141, 142);
topView.backgroundColor = BIT_RGBCOLOR(140, 141, 142);
[self.tableView addSubview:topView];
appStoreHeader_ = [[PSAppStoreHeader alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kAppStoreViewHeight)];
[self updateAppStoreHeader_];
_appStoreHeader = [[PSAppStoreHeader alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kAppStoreViewHeight)];
[self updateAppStoreHeader];
NSString *iconString = nil;
NSArray *icons = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFiles"];
@ -362,7 +357,7 @@
if (icons) {
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) {
iconString = icon;
@ -386,12 +381,12 @@
}
if (addGloss) {
appStoreHeader_.iconImage = [self addGlossToImage_:[UIImage imageNamed:iconString]];
_appStoreHeader.iconImage = [self addGlossToImage:[UIImage imageNamed:iconString]];
} else {
appStoreHeader_.iconImage = [UIImage imageNamed:iconString];
_appStoreHeader.iconImage = [UIImage imageNamed:iconString];
}
self.tableView.tableHeaderView = appStoreHeader_;
self.tableView.tableHeaderView = _appStoreHeader;
if (self.modal) {
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
@ -406,47 +401,47 @@
storeButton.buttonData = [PSStoreButtonData dataWithLabel:@"" colors:[PSStoreButton appStoreGrayColor] enabled:NO];
self.appStoreButtonState = AppStoreButtonStateCheck;
[storeButton alignToSuperview];
appStoreButton_ = [storeButton retain];
_appStoreButton = [storeButton retain];
}
- (void)viewWillAppear:(BOOL)animated {
if ([self.hockeyManager isAppStoreEnvironment])
if (_isAppStoreEnvironment)
self.appStoreButtonState = AppStoreButtonStateOffline;
self.hockeyManager.currentHockeyViewController = self;
_updateManager.currentHockeyViewController = self;
[super viewWillAppear:animated];
statusBarStyle_ = [[UIApplication sharedApplication] statusBarStyle];
_statusBarStyle = [[UIApplication sharedApplication] statusBarStyle];
[[UIApplication sharedApplication] setStatusBarStyle:(self.navigationController.navigationBar.barStyle == UIBarStyleDefault) ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque];
[self redrawTableView];
}
- (void)viewWillDisappear:(BOOL)animated {
self.hockeyManager.currentHockeyViewController = nil;
_updateManager.currentHockeyViewController = nil;
//if the popover is still visible, dismiss it
[popOverController_ dismissPopoverAnimated:YES];
[_popOverController dismissPopoverAnimated:YES];
[super viewWillDisappear:animated];
[[UIApplication sharedApplication] setStatusBarStyle:statusBarStyle_];
[[UIApplication sharedApplication] setStatusBarStyle:_statusBarStyle];
}
- (void)redrawTableView {
[self restoreStoreButtonStateAnimated_:NO];
[self updateAppStoreHeader_];
[self restoreStoreButtonStateAnimated:NO];
[self updateAppStoreHeader];
// clean up and remove any pending overservers
for (UITableViewCell *cell in cells_) {
for (UITableViewCell *cell in _cells) {
[cell removeObserver:self forKeyPath:@"webViewSize"];
}
[cells_ removeAllObjects];
[_cells removeAllObjects];
int i = 0;
BOOL breakAfterThisApp = NO;
for (BWApp *app in self.hockeyManager.apps) {
BOOL breakAfterThisAppVersion = NO;
for (BITAppVersionMetaInfo *appVersion in _updateManager.appVersions) {
i++;
// only show the newer version of the app by default, if we don't show all versions
if (!showAllVersions_) {
if ([app.version isEqualToString:[self.hockeyManager currentAppVersion]]) {
if (!_showAllVersions) {
if ([appVersion.version isEqualToString:[_updateManager currentAppVersion]]) {
if (i == 1) {
breakAfterThisApp = YES;
breakAfterThisAppVersion = YES;
} else {
break;
}
@ -454,10 +449,10 @@
}
PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease];
[self configureWebCell:cell forApp_:app];
[cells_ addObject:cell];
[self configureWebCell:cell forAppVersion:appVersion];
[_cells addObject:cell];
if (breakAfterThisApp) break;
if (breakAfterThisAppVersion) break;
}
[self.tableView reloadData];
@ -465,14 +460,14 @@
}
- (void)showPreviousVersionAction {
showAllVersions_ = YES;
_showAllVersions = YES;
BOOL showAllPending = NO;
for (BWApp *app in self.hockeyManager.apps) {
for (BITAppVersionMetaInfo *appVersion in _updateManager.appVersions) {
if (!showAllPending) {
if ([app.version isEqualToString:[self.hockeyManager currentAppVersion]]) {
if ([appVersion.version isEqualToString:[_updateManager currentAppVersion]]) {
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
}
} else {
@ -481,33 +476,32 @@
}
PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease];
[self configureWebCell:cell forApp_:app];
[cells_ addObject:cell];
[self configureWebCell:cell forAppVersion:appVersion];
[_cells addObject:cell];
}
[self.tableView reloadData];
[self showHidePreviousVersionsButton];
}
- (void)viewDidUnload {
[appStoreHeader_ release]; appStoreHeader_ = nil;
[popOverController_ release], popOverController_ = nil;
[_appStoreHeader release]; _appStoreHeader = nil;
[_popOverController release], _popOverController = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
// test if KVO's are registered. if class is destroyed before it was shown(viewDidLoad) no KVOs are registered.
if (kvoRegistered_) {
[self.hockeyManager removeObserver:self forKeyPath:@"checkInProgress"];
[self.hockeyManager removeObserver:self forKeyPath:@"isUpdateURLOffline"];
[self.hockeyManager removeObserver:self forKeyPath:@"updateAvailable"];
[self.hockeyManager removeObserver:self forKeyPath:@"apps"];
kvoRegistered_ = NO;
if (_kvoRegistered) {
[_updateManager removeObserver:self forKeyPath:@"checkInProgress"];
[_updateManager removeObserver:self forKeyPath:@"isUpdateURLOffline"];
[_updateManager removeObserver:self forKeyPath:@"updateAvailable"];
[_updateManager removeObserver:self forKeyPath:@"apps"];
_kvoRegistered = NO;
}
[super viewDidUnload];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Table view data source
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
@ -516,31 +510,30 @@
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat rowHeight = 0;
if ([cells_ count] > (NSUInteger)indexPath.row) {
PSWebTableViewCell *cell = [cells_ objectAtIndex:indexPath.row];
if ([_cells count] > (NSUInteger)indexPath.row) {
PSWebTableViewCell *cell = [_cells objectAtIndex:indexPath.row];
rowHeight = cell.webViewSize.height;
}
if ([self.hockeyManager.apps count] > 1 && !showAllVersions_) {
self.tableView.backgroundColor = BW_RGBCOLOR(183, 183, 183);
if ([_updateManager.appVersions count] > 1 && !_showAllVersions) {
self.tableView.backgroundColor = BIT_RGBCOLOR(183, 183, 183);
}
if (rowHeight == 0) {
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;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger cellCount = [cells_ count];
NSInteger cellCount = [_cells count];
return cellCount;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark KVO
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
// only make changes if we are visible
@ -549,15 +542,15 @@
[self.tableView reloadData];
[self realignPreviousVersionButton];
} else if ([keyPath isEqualToString:@"checkInProgress"]) {
if (self.hockeyManager.isCheckInProgress) {
if (_updateManager.isCheckInProgress) {
[self setAppStoreButtonState:AppStoreButtonStateSearching animated:YES];
}else {
[self restoreStoreButtonStateAnimated_:YES];
[self restoreStoreButtonStateAnimated:YES];
}
} else if ([keyPath isEqualToString:@"isUpdateURLOffline"]) {
[self restoreStoreButtonStateAnimated_:YES];
[self restoreStoreButtonStateAnimated:YES];
} else if ([keyPath isEqualToString:@"updateAvailable"]) {
[self restoreStoreButtonStateAnimated_:YES];
[self restoreStoreButtonStateAnimated:YES];
} else if ([keyPath isEqualToString:@"apps"]) {
[self redrawTableView];
}
@ -566,18 +559,16 @@
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([cells_ count] > (NSUInteger)indexPath.row) {
return [cells_ objectAtIndex:indexPath.row];
if ([_cells count] > (NSUInteger)indexPath.row) {
return [_cells objectAtIndex:indexPath.row];
} 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;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Rotation
#pragma mark - Rotation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
BOOL shouldAutorotate;
@ -595,12 +586,11 @@
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
// update all cells
[cells_ makeObjectsPerformSelector:@selector(addWebView)];
[_cells makeObjectsPerformSelector:@selector(addWebView)];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark PSAppStoreHeaderDelegate
#pragma mark - PSAppStoreHeaderDelegate
- (void)setAppStoreButtonState:(AppStoreButtonState)anAppStoreButtonState {
[self setAppStoreButtonState:anAppStoreButtonState animated:NO];
@ -611,19 +601,19 @@
switch (anAppStoreButtonState) {
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;
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;
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;
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;
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;
default:
break;
@ -633,10 +623,10 @@
- (void)storeButtonFired:(PSStoreButton *)button {
switch (appStoreButtonState_) {
case AppStoreButtonStateCheck:
[self.hockeyManager checkForUpdateShowFeedback:YES];
[_updateManager checkForUpdateShowFeedback:YES];
break;
case AppStoreButtonStateUpdate:
if ([self.hockeyManager initiateAppDownload]) {
if ([_updateManager initiateAppDownload]) {
[self setAppStoreButtonState:AppStoreButtonStateInstalling animated:YES];
};
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.
// 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
// of this software and associated documentation files (the "Software"), to deal
@ -25,11 +24,11 @@
#import <Foundation/Foundation.h>
@interface NSString (HockeyAdditions)
@interface NSString (BITHockeyAdditions)
- (NSString *)bw_URLEncodedString;
- (NSString *)bw_URLDecodedString;
- (NSString *)bit_URLEncodedString;
- (NSString *)bit_URLDecodedString;
- (NSComparisonResult)versionCompare:(NSString *)other;
- (NSComparisonResult)bit_versionCompare:(NSString *)other;
@end

View File

@ -1,8 +1,7 @@
//
// NSString+HockeyAdditions.m
//
// Created by Jon Crosby on 10/19/07.
// 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
// of this software and associated documentation files (the "Software"), to deal
@ -23,16 +22,11 @@
// THE SOFTWARE.
#import "NSString+HockeyAdditions.h"
#import "NSString+BITHockeyAdditions.h"
#ifdef HOCKEYLIB_STATIC_LIBRARY
#import "CNSFixCategoryBug.h"
CNS_FIX_CATEGORY_BUG(NSString_HockeyAdditions)
#endif
@implementation NSString (BITHockeyAdditions)
@implementation NSString (HockeyAdditions)
- (NSString *)bw_URLEncodedString {
- (NSString *)bit_URLEncodedString {
NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)self,
NULL,
@ -42,7 +36,7 @@ CNS_FIX_CATEGORY_BUG(NSString_HockeyAdditions)
return result;
}
- (NSString*)bw_URLDecodedString {
- (NSString*)bit_URLDecodedString {
NSString *result = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
(CFStringRef)self,
CFSTR(""),
@ -51,7 +45,7 @@ CNS_FIX_CATEGORY_BUG(NSString_HockeyAdditions)
return result;
}
- (NSComparisonResult)versionCompare:(NSString *)other {
- (NSComparisonResult)bit_versionCompare:(NSString *)other {
// Extract plain version number from self
NSString *plainSelf = self;
NSRange letterRange = [plainSelf rangeOfCharacterFromSet: [NSCharacterSet letterCharacterSet]];

View File

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

View File

@ -1,9 +1,6 @@
//
// PSStoreButton.h
// HockeyDemo
//
// 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
// 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.
// 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
//
@ -39,9 +36,8 @@
@synthesize colors = colors_;
@synthesize enabled = enabled_;
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark NSObject
#pragma mark - NSObject
- (id)initWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag {
if ((self = [super init])) {
@ -77,9 +73,8 @@
@synthesize buttonDelegate = buttonDelegate_;
@synthesize customPadding = customPadding_;
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark private
#pragma mark - private
- (void)buttonPressed:(id)sender {
[buttonDelegate_ storeButtonFired:self];
@ -159,9 +154,8 @@
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark NSObject
#pragma mark - NSObject
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
@ -214,9 +208,8 @@
[super dealloc];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark UIView
#pragma mark - UIView
- (CGSize)sizeThatFits:(CGSize)size {
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 {
[self setButtonData:aButtonData animated:NO];
@ -258,9 +250,8 @@
[self updateButtonAnimated:animated];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Static
#pragma mark - Static
+ (NSArray *)appStoreGreenColor {
return [NSArray arrayWithObjects:(id)

View File

@ -1,9 +1,6 @@
//
// PSWebTableViewCell.h
// HockeyDemo
//
// 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
// 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.
// 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
// of this software and associated documentation files (the "Software"), to deal
@ -24,7 +21,7 @@
// THE SOFTWARE.
#import "PSWebTableViewCell.h"
#import "BWGlobal.h"
@implementation PSWebTableViewCell
@ -47,9 +44,8 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
@synthesize webViewSize = webViewSize_;
@synthesize cellBackgroundColor = cellBackgroundColor_;
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark private
#pragma mark - private
- (void)addWebView {
if(webViewContent_) {
@ -83,7 +79,7 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
webView_.frame = webViewRect;
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];
[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 {
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];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark UIView
#pragma mark - UIView
- (void)setFrame:(CGRect)aFrame {
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 {
[self removeWebView];
@ -158,9 +151,8 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
[super prepareForReuse];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark UIWebView
#pragma mark - UIWebView
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if(navigationType == UIWebViewNavigationTypeOther)

View File

@ -1,9 +1,10 @@
//
// UIImage+HockeyAdditions.h
// HockeyDemo
// UIImage+BITHockeySDKAdditions.h
//
// 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
// of this software and associated documentation files (the "Software"), to deal
@ -25,14 +26,14 @@
#import <UIKit/UIKit.h>
@interface UIImage (HockeyAdditions)
@interface UIImage (BITHockeySDKAdditions)
- (UIImage *)bw_roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize;
- (UIImage *)bw_imageToFitSize:(CGSize)fitSize honorScaleFactor:(BOOL)honorScaleFactor;
- (UIImage *)bw_reflectedImageWithHeight:(NSUInteger)height fromAlpha:(float)fromAlpha toAlpha:(float)toAlpha;
- (UIImage *)bit_roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize;
- (UIImage *)bit_imageToFitSize:(CGSize)fitSize honorScaleFactor:(BOOL)honorScaleFactor;
- (UIImage *)bit_reflectedImageWithHeight:(NSUInteger)height fromAlpha:(float)fromAlpha toAlpha:(float)toAlpha;
- (id)bw_initWithContentsOfResolutionIndependentFile:(NSString *)path NS_RETURNS_RETAINED;
+ (UIImage*)bw_imageWithContentsOfResolutionIndependentFile:(NSString *)path;
+ (UIImage *)bw_imageNamed:(NSString *)imageName bundle:(NSString *)bundleName;
- (id)bit_initWithContentsOfResolutionIndependentFile:(NSString *)path NS_RETURNS_RETAINED;
+ (UIImage *)bit_imageWithContentsOfResolutionIndependentFile:(NSString *)path;
+ (UIImage *)bit_imageNamed:(NSString *)imageName bundle:(NSString *)bundleName;
@end

View File

@ -1,9 +1,10 @@
//
// UIImage+HockeyAdditions.m
// HockeyDemo
// UIImage+BITHockeySDKAdditions.m
//
// 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
// 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
// THE SOFTWARE.
#import "UIImage+HockeyAdditions.h"
#import "BWGlobal.h"
#ifdef HOCKEYLIB_STATIC_LIBRARY
#import "CNSFixCategoryBug.h"
CNS_FIX_CATEGORY_BUG(UIImage_HockeyAdditionsPrivate)
#endif
#import "UIImage+BITHockeyAdditions.h"
// Private helper methods
@interface UIImage (HockeyAdditionsPrivate)
- (void)addRoundedRectToPath:(CGRect)rect context:(CGContextRef)context ovalWidth:(CGFloat)ovalWidth ovalHeight:(CGFloat)ovalHeight;
@interface UIImage (BITHockeyAdditionsPrivate)
- (void)bit_addRoundedRectToPath:(CGRect)rect context:(CGContextRef)context ovalWidth:(CGFloat)ovalWidth ovalHeight:(CGFloat)ovalHeight;
@end
@implementation UIImage (HockeyAdditions)
@implementation UIImage (BITHockeyAdditions)
CGContextRef MyOpenBitmapContext(int pixelsWide, int pixelsHigh);
CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha, float toAlpha);
@ -84,32 +79,29 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
// 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
// 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
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".
CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], CGRectMake(0, 0, self.size.width * self.scale, self.size.height * self.scale)); // cropping happens here.
// Create a clipping path with rounded corners
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextBeginPath(context);
[self addRoundedRectToPath:CGRectMake(borderSize, borderSize, self.size.width - borderSize * 2, self.size.height - borderSize * 2)
context:context
ovalWidth:cornerSize
ovalHeight:cornerSize];
CGContextClosePath(context);
CGContextClip(context);
roundedImage = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage.
[roundedImage drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)]; // the actual scaling happens here, and orientation is taken care of automatically.
CGImageRelease(sourceImg);
roundedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
)
#endif
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.
// Create a clipping path with rounded corners
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextBeginPath(context);
[self addRoundedRectToPath:CGRectMake(borderSize, borderSize, self.size.width - borderSize * 2, self.size.height - borderSize * 2)
context:context
ovalWidth:cornerSize
ovalHeight:cornerSize];
CGContextClosePath(context);
CGContextClip(context);
roundedImage = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage.
[roundedImage drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)]; // the actual scaling happens here, and orientation is taken care of automatically.
CGImageRelease(sourceImg);
roundedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if (!roundedImage) {
// Try older method.
UIImage *image = [self imageWithAlpha];
@ -146,8 +138,7 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
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
// 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);
}
- (UIImage *)bw_imageToFitSize:(CGSize)fitSize honorScaleFactor:(BOOL)honorScaleFactor
- (UIImage *)bit_imageToFitSize:(CGSize)fitSize honorScaleFactor:(BOOL)honorScaleFactor
{
float imageScaleFactor = 1.0;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
if (honorScaleFactor) {
if ([self respondsToSelector:@selector(scale)]) {
imageScaleFactor = [self scale];
}
}
#endif
float sourceWidth = [self size].width * imageScaleFactor;
float sourceHeight = [self size].height * imageScaleFactor;
@ -214,16 +203,13 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
// Create appropriately modified image.
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".
CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], sourceRect); // cropping happens here.
image = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage.
[image drawInRect:destRect]; // the actual scaling happens here, and orientation is taken care of automatically.
CGImageRelease(sourceImg);
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
)
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.
image = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage.
[image drawInRect:destRect]; // the actual scaling happens here, and orientation is taken care of automatically.
CGImageRelease(sourceImg);
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if (!image) {
// Try older method.
@ -292,7 +278,7 @@ CGContextRef MyOpenBitmapContext(int pixelsWide, int pixelsHigh) {
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)
return nil;
@ -319,7 +305,7 @@ CGContextRef MyOpenBitmapContext(int pixelsWide, int pixelsHigh) {
return theImage;
}
- (id)bw_initWithContentsOfResolutionIndependentFile:(NSString *)path {
- (id)bit_initWithContentsOfResolutionIndependentFile:(NSString *)path {
if ([UIScreen instancesRespondToSelector:@selector(scale)] && (int)[[UIScreen mainScreen] scale] == 2.0) {
NSString *path2x = [[path stringByDeletingLastPathComponent]
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@@2x.%@",
@ -334,19 +320,19 @@ CGContextRef MyOpenBitmapContext(int pixelsWide, int pixelsHigh) {
return [self initWithContentsOfFile:path];
}
+ (UIImage*)bw_imageWithContentsOfResolutionIndependentFile:(NSString *)path {
+ (UIImage*)bit_imageWithContentsOfResolutionIndependentFile:(NSString *)path {
#ifndef __clang_analyzer__
// clang alayzer in 4.2b3 thinks here's a leak, which is not the case.
return [[[UIImage alloc] bw_initWithContentsOfResolutionIndependentFile:path] autorelease];
return [[[UIImage alloc] bit_initWithContentsOfResolutionIndependentFile:path] autorelease];
#endif
}
+ (UIImage *)bw_imageNamed:(NSString *)imageName bundle:(NSString *)bundleName {
+ (UIImage *)bit_imageNamed:(NSString *)imageName bundle:(NSString *)bundleName {
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *bundlePath = [resourcePath stringByAppendingPathComponent:bundleName];
NSString *imagePath = [bundlePath stringByAppendingPathComponent:imageName];
return [UIImage bw_imageWithContentsOfResolutionIndependentFile:imagePath];
return [UIImage bit_imageWithContentsOfResolutionIndependentFile:imagePath];
}
@end

View File

@ -1,12 +1,12 @@
Pod::Spec.new do |s|
s.name = 'HockeySDK'
s.version = '2.2.6'
s.version = '2.3.0'
s.license = 'MIT'
s.platform = :ios
s.summary = 'Distribute beta apps and collect crash reports with HockeyApp.'
s.homepage = 'http://hockeyapp.net/'
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. ' \
'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.'
s.source_files = 'Classes'
s.resources = 'Resources/Hockey.bundle', 'Resources/Quincy.bundle'
s.resources = 'Resources/HockeySDKResources.bundle'
s.frameworks = 'QuartzCore', 'SystemConfiguration', 'CrashReporter'
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
The Hockey SDK is provided under the following 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
obtaining a copy of this software and associated documentation
@ -41,6 +31,7 @@ Except as noted below, PLCrashReporter
is provided under the following license:
Copyright (c) 2008 - 2012 Plausible Labs Cooperative, Inc.
Copyright (c) 2012 HockeyApp, Bit Stadium GmbH.
All rights reserved.
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