├── .gitignore ├── .gitmodules ├── Acknowledgements.txt ├── AdHoc.mobileprovision ├── App ├── Build-Info.plist ├── Classes │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── PSBaseViewController.h │ ├── PSBaseViewController.m │ ├── PSDefines.h │ ├── PSIncludes.h │ ├── PSWindow.h │ ├── PSWindow.m │ ├── RootViewController.h │ └── RootViewController.m ├── Images │ ├── Default.png │ ├── Icon-72.png │ ├── Icon-Small-50.png │ ├── Icon-Small.png │ ├── Icon-Small@2x.png │ ├── Icon.png │ ├── Icon@2x.png │ ├── iTunesArtwork │ └── lolcat.png ├── Info.plist ├── Localization │ ├── English.lproj │ │ └── Localizable.strings │ └── German.lproj │ │ └── Localizable.strings ├── PSAppTemplate.xcodeproj │ └── project.pbxproj ├── Prefix.pch └── main.m ├── CrashReporter.framework ├── CrashReporter ├── Headers ├── Resources └── Versions │ ├── A │ ├── CrashReporter │ ├── Headers │ │ ├── CrashReporter.h │ │ ├── PLCrashReport.h │ │ ├── PLCrashReportApplicationInfo.h │ │ ├── PLCrashReportBinaryImageInfo.h │ │ ├── PLCrashReportExceptionInfo.h │ │ ├── PLCrashReportFormatter.h │ │ ├── PLCrashReportProcessInfo.h │ │ ├── PLCrashReportSignalInfo.h │ │ ├── PLCrashReportSystemInfo.h │ │ ├── PLCrashReportTextFormatter.h │ │ ├── PLCrashReportThreadInfo.h │ │ └── PLCrashReporter.h │ └── Resources │ │ └── Info.plist │ └── Current ├── CrashReporterSender ├── CrashReportSender.h ├── CrashReportSender.m ├── English.lproj │ └── CrashReporter.strings └── German.lproj │ └── CrashReporter.strings ├── Flurry ├── Analytics-README.txt ├── AppCircle-README.txt ├── RELEASE_NOTES.txt └── iPhone v2.7 (build 42) │ ├── FlurryLib │ ├── FlurryAPI.h │ ├── FlurryAdDelegate.h │ └── libFlurry.a │ └── FlurryLibWithLocation │ ├── FlurryAPI.h │ ├── FlurryAdDelegate.h │ └── libFlurryWithLocation.a ├── README.mdown ├── ReleaseNotes.html ├── STYLEGUIDE.md ├── Xcode ├── appstore.xcconfig ├── appversion.xcconfig ├── buildnumber.xcconfig ├── debug.xcconfig ├── distribution.xcconfig └── increase.sh ├── regexkitlite ├── License.html ├── License.rtf ├── RegexKitLite.h ├── RegexKitLite.html └── RegexKitLite.m └── symbolicator ├── com.crashreportsender.symbolicator.plist ├── serverconfig.php ├── symbolicate.php ├── symbolicate.sh └── symbolicatecrash.pl /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | */build 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | 17 | # Xcode 4 18 | *.xcworkspace 19 | xcuserdata 20 | 21 | # osx noise 22 | .DS_Store 23 | profile 24 | 25 | Development 26 | Releases -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "PSFoundation"] 2 | path = PSFoundation 3 | url = https://github.com/steipete/PSFoundation.git 4 | [submodule "asi-http-request"] 5 | path = asi-http-request 6 | url = https://github.com/pokeb/asi-http-request.git 7 | [submodule "JSONKit"] 8 | path = JSONKit 9 | url = https://github.com/johnezang/JSONKit.git 10 | [submodule "HockeyKit"] 11 | path = HockeyKit 12 | url = git://github.com/TheRealKerni/HockeyKit.git 13 | [submodule "DCIntrospect"] 14 | path = DCIntrospect 15 | url = https://github.com/domesticcatsoftware/DCIntrospect.git 16 | -------------------------------------------------------------------------------- /Acknowledgements.txt: -------------------------------------------------------------------------------- 1 | Acknowledgments 2 | Portions of this Software may utilize the following copyrighted material, the use of which is hereby acknowledged. 3 | 4 | 5 | RegexKitLite 6 | BSD LICENSE 7 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 3. Neither the name of Apple Inc. ("Apple") nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /AdHoc.mobileprovision: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/AdHoc.mobileprovision -------------------------------------------------------------------------------- /App/Build-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.petersteinberger.apptemplate 13 | CFBundleIconFiles 14 | 15 | Icon.png 16 | Icon@2x.png 17 | Icon-72.png 18 | Icon-Small-50.png 19 | Icon-Small.png 20 | Icon-Small@2x.png 21 | 22 | CFBundleInfoDictionaryVersion 23 | 6.0 24 | CFBundleName 25 | ${PRODUCT_NAME} 26 | CFBundlePackageType 27 | APPL 28 | CFBundleSignature 29 | ???? 30 | CFBundleVersion 31 | ${BUILD_NUMBER} 32 | CFBundleShortVersionString 33 | ${APP_VERSION} 34 | UIPrerenderedIcon 35 | 36 | LSRequiresIPhoneOS 37 | 38 | UIStatusBarStyle 39 | UIStatusBarStyleDefault 40 | 41 | 42 | -------------------------------------------------------------------------------- /App/Classes/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // PSAppTemplateAppDelegate.h 3 | // PSAppTemplate 4 | // 5 | // Created by Peter Steinberger on 12.12.10. 6 | // Template by Peter Steinberger 7 | // 8 | 9 | #import "PSDefines.h" 10 | #import "PSWindow.h" 11 | 12 | #ifdef kUseCrashReporter 13 | #import "CrashReportSender.h" 14 | #endif 15 | 16 | #ifdef kUseAutoUpdater 17 | #import "BWHockeyManager.h" 18 | #endif 19 | 20 | @interface AppDelegate : NSObject { 28 | PSWindow *window_; 29 | UINavigationController *navigationController_; 30 | } 31 | 32 | @property (nonatomic, retain) UIWindow *window; 33 | @property (nonatomic, retain) UINavigationController *navigationController; 34 | 35 | @end 36 | 37 | -------------------------------------------------------------------------------- /App/Classes/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // PSAppTemplateAppDelegate.m 3 | // PSAppTemplate 4 | // 5 | // Created by Peter Steinberger on 12.12.10. 6 | // Template by Peter Steinberger 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "PSIncludes.h" 11 | #import "BWHockeyManager.h" 12 | #import "RootViewController.h" 13 | 14 | #ifdef kUseFlurryStatistics 15 | #import "FlurryAPI.h" 16 | #endif 17 | 18 | #ifdef kDCIntrospectEnabled 19 | #import "DCIntrospect.h" 20 | #endif 21 | 22 | 23 | @interface AppDelegate () 24 | 25 | - (void)configureLogger; 26 | - (void)appplicationPrepareForBackgroundOrTermination:(UIApplication *)application; 27 | - (void)postFinishLaunch; 28 | @end 29 | 30 | 31 | @implementation AppDelegate 32 | 33 | @synthesize window = window_; 34 | @synthesize navigationController = navigationController_; 35 | 36 | 37 | /////////////////////////////////////////////////////////////////////////////////////////////////// 38 | #pragma mark - 39 | #pragma mark NSObject 40 | /////////////////////////////////////////////////////////////////////////////////////////////////// 41 | 42 | - (void)dealloc { 43 | MCRelease(window_); 44 | MCRelease(navigationController_); 45 | 46 | [super dealloc]; 47 | } 48 | 49 | /////////////////////////////////////////////////////////////////////////////////////////////////// 50 | #pragma mark - 51 | #pragma mark UIApplicationDelegate 52 | /////////////////////////////////////////////////////////////////////////////////////////////////// 53 | 54 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 55 | [self configureLogger]; 56 | DDLogInfo(_(@"PSTemplateWelcomeMessage")); 57 | 58 | #ifdef kUseCrashReporter 59 | [[CrashReportSender sharedCrashReportSender] sendCrashReportToURL:[NSURL URLWithString:kCrashReporterUrl] 60 | delegate:self activateFeedback:kCrashReporterFeedbackEnabled]; 61 | #endif 62 | 63 | // check for NSZombie (memory leak if enabled, but very useful!) 64 | if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled")) { 65 | DDLogWarn(@"NSZombieEnabled / NSAutoreleaseFreedObjectCheckEnabled enabled! Disable for release."); 66 | } 67 | 68 | // Add the navigation controller's view to the window and display. 69 | RootViewController *rootController = [[[RootViewController alloc] initWithStyle:UITableViewStylePlain] autorelease]; 70 | navigationController_ = [[UINavigationController alloc] initWithRootViewController:rootController]; 71 | window_ = [[PSWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 72 | window_.rootViewController = navigationController_; 73 | [window_ makeKeyAndVisible]; 74 | 75 | // fade animation! 76 | #ifdef kIntroFadeAnimation 77 | MTSplashScreen *splashScreen = [MTSplashScreen splashScreen]; 78 | [self.navigationController presentModalViewController:splashScreen animated:NO]; 79 | #endif 80 | 81 | // visual debugging! 82 | #ifdef kDCIntrospectEnabled 83 | [[DCIntrospect sharedIntrospector] start]; 84 | #endif 85 | 86 | #if !defined (APPSTORE) 87 | DDLogInfo(@"Autoupdate is enabled."); 88 | [BWHockeyManager sharedHockeyManager].updateURL = kHockeyUpdateDistributionUrl; 89 | [BWHockeyManager sharedHockeyManager].delegate = self; 90 | [BWHockeyManager sharedHockeyManager].alwaysShowUpdateReminder = YES; 91 | #endif 92 | 93 | if (kPostFinishLaunchDelay > 0) { 94 | [self performSelector:@selector(postFinishLaunch) withObject:nil afterDelay:kPostFinishLaunchDelay]; 95 | } 96 | 97 | return YES; 98 | } 99 | 100 | - (void)applicationWillResignActive:(UIApplication *)application { 101 | } 102 | 103 | 104 | - (void)applicationDidEnterBackground:(UIApplication *)application { 105 | [self appplicationPrepareForBackgroundOrTermination:application]; 106 | } 107 | 108 | 109 | - (void)applicationWillEnterForeground:(UIApplication *)application { 110 | } 111 | 112 | 113 | - (void)applicationDidBecomeActive:(UIApplication *)application { 114 | } 115 | 116 | 117 | - (void)applicationWillTerminate:(UIApplication *)application { 118 | [self appplicationPrepareForBackgroundOrTermination:application]; 119 | } 120 | 121 | 122 | /////////////////////////////////////////////////////////////////////////////////////////////////// 123 | #pragma mark - 124 | #pragma mark Memory management 125 | /////////////////////////////////////////////////////////////////////////////////////////////////// 126 | 127 | - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { 128 | // TODO: Release memory, or hell freazes over! 129 | } 130 | 131 | /////////////////////////////////////////////////////////////////////////////////////////////////// 132 | #pragma mark - 133 | #pragma mark CrashReportSenderDelegate AND BWHockeyManagerDelegate 134 | /////////////////////////////////////////////////////////////////////////////////////////////////// 135 | 136 | #if defined(kUseCrashReporter) || defined(kUseAutoUpdater) 137 | - (void)connectionOpened { 138 | [[IKNetworkActivityManager sharedInstance] addNetworkUser:self]; 139 | } 140 | 141 | - (void)connectionClosed { 142 | [[IKNetworkActivityManager sharedInstance] removeNetworkUser:self]; 143 | } 144 | #endif 145 | 146 | #if defined(kUseCrashReporter) 147 | - (NSString *)crashReportDescription { 148 | NSString *deviceInfo = [UIDevice debugInfo]; 149 | DDLogInfo(deviceInfo); 150 | 151 | return deviceInfo; 152 | } 153 | #endif 154 | 155 | /////////////////////////////////////////////////////////////////////////////////////////////////// 156 | #pragma mark - 157 | #pragma mark Reachability 158 | /////////////////////////////////////////////////////////////////////////////////////////////////// 159 | 160 | - (void)configureForNetworkStatus:(NSNotification *)notification { 161 | // NetworkStatus networkStatus = [[notification.userInfo valueForKey:kPSNetworkStatusKey] intValue]; 162 | 163 | } 164 | 165 | 166 | /////////////////////////////////////////////////////////////////////////////////////////////////// 167 | #pragma mark - 168 | #pragma mark Private Methods 169 | /////////////////////////////////////////////////////////////////////////////////////////////////// 170 | 171 | - (void)configureLogger { 172 | PSDDFormatter *psLogger = [[[PSDDFormatter alloc] init] autorelease]; 173 | [[DDTTYLogger sharedInstance] setLogFormatter:psLogger]; 174 | [DDLog addLogger:[DDTTYLogger sharedInstance]]; 175 | 176 | #ifndef APPSTORE 177 | // log to file 178 | DDFileLogger *fileLogger = [[[DDFileLogger alloc] init] autorelease]; 179 | fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling 180 | fileLogger.logFileManager.maximumNumberOfLogFiles = 7; 181 | [DDLog addLogger:fileLogger]; 182 | 183 | #ifndef DISTRIBUTION 184 | // log to network (disabled for now, as it breaks clang 1.7) 185 | // [DDLog addLogger:[DDNSLoggerLogger sharedInstance]]; 186 | #endif 187 | 188 | #endif 189 | } 190 | 191 | - (void)appplicationPrepareForBackgroundOrTermination:(UIApplication *)application { 192 | DDLogInfo(@"detected application termination."); 193 | 194 | // post notification to all listeners 195 | [[NSNotificationCenter defaultCenter] postNotificationName:kAppplicationWillSuspendNotification object:application]; 196 | [[PSReachability sharedPSReachability] shutdownReachabilityFor:self]; 197 | } 198 | 199 | // launched via post selector to speed up launch time 200 | - (void)postFinishLaunch { 201 | #ifdef kUseFlurryStatistics 202 | [FlurryAPI startSession:kFlurryStatisticsKey]; 203 | #endif 204 | 205 | [[PSReachability sharedPSReachability] startCheckingHostAddress:kReachabilityHostURL]; 206 | [[PSReachability sharedPSReachability] setupReachabilityFor:self]; 207 | } 208 | 209 | @end 210 | 211 | -------------------------------------------------------------------------------- /App/Classes/PSBaseViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PSBaseViewController.h 3 | // PSAppTemplate 4 | // 5 | // Created by Tretter Matthias on 25.06.11. 6 | // Copyright 2011 @myell0w. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PSIncludes.h" 11 | 12 | @interface PSBaseViewController : UIViewController { 13 | 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /App/Classes/PSBaseViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PSBaseViewController.m 3 | // PSAppTemplate 4 | // 5 | // Created by Tretter Matthias on 25.06.11. 6 | // Copyright 2011 @myell0w. All rights reserved. 7 | // 8 | 9 | #import "PSBaseViewController.h" 10 | 11 | @implementation PSBaseViewController 12 | 13 | //////////////////////////////////////////////////////////////////////// 14 | #pragma mark - 15 | #pragma mark Lifecycle 16 | //////////////////////////////////////////////////////////////////////// 17 | 18 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { 19 | if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { 20 | 21 | } 22 | 23 | return self; 24 | } 25 | 26 | - (void)dealloc { 27 | 28 | [super dealloc]; 29 | } 30 | 31 | //////////////////////////////////////////////////////////////////////// 32 | #pragma mark - 33 | #pragma mark UIView 34 | //////////////////////////////////////////////////////////////////////// 35 | 36 | - (void)viewDidLoad { 37 | [super viewDidLoad]; 38 | 39 | [[PSReachability sharedPSReachability] setupReachabilityFor:self]; 40 | } 41 | 42 | - (void)viewDidUnload { 43 | [super viewDidUnload]; 44 | 45 | [[PSReachability sharedPSReachability] shutdownReachabilityFor:self]; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /App/Classes/PSDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // PSDefines.h 3 | // PSAppTemplate 4 | // 5 | // Created by Peter Steinberger on 12.12.10. 6 | // 7 | 8 | //////////////////////////////////////////////////////////////////////// 9 | #pragma mark - 10 | #pragma mark Template Configuration 11 | //////////////////////////////////////////////////////////////////////// 12 | 13 | #define kIntroFadeAnimation 14 | #define kUseCrashReporter 15 | #define kCrashReporterFeedbackEnabled NO // boolean switch 16 | #define kPostFinishLaunchDelay 1.5 // set to positive value to call postFinishLaunch in AppDelegate after delay 17 | 18 | #ifdef DEBUG 19 | #define kMemoryWarningAfterDeviceShake 20 | #endif 21 | 22 | #ifdef APPSTORE 23 | #define kUseFlurryStatistics 24 | #else 25 | #define kUseAutoUpdater 26 | #endif 27 | 28 | //////////////////////////////////////////////////////////////////////// 29 | #pragma mark - 30 | #pragma mark DCInstropect - Awesome visual debugging 31 | //////////////////////////////////////////////////////////////////////// 32 | 33 | #ifdef TARGET_IPHONE_SIMULATOR 34 | #define kDCIntrospectEnabled 35 | #endif 36 | 37 | 38 | //////////////////////////////////////////////////////////////////////// 39 | #pragma mark - 40 | #pragma mark URLs 41 | //////////////////////////////////////////////////////////////////////// 42 | 43 | #ifndef APPSTORE 44 | #define kHockeyUpdateDistributionUrl @"http://petersteinberger.com/appstore" 45 | #endif 46 | 47 | #define kCrashReporterUrl @"http://path-to-crashreporter.com/crashreporter/crash_v200.php" 48 | #define kReachabilityHostURL @"www.apple.com" 49 | 50 | //////////////////////////////////////////////////////////////////////// 51 | #pragma mark - 52 | #pragma mark Keys 53 | //////////////////////////////////////////////////////////////////////// 54 | 55 | #define kFlurryStatisticsKey @"INSERT_FLURRY_KEY" 56 | 57 | //////////////////////////////////////////////////////////////////////// 58 | #pragma mark - 59 | #pragma mark Notifications 60 | //////////////////////////////////////////////////////////////////////// 61 | 62 | // suspend/kill delegate 63 | #define kAppplicationWillSuspendNotification @"kAppplicationWillSuspendNotification" 64 | // device shaken 65 | #define kDeviceWasShakenNotification @"kDeviceWasShakenNotification" -------------------------------------------------------------------------------- /App/Classes/PSIncludes.h: -------------------------------------------------------------------------------- 1 | // 2 | // PSIncludes.h 3 | // PSAppTemplate 4 | // 5 | // Created by Matthias Tretter on 02.06.11. 6 | // Copyright 2011 NOUS Wissensmanagement GmbH. All rights reserved. 7 | // 8 | 9 | // Since Syntax-Highlighting and Auto-Comletion currently break under Xcode 4, 10 | // if you put custom imports into your Precompiled Headers File, this file 11 | // serves as a replacement that can be included into other files 12 | 13 | #import "PSDefines.h" 14 | #import "PSFoundation.h" 15 | -------------------------------------------------------------------------------- /App/Classes/PSWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // PSWindow.h 3 | // PSAppTemplate 4 | // 5 | // Created by Matthias Tretter on 03.06.11. 6 | // Copyright 2011 @myell0w. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface PSWindow : UIWindow { 13 | 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /App/Classes/PSWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // PSWindow.m 3 | // PSAppTemplate 4 | // 5 | // Created by Matthias Tretter on 03.06.11. 6 | // Copyright 2011 @myell0w. All rights reserved. 7 | // 8 | 9 | #import "PSWindow.h" 10 | #import "PSIncludes.h" 11 | 12 | 13 | @implementation PSWindow 14 | 15 | - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { 16 | if (event.type == UIEventTypeMotion && event.subtype == UIEventSubtypeMotionShake) { 17 | [[NSNotificationCenter defaultCenter] postNotificationName:kDeviceWasShakenNotification object:self]; 18 | 19 | #ifdef kMemoryWarningAfterDeviceShake 20 | DDLogInfo(@"Detected Device Shake, will simulate memory warning"); 21 | PSSimulateMemoryWarning(); 22 | #else 23 | [super motionEnded:motion withEvent:event]; 24 | #endif 25 | 26 | } else { 27 | [super motionEnded:motion withEvent:event]; 28 | } 29 | } 30 | 31 | - (void)remoteControlReceivedWithEvent:(UIEvent *)event { 32 | [super remoteControlReceivedWithEvent:event]; 33 | 34 | // Handle Remote Control Event 35 | if (event.type == UIEventTypeRemoteControl) { 36 | switch (event.subtype) { 37 | case UIEventSubtypeRemoteControlPlay: 38 | break; 39 | 40 | case UIEventSubtypeRemoteControlTogglePlayPause: 41 | break; 42 | 43 | case UIEventSubtypeRemoteControlPause: 44 | break; 45 | 46 | case UIEventSubtypeRemoteControlStop: 47 | break; 48 | 49 | case UIEventSubtypeRemoteControlPreviousTrack: 50 | break; 51 | 52 | case UIEventSubtypeRemoteControlNextTrack: 53 | break; 54 | 55 | case UIEventSubtypeRemoteControlBeginSeekingForward: 56 | break; 57 | 58 | case UIEventSubtypeRemoteControlEndSeekingForward: 59 | break; 60 | 61 | case UIEventSubtypeRemoteControlBeginSeekingBackward: 62 | break; 63 | 64 | case UIEventSubtypeRemoteControlEndSeekingBackward: 65 | break; 66 | 67 | default: 68 | break; 69 | } 70 | } 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /App/Classes/RootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.h 3 | // PSAppTemplate 4 | // 5 | // Created by Peter Steinberger on 12.12.10. 6 | // Template by Peter Steinberger 7 | // 8 | 9 | #import "PSIncludes.h" 10 | 11 | @interface RootViewController : PSTableViewController { 12 | } 13 | 14 | - (id)initWithStyle:(UITableViewStyle)style; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /App/Classes/RootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.m 3 | // PSAppTemplate 4 | // 5 | // Created by Peter Steinberger on 12.12.10. 6 | // Template by Peter Steinberger 7 | // 8 | 9 | #import "RootViewController.h" 10 | #import "JSONKit.h" 11 | #import "PSDefines.h" 12 | #import "RegexKitLite.h" 13 | 14 | #ifdef kUseAutoUpdater 15 | #import "BWHockeyManager.h" 16 | #endif 17 | 18 | @interface RootViewController() 19 | // private stuff 20 | @end 21 | 22 | @implementation RootViewController 23 | 24 | /////////////////////////////////////////////////////////////////////////////////////////////////// 25 | #pragma mark - 26 | #pragma mark private 27 | 28 | /////////////////////////////////////////////////////////////////////////////////////////////////// 29 | #pragma mark - 30 | #pragma mark NSObject 31 | 32 | - (id)initWithStyle:(UITableViewStyle)style { 33 | if ((self = [super initWithStyle:style])) { 34 | NSString *versionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; 35 | NSString *shortVersionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; 36 | self.title = [NSString stringWithFormat:@"PSiOSAppTemplate %@ (%@)", shortVersionString, versionString]; 37 | 38 | self.useShadows = YES; // PSTableViewController 39 | } 40 | return self; 41 | } 42 | 43 | - (void)dealloc { 44 | [super dealloc]; 45 | } 46 | 47 | /////////////////////////////////////////////////////////////////////////////////////////////////// 48 | #pragma mark - 49 | #pragma mark UIView 50 | 51 | - (void)viewDidLoad { 52 | [super viewDidLoad]; 53 | } 54 | 55 | - (void)viewDidUnload { 56 | // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand. 57 | // For example: self.myOutlet = nil; 58 | } 59 | 60 | - (void)viewWillAppear:(BOOL)animated { 61 | [super viewWillAppear:animated]; 62 | } 63 | 64 | - (void)viewDidAppear:(BOOL)animated { 65 | [super viewDidAppear:animated]; 66 | 67 | UIImageView *lolcatImage = [UIImageView imageViewNamed:@"lolcat"]; 68 | lolcatImage.frame = CGRectMake(10, 100, 356*0.8, 512*0.8); 69 | // [self.tableView addSubview:lolcatImage]; 70 | } 71 | 72 | - (void)viewWillDisappear:(BOOL)animated { 73 | [super viewWillDisappear:animated]; 74 | } 75 | 76 | - (void)viewDidDisappear:(BOOL)animated { 77 | [super viewDidDisappear:animated]; 78 | } 79 | 80 | // Override to allow orientations other than the default portrait orientation. 81 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 82 | // Return YES for supported orientations. 83 | return (interfaceOrientation == UIInterfaceOrientationPortrait); 84 | } 85 | 86 | /////////////////////////////////////////////////////////////////////////////////////////////////// 87 | #pragma mark - 88 | #pragma mark UITableViewDataSource/Delegate 89 | 90 | // Customize the number of sections in the table view. 91 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 92 | return 1; 93 | } 94 | 95 | 96 | // Customize the number of rows in the table view. 97 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 98 | return 2; 99 | } 100 | 101 | 102 | // Customize the appearance of table view cells. 103 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 104 | 105 | static NSString *CellIdentifier = @"Cell"; 106 | 107 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 108 | if (cell == nil) { 109 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 110 | } 111 | 112 | // Configure the cell. 113 | if (indexPath.row == 0) { 114 | cell.textLabel.text = @"PSAlertView - Test"; 115 | }else if (indexPath.row == 1) { 116 | cell.textLabel.text = @"HockeyKitv2 AdHoc Update"; 117 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 118 | } 119 | 120 | cell.backgroundColor = [UIColor lightGrayColor]; 121 | 122 | return cell; 123 | } 124 | 125 | /* 126 | // Override to support conditional editing of the table view. 127 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 128 | // Return NO if you do not want the specified item to be editable. 129 | return YES; 130 | } 131 | */ 132 | 133 | /* 134 | // Override to support editing the table view. 135 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 136 | 137 | if (editingStyle == UITableViewCellEditingStyleDelete) { 138 | // Delete the row from the data source. 139 | [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 140 | } 141 | else if (editingStyle == UITableViewCellEditingStyleInsert) { 142 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. 143 | } 144 | } 145 | */ 146 | 147 | /* 148 | // Override to support rearranging the table view. 149 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 150 | } 151 | */ 152 | 153 | 154 | /* 155 | // Override to support conditional rearranging of the table view. 156 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 157 | // Return NO if you do not want the item to be re-orderable. 158 | return YES; 159 | } 160 | */ 161 | 162 | 163 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 164 | [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; 165 | 166 | if (indexPath.row == 0) { 167 | PSAlertView *blockAlert = [PSAlertView alertWithTitle:@"Hello World" message:@"This is a Alert with blocks!"]; 168 | [blockAlert addButtonWithTitle:@"Wow!" block:nil]; 169 | [blockAlert addButtonWithTitle:@"Cool!" block:^{ 170 | // do stuff on button press 171 | }]; 172 | [blockAlert show]; 173 | }else if (indexPath.row == 1) { 174 | #ifdef kUseAutoUpdater 175 | BWHockeyViewController *hockeyViewController = [[BWHockeyManager sharedHockeyManager] hockeyViewController:NO]; 176 | [self.navigationController pushViewController:hockeyViewController animated:YES]; 177 | #endif 178 | } 179 | } 180 | 181 | 182 | /////////////////////////////////////////////////////////////////////////////////////////////////// 183 | #pragma mark - 184 | #pragma mark Memory management 185 | 186 | - (void)didReceiveMemoryWarning { 187 | [super didReceiveMemoryWarning]; 188 | } 189 | 190 | @end 191 | 192 | -------------------------------------------------------------------------------- /App/Images/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/App/Images/Default.png -------------------------------------------------------------------------------- /App/Images/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/App/Images/Icon-72.png -------------------------------------------------------------------------------- /App/Images/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/App/Images/Icon-Small-50.png -------------------------------------------------------------------------------- /App/Images/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/App/Images/Icon-Small.png -------------------------------------------------------------------------------- /App/Images/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/App/Images/Icon-Small@2x.png -------------------------------------------------------------------------------- /App/Images/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/App/Images/Icon.png -------------------------------------------------------------------------------- /App/Images/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/App/Images/Icon@2x.png -------------------------------------------------------------------------------- /App/Images/iTunesArtwork: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/App/Images/iTunesArtwork -------------------------------------------------------------------------------- /App/Images/lolcat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/App/Images/lolcat.png -------------------------------------------------------------------------------- /App/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFiles 12 | 13 | Icon.png 14 | Icon@2x.png 15 | Icon-72.png 16 | Icon-Small-50.png 17 | Icon-Small.png 18 | Icon-Small@2x.png 19 | 20 | CFBundleIdentifier 21 | com.petersteinberger.apptemplate 22 | CFBundleInfoDictionaryVersion 23 | 6.0 24 | CFBundleName 25 | ${PRODUCT_NAME} 26 | CFBundlePackageType 27 | APPL 28 | CFBundleSignature 29 | ???? 30 | CFBundleVersion 31 | ${APP_VERSION} 32 | LSRequiresIPhoneOS 33 | 34 | UIPrerenderedIcon 35 | 36 | UIStatusBarStyle 37 | UIStatusBarStyleDefault 38 | 39 | 40 | -------------------------------------------------------------------------------- /App/Localization/English.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/App/Localization/English.lproj/Localizable.strings -------------------------------------------------------------------------------- /App/Localization/German.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/App/Localization/German.lproj/Localizable.strings -------------------------------------------------------------------------------- /App/Prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #import 4 | #import 5 | #endif -------------------------------------------------------------------------------- /App/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PSAppTemplate 4 | // 5 | // Created by Peter Steinberger on 12.12.10. 6 | // Template by Peter Steinberger 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data); 14 | #if !defined(PT_DENY_ATTACH) 15 | #define PT_DENY_ATTACH 31 16 | #endif // !defined(PT_DENY_ATTACH) 17 | 18 | int main(int argc, char *argv[]) { 19 | 20 | // prevent debugger in AppStore-builds (crack prevention) 21 | #ifdef DEBUG 22 | //do nothing 23 | #else 24 | void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW); 25 | ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace"); 26 | ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0); 27 | dlclose(handle); 28 | #endif 29 | 30 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 31 | int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate"); 32 | [pool release]; 33 | return retVal; 34 | } 35 | -------------------------------------------------------------------------------- /CrashReporter.framework/CrashReporter: -------------------------------------------------------------------------------- 1 | Versions/Current/CrashReporter -------------------------------------------------------------------------------- /CrashReporter.framework/Headers: -------------------------------------------------------------------------------- 1 | Versions/Current/Headers -------------------------------------------------------------------------------- /CrashReporter.framework/Resources: -------------------------------------------------------------------------------- 1 | Versions/Current/Resources -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/CrashReporter: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/CrashReporter.framework/Versions/A/CrashReporter -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/CrashReporter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Landon Fuller 3 | * 4 | * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. 5 | * All rights reserved. 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #import 30 | 31 | #ifdef __APPLE__ 32 | #import 33 | #endif 34 | 35 | #import "PLCrashReporter.h" 36 | #import "PLCrashReport.h" 37 | #import "PLCrashReportTextFormatter.h" 38 | 39 | /** 40 | * @defgroup functions Crash Reporter Functions Reference 41 | */ 42 | 43 | /** 44 | * @defgroup types Crash Reporter Data Types Reference 45 | */ 46 | 47 | /** 48 | * @defgroup constants Crash Reporter Constants Reference 49 | */ 50 | 51 | /** 52 | * @defgroup plcrash_internal Crash Reporter Internal Documentation 53 | */ 54 | 55 | /** 56 | * @defgroup enums Enumerations 57 | * @ingroup constants 58 | */ 59 | 60 | /** 61 | * @defgroup globals Global Variables 62 | * @ingroup constants 63 | */ 64 | 65 | /** 66 | * @defgroup exceptions Exceptions 67 | * @ingroup constants 68 | */ 69 | 70 | /* Exceptions */ 71 | extern NSString *PLCrashReporterException; 72 | 73 | /* Error Domain and Codes */ 74 | extern NSString *PLCrashReporterErrorDomain; 75 | 76 | /** 77 | * NSError codes in the Plausible Crash Reporter error domain. 78 | * @ingroup enums 79 | */ 80 | typedef enum { 81 | /** An unknown error has occured. If this 82 | * code is received, it is a bug, and should be reported. */ 83 | PLCrashReporterErrorUnknown = 0, 84 | 85 | /** An Mach or POSIX operating system error has occured. The underlying NSError cause may be fetched from the userInfo 86 | * dictionary using the NSUnderlyingErrorKey key. */ 87 | PLCrashReporterErrorOperatingSystem = 1, 88 | 89 | /** The crash report log file is corrupt or invalid */ 90 | PLCrashReporterErrorCrashReportInvalid = 2, 91 | } PLCrashReporterError; 92 | 93 | 94 | /* Library Imports */ 95 | #import "PLCrashReporter.h" 96 | #import "PLCrashReport.h" 97 | #import "PLCrashReportTextFormatter.h" 98 | 99 | /** 100 | * @mainpage Plausible Crash Reporter 101 | * 102 | * @section intro_sec Introduction 103 | * 104 | * Plausile CrashReporter implements in-process crash reporting on the iPhone and Mac OS X. 105 | * 106 | * The following features are supported: 107 | * 108 | * - Implemented as an in-process signal handler. 109 | * - Does not interfer with debugging in gdb.. 110 | * - Handles both uncaught Objective-C exceptions and fatal signals (SIGSEGV, SIGBUS, etc). 111 | * - Full thread state for all active threads (backtraces, register dumps) is provided. 112 | * 113 | * If your application crashes, a crash report will be written. When the application is next run, you may check for a 114 | * pending crash report, and submit the report to your own HTTP server, send an e-mail, or even introspect the 115 | * report locally. 116 | * 117 | * @section intro_encoding Crash Report Format 118 | * 119 | * Crash logs are encoded using google protobuf, and may be decoded 120 | * using the provided PLCrashReport API. Additionally, the include plcrashutil handles conversion of binary crash reports to the 121 | * symbolicate-compatible iPhone text format. 122 | * 123 | * @section doc_sections Documentation Sections 124 | * - @subpage example_usage_iphone 125 | * - @subpage error_handling 126 | */ 127 | 128 | /** 129 | * @page example_usage_iphone Example iPhone Usage 130 | * 131 | * @code 132 | * // 133 | * // Called to handle a pending crash report. 134 | * // 135 | * - (void) handleCrashReport { 136 | * PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter]; 137 | * NSData *crashData; 138 | * NSError *error; 139 | * 140 | * // Try loading the crash report 141 | * crashData = [crashReporter loadPendingCrashReportDataAndReturnError: &error]; 142 | * if (crashData == nil) { 143 | * NSLog(@"Could not load crash report: %@", error); 144 | * goto finish; 145 | * } 146 | * 147 | * // We could send the report from here, but we'll just print out 148 | * // some debugging info instead 149 | * PLCrashReport *report = [[[PLCrashReport alloc] initWithData: crashData error: &error] autorelease]; 150 | * if (report == nil) { 151 | * NSLog(@"Could not parse crash report"); 152 | * goto finish; 153 | * } 154 | * 155 | * NSLog(@"Crashed on %@", report.systemInfo.timestamp); 156 | * NSLog(@"Crashed with signal %@ (code %@, address=0x%" PRIx64 ")", report.signalInfo.name, 157 | * report.signalInfo.code, report.signalInfo.address); 158 | * 159 | * // Purge the report 160 | * finish: 161 | * [crashReporter purgePendingCrashReport]; 162 | * return; 163 | * } 164 | * 165 | * // from UIApplicationDelegate protocol 166 | * - (void) applicationDidFinishLaunching: (UIApplication *) application { 167 | * PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter]; 168 | * NSError *error; 169 | * 170 | * // Check if we previously crashed 171 | * if ([crashReporter hasPendingCrashReport]) 172 | * [self handleCrashReport]; 173 | 174 | * // Enable the Crash Reporter 175 | * if (![crashReporter enableCrashReporterAndReturnError: &error]) 176 | * NSLog(@"Warning: Could not enable crash reporter: %@", error); 177 | * 178 | * } 179 | * @endcode 180 | * 181 | */ 182 | 183 | /** 184 | * @page error_handling Error Handling Programming Guide 185 | * 186 | * Where a method may return an error, Plausible Crash Reporter provides access to the underlying 187 | * cause via an optional NSError argument. 188 | * 189 | * All returned errors will be a member of one of the below defined domains, however, new domains and 190 | * error codes may be added at any time. If you do not wish to report on the error cause, many methods 191 | * support a simple form that requires no NSError argument. 192 | * 193 | * @section Error Domains, Codes, and User Info 194 | * 195 | * @subsection crashreporter_errors Crash Reporter Errors 196 | * 197 | * Any errors in Plausible Crash Reporter use the #PLCrashReporterErrorDomain error domain, and and one 198 | * of the error codes defined in #PLCrashReporterError. 199 | */ 200 | -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/PLCrashReport.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Landon Fuller 3 | * 4 | * Copyright (c) 2008-2010 Plausible Labs Cooperative, Inc. 5 | * All rights reserved. 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #import 30 | #import "PLCrashReportSystemInfo.h" 31 | #import "PLCrashReportApplicationInfo.h" 32 | #import "PLCrashReportProcessInfo.h" 33 | #import "PLCrashReportSignalInfo.h" 34 | #import "PLCrashReportThreadInfo.h" 35 | #import "PLCrashReportBinaryImageInfo.h" 36 | #import "PLCrashReportExceptionInfo.h" 37 | 38 | /** 39 | * @ingroup constants 40 | * Crash file magic identifier */ 41 | #define PLCRASH_REPORT_FILE_MAGIC "plcrash" 42 | 43 | /** 44 | * @ingroup constants 45 | * Crash format version byte identifier. Will not change outside of the introduction of 46 | * an entirely new crash log format. */ 47 | #define PLCRASH_REPORT_FILE_VERSION 1 48 | 49 | /** 50 | * @ingroup types 51 | * Crash log file header format. 52 | * 53 | * Crash log files start with 7 byte magic identifier (#PLCRASH_REPORT_FILE_MAGIC), 54 | * followed by a single unsigned byte version number (#PLCRASH_REPORT_FILE_VERSION). 55 | * The crash log message format itself is extensible, so this version number will only 56 | * be incremented in the event of an incompatible encoding or format change. 57 | */ 58 | struct PLCrashReportFileHeader { 59 | /** Crash log magic identifier, not NULL terminated */ 60 | const char magic[7]; 61 | 62 | /** Crash log encoding/format version */ 63 | const uint8_t version; 64 | 65 | /** File data */ 66 | const uint8_t data[]; 67 | } __attribute__((packed)); 68 | 69 | 70 | /** 71 | * @internal 72 | * Private decoder instance variables (used to hide the underlying protobuf parser). 73 | */ 74 | typedef struct _PLCrashReportDecoder _PLCrashReportDecoder; 75 | 76 | @interface PLCrashReport : NSObject { 77 | @private 78 | /** Private implementation variables (used to hide the underlying protobuf parser) */ 79 | _PLCrashReportDecoder *_decoder; 80 | 81 | /** System info */ 82 | PLCrashReportSystemInfo *_systemInfo; 83 | 84 | /** Application info */ 85 | PLCrashReportApplicationInfo *_applicationInfo; 86 | 87 | /** Process info */ 88 | PLCrashReportProcessInfo *_processInfo; 89 | 90 | /** Signal info */ 91 | PLCrashReportSignalInfo *_signalInfo; 92 | 93 | /** Thread info (PLCrashReportThreadInfo instances) */ 94 | NSArray *_threads; 95 | 96 | /** Binary images (PLCrashReportBinaryImageInfo instances */ 97 | NSArray *_images; 98 | 99 | /** Exception information (may be nil) */ 100 | PLCrashReportExceptionInfo *_exceptionInfo; 101 | } 102 | 103 | - (id) initWithData: (NSData *) encodedData error: (NSError **) outError; 104 | 105 | - (PLCrashReportBinaryImageInfo *) imageForAddress: (uint64_t) address; 106 | 107 | /** 108 | * System information. 109 | */ 110 | @property(nonatomic, readonly) PLCrashReportSystemInfo *systemInfo; 111 | 112 | /** 113 | * Application information. 114 | */ 115 | @property(nonatomic, readonly) PLCrashReportApplicationInfo *applicationInfo; 116 | 117 | /** 118 | * YES if process information is available. 119 | */ 120 | @property(nonatomic, readonly) BOOL hasProcessInfo; 121 | 122 | /** 123 | * Process information. Only available in later (v1.1+) crash report format versions. If not available, 124 | * will be nil. 125 | */ 126 | @property(nonatomic, readonly) PLCrashReportProcessInfo *processInfo; 127 | 128 | /** 129 | * Signal information. This provides the signal and signal code of the fatal signal. 130 | */ 131 | @property(nonatomic, readonly) PLCrashReportSignalInfo *signalInfo; 132 | 133 | /** 134 | * Thread information. Returns a list of PLCrashReportThreadInfo instances. 135 | */ 136 | @property(nonatomic, readonly) NSArray *threads; 137 | 138 | /** 139 | * Binary image information. Returns a list of PLCrashReportBinaryImageInfo instances. 140 | */ 141 | @property(nonatomic, readonly) NSArray *images; 142 | 143 | /** 144 | * YES if exception information is available. 145 | */ 146 | @property(nonatomic, readonly) BOOL hasExceptionInfo; 147 | 148 | /** 149 | * Exception information. Only available if a crash was caused by an uncaught exception, 150 | * otherwise nil. 151 | */ 152 | @property(nonatomic, readonly) PLCrashReportExceptionInfo *exceptionInfo; 153 | 154 | @end 155 | -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/PLCrashReportApplicationInfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Landon Fuller 3 | * 4 | * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. 5 | * All rights reserved. 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #import 30 | 31 | @interface PLCrashReportApplicationInfo : NSObject { 32 | @private 33 | /** Application identifier */ 34 | NSString *_applicationIdentifier; 35 | 36 | /** Application version */ 37 | NSString *_applicationVersion; 38 | } 39 | 40 | - (id) initWithApplicationIdentifier: (NSString *) applicationIdentifier 41 | applicationVersion: (NSString *) applicationVersion; 42 | 43 | /** 44 | * The application identifier. This is usually the application's CFBundleIdentifier value. 45 | */ 46 | @property(nonatomic, readonly) NSString *applicationIdentifier; 47 | 48 | /** 49 | * The application version. This is usually the application's CFBundleVersion value. 50 | */ 51 | @property(nonatomic, readonly) NSString *applicationVersion; 52 | 53 | @end -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/PLCrashReportBinaryImageInfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Landon Fuller 3 | * 4 | * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. 5 | * All rights reserved. 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #import 30 | 31 | @interface PLCrashReportBinaryImageInfo : NSObject { 32 | @private 33 | /** Base image address */ 34 | uint64_t _baseAddress; 35 | 36 | /** Image segment size */ 37 | uint64_t _imageSize; 38 | 39 | /** Name of binary image */ 40 | NSString *_imageName; 41 | 42 | /** If the UUID is available */ 43 | BOOL _hasImageUUID; 44 | 45 | /** 128-bit object UUID. May be nil. */ 46 | NSString *_imageUUID; 47 | } 48 | 49 | - (id) initWithImageBaseAddress: (uint64_t) baseAddress 50 | imageSize: (uint64_t) imageSize 51 | imageName: (NSString *) imageName 52 | imageUUID: (NSString *) imageUUID; 53 | 54 | /** 55 | * Image base address. 56 | */ 57 | @property(nonatomic, readonly) uint64_t imageBaseAddress; 58 | 59 | /** 60 | * Segment size. 61 | */ 62 | @property(nonatomic, readonly) uint64_t imageSize; 63 | 64 | /** 65 | * Image name (absolute path) 66 | */ 67 | @property(nonatomic, readonly) NSString *imageName; 68 | 69 | 70 | /** 71 | * YES if this image has an associated UUID. 72 | */ 73 | @property(nonatomic, readonly) BOOL hasImageUUID; 74 | 75 | /** 76 | * 128-bit object UUID (matches Mach-O DWARF dSYM files). May be nil if unavailable. 77 | */ 78 | @property(nonatomic, readonly) NSString *imageUUID; 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/PLCrashReportExceptionInfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Landon Fuller 3 | * 4 | * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. 5 | * All rights reserved. 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #import 30 | 31 | 32 | @interface PLCrashReportExceptionInfo : NSObject { 33 | @private 34 | /** Name */ 35 | NSString *_name; 36 | 37 | /** Reason */ 38 | NSString *_reason; 39 | } 40 | 41 | - (id) initWithExceptionName: (NSString *) name reason: (NSString *) reason; 42 | 43 | /** 44 | * The exception name. 45 | */ 46 | @property(nonatomic, readonly) NSString *exceptionName; 47 | 48 | /** 49 | * The exception reason. 50 | */ 51 | @property(nonatomic, readonly) NSString *exceptionReason; 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/PLCrashReportFormatter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Landon Fuller 3 | * 4 | * Copyright (c) 2008-2010 Plausible Labs Cooperative, Inc. 5 | * All rights reserved. 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #import 30 | 31 | #import "PLCrashReport.h" 32 | 33 | /** 34 | * A crash report formatter accepts a PLCrashReport and formats according to implementation-specified rules (such 35 | * as implementing text output support), writing the formatted result to a given output stream. 36 | */ 37 | @protocol PLCrashReportFormatter 38 | 39 | /** 40 | * Format the provided @a report. 41 | * 42 | * @param report Report to be formatted. 43 | * @param outError A pointer to an NSError object variable. If an error occurs, this pointer will contain an error 44 | * object indicating why the pending crash report could not be formatted. If no error occurs, this parameter will 45 | * be left unmodified. You may specify nil for this parameter, and no error information will be provided. 46 | * 47 | * @return Returns the formatted report data on success, or nil on failure. 48 | */ 49 | - (NSData *) formatReport: (PLCrashReport *) report error: (NSError **) outError; 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessInfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Damian Morris 3 | * 4 | * Copyright (c) 2010 MOSO Corporation, Pty Ltd. 5 | * Copyright (c) 2010 Plausible Labs Cooperative, Inc. 6 | * 7 | * All rights reserved. 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, 13 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the 15 | * Software is furnished to do so, subject to the following 16 | * conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 23 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 25 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 28 | * OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | #import 32 | 33 | @interface PLCrashReportProcessInfo : NSObject { 34 | @private 35 | /** Process name */ 36 | NSString *_processName; 37 | 38 | /** Process ID */ 39 | NSUInteger _processID; 40 | 41 | /** Process path */ 42 | NSString* _processPath; 43 | 44 | /** Parent process name */ 45 | NSString *_parentProcessName; 46 | 47 | /** Parent process ID */ 48 | NSUInteger _parentProcessID; 49 | } 50 | 51 | - (id) initWithProcessName: (NSString *) processName 52 | processID: (NSUInteger) processID 53 | processPath: (NSString *) processPath 54 | parentProcessName: (NSString *) parentProcessName 55 | parentProcessID: (NSUInteger) parentProcessID; 56 | 57 | /** 58 | * The process name. This value may not be included in the crash report, in which case this property 59 | * will be nil. 60 | */ 61 | @property(nonatomic, readonly) NSString *processName; 62 | 63 | /** 64 | * The process ID. 65 | */ 66 | @property(nonatomic, readonly) NSUInteger processID; 67 | 68 | /** 69 | * The path to the process executable. This value may not be included in the crash report, in which case this property 70 | * will be nil. 71 | */ 72 | @property(nonatomic, readonly) NSString *processPath; 73 | 74 | /** 75 | * The parent process name. This value may not be included in the crash report, in which case this property 76 | * will be nil. 77 | */ 78 | @property(nonatomic, readonly) NSString *parentProcessName; 79 | 80 | /** 81 | * The parent process ID. 82 | */ 83 | @property(nonatomic, readonly) NSUInteger parentProcessID; 84 | 85 | @end -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/PLCrashReportSignalInfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Landon Fuller 3 | * 4 | * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. 5 | * All rights reserved. 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #import 30 | 31 | @interface PLCrashReportSignalInfo : NSObject { 32 | @private 33 | /** Signal name */ 34 | NSString *_name; 35 | 36 | /** Signal code */ 37 | NSString *_code; 38 | 39 | /** Fauling instruction or address */ 40 | uint64_t _address; 41 | } 42 | 43 | - (id) initWithSignalName: (NSString *) name code: (NSString *) code address: (uint64_t) address; 44 | 45 | /** 46 | * The signal name. 47 | */ 48 | @property(nonatomic, readonly) NSString *name; 49 | 50 | /** 51 | * The signal code. 52 | */ 53 | @property(nonatomic, readonly) NSString *code; 54 | 55 | /** 56 | * The faulting instruction or address. 57 | */ 58 | @property(nonatomic, readonly) uint64_t address; 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/PLCrashReportSystemInfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Landon Fuller 3 | * 4 | * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. 5 | * All rights reserved. 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #import 30 | 31 | /** 32 | * @ingroup constants 33 | * 34 | * Indicates the Operating System under which a Crash Log was generated. 35 | * 36 | * @internal 37 | * These enum values match the protobuf values. Keep them synchronized. 38 | */ 39 | typedef enum { 40 | /** Mac OS X. */ 41 | PLCrashReportOperatingSystemMacOSX = 0, 42 | 43 | /** iPhone OS */ 44 | PLCrashReportOperatingSystemiPhoneOS = 1, 45 | 46 | /** iPhone Simulator (Mac OS X with additional simulator-specific runtime libraries) */ 47 | PLCrashReportOperatingSystemiPhoneSimulator = 2 48 | } PLCrashReportOperatingSystem; 49 | 50 | /** 51 | * @ingroup constants 52 | * 53 | * Indicates the architecture under which a Crash Log was generated. 54 | * 55 | * @internal 56 | * These enum values match the protobuf values. Keep them synchronized. 57 | */ 58 | typedef enum { 59 | /** x86-32. */ 60 | PLCrashReportArchitectureX86_32 = 0, 61 | 62 | /** x86-64 */ 63 | PLCrashReportArchitectureX86_64 = 1, 64 | 65 | /** ARM */ 66 | PLCrashReportArchitectureARM = 2, 67 | 68 | /** PPC */ 69 | PLCrashReportArchitecturePPC = 3 70 | } PLCrashReportArchitecture; 71 | 72 | 73 | extern PLCrashReportOperatingSystem PLCrashReportHostOperatingSystem; 74 | extern PLCrashReportArchitecture PLCrashReportHostArchitecture; 75 | 76 | @interface PLCrashReportSystemInfo : NSObject { 77 | @private 78 | /** Operating system */ 79 | PLCrashReportOperatingSystem _operatingSystem; 80 | 81 | /** Operating system version */ 82 | NSString *_osVersion; 83 | 84 | /** Architecture */ 85 | PLCrashReportArchitecture _architecture; 86 | 87 | /** Date crash report was generated. May be nil if the date is unknown. */ 88 | NSDate *_timestamp; 89 | } 90 | 91 | - (id) initWithOperatingSystem: (PLCrashReportOperatingSystem) operatingSystem 92 | operatingSystemVersion: (NSString *) operatingSystemVersion 93 | architecture: (PLCrashReportArchitecture) architecture 94 | timestamp: (NSDate *) timestamp; 95 | 96 | /** 97 | * The operating system. 98 | */ 99 | @property(nonatomic, readonly) PLCrashReportOperatingSystem operatingSystem; 100 | 101 | /** 102 | * The operating system's release version. 103 | */ 104 | @property(nonatomic, readonly) NSString *operatingSystemVersion; 105 | 106 | /** 107 | * Architecture. 108 | */ 109 | @property(nonatomic, readonly) PLCrashReportArchitecture architecture; 110 | 111 | /** 112 | * Date and time that the crash report was generated. This may 113 | * be unavailable, and this property will be nil. 114 | */ 115 | @property(nonatomic, readonly) NSDate *timestamp; 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/PLCrashReportTextFormatter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Authors: 3 | * Landon Fuller 4 | * Damian Morris 5 | * 6 | * Copyright (c) 2008-2010 Plausible Labs Cooperative, Inc. 7 | * Copyright (c) 2010 MOSO Corporation, Pty Ltd. 8 | * All rights reserved. 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, 14 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the 16 | * Software is furnished to do so, subject to the following 17 | * conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 24 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 29 | * OTHER DEALINGS IN THE SOFTWARE. 30 | */ 31 | 32 | 33 | #import 34 | 35 | #import "PLCrashReportFormatter.h" 36 | 37 | /** 38 | * Supported text output formats. 39 | * 40 | * @ingroup enums 41 | */ 42 | typedef enum { 43 | /** An iOS-compatible crash log text format. Compatible with the crash logs generated by the device and available 44 | * through iTunes Connect. */ 45 | PLCrashReportTextFormatiOS = 0 46 | } PLCrashReportTextFormat; 47 | 48 | 49 | @interface PLCrashReportTextFormatter : NSObject { 50 | @private 51 | /** Text output format. */ 52 | PLCrashReportTextFormat _textFormat; 53 | 54 | /** Encoding to use for string output. */ 55 | NSStringEncoding _stringEncoding; 56 | } 57 | 58 | + (NSString *) stringValueForCrashReport: (PLCrashReport *) report withTextFormat: (PLCrashReportTextFormat) textFormat; 59 | 60 | - (id) initWithTextFormat: (PLCrashReportTextFormat) textFormat stringEncoding: (NSStringEncoding) stringEncoding; 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/PLCrashReportThreadInfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Landon Fuller 3 | * 4 | * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. 5 | * All rights reserved. 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #import 30 | 31 | @interface PLCrashReportStackFrameInfo : NSObject { 32 | @private 33 | /** Frame instruction pointer. */ 34 | uint64_t _instructionPointer; 35 | } 36 | 37 | - (id) initWithInstructionPointer: (uint64_t) instructionPointer; 38 | 39 | /** 40 | * Frame's instruction pointer. 41 | */ 42 | @property(nonatomic, readonly) uint64_t instructionPointer; 43 | 44 | @end 45 | 46 | 47 | @interface PLCrashReportRegisterInfo : NSObject { 48 | @private 49 | /** Register name */ 50 | NSString *_registerName; 51 | 52 | /** Register value */ 53 | uint64_t _registerValue; 54 | } 55 | 56 | - (id) initWithRegisterName: (NSString *) registerName registerValue: (uint64_t) registerValue; 57 | 58 | /** 59 | * Register name. 60 | */ 61 | @property(nonatomic, readonly) NSString *registerName; 62 | 63 | /** 64 | * Register value. 65 | */ 66 | @property(nonatomic, readonly) uint64_t registerValue; 67 | 68 | @end 69 | 70 | 71 | @interface PLCrashReportThreadInfo : NSObject { 72 | @private 73 | /** The thread number. Should be unique within a given crash log. */ 74 | NSInteger _threadNumber; 75 | 76 | /** Ordered list of PLCrashReportStackFrame instances */ 77 | NSArray *_stackFrames; 78 | 79 | /** YES if this thread crashed. */ 80 | BOOL _crashed; 81 | 82 | /** List of PLCrashReportRegister instances. Will be empty if _crashed is NO. */ 83 | NSArray *_registers; 84 | } 85 | 86 | - (id) initWithThreadNumber: (NSInteger) threadNumber 87 | stackFrames: (NSArray *) stackFrames 88 | crashed: (BOOL) crashed 89 | registers: (NSArray *) registers; 90 | 91 | /** 92 | * Application thread number. 93 | */ 94 | @property(nonatomic, readonly) NSInteger threadNumber; 95 | 96 | /** 97 | * Thread backtrace. Provides an array of PLCrashReportStackFrame instances. 98 | * The array is ordered, last callee to first. 99 | */ 100 | @property(nonatomic, readonly) NSArray *stackFrames; 101 | 102 | /** 103 | * If this thread crashed, set to YES. 104 | */ 105 | @property(nonatomic, readonly) BOOL crashed; 106 | 107 | /** 108 | * State of the general purpose and related registers, as a list of 109 | * PLCrashReportRegister instances. If this thead did not crash (crashed returns NO), 110 | * this list will be empty. 111 | */ 112 | @property(nonatomic, readonly) NSArray *registers; 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Headers/PLCrashReporter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Landon Fuller 3 | * 4 | * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc. 5 | * All rights reserved. 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #import 30 | 31 | @interface PLCrashReporter : NSObject { 32 | @private 33 | /** YES if the crash reporter has been enabled */ 34 | BOOL _enabled; 35 | 36 | /** Application identifier */ 37 | NSString *_applicationIdentifier; 38 | 39 | /** Application version */ 40 | NSString *_applicationVersion; 41 | 42 | /** Path to the crash reporter internal data directory */ 43 | NSString *_crashReportDirectory; 44 | } 45 | 46 | + (PLCrashReporter *) sharedReporter; 47 | 48 | - (BOOL) hasPendingCrashReport; 49 | 50 | - (NSData *) loadPendingCrashReportData; 51 | - (NSData *) loadPendingCrashReportDataAndReturnError: (NSError **) outError; 52 | 53 | - (BOOL) purgePendingCrashReport; 54 | - (BOOL) purgePendingCrashReportAndReturnError: (NSError **) outError; 55 | 56 | - (BOOL) enableCrashReporter; 57 | - (BOOL) enableCrashReporterAndReturnError: (NSError **) outError; 58 | 59 | @end -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/A/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | CrashReporter 9 | CFBundleIdentifier 10 | com.yourcompany.CrashReporter 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | CrashReporter 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1.0 21 | 22 | 23 | -------------------------------------------------------------------------------- /CrashReporter.framework/Versions/Current: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /CrashReporterSender/CrashReportSender.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Andreas Linde 3 | * Kent Sutherland 4 | * 5 | * Copyright (c) 2009 Andreas Linde & Kent Sutherland. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Permission is hereby granted, free of charge, to any person 9 | * obtaining a copy of this software and associated documentation 10 | * files (the "Software"), to deal in the Software without 11 | * restriction, including without limitation the rights to use, 12 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the 14 | * Software is furnished to do so, subject to the following 15 | * conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | * OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | 32 | #define kCrashReportAnalyzerStarted @"CrashReportAnalyzerStarted" // flags if the crashlog analyzer is started. since this may crash we need to track it 33 | #define kCrashReportActivated @"CrashReportActivated" // flags if the crashreporter is activated at all 34 | #define kAutomaticallySendCrashReports @"AutomaticallySendCrashReports" // flags if the crashreporter should automatically send crashes without asking the user again 35 | 36 | typedef enum CrashAlertType { 37 | CrashAlertTypeSend = 0, 38 | CrashAlertTypeFeedback = 1, 39 | } CrashAlertType; 40 | 41 | typedef enum CrashReportStatus { 42 | CrashReportStatusFailureVersionDiscontinued = -30, // This app version is set to discontinued, no new crash reports accepted by the server 43 | CrashReportStatusFailureXMLSenderVersionNotAllowed = -21, // XML: Sender ersion string contains not allowed characters, only alphanumberical including space and . are allowed 44 | CrashReportStatusFailureXMLVersionNotAllowed = -20, // XML: Version string contains not allowed characters, only alphanumberical including space and . are allowed 45 | CrashReportStatusFailureSQLAddSymbolicateTodo = -18, // SQL for adding a symoblicate todo entry in the database failed 46 | CrashReportStatusFailureSQLAddCrashlog = -17, // SQL for adding crash log in the database failed 47 | CrashReportStatusFailureSQLAddVersion = -16, // SQL for adding a new version in the database failed 48 | CrashReportStatusFailureSQLCheckVersionExists = -15, // SQL for checking if the version is already added in the database failed 49 | CrashReportStatusFailureSQLAddPattern = -14, // SQL for creating a new pattern for this bug and set amount of occurrances to 1 in the database failed 50 | CrashReportStatusFailureSQLCheckBugfixStatus = -13, // SQL for checking the status of the bugfix version in the database failed 51 | CrashReportStatusFailureSQLUpdatePatternOccurances = -12, // SQL for updating the occurances of this pattern in the database failed 52 | CrashReportStatusFailureSQLFindKnownPatterns = -11, // SQL for getting all the known bug patterns for the current app version in the database failed 53 | CrashReportStatusFailureSQLSearchAppName = -10, // SQL for finding the bundle identifier in the database failed 54 | CrashReportStatusFailureInvalidPostData = -3, // the post request didn't contain valid data 55 | CrashReportStatusFailureInvalidIncomingData = -2, // incoming data may not be added, because e.g. bundle identifier wasn't found 56 | CrashReportStatusFailureDatabaseNotAvailable = -1, // database cannot be accessed, check hostname, username, password and database name settings in config.php 57 | CrashReportStatusUnknown = 0, 58 | CrashReportStatusAssigned = 1, 59 | CrashReportStatusSubmitted = 2, 60 | CrashReportStatusAvailable = 3, 61 | } CrashReportStatus; 62 | 63 | // This protocol is used to send the image updates 64 | @protocol CrashReportSenderDelegate 65 | 66 | @optional 67 | 68 | -(NSString *) crashReportUserID; // Return the userid the crashreport should contain, empty by default 69 | -(NSString *) crashReportContact; // Return the contact value (e.g. email) the crashreport should contain, empty by default 70 | -(NSString *) crashReportDescription; // Return the description the crashreport should contain, empty by default 71 | 72 | -(void) connectionOpened; // Invoked when the internet connection is started, to let the app enable the activity indicator 73 | -(void) connectionClosed; // Invoked when the internet connection is closed, to let the app disable the activity indicator 74 | 75 | @end 76 | 77 | @interface CrashReportSender : NSObject { 78 | NSTimer *_submitTimer; 79 | 80 | NSMutableString *_contentOfProperty; 81 | CrashReportStatus _serverResult; 82 | 83 | BOOL _crashReportActivated; 84 | BOOL _crashReportFeedbackActivated; 85 | 86 | int _crashReportAnalyzerStarted; 87 | NSString *_crashesDir; 88 | 89 | int _amountCrashes; 90 | BOOL _crashIdenticalCurrentVersion; 91 | 92 | id _delegate; 93 | 94 | NSMutableArray *_crashFiles; 95 | 96 | NSURL *_submissionURL; 97 | NSMutableData *_responseData; 98 | NSInteger _statusCode; 99 | 100 | NSURLConnection *_urlConnection; 101 | 102 | NSData *_crashData; 103 | } 104 | 105 | + (CrashReportSender *)sharedCrashReportSender; 106 | 107 | - (void)sendCrashReportToURL:(NSURL *)submissionURL delegate:(id )delegate activateFeedback:(BOOL)activateFeedback; 108 | 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /CrashReporterSender/CrashReportSender.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Andreas Linde 3 | * Kent Sutherland 4 | * 5 | * Copyright (c) 2009 Andreas Linde & Kent Sutherland. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Permission is hereby granted, free of charge, to any person 9 | * obtaining a copy of this software and associated documentation 10 | * files (the "Software"), to deal in the Software without 11 | * restriction, including without limitation the rights to use, 12 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the 14 | * Software is furnished to do so, subject to the following 15 | * conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | * OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | #import 32 | #import "CrashReportSender.h" 33 | 34 | #include 35 | 36 | #define USER_AGENT @"CrashReportSender/1.0" 37 | 38 | @interface CrashReportSender () 39 | 40 | - (void)attemptCrashReportSubmission; 41 | - (void)showCrashStatusMessage; 42 | 43 | - (void)handleCrashReport; 44 | - (void)_cleanCrashReports; 45 | - (void)_sendCrashReports; 46 | 47 | - (NSString *)_crashLogStringForReport:(PLCrashReport *)report; 48 | - (void)_postXML:(NSString*)xml toURL:(NSURL*)url; 49 | - (BOOL)_isSubmissionHostReachable; 50 | - (NSString *)_getDevicePlatform; 51 | 52 | - (BOOL)hasPendingCrashReport; 53 | - (void)wentOnline:(NSNotification *)note; 54 | 55 | @end 56 | 57 | @implementation CrashReportSender 58 | 59 | + (CrashReportSender *)sharedCrashReportSender 60 | { 61 | static CrashReportSender *crashReportSender = nil; 62 | 63 | if (crashReportSender == nil) { 64 | crashReportSender = [[CrashReportSender alloc] init]; 65 | } 66 | 67 | return crashReportSender; 68 | } 69 | 70 | - (id) init 71 | { 72 | self = [super init]; 73 | 74 | if ( self != nil) 75 | { 76 | _serverResult = -1; 77 | _amountCrashes = 0; 78 | _crashIdenticalCurrentVersion = YES; 79 | _crashReportFeedbackActivated = NO; 80 | _delegate = nil; 81 | _crashData = nil; 82 | _urlConnection = nil; 83 | 84 | NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kCrashReportAnalyzerStarted]; 85 | if (testValue == nil) 86 | { 87 | _crashReportAnalyzerStarted = 0; 88 | } else { 89 | _crashReportAnalyzerStarted = [[NSUserDefaults standardUserDefaults] integerForKey:kCrashReportAnalyzerStarted]; 90 | } 91 | 92 | testValue = nil; 93 | testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kCrashReportActivated]; 94 | if (testValue == nil) 95 | { 96 | _crashReportActivated = YES; 97 | [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:YES] forKey:kCrashReportActivated]; 98 | } else { 99 | _crashReportActivated = [[NSUserDefaults standardUserDefaults] boolForKey:kCrashReportActivated]; 100 | } 101 | 102 | if (_crashReportActivated) 103 | { 104 | _crashFiles = [[NSMutableArray alloc] init]; 105 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); 106 | _crashesDir = [[NSString stringWithFormat:@"%@", [[paths objectAtIndex:0] stringByAppendingPathComponent:@"/crashes/"]] retain]; 107 | 108 | NSFileManager *fm = [NSFileManager defaultManager]; 109 | 110 | if (![fm fileExistsAtPath:_crashesDir]) 111 | { 112 | NSDictionary *attributes = [NSDictionary dictionaryWithObject: [NSNumber numberWithUnsignedLong: 0755] forKey: NSFilePosixPermissions]; 113 | NSError *theError = NULL; 114 | 115 | [fm createDirectoryAtPath:_crashesDir withIntermediateDirectories: YES attributes: attributes error: &theError]; 116 | } 117 | 118 | PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter]; 119 | NSError *error; 120 | 121 | // Check if we previously crashed 122 | if ([crashReporter hasPendingCrashReport]) 123 | [self handleCrashReport]; 124 | 125 | // Enable the Crash Reporter 126 | if (![crashReporter enableCrashReporterAndReturnError: &error]) 127 | NSLog(@"Warning: Could not enable crash reporter: %@", error); 128 | } 129 | } 130 | return self; 131 | } 132 | 133 | 134 | - (void) dealloc 135 | { 136 | [_urlConnection cancel]; 137 | [_urlConnection release]; 138 | _urlConnection = nil; 139 | [_crashData release]; 140 | 141 | [_crashesDir release]; 142 | [_crashFiles release]; 143 | if (_submitTimer != nil) 144 | { 145 | [_submitTimer invalidate]; 146 | [_submitTimer release]; 147 | } 148 | [super dealloc]; 149 | } 150 | 151 | 152 | - (BOOL)hasPendingCrashReport 153 | { 154 | if (_crashReportActivated) 155 | { 156 | NSFileManager *fm = [NSFileManager defaultManager]; 157 | 158 | if ([_crashFiles count] == 0 && [fm fileExistsAtPath:_crashesDir]) 159 | { 160 | NSString *file; 161 | NSError *error = nil; 162 | 163 | NSDirectoryEnumerator *dirEnum = [fm enumeratorAtPath: _crashesDir]; 164 | 165 | while ((file = [dirEnum nextObject])) 166 | { 167 | NSDictionary *fileAttributes = [fm attributesOfItemAtPath:[_crashesDir stringByAppendingPathComponent:file] error:&error]; 168 | if ([[fileAttributes objectForKey:NSFileSize] intValue] > 0) 169 | { 170 | [_crashFiles addObject:file]; 171 | } 172 | } 173 | } 174 | 175 | if ([_crashFiles count] > 0) 176 | { 177 | _amountCrashes = [_crashFiles count]; 178 | return YES; 179 | } 180 | else 181 | return NO; 182 | } else 183 | return NO; 184 | } 185 | 186 | - (void)sendCrashReportToURL:(NSURL *)submissionURL delegate:(id )delegate activateFeedback:(BOOL)activateFeedback; 187 | { 188 | if ([self hasPendingCrashReport]) 189 | { 190 | [_submissionURL autorelease]; 191 | _submissionURL = [submissionURL copy]; 192 | 193 | _crashReportFeedbackActivated = activateFeedback; 194 | _delegate = delegate; 195 | 196 | if (_submitTimer == nil) { 197 | _submitTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(attemptCrashReportSubmission) userInfo:nil repeats:NO]; 198 | } 199 | } 200 | } 201 | 202 | - (void)registerOnline 203 | { 204 | [[NSNotificationCenter defaultCenter] addObserver:self 205 | selector:@selector(wentOnline:) 206 | name:@"kNetworkReachabilityChangedNotification" 207 | object:nil]; 208 | } 209 | 210 | - (void)unregisterOnline 211 | { 212 | [[NSNotificationCenter defaultCenter] removeObserver:self 213 | name:@"kNetworkReachabilityChangedNotification" 214 | object:nil]; 215 | } 216 | 217 | - (void)wentOnline:(NSNotification *)note 218 | { 219 | [self unregisterOnline]; 220 | [self attemptCrashReportSubmission]; 221 | } 222 | 223 | - (void)attemptCrashReportSubmission 224 | { 225 | _submitTimer = nil; 226 | 227 | if (![self _isSubmissionHostReachable]) { 228 | [self registerOnline]; 229 | } else if ([self hasPendingCrashReport]) { 230 | [self unregisterOnline]; 231 | 232 | if (![[NSUserDefaults standardUserDefaults] boolForKey: kAutomaticallySendCrashReports]) { 233 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedStringFromTable(@"CrashDataFoundTitle", @"CrashReporter", @"Title showing in the alert box when crash report data has been found") 234 | message:NSLocalizedStringFromTable(@"CrashDataFoundDescription", @"CrashReporter", @"Description explaining that crash data has been found and ask the user if the data might be uplaoded to the developers server") 235 | delegate:self 236 | cancelButtonTitle:NSLocalizedStringFromTable(@"No", @"CrashReporter", @"") 237 | otherButtonTitles:NSLocalizedStringFromTable(@"Yes", @"CrashReporter", @""), NSLocalizedStringFromTable(@"Always", @"CrashReporter", @""), nil]; 238 | 239 | [alertView setTag: CrashAlertTypeSend]; 240 | [alertView show]; 241 | [alertView release]; 242 | } else { 243 | [self _sendCrashReports]; 244 | } 245 | } 246 | } 247 | 248 | 249 | - (void) showCrashStatusMessage 250 | { 251 | UIAlertView *alertView; 252 | 253 | _amountCrashes--; 254 | if (_crashReportFeedbackActivated && _amountCrashes == 0 && _serverResult >= CrashReportStatusAssigned && _crashIdenticalCurrentVersion) 255 | { 256 | // show some feedback to the user about the crash status 257 | NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; 258 | switch (_serverResult) { 259 | case CrashReportStatusAssigned: 260 | alertView = [[UIAlertView alloc] initWithTitle: NSLocalizedStringFromTable(@"CrashResponseTitle", @"CrashReporter", @"Title for the alertview giving feedback about the crash") 261 | message:[NSString stringWithFormat:NSLocalizedStringFromTable(@"CrashResponseNextRelease", @"CrashReporter", @"Full text telling the bug is fixed and will be available in an upcoming release"), appName] 262 | delegate: self 263 | cancelButtonTitle: NSLocalizedStringFromTable(@"OK", @"CrashReporter", @"") 264 | otherButtonTitles: nil]; 265 | break; 266 | case CrashReportStatusSubmitted: 267 | alertView = [[UIAlertView alloc] initWithTitle: NSLocalizedStringFromTable(@"CrashResponseTitle", @"CrashReporter", @"Title for the alertview giving feedback about the crash") 268 | message: [NSString stringWithFormat:NSLocalizedStringFromTable(@"CrashResponseWaitingApple", @"CrashReporter", @"Full text telling the bug is fixed and the new release is waiting at Apple for approval"), appName] 269 | delegate: self 270 | cancelButtonTitle: NSLocalizedStringFromTable(@"OK", @"CrashReporter", @"") 271 | otherButtonTitles: nil]; 272 | break; 273 | case CrashReportStatusAvailable: 274 | alertView = [[UIAlertView alloc] initWithTitle: NSLocalizedStringFromTable(@"CrashResponseTitle", @"CrashReporter", @"Title for the alertview giving feedback about the crash") 275 | message: [NSString stringWithFormat:NSLocalizedStringFromTable(@"CrashResponseAvailable", @"CrashReporter", @"Full text telling the bug is fixed and an update is available in the AppStore for download"), appName] 276 | delegate: self 277 | cancelButtonTitle: NSLocalizedStringFromTable(@"OK", @"CrashReporter", @"") 278 | otherButtonTitles: nil]; 279 | break; 280 | default: 281 | alertView = nil; 282 | break; 283 | } 284 | 285 | if (alertView != nil) 286 | { 287 | [alertView setTag: CrashAlertTypeFeedback]; 288 | [alertView show]; 289 | [alertView release]; 290 | } 291 | } 292 | } 293 | 294 | 295 | #pragma mark - 296 | #pragma mark UIAlertView Delegate 297 | 298 | - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex 299 | { 300 | if ([alertView tag] == CrashAlertTypeSend) 301 | { 302 | switch (buttonIndex) { 303 | case 0: 304 | [self _cleanCrashReports]; 305 | break; 306 | case 1: 307 | [self _sendCrashReports]; 308 | break; 309 | case 2: 310 | [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kAutomaticallySendCrashReports]; 311 | 312 | [self _sendCrashReports]; 313 | break; 314 | } 315 | } 316 | } 317 | 318 | #pragma mark - 319 | #pragma mark NSXMLParser Delegate 320 | 321 | #pragma mark NSXMLParser 322 | 323 | - (BOOL)parseXMLFileAtURL:(NSString *)url parseError:(NSError **)error 324 | { 325 | NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:url]]; 326 | // Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks. 327 | [parser setDelegate:self]; 328 | // Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser. 329 | [parser setShouldProcessNamespaces:NO]; 330 | [parser setShouldReportNamespacePrefixes:NO]; 331 | [parser setShouldResolveExternalEntities:NO]; 332 | 333 | [parser parse]; 334 | 335 | NSError *parseError = [parser parserError]; 336 | if (parseError && error) { 337 | *error = parseError; 338 | } 339 | 340 | [parser release]; 341 | 342 | return (parseError) ? YES : NO; 343 | } 344 | 345 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict 346 | { 347 | if (qName) 348 | { 349 | elementName = qName; 350 | } 351 | 352 | if ([elementName isEqualToString:@"result"]) { 353 | _contentOfProperty = [NSMutableString string]; 354 | } 355 | } 356 | 357 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 358 | { 359 | if (qName) 360 | { 361 | elementName = qName; 362 | } 363 | 364 | if ([elementName isEqualToString: @"result"]) { 365 | if ([_contentOfProperty intValue] > _serverResult) { 366 | _serverResult = [_contentOfProperty intValue]; 367 | } else { 368 | CrashReportStatus errorcode = [_contentOfProperty intValue]; 369 | NSLog(@"CrashReporter ended in error code: %i", errorcode); 370 | } 371 | } 372 | } 373 | 374 | 375 | - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 376 | { 377 | if (_contentOfProperty) 378 | { 379 | // If the current element is one whose content we care about, append 'string' 380 | // to the property that holds the content of the current element. 381 | if (string != nil) 382 | { 383 | [_contentOfProperty appendString:string]; 384 | } 385 | } 386 | } 387 | 388 | #pragma mark - 389 | #pragma mark Private 390 | 391 | 392 | - (NSString *)_getDevicePlatform 393 | { 394 | size_t size; 395 | sysctlbyname("hw.machine", NULL, &size, NULL, 0); 396 | char *answer = malloc(size); 397 | sysctlbyname("hw.machine", answer, &size, NULL, 0); 398 | NSString *platform = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding]; 399 | free(answer); 400 | return platform; 401 | } 402 | 403 | - (void)_cleanCrashReports 404 | { 405 | NSError *error; 406 | 407 | NSFileManager *fm = [NSFileManager defaultManager]; 408 | 409 | for (int i=0; i < [_crashFiles count]; i++) 410 | { 411 | [fm removeItemAtPath:[_crashesDir stringByAppendingPathComponent:[_crashFiles objectAtIndex:i]] error:&error]; 412 | } 413 | [_crashFiles removeAllObjects]; 414 | } 415 | 416 | - (void)_sendCrashReports 417 | { 418 | NSError *error; 419 | 420 | NSString *userid = @""; 421 | NSString *contact = @""; 422 | NSString *description = @""; 423 | 424 | if (_delegate != nil && [_delegate respondsToSelector:@selector(crashReportUserID)]) 425 | { 426 | userid = [_delegate crashReportUserID]; 427 | } 428 | 429 | if (_delegate != nil && [_delegate respondsToSelector:@selector(crashReportContact)]) 430 | { 431 | contact = [_delegate crashReportContact]; 432 | } 433 | 434 | if (_delegate != nil && [_delegate respondsToSelector:@selector(crashReportDescription)]) 435 | { 436 | description = [_delegate crashReportDescription]; 437 | } 438 | 439 | 440 | for (int i=0; i < [_crashFiles count]; i++) 441 | { 442 | NSString *filename = [_crashesDir stringByAppendingPathComponent:[_crashFiles objectAtIndex:i]]; 443 | NSData *crashData = [NSData dataWithContentsOfFile:filename]; 444 | 445 | if ([crashData length] > 0) 446 | { 447 | PLCrashReport *report = [[[PLCrashReport alloc] initWithData:crashData error:&error] autorelease]; 448 | 449 | NSString *crashLogString = [self _crashLogStringForReport:report]; 450 | 451 | if ([report.applicationInfo.applicationVersion compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] != NSOrderedSame) 452 | { 453 | _crashIdenticalCurrentVersion = NO; 454 | } 455 | 456 | NSString *xml = [NSString stringWithFormat:@"%s%@%@%@%@%@%@%@", 457 | [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String], 458 | report.applicationInfo.applicationIdentifier, 459 | [[UIDevice currentDevice] systemVersion], 460 | [self _getDevicePlatform], 461 | [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"], 462 | report.applicationInfo.applicationVersion, 463 | userid, 464 | contact, 465 | description, 466 | crashLogString]; 467 | 468 | 469 | [self _postXML:xml toURL:_submissionURL]; 470 | } 471 | } 472 | 473 | [self _cleanCrashReports]; 474 | } 475 | 476 | 477 | - (NSString *)_crashLogStringForReport:(PLCrashReport *)report 478 | { 479 | NSMutableString *xmlString = [NSMutableString string]; 480 | 481 | /* Header */ 482 | boolean_t lp64; 483 | 484 | /* Map to apple style OS nane */ 485 | const char *osName; 486 | switch (report.systemInfo.operatingSystem) { 487 | case PLCrashReportOperatingSystemiPhoneOS: 488 | osName = "iPhone OS"; 489 | break; 490 | case PLCrashReportOperatingSystemiPhoneSimulator: 491 | osName = "Mac OS X"; 492 | break; 493 | default: 494 | osName = "iPhone OS"; 495 | break; 496 | } 497 | 498 | /* Map to Apple-style code type */ 499 | NSString *codeType; 500 | switch (report.systemInfo.architecture) { 501 | case PLCrashReportArchitectureARM: 502 | codeType = @"ARM (Native)"; 503 | lp64 = false; 504 | break; 505 | case PLCrashReportArchitectureX86_32: 506 | codeType = @"X86"; 507 | lp64 = false; 508 | break; 509 | case PLCrashReportArchitectureX86_64: 510 | codeType = @"X86-64"; 511 | lp64 = true; 512 | break; 513 | case PLCrashReportArchitecturePPC: 514 | codeType = @"PPC"; 515 | lp64 = false; 516 | break; 517 | default: 518 | codeType = @"ARM (Native)"; 519 | lp64 = false; 520 | break; 521 | } 522 | 523 | [xmlString appendString:@"Incident Identifier: [TODO]\n"]; 524 | [xmlString appendString:@"CrashReporter Key: [TODO]\n"]; 525 | 526 | /* Application and process info */ 527 | { 528 | NSString *unknownString = @"???"; 529 | 530 | NSString *processName = unknownString; 531 | NSString *processId = unknownString; 532 | NSString *processPath = unknownString; 533 | NSString *parentProcessName = unknownString; 534 | NSString *parentProcessId = unknownString; 535 | 536 | /* Process information was not available in earlier crash report versions */ 537 | if (report.hasProcessInfo) { 538 | /* Process Name */ 539 | if (report.processInfo.processName != nil) 540 | processName = report.processInfo.processName; 541 | 542 | /* PID */ 543 | processId = [[NSNumber numberWithUnsignedInteger: report.processInfo.processID] stringValue]; 544 | 545 | /* Process Path */ 546 | if (report.processInfo.processPath != nil) 547 | processPath = report.processInfo.processPath; 548 | 549 | /* Parent Process Name */ 550 | if (report.processInfo.parentProcessName != nil) 551 | parentProcessName = report.processInfo.parentProcessName; 552 | 553 | /* Parent Process ID */ 554 | parentProcessId = [[NSNumber numberWithUnsignedInteger: report.processInfo.parentProcessID] stringValue]; 555 | } 556 | 557 | [xmlString appendFormat: @"Process: %@ [%@]\n", processName, processId]; 558 | [xmlString appendFormat: @"Path: %@\n", processPath]; 559 | [xmlString appendFormat: @"Identifier: %@\n", report.applicationInfo.applicationIdentifier]; 560 | [xmlString appendFormat: @"Version: %@\n", report.applicationInfo.applicationVersion]; 561 | [xmlString appendFormat: @"Code Type: %@\n", codeType]; 562 | [xmlString appendFormat: @"Parent Process: %@ [%@]\n", parentProcessName, parentProcessId]; 563 | } 564 | 565 | [xmlString appendString:@"\n"]; 566 | 567 | /* System info */ 568 | [xmlString appendFormat:@"Date/Time: %s\n", [[report.systemInfo.timestamp description] UTF8String]]; 569 | [xmlString appendFormat:@"OS Version: %s %s\n", osName, [report.systemInfo.operatingSystemVersion UTF8String]]; 570 | [xmlString appendString:@"Report Version: 104\n"]; 571 | 572 | [xmlString appendString:@"\n"]; 573 | 574 | /* Exception code */ 575 | [xmlString appendFormat:@"Exception Type: %s\n", [report.signalInfo.name UTF8String]]; 576 | [xmlString appendFormat:@"Exception Codes: %@ at 0x%" PRIx64 "\n", report.signalInfo.code, report.signalInfo.address]; 577 | 578 | for (PLCrashReportThreadInfo *thread in report.threads) { 579 | if (thread.crashed) { 580 | [xmlString appendFormat: @"Crashed Thread: %ld\n", (long) thread.threadNumber]; 581 | break; 582 | } 583 | } 584 | 585 | [xmlString appendString:@"\n"]; 586 | 587 | if (report.hasExceptionInfo) { 588 | [xmlString appendString:@"Application Specific Information:\n"]; 589 | [xmlString appendFormat: @"*** Terminating app due to uncaught exception '%@', reason: '%@'\n", 590 | report.exceptionInfo.exceptionName, report.exceptionInfo.exceptionReason]; 591 | [xmlString appendString:@"\n"]; 592 | } 593 | 594 | /* Threads */ 595 | PLCrashReportThreadInfo *crashed_thread = nil; 596 | for (PLCrashReportThreadInfo *thread in report.threads) { 597 | if (thread.crashed) { 598 | [xmlString appendFormat: @"Thread %ld Crashed:\n", (long) thread.threadNumber]; 599 | crashed_thread = thread; 600 | } else { 601 | [xmlString appendFormat: @"Thread %ld:\n", (long) thread.threadNumber]; 602 | } 603 | for (NSUInteger frame_idx = 0; frame_idx < [thread.stackFrames count]; frame_idx++) { 604 | PLCrashReportStackFrameInfo *frameInfo = [thread.stackFrames objectAtIndex: frame_idx]; 605 | PLCrashReportBinaryImageInfo *imageInfo; 606 | 607 | /* Base image address containing instrumention pointer, offset of the IP from that base 608 | * address, and the associated image name */ 609 | uint64_t baseAddress = 0x0; 610 | uint64_t pcOffset = 0x0; 611 | NSString *imageName = @"\?\?\?"; 612 | 613 | imageInfo = [report imageForAddress: frameInfo.instructionPointer]; 614 | if (imageInfo != nil) { 615 | imageName = [imageInfo.imageName lastPathComponent]; 616 | baseAddress = imageInfo.imageBaseAddress; 617 | pcOffset = frameInfo.instructionPointer - imageInfo.imageBaseAddress; 618 | } 619 | 620 | [xmlString appendFormat: @"%-4ld%-36s0x%08" PRIx64 " 0x%" PRIx64 " + %" PRId64 "\n", 621 | (long) frame_idx, [imageName UTF8String], frameInfo.instructionPointer, baseAddress, pcOffset]; 622 | } 623 | [xmlString appendString: @"\n"]; 624 | } 625 | 626 | /* Registers */ 627 | if (crashed_thread != nil) { 628 | [xmlString appendFormat: @"Thread %ld crashed with %@ Thread State:\n", (long) crashed_thread.threadNumber, codeType]; 629 | 630 | int regColumn = 1; 631 | for (PLCrashReportRegisterInfo *reg in crashed_thread.registers) { 632 | NSString *reg_fmt; 633 | 634 | /* Use 32-bit or 64-bit fixed width format for the register values */ 635 | if (lp64) 636 | reg_fmt = @"%6s:\t0x%016" PRIx64 " "; 637 | else 638 | reg_fmt = @"%6s:\t0x%08" PRIx64 " "; 639 | 640 | [xmlString appendFormat: reg_fmt, [reg.registerName UTF8String], reg.registerValue]; 641 | 642 | if (regColumn % 4 == 0) 643 | [xmlString appendString: @"\n"]; 644 | regColumn++; 645 | } 646 | 647 | if (regColumn % 3 != 0) 648 | [xmlString appendString: @"\n"]; 649 | 650 | [xmlString appendString: @"\n"]; 651 | } 652 | 653 | /* Images */ 654 | [xmlString appendFormat:@"Binary Images:\n"]; 655 | 656 | for (PLCrashReportBinaryImageInfo *imageInfo in report.images) { 657 | NSString *uuid; 658 | /* Fetch the UUID if it exists */ 659 | if (imageInfo.hasImageUUID) 660 | uuid = imageInfo.imageUUID; 661 | else 662 | uuid = @"???"; 663 | 664 | NSString *device = @"\?\?\? (\?\?\?)"; 665 | 666 | #ifdef _ARM_ARCH_7 667 | device = @"armv7"; 668 | #else 669 | device = @"armv6"; 670 | #endif 671 | 672 | /* base_address - terminating_address file_name identifier () file_path */ 673 | [xmlString appendFormat:@"0x%" PRIx64 " - 0x%" PRIx64 " %@ %@ <%@> %@\n", 674 | imageInfo.imageBaseAddress, 675 | imageInfo.imageBaseAddress + imageInfo.imageSize, 676 | [imageInfo.imageName lastPathComponent], 677 | device, 678 | uuid, 679 | imageInfo.imageName]; 680 | } 681 | 682 | return xmlString; 683 | } 684 | 685 | - (void)_postXML:(NSString*)xml toURL:(NSURL*)url 686 | { 687 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 688 | NSString *boundary = @"----FOO"; 689 | 690 | [request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData]; 691 | [request setValue:USER_AGENT forHTTPHeaderField:@"User-Agent"]; 692 | [request setTimeoutInterval: 15]; 693 | [request setHTTPMethod:@"POST"]; 694 | NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; 695 | [request setValue:contentType forHTTPHeaderField:@"Content-type"]; 696 | 697 | NSMutableData *postBody = [NSMutableData data]; 698 | [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 699 | [postBody appendData:[@"Content-Disposition: form-data; name=\"xmlstring\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; 700 | [postBody appendData:[xml dataUsingEncoding:NSUTF8StringEncoding]]; 701 | [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 702 | [request setHTTPBody:postBody]; 703 | 704 | _serverResult = CrashReportStatusUnknown; 705 | _statusCode = 200; 706 | 707 | //Release when done in the delegate method 708 | _responseData = [[NSMutableData alloc] init]; 709 | 710 | if (_delegate != nil && [_delegate respondsToSelector:@selector(connectionOpened)]) 711 | { 712 | [_delegate connectionOpened]; 713 | } 714 | 715 | _urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 716 | } 717 | 718 | #pragma mark NSURLConnection Delegate 719 | 720 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 721 | { 722 | if ([response isKindOfClass:[NSHTTPURLResponse class]]) { 723 | _statusCode = [(NSHTTPURLResponse *)response statusCode]; 724 | } 725 | } 726 | 727 | - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 728 | { 729 | [_responseData appendData:data]; 730 | } 731 | 732 | - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 733 | { 734 | [_responseData release]; 735 | _responseData = nil; 736 | [connection autorelease]; 737 | 738 | if (_delegate != nil && [_delegate respondsToSelector:@selector(connectionClosed)]) 739 | { 740 | [_delegate connectionClosed]; 741 | } 742 | 743 | [self showCrashStatusMessage]; 744 | } 745 | 746 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection 747 | { 748 | if (_statusCode >= 200 && _statusCode < 400) 749 | { 750 | NSXMLParser *parser = [[NSXMLParser alloc] initWithData:_responseData]; 751 | // Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks. 752 | [parser setDelegate:self]; 753 | // Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser. 754 | [parser setShouldProcessNamespaces:NO]; 755 | [parser setShouldReportNamespacePrefixes:NO]; 756 | [parser setShouldResolveExternalEntities:NO]; 757 | 758 | [parser parse]; 759 | 760 | [parser release]; 761 | } 762 | 763 | [_responseData release]; 764 | _responseData = nil; 765 | [connection autorelease]; 766 | 767 | if (_delegate != nil && [_delegate respondsToSelector:@selector(connectionClosed)]) 768 | { 769 | [_delegate connectionClosed]; 770 | } 771 | 772 | [self showCrashStatusMessage]; 773 | } 774 | 775 | #pragma mark PLCrashReporter 776 | 777 | // 778 | // Called to handle a pending crash report. 779 | // 780 | - (void) handleCrashReport 781 | { 782 | PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter]; 783 | NSError *error; 784 | 785 | // check if the next call ran successfully the last time 786 | if (_crashReportAnalyzerStarted == 0) 787 | { 788 | // mark the start of the routine 789 | _crashReportAnalyzerStarted = 1; 790 | [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_crashReportAnalyzerStarted] forKey:kCrashReportAnalyzerStarted]; 791 | 792 | 793 | // Try loading the crash report 794 | _crashData = [[NSData alloc] initWithData:[crashReporter loadPendingCrashReportDataAndReturnError: &error]]; 795 | 796 | NSString *cacheFilename = [NSString stringWithFormat: @"%.0f", [NSDate timeIntervalSinceReferenceDate]]; 797 | 798 | if (_crashData == nil) { 799 | NSLog(@"Could not load crash report: %@", error); 800 | goto finish; 801 | } else { 802 | [_crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES]; 803 | } 804 | 805 | // We could send the report from here, but we'll just print out 806 | // some debugging info instead 807 | PLCrashReport *report = [[[PLCrashReport alloc] initWithData: _crashData error: &error] autorelease]; 808 | if (report == nil) { 809 | NSLog(@"Could not parse crash report"); 810 | goto finish; 811 | } 812 | } 813 | 814 | // Purge the report 815 | finish: 816 | // mark the end of the routine 817 | _crashReportAnalyzerStarted = 0; 818 | [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_crashReportAnalyzerStarted] forKey:kCrashReportAnalyzerStarted]; 819 | 820 | [crashReporter purgePendingCrashReport]; 821 | return; 822 | } 823 | 824 | #pragma mark Reachability 825 | 826 | - (BOOL)_isSubmissionHostReachable 827 | { 828 | SCNetworkReachabilityFlags flags; 829 | SCNetworkReachabilityRef reachabilityRef = nil; 830 | 831 | if (![_submissionURL host] || ![[_submissionURL host] length]) { 832 | return NO; 833 | } 834 | 835 | reachabilityRef = SCNetworkReachabilityCreateWithName(NULL, [[_submissionURL host] UTF8String]); 836 | 837 | if (!reachabilityRef) { 838 | return NO; 839 | } 840 | 841 | BOOL gotFlags = SCNetworkReachabilityGetFlags(reachabilityRef, &flags); 842 | 843 | if (reachabilityRef != nil) 844 | CFRelease(reachabilityRef); 845 | 846 | return gotFlags && flags & kSCNetworkReachabilityFlagsReachable && (flags & kSCNetworkReachabilityFlagsIsWWAN || !(flags & kSCNetworkReachabilityFlagsConnectionRequired)); 847 | } 848 | 849 | 850 | @end 851 | -------------------------------------------------------------------------------- /CrashReporterSender/English.lproj/CrashReporter.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/CrashReporterSender/English.lproj/CrashReporter.strings -------------------------------------------------------------------------------- /CrashReporterSender/German.lproj/CrashReporter.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/CrashReporterSender/German.lproj/CrashReporter.strings -------------------------------------------------------------------------------- /Flurry/Analytics-README.txt: -------------------------------------------------------------------------------- 1 | Welcome to Flurry Analytics! 2 | 3 | This README contains: 4 | 5 | 1. Introduction 6 | 2. Integration 7 | 3. Latest SDK Update 8 | 4. Optional Features 9 | 5. Recommendations 10 | 6. FAQ 11 | 12 | ===================================== 13 | 1. Introduction 14 | 15 | The Flurry iPhone Analytics Agent allows you to track the usage and behavior of your iPhone application 16 | on users' phones for viewing in the Flurry Analytics system. It is designed to be as easy as possible 17 | with a basic setup complete in under 5 minutes. 18 | 19 | Please note that this SDK will only work with Xcode 3.2.3 or above. If you need an SDK for an older Xcode version please email support. 20 | 21 | This archive should contain these files: 22 | - ProjectApiKey.txt : This file contains the name of your project and your project's API key. 23 | - Analytics-README.txt : This text file containing instructions. 24 | - FlurryLibWithLocation/FlurryAPI.h 25 | - FlurryLibWithLocation/libFlurryWithLocation.a : The library containing Flurry's collection and reporting code. This version includes GPS location capabilities. 26 | - FlurryLib/FlurryAPI.h 27 | - FlurryLib/libFlurry.a : The library containing Flurry's collection and reporting code. This version does not include GPS location capabilities. 28 | 29 | These are optional files for use with Flurry AppCircle. You do NOT need them for Flurry Analytics. 30 | - FlurryLib/FlurryAdDelegate.h 31 | - FlurryLibWithLocation/FlurryAdDelegate.h 32 | 33 | Note that there are two versions of the Flurry analytics library: With and without location. We recommend using FlurryLibWithLocation so that you can receive detailed analytics about where your users are using your app. 34 | However, if you do not currently use location in your application, you can use FlurryLib and receive all of the same analytics without detailed location information. 35 | We also recommend calling FlurryAPI from the main thread. FlurryAPI is not supported when called from other threads. 36 | 37 | ===================================== 38 | 2. Integration 39 | 40 | To integrate Flurry Analytics into your iPhone application, first decide if you want to use location services or not. 41 | If you do wish to use location, see the steps in 2a. If you do not wish to use location, skip to 2b. 42 | 43 | Note that you should only use Flurry location services if your application already uses the CLLocationManager. You should not enable location services for analytics if you do not already use the CLLocationManager as your application will be rejected by Apple. 44 | Apple requires that your application use location in a way useful to the end user in order to access the CLLocationManager. 45 | 46 | 2a. Integration without Location 47 | ------------------------------------------------------------- 48 | 49 | 1. In the finder, drag FlurryLib into project's file folder. 50 | NOTE: If you are upgrading the Flurry iPhone SDK, be sure to remove any existing Flurry library folders from your project's file folder before proceeding. 51 | 52 | 2. Now add it to your project => Project > Add to project > FlurryLib 53 | - Choose 'Recursively create groups for any added folders' 54 | 55 | 3. In your Application Delegate: 56 | a. Import FlurryAPI => #import "FlurryAPI.h" 57 | b. Inside "applicationDidFinishLaunching:" add => [FlurryAPI startSession:@"YOUR_API_KEY"]; 58 | 59 | - (void)applicationDidFinishLaunching:(UIApplication *)application { 60 | [FlurryAPI startSession:@"YOUR_API_KEY"]; 61 | //your code 62 | } 63 | 64 | You're done! That's all you need to do to begin receiving basic metric data. 65 | 66 | 2b. Integration with location 67 | ------------------------------------------------------------- 68 | 1. In the finder, drag FlurryLibWithLocation into project's file folder. 69 | NOTE: If you are upgrading the Flurry iPhone SDK, be sure to remove any existing Flurry library folders from your project's file folder before proceeding. 70 | 71 | 2. Now add it to your project => Project > Add to project > FlurryLibWithLocation 72 | - Choose 'Recursively create groups for any added folders' 73 | 74 | 3. At this point, there are two options. First, if your application already has initialized a CLLocationManager, you can simply pass location information to the Flurry API for each session. For this option see the steps in 3a. 75 | Second, if your application has not already defined a CLLocationManager and you want Flurry to handle this for you, see the steps in 3b. 76 | 77 | 3a. You pass location information to the FlurryAPI. In your Application Delegate: 78 | a. Import FlurryAPI => #import "FlurryAPI.h" 79 | b. Inside "applicationDidFinishLaunching:" add => [FlurryAPI startSession:@"YOUR_API_KEY"]; 80 | 81 | - (void)applicationDidFinishLaunching:(UIApplication *)application { 82 | [FlurryAPI startSession:@"YOUR_API_KEY"]; 83 | //your code 84 | } 85 | c. Each time you want to update the location that Flurry Analytics will record, use the function below. Only the last location reported will be used for each session. 86 | [FlurryAPI setLocation:YOUR_UPDATED_CLLOCATION]; 87 | 88 | 3b. Flurry manages all location capabilities. In your Application Delegate: 89 | a. Import FlurryAPI => #import "FlurryAPI.h" 90 | b. Inside "applicationDidFinishLaunching:" add => [FlurryAPI startSessionWithLocationServices:@"YOUR_API_KEY"]; 91 | 92 | - (void)applicationDidFinishLaunching:(UIApplication *)application { 93 | [FlurryAPI startSessionWithLocationServices:@"YOUR_API_KEY"]; 94 | //your code 95 | } 96 | 97 | NOTE: You must also include the CoreLocation.framework if you do this. To add this framework, go to 98 | Project > Edit Active Target "YOUR_APP" > Add Libraries ('+' sign at the bottom) and select CoreLocation.framework 99 | 100 | You're done! That's all you need to do to begin receiving basic metric data. For optional advanced features, skip to Section 3. 101 | 102 | ===================================== 103 | 3. Latest SDK Update 104 | Going forward, the Flurry SDK will only support Xcode 3.2.3 and above. Please email support if you need to use older versions of the Flurry SDK. 105 | 106 | This version of the Flurry SDK is compatible with Xcode 3.2.3 and designed for OS 4.0 (iOS) applications. 107 | 108 | In this version of the Flurry SDK, we modified which data is collected. This updated SDK version does not collect the following device data: device name, operating system version and firmware version. Because Apple allows the collection of UDID for the purpose of advertising, we continue to collect this data as the Flurry SDK includes AppCircle, Flurry's mobile advertising solution. 109 | 110 | Per Flurry's existing Terms of Service and Privacy Policy, please inform your consumers about data you collect through the use of our services. Additionally, please remember that you must abide by the rules set forth in the new Apple iPhone Developer Program License Agreement. 111 | 112 | Despite our latest efforts, please understand that we are unable to guarantee whether Apple reviewers will approve your application in its App Store submission process. 113 | 114 | ===================================== 115 | 4. Optional / Advanced Features 116 | 117 | You can use the following methods to report additional data. These methods work exactly the same with or without location services enabled. 118 | 119 | [FlurryAPI logEvent:@"EVENT_NAME"]; 120 | Use logEvent to count the number of times certain events happen during a session of your application. This can be useful for measuring how often users perform various actions, for example. Your application is currently limited to counting occurrences for 100 different event ids (maximum length 255 characters). 121 | 122 | [FlurryAPI logEvent:@"EVENT_NAME" withParameters:YOUR_NSDictionary]; 123 | Use this version of logEvent to count the number of times certain events happen during a session of your application and to pass dynamic parameters to be recorded with that event. Event parameters can be passed in as a NSDictionary object where the key and value objects must be NSString objects. For example, you could record that a user used your search box tool and also dynamically record which search terms the user entered. Your application is currently limited to counting occurrences for 100 different event ids (maximum length 255 characters). Maximum of 10 event parameters per event is supported. 124 | 125 | An example NSDictionary to use with this method could be: 126 | NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"your dynamic parameter value", @"your dynamic parameter name", nil]; 127 | 128 | [FlurryAPI logEvent:@"EVENT_NAME" timed:YES]; 129 | Use this version of logEvent to start timed event. 130 | 131 | [FlurryAPI logEvent:@"EVENT_NAME" withParameters:YOUR_NSDictionary timed:YES]; 132 | Use this version of logEvent to start timed event with event parameters. 133 | 134 | [FlurryAPI endTimedEvent:@"EVENT_NAME" withParameters:YOUR_NSDictionary]; 135 | Use endTimedEvent to end timed event before app exists, otherwise timed events automatically end when app exists. When ending the timed event, a new event parameters NSDictionary object can be used to update event parameters. To keep event parameters the same, pass in nil for the event parameters NSDictionary object. 136 | 137 | [FlurryAPI logError:@"ERROR_NAME" message:@"ERROR_MESSAGE" exception:e]; 138 | Use this to log exceptions and/or errors that occur in your app. Flurry will report the first 10 errors that occur in each session. 139 | 140 | [FlurryAPI setUserID:@"USER_ID"]; 141 | Use this to log the user's assigned ID or username in your system after identifying the user. 142 | 143 | [FlurryAPI setAge:21]; 144 | Use this to log the user's age after identifying the user. Valid inputs are 0 or greater. 145 | 146 | [FlurryAPI setGender:@"m"]; 147 | Use this to log the user's gender after identifying the user. Valid inputs are m or f. 148 | 149 | [FlurryAPI countPageViews:navigationController]; 150 | To enable Flurry agent to automatically detect and log page view, pass in an instance of UINavigationController or UITabBarController to countPageViews. Flurry agent will create a delegate on your object to detect user interactions. Each detected user interaction will automatically be logged as a page view. Each instance needs to only be passed to Flurry agent once. Multiple UINavigationController or UITabBarController instances can be passed to Flurry agent. 151 | 152 | [FlurryAPI countPageView]; 153 | In the absence of UINavigationController and UITabBarController, you can manually detect user interactions. For each user interaction you want to manually log, you can use countPageView to log the page view. 154 | 155 | [FlurryAPI setSessionReportsOnCloseEnabled:(BOOL)sendSessionReportsOnClose]; 156 | This option is on by default. When enabled, Flurry will attempt to send session data when the app is exited as well as it normally does when the app is started. This will improve the speed at which your application analytics are updated but can prolong the app termination process due to network latency. In some cases, the network latency can cause the app to crash. 157 | 158 | [FlurryAPI setSessionReportsOnPauseEnabled:(BOOL)sendSessionReportsOnPause]; 159 | This option is on by default. When enabled, Flurry will attempt to send session data when the app is paused as well as it normally does when the app is started. This will improve the speed at which your application analytics are updated but can prolong the app pause process due to network latency. In some cases, the network latency can cause the app to crash. 160 | 161 | ===================================== 162 | 5. Recommendations 163 | 164 | We recommend adding an uncaught exception listener to your application (if you don't already have one) and use logError to record any application crashes. 165 | Adding an uncaught exception listener is easy; you just need to create a function that looks like the following: 166 | 167 | void uncaughtExceptionHandler(NSException *exception) { 168 | [FlurryAPI logError:@"Uncaught" message:@"Crash!" exception:exception]; 169 | } 170 | 171 | You then need to register this function as an uncaught exception listener as follows: 172 | 173 | - (void)applicationDidFinishLaunching:(UIApplication *)application { 174 | NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler); 175 | [FlurryAPI startSession:@"YOUR_API_KEY"]; 176 | .... 177 | } 178 | 179 | Note that you can name the function whatever you'd like and record whatever error information you'd like in the error name and event fields. 180 | 181 | ===================================== 182 | 6. FAQ 183 | 184 | When does the Flurry Agent send data? 185 | 186 | By default, the Flurry Agent will send the stored metrics data to Flurry servers when the app starts, resumes, and terminates. 187 | To override default Agent behavior, you can turn off sending data on termination with [FlurryAPI setSessionReportsOnCloseEnabled:NO]; 188 | Sending metrics data when the app pauses is also supported, but not enabled by default. You can enable sending data on pause with [FlurryAPI setSessionReportsOnPauseEnabled:YES]; 189 | 190 | How much data does the Agent send each session? 191 | 192 | All data sent by the Flurry Agent is sent in a compact binary format. 193 | 194 | What data does the Agent send? 195 | 196 | The data sent by the Flurry Agent includes time stamps, logged events, logged errors, and various device specific information. This is the same information that can be seen in the custom event logs on in the Event Analytics section. 197 | If AppCircle is used, Flurry Agent will also send AppCircle user interaction data. These information can be seen in the AppCircle section. 198 | We are also collecting App Store ID, purchase date, release date, and purchase price in order to provide more metrics in the future. 199 | We do not collect personally identifiable information. 200 | 201 | Does the Agent support iPhone OS 3.x? 202 | 203 | To support OS 3.x, please set Base SDK to iPhone Device 4.0 and iPhone OS Deployment Target to iPhone OS 3.x. Extra linker flags may be needed if NSConcreteGlobalBlock and UIBackgroundTaskInvalid runtime error occur under 3.x. 204 | The linker flags are: 205 | -weak_framework UIKit 206 | -weak_library /usr/lib/libSystem.B.dylib 207 | 208 | ===================================== 209 | 210 | Please let us know if you have any questions. If you need any help, just email iphonesupport@flurry.com! 211 | 212 | Cheers, 213 | The Flurry Team 214 | http://www.flurry.com 215 | iphonesupport@flurry.com -------------------------------------------------------------------------------- /Flurry/AppCircle-README.txt: -------------------------------------------------------------------------------- 1 | Welcome to Flurry AppCircle! 2 | 3 | This README contains: 4 | 5 | 1. Introduction 6 | 2. AppCircle Integration 7 | 3. Optional Features 8 | 4. Banner-less Integration 9 | 5. Callbacks 10 | 6. FAQ 11 | 12 | ===================================== 13 | 1. Introduction 14 | 15 | Flurry AppCircle is an application recommendation network. Publishers can integrate AppCircle into their applications to provide new application recommendations to their users and earn commissions on sales they generate. 16 | Promoters can use the AppCircle network of publishers to promote their applications to new users. 17 | 18 | These instructions describe how to become a Publisher by adding AppCircle recommendations to your application. 19 | It is designed to be as easy as possible and since it uses the same SDK as Flurry Analytics, you can get set up in under 5 minutes. 20 | 21 | Note that you don't have to use AppCircle in order to enjoy Flurry Analytics. However, you do need to have Flurry Analytics integrated into your application to enjoy the benefits of AppCircle. 22 | 23 | ===================================== 24 | 2. AppCircle Integration 25 | 26 | When you integrate AppCircle into your application, a banner will be placed over your application's view to display recommendations. Clicking on the banner will display a canvas that gives more information about the application recommended in the banner. 27 | The user never leaves your application while browsing recommendations, so a user can cancel out of the canvas and go back to the previous application view. 28 | 29 | First, enable AppCircle before starting the session: 30 | 31 | [FlurryAPI setAppCircleEnabled:YES]; 32 | [FlurryAPI startSession:@"YOUR_API_KEY"]; 33 | 34 | Adding AppCircle hooks is as easy as adding a single call to getHook in any view controller where you want to add a promotion. 35 | The only code you need to add is the following: 36 | 37 | UIView *banner = [FlurryAPI getHook:@"PUT_YOUR_HOOK_NAME_HERE" xLoc:0 yLoc:0 view:self.view]; 38 | 39 | If you don't use a view controller, feel free to use another view that you display in the application. 40 | 41 | Note that this should be done after you've created your view. When this view is loaded the AppCircle system will promote other applications and pay you for any installations generated by those promotions. 42 | 43 | That is all that is required to add basic AppCircle recommendations to your application. You're done! 44 | 45 | ===================================== 46 | 3. Optional Features 47 | 48 | You can pass in any UIView as the banner's parent view, here's an example using the key window as the parent view: 49 | 50 | UIView *banner = [FlurryAPI getHook:@"PUT_YOUR_HOOK_NAME_HERE" xLoc:0 yLoc:0 view:self.view]; 51 | 52 | If you require more control on the banner itself, use the longer getHook method with optional parameters: 53 | 54 | UIView *banner = [FlurryAPI getHook:@"USE_YOUR_OWN_HOOK_NAME" xLoc:0 yLoc:0 view:self.view attachToView:YES orientation:@"portrait" canvasOrientation:@"portrait" autoRefresh:YES canvasAnimated:YES]; 55 | 56 | - attachToView controls whether the banner is automatically placed on the parent view. The default setting is YES. 57 | - orientation controls the length of the banner. The values are @"portrait" and @"landscape". @"portrait" sets the banner dimension at 320x48. @"landscape" sets the banner dimension at 480x48. The default setting is @"portrait". 58 | - canvasOrientation controls the canvas orientation. The values are @"portrait", @"landscapeRight", and @"landscapeLeft". The default setting is @"portrait". 59 | - autoRefresh controls whether the banner will automatically update itself with new ads after a given period provided from the Flurry server. The current refresh interval is 20 seconds. The default setting is NO. 60 | - canvasAnimated controls whether the canvas will animate when it displays and closes. The default setting is YES. 61 | 62 | After requesting the banner with getHook method, subsequent calls with the same parent and hook will result in the same banner instance being returned. Only one banner will be created per hook and parent view. We recommend updating existing banners with new ads instead of creating new banners. 63 | 64 | To update an existing banner with new ad: 65 | 66 | [FlurryAPI updateHook:banner]; 67 | 68 | To remove an existing banner from its parent view and hook in order to create additional banners on the same hook and parent view: 69 | 70 | [FlurryAPI removeHook:banner]; 71 | [banner removeFromSuperview]; 72 | 73 | ===================================== 74 | 4. Banner-less Integration 75 | 76 | While the AppCircle recommendation banner is a popular option due to it's standard size and shape, some developers prefer to integrate AppCircle into their application menu or other custom interface elements. 77 | To satisfy this need, you can launch the AppCircle recommendation interface without using the banner display. 78 | 79 | If you want to display a canvas page without displaying any banner, call this method anywhere in your application: 80 | 81 | [FlurryAPI openCatalog:@"USE_YOUR_OWN_HOOK_NAME" canvasOrientation:@"portrait" canvasAnimated:YES]; 82 | 83 | A new view will open on top of your current view and display recommended applications. The user will be able to go back to whatever view launched the interface easily by clicking the "Back" button. 84 | 85 | ===================================== 86 | 5. Callbacks 87 | 88 | You can pass in a delegate to FlurryAPI in order to receive callbacks from FlurryAPI. This is an optional feature that allows more control over the how your application interacts with AppCircle. 89 | The following example shows how it can be used with the application delegate. You can pass in any object as the delegate. 90 | 91 | First, include the FlurryAdDelegate.h file from the Flurry SDK (FlurryLib or FlurryLibWithLocation) that you are using into your project. 92 | 93 | In your AppDelegate.h: 94 | // add FlurryAdDelegate.h file to the project if you are using FlurryAdDelegate 95 | #import "FlurryAdDelegate.h" 96 | 97 | // add FlurryAdDelegate as a protocol 98 | @interface AppDelegate : NSObject { 99 | } 100 | 101 | In your AppDelegate.m: 102 | // implement to do something when the data is available 103 | // currently just output debug message 104 | - (void)dataAvailable { 105 | NSLog(@"Flurry data is available"); 106 | } 107 | // implement to do something when the data is unavailable 108 | // currently just output debug message 109 | - (void)dataUnavailable { 110 | NSLog(@"Flurry data is unavailable"); 111 | } 112 | // implement to do something when the canvas will open 113 | // currently just output debug message 114 | - (void)canvasWillDisplay:(NSString *)hook { 115 | NSLog(@"Flurry canvas will display:%@", hook); 116 | } 117 | // implement to do something when the canvas will close 118 | // currently just output debug message 119 | - (void)canvasWillClose { 120 | NSLog(@"Flurry canvas will close"); 121 | } 122 | // set FlurryAdDelegate before the session starts 123 | - (void)applicationDidFinishLaunching:(UIApplication *)application { 124 | [FlurryAPI setAppCircleDelegate:self]; 125 | [FlurryAPI startSession:@"YOUR_API_KEY"]; 126 | } 127 | 128 | ===================================== 129 | 6. FAQ 130 | 131 | Do you have to use AppCircle? 132 | 133 | If you want to just use the analytics tool in Flurry Agent, you can turn off AppCircle with an optional setting: [FlurryAPI setAppCircleEnabled:NO]; 134 | 135 | ===================================== 136 | 137 | Please let us know if you have any questions. If you need any help, just email iphonesupport@flurry.com! 138 | 139 | Cheers, 140 | The Flurry Team 141 | http://www.flurry.com 142 | iphonesupport@flurry.com -------------------------------------------------------------------------------- /Flurry/RELEASE_NOTES.txt: -------------------------------------------------------------------------------- 1 | Flurry iPhone SDK v2.7 2 | Build: 42 3 | Released: 7/12/10 4 | 5 | Release notes for v2.7: 6 | ------------------------------------------------ 7 | - Supports Xcode 3.2.3 and above 8 | - Default pause session reporting is on for applications using iOS4 features 9 | - Configurable pause time before new session is started 10 | - Displaying and closing canvas can be animated 11 | - Allow endTimedEvent to update event parameters 12 | - Change setAppVersion to be configured before session starts 13 | - To support OS 3.x, please set Base SDK to iPhone Device 4.0 and iPhone 14 | OS Deployment Target to iPhone OS 3.0. Extra linker flags may be 15 | needed if NSConcreteGlobalBlock and UIBackgroundTaskInvalid runtime 16 | error occur under 3.x. 17 | 18 | The linker flags are: 19 | -weak_framework UIKit 20 | -weak_library /usr/lib/libSystem.B.dylib 21 | 22 | Release notes for v2.6: 23 | ------------------------------------------------ 24 | - Improve memory usage in pause/resume cycle 25 | - Pausing the app will not send sessions by default 26 | - Fix AppCircle image parse error 27 | - Close AppCircle canvas on pause 28 | 29 | Release notes for v2.5: 30 | ------------------------------------------------ 31 | - Send sessions data when paused. 32 | - May create a new session depending on length of pause or will continue the current session on resume. 33 | 34 | Release notes for v2.4: 35 | ------------------------------------------------ 36 | - Supports Xcode 3.2.3 and below 37 | - Removed device data collection including Model Name, OS Version and Firmware Version 38 | 39 | Release notes for v2.3: 40 | ------------------------------------------------ 41 | - Adds support for features from the old PinchMedia API including the ability to: 42 | * Track page views 43 | * Time events 44 | * Acquire age demographics 45 | 46 | Release notes for v2.2: 47 | ------------------------------------------------ 48 | - AppCircle is now available to all developers! 49 | - Applications will attempt to send session reports at the end of the session by default to improve 50 | reporting speed. This can be disabled via the SDK. 51 | - Note thatAppCircle is disabled by default, please enable AppCircle from the SDK before using 52 | AppCircle banners. 53 | 54 | Release notes for v2.1: 55 | ------------------------------------------------ 56 | - AppCircle release candidate SDK for use in the Beta program 57 | 58 | Release notes for v2.0b18: 59 | ------------------------------------------------ 60 | - Added tracking of when sessions are paused for new analytics 61 | - Fixed jailbreak metrics reporting in the iPhone simulator 62 | 63 | Release notes for v1.4: 64 | ------------------------------------------------ 65 | - Added the ability to detect jailbroken devices which will be shown as a metric soon. 66 | - Add automatic detection of the AppStore Id of the application to make categorization easier. 67 | 68 | Release notes for v1.3: 69 | ------------------------------------------------ 70 | - Includes minor bug fixes including minor memory leak fixes. 71 | 72 | Release notes for v1.2: 73 | ------------------------------------------------ 74 | - Added the option to enable session reports to be sent at the end of a user session. This will 75 | increase the speed at which event data, error logging and session length metrics are updated as it 76 | does not require waiting until the next session to report. 77 | 78 | Release notes for v1.1: 79 | ------------------------------------------------ 80 | - Added the ability to track user paths and event parameters to allow for more robust reporting around 81 | custom events. 82 | 83 | -------------------------------------------------------------------------------- /Flurry/iPhone v2.7 (build 42)/FlurryLib/FlurryAPI.h: -------------------------------------------------------------------------------- 1 | // 2 | // FlurryAPI.h 3 | // Flurry iPhone Analytics Agent 4 | // 5 | // Copyright 2009 Flurry, Inc. All rights reserved. 6 | // 7 | #import 8 | 9 | @class CLLocationManager; 10 | @class CLLocation; 11 | 12 | @interface FlurryAPI : NSObject { 13 | } 14 | 15 | /* 16 | optional sdk settings that should be called before start session 17 | */ 18 | + (void)setAppVersion:(NSString *)version; // override the app version 19 | + (NSString *)getFlurryAgentVersion; // get the Flurry Agent version number 20 | + (void)setAppCircleEnabled:(BOOL)value; // default is NO 21 | + (void)setShowErrorInLogEnabled:(BOOL)value; // default is NO 22 | + (void)unlockDebugMode:(NSString*)debugModeKey apiKey:(NSString *)apiKey; // generate debug logs for Flurry support 23 | + (void)setPauseSecondsBeforeStartingNewSession:(int)seconds; // default is 10 seconds 24 | 25 | /* 26 | start session, attempt to send saved sessions to server 27 | */ 28 | + (void)startSession:(NSString *)apiKey; 29 | 30 | /* 31 | log events or errors after session has started 32 | */ 33 | + (void)logEvent:(NSString *)eventName; 34 | + (void)logEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters; 35 | + (void)logError:(NSString *)errorID message:(NSString *)message exception:(NSException *)exception; 36 | + (void)logError:(NSString *)errorID message:(NSString *)message error:(NSError *)error; 37 | 38 | /* 39 | start or end timed events 40 | */ 41 | + (void)logEvent:(NSString *)eventName timed:(BOOL)timed; 42 | + (void)logEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters timed:(BOOL)timed; 43 | + (void)endTimedEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters; // non-nil parameters will update the parameters 44 | 45 | /* 46 | count page views 47 | */ 48 | + (void)countPageViews:(id)target; // automatically track page view on UINavigationController or UITabBarController 49 | + (void)countPageView; // manually increment page view by 1 50 | 51 | /* 52 | set user info 53 | */ 54 | + (void)setUserID:(NSString *)userID; // user's id in your system 55 | + (void)setAge:(int)age; // user's age in years 56 | + (void)setGender:(NSString *)gender; // user's gender m or f 57 | 58 | /* 59 | optional session settings that can be changed after start session 60 | */ 61 | + (void)setSessionReportsOnCloseEnabled:(BOOL)sendSessionReportsOnClose; // default is YES 62 | + (void)setSessionReportsOnPauseEnabled:(BOOL)setSessionReportsOnPauseEnabled; // default is YES 63 | + (void)setEventLoggingEnabled:(BOOL)value; // default is YES 64 | 65 | /* 66 | create an AppCircle banner on a hook and a view parent 67 | subsequent calls will return the same banner for the same hook and parent until removed with the API 68 | */ 69 | + (UIView *)getHook:(NSString *)hook xLoc:(int)x yLoc:(int)y view:(UIView *)view; 70 | /* 71 | create an AppCircle banner on a hook and view parent using optional parameters 72 | */ 73 | + (UIView *)getHook:(NSString *)hook xLoc:(int)x yLoc:(int)y view:(UIView *)view attachToView:(BOOL)attachToView orientation:(NSString *)orientation canvasOrientation:(NSString *)canvasOrientation autoRefresh:(BOOL)refresh canvasAnimated:(BOOL)canvasAnimated; 74 | /* 75 | update an existing AppCircle banner with a new ad 76 | */ 77 | + (void)updateHook:(UIView *)banner; 78 | /* 79 | remove an existing AppCircle banner from its hook and parent 80 | a new banner can be created on the same hook and parent after the existing banner is removed 81 | */ 82 | + (void)removeHook:(UIView *)banner; 83 | /* 84 | open the canvas without using a banner 85 | */ 86 | + (void)openCatalog:(NSString *)hook canvasOrientation:(NSString *)canvasOrientation canvasAnimated:(BOOL)canvasAnimated; 87 | /* 88 | refer to FlurryAdDelegate.h for delegate details 89 | */ 90 | + (void)setAppCircleDelegate:(id)delegate; 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /Flurry/iPhone v2.7 (build 42)/FlurryLib/FlurryAdDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // FlurryAdDelegate.h 3 | // FlurryAnalytics 4 | // 5 | // Created by chunhao on 3/2/10. 6 | // Copyright 2010 Flurry Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @protocol FlurryAdDelegate 13 | 14 | @optional 15 | /* 16 | called after data is received 17 | */ 18 | - (void)dataAvailable; 19 | /* 20 | called after data is determined to be unavailable 21 | */ 22 | - (void)dataUnavailable; 23 | /* 24 | called before canvas displays 25 | code to pause app states can be set here 26 | */ 27 | - (void)canvasWillDisplay:(NSString *)hook; 28 | /* 29 | called before canvas closes 30 | code to resume app states can be set here 31 | */ 32 | - (void)canvasWillClose; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Flurry/iPhone v2.7 (build 42)/FlurryLib/libFlurry.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/Flurry/iPhone v2.7 (build 42)/FlurryLib/libFlurry.a -------------------------------------------------------------------------------- /Flurry/iPhone v2.7 (build 42)/FlurryLibWithLocation/FlurryAPI.h: -------------------------------------------------------------------------------- 1 | // 2 | // FlurryAPI.h 3 | // Flurry iPhone Analytics Agent 4 | // 5 | // Copyright 2009 Flurry, Inc. All rights reserved. 6 | // 7 | #import 8 | 9 | @class CLLocationManager; 10 | @class CLLocation; 11 | 12 | @interface FlurryAPI : NSObject { 13 | } 14 | 15 | /* 16 | optional sdk settings that should be called before start session 17 | */ 18 | + (void)setAppVersion:(NSString *)version; // override the app version 19 | + (NSString *)getFlurryAgentVersion; // get the Flurry Agent version number 20 | + (void)setAppCircleEnabled:(BOOL)value; // default is NO 21 | + (void)setShowErrorInLogEnabled:(BOOL)value; // default is NO 22 | + (void)unlockDebugMode:(NSString*)debugModeKey apiKey:(NSString *)apiKey; // generate debug logs for Flurry support 23 | + (void)setPauseSecondsBeforeStartingNewSession:(int)seconds; // default is 10 seconds 24 | 25 | /* 26 | start session, attempt to send saved sessions to server 27 | */ 28 | + (void)startSession:(NSString *)apiKey; 29 | 30 | /* 31 | log events or errors after session has started 32 | */ 33 | + (void)logEvent:(NSString *)eventName; 34 | + (void)logEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters; 35 | + (void)logError:(NSString *)errorID message:(NSString *)message exception:(NSException *)exception; 36 | + (void)logError:(NSString *)errorID message:(NSString *)message error:(NSError *)error; 37 | 38 | /* 39 | start or end timed events 40 | */ 41 | + (void)logEvent:(NSString *)eventName timed:(BOOL)timed; 42 | + (void)logEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters timed:(BOOL)timed; 43 | + (void)endTimedEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters; // non-nil parameters will update the parameters 44 | 45 | /* 46 | count page views 47 | */ 48 | + (void)countPageViews:(id)target; // automatically track page view on UINavigationController or UITabBarController 49 | + (void)countPageView; // manually increment page view by 1 50 | 51 | /* 52 | set user info 53 | */ 54 | + (void)setUserID:(NSString *)userID; // user's id in your system 55 | + (void)setAge:(int)age; // user's age in years 56 | + (void)setGender:(NSString *)gender; // user's gender m or f 57 | 58 | /* 59 | optional session settings that can be changed after start session 60 | */ 61 | + (void)setSessionReportsOnCloseEnabled:(BOOL)sendSessionReportsOnClose; // default is YES 62 | + (void)setSessionReportsOnPauseEnabled:(BOOL)setSessionReportsOnPauseEnabled; // default is YES 63 | + (void)setEventLoggingEnabled:(BOOL)value; // default is YES 64 | 65 | /* 66 | create an AppCircle banner on a hook and a view parent 67 | subsequent calls will return the same banner for the same hook and parent until removed with the API 68 | */ 69 | + (UIView *)getHook:(NSString *)hook xLoc:(int)x yLoc:(int)y view:(UIView *)view; 70 | /* 71 | create an AppCircle banner on a hook and view parent using optional parameters 72 | */ 73 | + (UIView *)getHook:(NSString *)hook xLoc:(int)x yLoc:(int)y view:(UIView *)view attachToView:(BOOL)attachToView orientation:(NSString *)orientation canvasOrientation:(NSString *)canvasOrientation autoRefresh:(BOOL)refresh canvasAnimated:(BOOL)canvasAnimated; 74 | /* 75 | update an existing AppCircle banner with a new ad 76 | */ 77 | + (void)updateHook:(UIView *)banner; 78 | /* 79 | remove an existing AppCircle banner from its hook and parent 80 | a new banner can be created on the same hook and parent after the existing banner is removed 81 | */ 82 | + (void)removeHook:(UIView *)banner; 83 | /* 84 | open the canvas without using a banner 85 | */ 86 | + (void)openCatalog:(NSString *)hook canvasOrientation:(NSString *)canvasOrientation canvasAnimated:(BOOL)canvasAnimated; 87 | /* 88 | refer to FlurryAdDelegate.h for delegate details 89 | */ 90 | + (void)setAppCircleDelegate:(id)delegate; 91 | 92 | // Only availible if using library with location services 93 | + (CLLocationManager *)startSessionWithLocationServices:(NSString *)apiKey; 94 | + (void)setLocation:(CLLocation *)location; 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /Flurry/iPhone v2.7 (build 42)/FlurryLibWithLocation/FlurryAdDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // FlurryAdDelegate.h 3 | // FlurryAnalytics 4 | // 5 | // Created by chunhao on 3/2/10. 6 | // Copyright 2010 Flurry Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @protocol FlurryAdDelegate 13 | 14 | @optional 15 | /* 16 | called after data is received 17 | */ 18 | - (void)dataAvailable; 19 | /* 20 | called after data is determined to be unavailable 21 | */ 22 | - (void)dataUnavailable; 23 | /* 24 | called before canvas displays 25 | code to pause app states can be set here 26 | */ 27 | - (void)canvasWillDisplay:(NSString *)hook; 28 | /* 29 | called before canvas closes 30 | code to resume app states can be set here 31 | */ 32 | - (void)canvasWillClose; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Flurry/iPhone v2.7 (build 42)/FlurryLibWithLocation/libFlurryWithLocation.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/Flurry/iPhone v2.7 (build 42)/FlurryLibWithLocation/libFlurryWithLocation.a -------------------------------------------------------------------------------- /README.mdown: -------------------------------------------------------------------------------- 1 | **Note: I consider this template deprecated. There are *much* better choices available now, like 2 | AFNetworking, JSONKit, HockeyKit, SSToolKit, ...** 3 | 4 | **Some stuff is really a bad idea (like Flurry), other is now integrated in Foundation (like regular expressions).** 5 | 6 | **I'll keep it around a little longer, but please don't use it anymore.** 7 | 8 | 9 | 10 | 11 | 12 | This is a working start point for an iOS App. All the little bits are set for you. 13 | Remember to init all submodules: 14 | 15 | git submodule init 16 | 17 | git submodule update 18 | 19 | This basic template opens a PSTableViewController connected to a navigationController, all in code (there are no nibs). 20 | 21 | Whats in the box? 22 | ----------------- 23 | 24 | * Localization for English/German pre-setup 25 | 26 | * Xcode agnostic gitignore setup 27 | 28 | * Completely setup autoupdating via Hockey, with custom Target for instant App-Distribution. 29 | All you need is to modify the ssh script in the BetaDistribute target and setup a server with the Hockey server parts: 30 | https://github.com/TheRealKerni/Hockey 31 | 32 | * Integrated Crash Reporter Server sender. Just activate in PSDefines and 33 | https://github.com/TheRealKerni/CrashReporterDemo 34 | 35 | * Adapted symbolicator for remove crash report symbolication 36 | 37 | * Integrated super fast and efficient YAJL JSON parser 38 | http://lloyd.github.com/yajl/ 39 | 40 | * PSFoundation for all those little categories, reachability and co: 41 | https://github.com/steipete/PSFoundation 42 | 43 | * Flurry for app statistics. Just add your statistics key to kFlurryStatisticsKey 44 | http://www.flurry.com/ 45 | 46 | * Custom logging (cocoa-lumberjack) with file logging and NSLogger integration 47 | See https://github.com/robbiehanson/CocoaLumberjack and https://github.com/fpillet/NSLogger 48 | 49 | * Colored Logging-Output using XcodeColors in Simulator 50 | http://deepit.ru/products/XcodeColors/info/ 51 | 52 | * RegexKitLite 53 | http://regexkit.sourceforge.net/RegexKitLite/ 54 | 55 | * FTLocationSimualtor for debugging CoreLocation in the Simulator 56 | https://github.com/futuretap/FTLocationSimulator 57 | 58 | 59 | * asi-http-request for everything http-related; better alternative to NSURLConnection 60 | https://github.com/pokeb/asi-http-request 61 | 62 | Note: This Template uses many software components, all of them under various open source licenses which some of them with the need for Acknowledgements, see the source files and Acknowledgements.txt for more information. 63 | -------------------------------------------------------------------------------- /ReleaseNotes.html: -------------------------------------------------------------------------------- 1 | Transparent Kittens!!! -------------------------------------------------------------------------------- /STYLEGUIDE.md: -------------------------------------------------------------------------------- 1 | # Guidelines 2 | 3 | * All commits are in English language, lowercase (except class and method names; as defined), short and precise 4 | * All classes are prefixed with default class prefix. e.g. "PS" 5 | * Use spaces in Xcode 6 | * Install and use [git-flow](http://github.com/nvie/gitflow) 7 | * Code has to be formatted as stated in the sample code below 8 | * Don't commit huge files into the repository 9 | * Development is done on the 'develop' branch created by git-flow, never on master 10 | * Experimental feature branches are prefixed with 'x-' 11 | * Only letters from 'a' to 'z' and hyphens are used in branch names 12 | 13 | # Code Style Example 14 | 15 | Sample Header: 16 | 17 | // GTMFoo.h 18 | // FooProject 19 | // 20 | // Created by Greg Miller on 6/13/08. 21 | // Copyright 2008 Google, Inc. All rights reserved. 22 | // 23 | 24 | #import 25 | 26 | // A sample class demonstrating good Objective-C style. All interfaces, 27 | // categories, and protocols (read: all top-level declarations in a header) 28 | // MUST be commented. Comments must also be adjacent to the object they're 29 | // documenting. 30 | // 31 | // (no blank line between this comment and the interface) 32 | @interface GTMFoo : NSObject { 33 | NSString *stringProperty_; 34 | NSObject *otherObject_; 35 | NSString *foo_; 36 | NSString *bar_; 37 | } 38 | 39 | // Always copy NSStrings 40 | @property (nonatomic, copy) NSString *stringProperty; 41 | 42 | // Other objects are simply retained 43 | @property (nonatomic, retain) NSObject *otherObject; 44 | 45 | // Returns an autoreleased instance of GMFoo. See -initWithString: for details 46 | // about the argument. 47 | + (id)fooWithString:(NSString *)string; 48 | 49 | // Designated initializer. |string| will be copied and assigned to |foo_|. 50 | - (id)initWithString:(NSString *)string; 51 | 52 | // Gets and sets the string for |foo_|. 53 | - (NSString *)foo; 54 | - (void)setFoo:(NSString *)newFoo; 55 | 56 | // Does some work on |blah| and returns YES if the work was completed 57 | // successfuly, and NO otherwise. 58 | - (BOOL)doWorkWithString:(NSString *)blah; 59 | 60 | @end 61 | 62 | Sample Implementation: 63 | 64 | // 65 | // GTMFoo.m 66 | // FooProject 67 | // 68 | // Created by Greg Miller on 6/13/08. 69 | // Copyright 2008 Google, Inc. All rights reserved. 70 | // 71 | 72 | #import "GTMFoo.h" 73 | 74 | @implementation GTMFoo 75 | @synthesize stringProperty; 76 | @synthesize otherProperty; 77 | 78 | + (id)fooWithString:(NSString *)string { 79 | return [[[self alloc] initWithString:string] autorelease]; 80 | } 81 | 82 | // Must always override super's designated initializer. 83 | - (id)init { 84 | return [self initWithString:nil]; 85 | } 86 | 87 | - (id)initWithString:(NSString *)string { 88 | if (self = [super init]) { 89 | foo_ = [string copy]; 90 | bar_ = [[NSString alloc] initWithFormat:@"hi %d", 3]; 91 | } 92 | return self; 93 | } 94 | 95 | - (void)dealloc { 96 | MCRelease(foo_); 97 | MCRelease(bar_); 98 | 99 | [super dealloc]; 100 | } 101 | 102 | - (NSString *)foo { 103 | return foo_; 104 | } 105 | 106 | - (void)setFoo:(NSString *)newFoo { 107 | [foo_ autorelease]; 108 | foo_ = [newFoo copy]; 109 | } 110 | 111 | - (BOOL)doWorkWithString:(NSString *)blah { 112 | // ... 113 | return NO; 114 | } 115 | 116 | @end 117 | 118 | -------------------------------------------------------------------------------- /Xcode/appstore.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // appstore.xcconfig 3 | // 4 | 5 | #include "buildnumber.xcconfig" 6 | #include "appversion.xcconfig" 7 | -------------------------------------------------------------------------------- /Xcode/appversion.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // appbuilder.xcconfig 3 | // 4 | 5 | APP_VERSION = 1.0.0 6 | -------------------------------------------------------------------------------- /Xcode/buildnumber.xcconfig: -------------------------------------------------------------------------------- 1 | BUILD_NUMBER = 39 -------------------------------------------------------------------------------- /Xcode/debug.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // debug.xcconfig 3 | // 4 | 5 | #include "buildnumber.xcconfig" 6 | #include "appversion.xcconfig" 7 | -------------------------------------------------------------------------------- /Xcode/distribution.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // distribution.xcconfig 3 | // 4 | 5 | #include "buildnumber.xcconfig" 6 | #include "appversion.xcconfig" 7 | -------------------------------------------------------------------------------- /Xcode/increase.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steipete/PSiOSAppTemplate/44854377e15c1142cbf85a9cc9a07d1b5a4a3a03/Xcode/increase.sh -------------------------------------------------------------------------------- /regexkitlite/License.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | RegexKitLite License 13 | 14 | 15 |
16 |

RegexKitList License

17 | 18 |

Copyright © 2008-2010, John Engelhart

19 | 20 |

All rights reserved.

21 | 22 |

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

23 | 24 |
    25 |
  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • 26 |
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • 27 |
  • Neither the name of the Zang Industries nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
  • 28 |
29 | 30 |

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /regexkitlite/License.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf290 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset0 LucidaGrande;\f2\fmodern\fcharset0 Courier; 3 | } 4 | {\colortbl;\red255\green255\blue255;} 5 | {\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid1}} 6 | {\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}} 7 | \margl1440\margr1440\vieww10960\viewh15160\viewkind0 8 | \deftab720 9 | \pard\pardeftab720\sa180\ql\qnatural 10 | 11 | \f0\b\fs38 \cf0 RegexKit 12 | \i Lite 13 | \i0 License 14 | \f1 \ 15 | \pard\pardeftab720\sa240\ql\qnatural 16 | 17 | \b0\fs24 \cf0 Copyright \'a9 2008-2010, John Engelhart\ 18 | All rights reserved.\ 19 | \pard\pardeftab720\sa240\qj 20 | \cf0 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\ 21 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa180\qj 22 | \ls1\ilvl0\cf0 {\listtext \'95 }Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\ 23 | {\listtext \'95 }Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\ 24 | {\listtext \'95 }Neither the name of the Zang Industries nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\ 25 | \pard\pardeftab720\sa240\qj 26 | 27 | \f2 \cf0 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.} -------------------------------------------------------------------------------- /regexkitlite/RegexKitLite.h: -------------------------------------------------------------------------------- 1 | // 2 | // RegexKitLite.h 3 | // http://regexkit.sourceforge.net/ 4 | // Licensed under the terms of the BSD License, as specified below. 5 | // 6 | 7 | /* 8 | Copyright (c) 2008-2010, John Engelhart 9 | 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | * Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 18 | * Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | 22 | * Neither the name of the Zang Industries nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 32 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 33 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 34 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 35 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | #ifdef __OBJC__ 40 | #import 41 | #import 42 | #import 43 | #import 44 | #import 45 | #endif // __OBJC__ 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | #ifndef REGEXKITLITE_VERSION_DEFINED 58 | #define REGEXKITLITE_VERSION_DEFINED 59 | 60 | #define _RKL__STRINGIFY(b) #b 61 | #define _RKL_STRINGIFY(a) _RKL__STRINGIFY(a) 62 | #define _RKL_JOIN_VERSION(a,b) _RKL_STRINGIFY(a##.##b) 63 | #define _RKL_VERSION_STRING(a,b) _RKL_JOIN_VERSION(a,b) 64 | 65 | #define REGEXKITLITE_VERSION_MAJOR 4 66 | #define REGEXKITLITE_VERSION_MINOR 0 67 | 68 | #define REGEXKITLITE_VERSION_CSTRING _RKL_VERSION_STRING(REGEXKITLITE_VERSION_MAJOR, REGEXKITLITE_VERSION_MINOR) 69 | #define REGEXKITLITE_VERSION_NSSTRING @REGEXKITLITE_VERSION_CSTRING 70 | 71 | #endif // REGEXKITLITE_VERSION_DEFINED 72 | 73 | #if !defined(RKL_BLOCKS) && defined(NS_BLOCKS_AVAILABLE) && (NS_BLOCKS_AVAILABLE == 1) 74 | #define RKL_BLOCKS 1 75 | #endif 76 | 77 | #if defined(RKL_BLOCKS) && (RKL_BLOCKS == 1) 78 | #define _RKL_BLOCKS_ENABLED 1 79 | #endif // defined(RKL_BLOCKS) && (RKL_BLOCKS == 1) 80 | 81 | #if defined(_RKL_BLOCKS_ENABLED) && !defined(__BLOCKS__) 82 | #warning RegexKitLite support for Blocks is enabled, but __BLOCKS__ is not defined. This compiler may not support Blocks, in which case the behavior is undefined. This will probably cause numerous compiler errors. 83 | #endif // defined(_RKL_BLOCKS_ENABLED) && !defined(__BLOCKS__) 84 | 85 | // For Mac OS X < 10.5. 86 | #ifndef NSINTEGER_DEFINED 87 | #define NSINTEGER_DEFINED 88 | #if defined(__LP64__) || defined(NS_BUILD_32_LIKE_64) 89 | typedef long NSInteger; 90 | typedef unsigned long NSUInteger; 91 | #define NSIntegerMin LONG_MIN 92 | #define NSIntegerMax LONG_MAX 93 | #define NSUIntegerMax ULONG_MAX 94 | #else // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64) 95 | typedef int NSInteger; 96 | typedef unsigned int NSUInteger; 97 | #define NSIntegerMin INT_MIN 98 | #define NSIntegerMax INT_MAX 99 | #define NSUIntegerMax UINT_MAX 100 | #endif // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64) 101 | #endif // NSINTEGER_DEFINED 102 | 103 | #ifndef RKLREGEXOPTIONS_DEFINED 104 | #define RKLREGEXOPTIONS_DEFINED 105 | 106 | // These must be identical to their ICU regex counterparts. See http://www.icu-project.org/userguide/regexp.html 107 | enum { 108 | RKLNoOptions = 0, 109 | RKLCaseless = 2, 110 | RKLComments = 4, 111 | RKLDotAll = 32, 112 | RKLMultiline = 8, 113 | RKLUnicodeWordBoundaries = 256 114 | }; 115 | typedef uint32_t RKLRegexOptions; // This must be identical to the ICU 'flags' argument type. 116 | 117 | #endif // RKLREGEXOPTIONS_DEFINED 118 | 119 | #ifndef RKLREGEXENUMERATIONOPTIONS_DEFINED 120 | #define RKLREGEXENUMERATIONOPTIONS_DEFINED 121 | 122 | enum { 123 | RKLRegexEnumerationNoOptions = 0UL, 124 | RKLRegexEnumerationCapturedStringsNotRequired = 1UL << 9, 125 | RKLRegexEnumerationReleaseStringReturnedByReplacementBlock = 1UL << 10, 126 | RKLRegexEnumerationFastCapturedStringsXXX = 1UL << 11, 127 | }; 128 | typedef NSUInteger RKLRegexEnumerationOptions; 129 | 130 | #endif // RKLREGEXENUMERATIONOPTIONS_DEFINED 131 | 132 | #ifndef _REGEXKITLITE_H_ 133 | #define _REGEXKITLITE_H_ 134 | 135 | #if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__APPLE_CC__) && (__APPLE_CC__ >= 5465) 136 | #define RKL_DEPRECATED_ATTRIBUTE __attribute__((deprecated)) 137 | #else 138 | #define RKL_DEPRECATED_ATTRIBUTE 139 | #endif 140 | 141 | #if defined(NS_REQUIRES_NIL_TERMINATION) 142 | #define RKL_REQUIRES_NIL_TERMINATION NS_REQUIRES_NIL_TERMINATION 143 | #else // defined(NS_REQUIRES_NIL_TERMINATION) 144 | #define RKL_REQUIRES_NIL_TERMINATION 145 | #endif // defined(NS_REQUIRES_NIL_TERMINATION) 146 | 147 | // This requires a few levels of rewriting to get the desired results. 148 | #define _RKL_CONCAT_2(c,d) c ## d 149 | #define _RKL_CONCAT(a,b) _RKL_CONCAT_2(a,b) 150 | 151 | #ifdef RKL_PREPEND_TO_METHODS 152 | #define RKL_METHOD_PREPEND(x) _RKL_CONCAT(RKL_PREPEND_TO_METHODS, x) 153 | #else // RKL_PREPEND_TO_METHODS 154 | #define RKL_METHOD_PREPEND(x) x 155 | #endif // RKL_PREPEND_TO_METHODS 156 | 157 | // If it looks like low memory notifications might be available, add code to register and respond to them. 158 | // This is (should be) harmless if it turns out that this isn't the case, since the notification that we register for, 159 | // UIApplicationDidReceiveMemoryWarningNotification, is dynamically looked up via dlsym(). 160 | #if ((defined(TARGET_OS_EMBEDDED) && (TARGET_OS_EMBEDDED != 0)) || (defined(TARGET_OS_IPHONE) && (TARGET_OS_IPHONE != 0))) && (!defined(RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS) || (RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS != 0)) 161 | #define RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS 1 162 | #endif 163 | 164 | #ifdef __OBJC__ 165 | 166 | // NSException exception name. 167 | extern NSString * const RKLICURegexException; 168 | 169 | // NSError error domains and user info keys. 170 | extern NSString * const RKLICURegexErrorDomain; 171 | 172 | extern NSString * const RKLICURegexEnumerationOptionsErrorKey; 173 | extern NSString * const RKLICURegexErrorCodeErrorKey; 174 | extern NSString * const RKLICURegexErrorNameErrorKey; 175 | extern NSString * const RKLICURegexLineErrorKey; 176 | extern NSString * const RKLICURegexOffsetErrorKey; 177 | extern NSString * const RKLICURegexPreContextErrorKey; 178 | extern NSString * const RKLICURegexPostContextErrorKey; 179 | extern NSString * const RKLICURegexRegexErrorKey; 180 | extern NSString * const RKLICURegexRegexOptionsErrorKey; 181 | extern NSString * const RKLICURegexReplacedCountErrorKey; 182 | extern NSString * const RKLICURegexReplacedStringErrorKey; 183 | extern NSString * const RKLICURegexReplacementStringErrorKey; 184 | extern NSString * const RKLICURegexSubjectRangeErrorKey; 185 | extern NSString * const RKLICURegexSubjectStringErrorKey; 186 | 187 | @interface NSString (RegexKitLiteAdditions) 188 | 189 | + (void)RKL_METHOD_PREPEND(clearStringCache); 190 | 191 | // Although these are marked as deprecated, a bug in GCC prevents a warning from being issues for + class methods. Filed bug with Apple, #6736857. 192 | + (NSInteger)RKL_METHOD_PREPEND(captureCountForRegex):(NSString *)regex RKL_DEPRECATED_ATTRIBUTE; 193 | + (NSInteger)RKL_METHOD_PREPEND(captureCountForRegex):(NSString *)regex options:(RKLRegexOptions)options error:(NSError **)error RKL_DEPRECATED_ATTRIBUTE; 194 | 195 | - (NSArray *)RKL_METHOD_PREPEND(componentsSeparatedByRegex):(NSString *)regex; 196 | - (NSArray *)RKL_METHOD_PREPEND(componentsSeparatedByRegex):(NSString *)regex range:(NSRange)range; 197 | - (NSArray *)RKL_METHOD_PREPEND(componentsSeparatedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error; 198 | 199 | - (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString *)regex; 200 | - (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString *)regex inRange:(NSRange)range; 201 | - (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error; 202 | 203 | - (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex; 204 | - (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex capture:(NSInteger)capture; 205 | - (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex inRange:(NSRange)range; 206 | - (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range capture:(NSInteger)capture error:(NSError **)error; 207 | 208 | - (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex; 209 | - (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex capture:(NSInteger)capture; 210 | - (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex inRange:(NSRange)range; 211 | - (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range capture:(NSInteger)capture error:(NSError **)error; 212 | 213 | - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement; 214 | - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement range:(NSRange)searchRange; 215 | - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement options:(RKLRegexOptions)options range:(NSRange)searchRange error:(NSError **)error; 216 | 217 | //// >= 3.0 218 | 219 | - (NSInteger)RKL_METHOD_PREPEND(captureCount); 220 | - (NSInteger)RKL_METHOD_PREPEND(captureCountWithOptions):(RKLRegexOptions)options error:(NSError **)error; 221 | 222 | - (BOOL)RKL_METHOD_PREPEND(isRegexValid); 223 | - (BOOL)RKL_METHOD_PREPEND(isRegexValidWithOptions):(RKLRegexOptions)options error:(NSError **)error; 224 | 225 | - (void)RKL_METHOD_PREPEND(flushCachedRegexData); 226 | 227 | - (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex; 228 | - (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex capture:(NSInteger)capture; 229 | - (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex range:(NSRange)range; 230 | - (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range capture:(NSInteger)capture error:(NSError **)error; 231 | 232 | 233 | - (NSArray *)RKL_METHOD_PREPEND(captureComponentsMatchedByRegex):(NSString *)regex; 234 | - (NSArray *)RKL_METHOD_PREPEND(captureComponentsMatchedByRegex):(NSString *)regex range:(NSRange)range; 235 | - (NSArray *)RKL_METHOD_PREPEND(captureComponentsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error; 236 | 237 | - (NSArray *)RKL_METHOD_PREPEND(arrayOfCaptureComponentsMatchedByRegex):(NSString *)regex; 238 | - (NSArray *)RKL_METHOD_PREPEND(arrayOfCaptureComponentsMatchedByRegex):(NSString *)regex range:(NSRange)range; 239 | - (NSArray *)RKL_METHOD_PREPEND(arrayOfCaptureComponentsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error; 240 | 241 | //// >= 4.0 242 | 243 | - (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION; 244 | - (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex range:(NSRange)range withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION; 245 | - (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION; 246 | - (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withFirstKey:(id)firstKey arguments:(va_list)varArgsList; 247 | 248 | - (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeys:(id *)keys forCaptures:(int *)captures count:(NSUInteger)count; 249 | 250 | - (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION; 251 | - (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex range:(NSRange)range withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION; 252 | - (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION; 253 | - (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withFirstKey:(id)firstKey arguments:(va_list)varArgsList; 254 | 255 | - (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeys:(id *)keys forCaptures:(int *)captures count:(NSUInteger)count; 256 | 257 | #ifdef _RKL_BLOCKS_ENABLED 258 | 259 | - (BOOL)RKL_METHOD_PREPEND(enumerateStringsMatchedByRegex):(NSString *)regex usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block; 260 | - (BOOL)RKL_METHOD_PREPEND(enumerateStringsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block; 261 | 262 | - (BOOL)RKL_METHOD_PREPEND(enumerateStringsSeparatedByRegex):(NSString *)regex usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block; 263 | - (BOOL)RKL_METHOD_PREPEND(enumerateStringsSeparatedByRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block; 264 | 265 | - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block; 266 | - (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block; 267 | 268 | #endif // _RKL_BLOCKS_ENABLED 269 | 270 | @end 271 | 272 | @interface NSMutableString (RegexKitLiteAdditions) 273 | 274 | - (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement; 275 | - (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement range:(NSRange)searchRange; 276 | - (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement options:(RKLRegexOptions)options range:(NSRange)searchRange error:(NSError **)error; 277 | 278 | //// >= 4.0 279 | 280 | #ifdef _RKL_BLOCKS_ENABLED 281 | 282 | - (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block; 283 | - (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block; 284 | 285 | #endif // _RKL_BLOCKS_ENABLED 286 | 287 | @end 288 | 289 | #endif // __OBJC__ 290 | 291 | #endif // _REGEXKITLITE_H_ 292 | 293 | #ifdef __cplusplus 294 | } // extern "C" 295 | #endif 296 | -------------------------------------------------------------------------------- /symbolicator/com.crashreportsender.symbolicator.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | com.crashreportsender.symbolicator 7 | ProgramArguments 8 | 9 | /symbolicate.sh 10 | 11 | RunAtLoad 12 | 13 | StartInterval 14 | 900 15 | 16 | 17 | -------------------------------------------------------------------------------- /symbolicator/serverconfig.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * Copyright (c) 2009 Andreas Linde. All rights reserved. 8 | * All rights reserved. 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, 14 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the 16 | * Software is furnished to do so, subject to the following 17 | * conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 24 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 26 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 29 | * OTHER DEALINGS IN THE SOFTWARE. 30 | */ 31 | 32 | $hostname = 'hostname.com'; // the server hosting the scripts 33 | $webuser = ''; // if you restricted /admin/ with .htaccess 34 | $webpwd = ''; // if you restricted /admin/ with .htaccess 35 | $downloadtodosurl = '/crashreporter/admin/symbolicate_todo.php'; // the path to the script delivering the todo list 36 | $getcrashdataurl = '/crashreporter/admin/crash_get.php?id='; // the path to the script delivering the crashlog 37 | $updatecrashdataurl = '/crashreporter/admin/crash_update.php'; // the path to the script updating the crashlog 38 | 39 | ?> -------------------------------------------------------------------------------- /symbolicator/symbolicate.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * Copyright (c) 2009 Andreas Linde. All rights reserved. 7 | * All rights reserved. 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, 13 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the 15 | * Software is furnished to do so, subject to the following 16 | * conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 23 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 25 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 28 | * OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | // 32 | // Symbolicate a list of crash logs locally 33 | // 34 | // This script symbolicates crash log data on a local machine by 35 | // querying a remote server for a todo list of crash logs and 36 | // using remote script to fetch the crash log data and also update 37 | // the very same on the remote servers 38 | // 39 | 40 | include "serverconfig.php"; 41 | 42 | function doPost($postdata) 43 | { 44 | global $updatecrashdataurl, $hostname, $webuser, $webpwd; 45 | 46 | $uri = $updatecrashdataurl; 47 | $host = $hostname; 48 | $handle = fsockopen($host, 80, $errno, $errstr); 49 | if (!$handle) { 50 | return 'error'; 51 | } 52 | else { 53 | $temp = "POST ".$uri." HTTP/1.1\r\n"; 54 | $temp .= "Host: ".$host."\r\n"; 55 | $temp .= "User-Agent: PHP Script\r\n"; 56 | $temp .= "Content-Type: application/x-www-form-urlencoded\r\n"; 57 | if ($webuser != "" && $webpwd != "") 58 | $temp .= "Authorization: Basic ".base64_encode($webuser.":".$webpwd)."\r\n"; 59 | $temp .= "Content-Length: ".strlen($postdata)."\r\n"; 60 | $temp .= "Connection: close\r\n\r\n"; 61 | $temp .= $postdata; 62 | $temp .= "\r\n\r\n"; 63 | 64 | fwrite($handle, $temp); 65 | 66 | $response = ''; 67 | 68 | while (!feof($handle)) 69 | $response.=fgets($handle, 128); 70 | 71 | $response=split("\r\n\r\n",$response); 72 | 73 | $header=$response[0]; 74 | $responsecontent=$response[1]; 75 | 76 | if(!(strpos($header,"Transfer-Encoding: chunked")===false)) 77 | { 78 | $aux=split("\r\n",$responsecontent); 79 | for($i=0;$i 0) 105 | { 106 | echo "To do list: ".$content."\n\n"; 107 | $crashids = split(',', $content); 108 | foreach ($crashids as $crashid) 109 | { 110 | $filename = $crashid.".crash"; 111 | $resultfilename = "result_".$crashid.".crash"; 112 | 113 | echo "Processing crash id ".$crashid." ...\n"; 114 | 115 | 116 | echo " Downloading crash data ...\n"; 117 | 118 | $log = file_get_contents($getcrashdataurl.$crashid); 119 | 120 | if ($log !== false && strlen($log) > 0) 121 | { 122 | echo " Writing log data into temporary file ...\n"; 123 | 124 | $output = fopen($filename, 'w+'); 125 | fwrite($output, $log); 126 | fclose($output); 127 | 128 | 129 | echo " Symbolicating ...\n"; 130 | 131 | exec('perl '.'./symbolicatecrash.pl -o '.$resultfilename.' '.$filename); 132 | 133 | unlink($filename); 134 | 135 | if (file_exists($resultfilename) && filesize($resultfilename) > 0) 136 | { 137 | echo " Sending symbolicated data back to the server ...\n"; 138 | 139 | $resultcontent = file_get_contents($resultfilename); 140 | 141 | $post_results = doPost('id='.$crashid.'&log='.urlencode($resultcontent)); 142 | 143 | if (is_string($post_results)) 144 | { 145 | if ($post_results == 'success') 146 | echo ' SUCCESS!'; 147 | } 148 | 149 | } 150 | 151 | 152 | echo " Deleting temporary files ...\n"; 153 | 154 | unlink($resultfilename); 155 | } 156 | } 157 | 158 | echo "\nDone\n\n"; 159 | 160 | } else if ($content !== false) { 161 | echo "Nothing to do.\n\n"; 162 | } 163 | 164 | 165 | ?> -------------------------------------------------------------------------------- /symbolicator/symbolicate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | php symbolicate.php 3 | # EOF 4 | -------------------------------------------------------------------------------- /symbolicator/symbolicatecrash.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # This script parses a crashdump file and attempts to resolve addresses into function names. 4 | # 5 | # It finds symbol-rich binaries by: 6 | # a) searching in Spotlight to find .dSYM files by UUID, then finding the executable from there. 7 | # That finds the symbols for binaries that a developer has built with "DWARF with dSYM File". 8 | # b) searching in various SDK directories. 9 | # 10 | # Copyright (c) 2008-2009 Apple Inc.. All Rights Reserved. 11 | # 12 | # 13 | 14 | use strict; 15 | use warnings; 16 | use Getopt::Std; 17 | use Cwd qw(realpath); 18 | 19 | ############################# 20 | 21 | # Forward definitons 22 | sub usage(); 23 | 24 | ############################# 25 | 26 | # read and parse command line 27 | my %opt; 28 | $Getopt::Std::STANDARD_HELP_VERSION = 1; 29 | 30 | getopts('Ahvo:',\%opt); 31 | 32 | usage() if $opt{'h'}; 33 | 34 | ############################# 35 | 36 | # have this thing to de-HTMLize Leopard-era plists 37 | my %entity2char = ( 38 | # Some normal chars that have special meaning in SGML context 39 | amp => '&', # ampersand 40 | 'gt' => '>', # greater than 41 | 'lt' => '<', # less than 42 | quot => '"', # double quote; this " character in the comment keeps Xcode syntax coloring happy 43 | apos => "'", # single quote ' 44 | ); 45 | 46 | # Array of all the supported architectures. 47 | my %architectures = ( 48 | ARM => "armv6", 49 | X86 => "i386", 50 | "X86-64" => "x86_64", 51 | PPC => "ppc", 52 | "PPC-64" => "ppc64", 53 | "ARMV4T" => "armv4t", 54 | "ARMV5" => "armv5", 55 | "ARMV6" => "armv6", 56 | "ARMV7" => "armv7", 57 | ); 58 | ############################# 59 | 60 | 61 | my $devToolsPath = `/usr/bin/xcode-select -print-path`; 62 | chomp $devToolsPath; 63 | 64 | # Find otool from the latest iphoneos 65 | my $otool = `xcrun -sdk iphoneos -find otool`; 66 | chomp($otool); 67 | my $atos = `xcrun -sdk iphoneos -find atos`; 68 | chomp($atos); 69 | 70 | if ( ! -f $otool ) { 71 | # if that doesn't exist, then assume the PDK was installed 72 | $otool = "/usr/bin/otool"; 73 | $atos = "/usr/bin/atos"; 74 | } 75 | print STDERR "otool path is '$otool'\n" if $opt{v}; 76 | print STDERR "atos path is '$atos'\n" if $opt{v}; 77 | 78 | # quotemeta makes the paths such that -f can't be used 79 | $devToolsPath = quotemeta($devToolsPath); 80 | $otool = quotemeta($otool); 81 | $atos = quotemeta($atos); 82 | 83 | 84 | ############################# 85 | # run the script 86 | 87 | symbolicate_log(@ARGV); 88 | 89 | 90 | ############################# 91 | 92 | # begin subroutines 93 | 94 | sub HELP_MESSAGE() { 95 | usage(); 96 | } 97 | 98 | sub usage() { 99 | print STDERR <] LOGFILE [SYMBOL_PATH ...] 102 | 103 | Symbolicates a crashdump LOGFILE which may be "-" to refer to stdin. By default, 104 | all heuristics will be employed in an attempt to symbolicate all addresses. 105 | Additional symbol files can be found under specified directories. 106 | 107 | Options: 108 | 109 | -A Only symbolicate the application, not libraries 110 | -o If specified, the symbolicated log will be written to OUTPUT_FILE (defaults to stdout) 111 | -h Display this message 112 | -v Verbose 113 | EOF 114 | exit 1; 115 | } 116 | 117 | ############## 118 | 119 | sub getSymbolDirPaths { 120 | my ($osBuild) = @_; 121 | 122 | my @devToolsPaths = ($devToolsPath); 123 | 124 | my @foundPaths = `mdfind -onlyin / "kMDItemCFBundleIdentifier == 'com.apple.Xcode'"`; 125 | 126 | foreach my $foundPath (@foundPaths) { 127 | chomp $foundPath; 128 | $foundPath =~ s/\/Applications\/Xcode.app$//; 129 | $foundPath = quotemeta($foundPath); 130 | if( $foundPath ne $devToolsPath ) { 131 | push(@devToolsPaths, $foundPath); 132 | } 133 | } 134 | 135 | my @result = (); 136 | 137 | foreach my $foundDevToolsPath (@devToolsPaths) { 138 | my $symbolDirs = $foundDevToolsPath . '\/Platforms\/*\.platform/DeviceSupport\/*\/Symbols*'; 139 | my @pathResults = grep { -e && -d && !/Simulator/ } glob $symbolDirs; 140 | print STDERR "Symbol directory paths: @pathResults\n" if $opt{v}; 141 | push(@result, @pathResults); 142 | } 143 | 144 | my @pathsForOSbuild = grep { /\($osBuild\)/ } @result; 145 | if ( @pathsForOSbuild >= 1) { 146 | print STDERR "Symbol directory path(s) for build $osBuild: @pathsForOSbuild\n" if $opt{v}; 147 | return @pathsForOSbuild; 148 | } else { 149 | # hmm, didn't find a path for the specific build, so return all the paths we got. 150 | return @result; 151 | } 152 | } 153 | 154 | sub getSymbolPathFor_searchpaths { 155 | my ($bin,$path,$build,@extra_search_paths) = @_; 156 | my @result; 157 | for my $item (@extra_search_paths) 158 | { 159 | my $glob = ""; 160 | 161 | $glob .= quotemeta($item) . '\/' . quotemeta($bin) . "*"; 162 | $glob .= " " . quotemeta($item) . '\/*\/' . quotemeta($bin) . "*"; 163 | $glob .= " " . quotemeta($item) . quotemeta($path) . "*"; 164 | 165 | #print STDERR "\nSearching [$glob]..." if $opt{v}; 166 | push(@result, grep { -e && (! -d) } glob $glob); 167 | } 168 | 169 | print STDERR "\nSearching [@result]..." if $opt{v}; 170 | return @result; 171 | } 172 | 173 | sub getSymbolPathFor_uuid{ 174 | my ($uuid, $uuidsPath) = @_; 175 | $uuid or return undef; 176 | $uuid =~ /(.{4})(.{4})(.{4})(.{4})(.{4})(.{4})(.{8})/; 177 | return Cwd::realpath("$uuidsPath/$1/$2/$3/$4/$5/$6/$7"); 178 | } 179 | 180 | # Look up a dsym file by UUID in Spotlight, then find the executable from the dsym. 181 | sub getSymbolPathFor_dsymUuid{ 182 | my ($uuid,$arch) = @_; 183 | $uuid or return undef; 184 | 185 | # Convert a uuid from the crash log, like "c42a118d722d2625f2357463535854fd", 186 | # to canonical format like "C42A118D-722D-2625-F235-7463535854FD". 187 | my $myuuid = uc($uuid); # uuid's in Spotlight database are all uppercase 188 | $myuuid =~ /(.{8})(.{4})(.{4})(.{4})(.{12})/; 189 | $myuuid = "$1-$2-$3-$4-$5"; 190 | 191 | # Do the search in Spotlight. 192 | my $cmd = "mdfind \"com_apple_xcode_dsym_uuids == $myuuid\""; 193 | print STDERR "Running $cmd\n" if $opt{v}; 194 | my $dsymdir = `$cmd`; 195 | chomp $dsymdir; 196 | $dsymdir or return undef; 197 | $dsymdir = quotemeta($dsymdir); # quote the result to handle spaces in path and executable names 198 | print STDERR "dsym directory: $dsymdir\n" if $opt{v}; 199 | 200 | # Find the executable from the dsym. 201 | $dsymdir =~ /(.*)\/(.*).dSYM/; 202 | my $pathToDsym = $1; 203 | my $dsymBaseName = $2; 204 | my $executable = $dsymBaseName; 205 | $executable =~ s/\..*//g; # strip off the suffix, if any 206 | 207 | chop($executable); 208 | my @paths = glob "$pathToDsym/$dsymBaseName/{,$executable,Contents/MacOS/$executable}"; 209 | print STDERR "paths: @paths\n" if $opt{v}; 210 | 211 | my @executablePath = grep { -x && ! -d } glob "$pathToDsym/$dsymBaseName/{,$executable,Contents/MacOS/$executable}"; 212 | my $executableCount = @executablePath; 213 | if ( $executableCount > 1 ) { 214 | print STDERR "Found more than one executable for a dsym: @executablePath\n" if $opt{v}; 215 | } 216 | if ( $executableCount >= 1 ) { 217 | if ( !matchesUUID($executablePath[0], $uuid, $arch) ) { 218 | print STDERR "UUID doesn't match dsym for executable $executablePath[0]\n" if $opt{v}; 219 | } else { 220 | print STDERR "Found executable $executablePath[0]\n" if $opt{v}; 221 | return $executablePath[0]; 222 | } 223 | } 224 | print STDERR "Did not find executable for dsym\n" if $opt{v}; 225 | return undef; 226 | } 227 | 228 | ######### 229 | 230 | sub matchesUUID 231 | { 232 | my ($path, $uuid, $arch) = @_; 233 | 234 | if ( ! -f $path ) { 235 | print STDERR "## $path doesn't exist " if $opt{v}; 236 | return 0; 237 | } 238 | 239 | my $TEST_uuid = `$otool -arch $arch -l "$path"`; 240 | 241 | if ( $TEST_uuid =~ /uuid ((0x[0-9A-Fa-f]{2}\s+?){16})/ || $TEST_uuid =~ /uuid ([^\s]+)\s/ ) { 242 | my $test = $1; 243 | 244 | if ( $test =~ /^0x/ ) { 245 | # old style 0xnn 0xnn 0xnn ... on two lines 246 | $test = join("", split /\s*0x/, $test); 247 | 248 | $test =~ s/0x//g; ## remove 0x 249 | $test =~ s/\s//g; ## remove spaces 250 | } else { 251 | # new style XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 252 | $test =~ s/-//g; ## remove - 253 | $test = lc($test); 254 | } 255 | 256 | if ( $test eq $uuid ) { 257 | ## See that it isn't stripped. Even fully stripped apps have one symbol, so ensure that there is more than one. 258 | my ($nlocalsym) = $TEST_uuid =~ /nlocalsym\s+([0-9A-Fa-f]+)/; 259 | my ($nextdefsym) = $TEST_uuid =~ /nextdefsym\s+([0-9A-Fa-f]+)/; 260 | my $totalsym = $nextdefsym + $nlocalsym; 261 | print STDERR "\nNumber of symbols in $path: $nextdefsym + $nlocalsym = $totalsym\n" if $opt{v}; 262 | return 1 if ( $totalsym > 1 ); 263 | 264 | print STDERR "## $path appears to be stripped, skipping.\n" if $opt{v}; 265 | } else { 266 | print STDERR "Given UUID $uuid for '$path' is really UUID $test\n" if $opt{v}; 267 | } 268 | } else { 269 | print "Can't understand the output from otool ($TEST_uuid)"; 270 | } 271 | 272 | return 0; 273 | } 274 | 275 | 276 | sub getSymbolPathFor { 277 | my ($path,$build,$uuid,$arch,@extra_search_paths) = @_; 278 | 279 | # derive a few more parameters... 280 | my $bin = ($path =~ /^.*?([^\/]+)$/)[0]; # basename 281 | 282 | # This setting can be tailored for a specific environment. If it's not present, oh well... 283 | my $uuidsPath = "/Volumes/Build/UUIDToSymbolMap"; 284 | if ( ! -d $uuidsPath ) { 285 | #print STDERR "No '$uuidsPath' path visible." if $opt{v}; 286 | } 287 | 288 | # First try the simplest route, looking for a UUID match. 289 | my $out_path; 290 | $out_path = getSymbolPathFor_uuid($uuid, $uuidsPath); 291 | undef $out_path if ( defined($out_path) && !length($out_path) ); 292 | 293 | print STDERR "--[$out_path] " if defined($out_path) and $opt{v}; 294 | print STDERR "--[undef] " if !defined($out_path) and $opt{v}; 295 | 296 | if ( !defined($out_path) || !matchesUUID($out_path, $uuid, $arch)) { 297 | undef $out_path; 298 | 299 | for my $func ( 300 | \&getSymbolPathFor_searchpaths, 301 | ) { 302 | my @out_path_arr = &$func($bin,$path,$build,@extra_search_paths); 303 | if(@out_path_arr) { 304 | foreach my $temp_path (@out_path_arr) { 305 | 306 | print STDERR "--[$temp_path] " if defined($temp_path) and $opt{v}; 307 | print STDERR "--[undef] " if !defined($temp_path) and $opt{v}; 308 | 309 | if ( defined($temp_path) && matchesUUID($temp_path, $uuid, $arch) ) { 310 | $out_path = $temp_path; 311 | @out_path_arr = {}; 312 | } else { 313 | undef $temp_path; 314 | print STDERR "-- NO MATCH\n" if $opt{v}; 315 | } 316 | } 317 | } else { 318 | print STDERR "-- NO MATCH\n" if $opt{v}; 319 | } 320 | 321 | last if defined $out_path; 322 | } 323 | } 324 | # if $out_path is defined here, then we have already verified that the UUID matches 325 | if ( !defined($out_path) ) { 326 | undef $out_path; 327 | if ($path =~ m/^\/System\// || $path =~ m/^\/usr\//) { 328 | # Don't use Spotlight to try to find dsym by UUID for system dylibs, since they won't have dsyms. 329 | # We get here if the host system no longer has an SDK whose frameworks match the UUIDs in the crash logs. 330 | print STDERR "NOT searching in Spotlight for dsym with UUID of $path\n" if $opt{v}; 331 | } else { 332 | print STDERR "Searching in Spotlight for dsym with UUID of $path\n" if $opt{v}; 333 | $out_path = getSymbolPathFor_dsymUuid($uuid, $arch); 334 | undef $out_path if ( defined($out_path) && !length($out_path) ); 335 | } 336 | } 337 | 338 | if (defined($out_path)) { 339 | print STDERR "-- MATCH\n" if $opt{v}; 340 | return $out_path; 341 | } 342 | 343 | print STDERR "## Warning: Can't find any unstripped binary that matches version of $path\n" if $opt{v}; 344 | print STDERR "\n" if $opt{v}; 345 | 346 | return undef; 347 | } 348 | 349 | ########################### 350 | # crashlog parsing 351 | ########################### 352 | 353 | # options: 354 | # - regex: don't escape regex metas in name 355 | # - continuous: don't reset pos when done. 356 | # - multiline: expect content to be on many lines following name 357 | sub parse_section { 358 | my ($log_ref, $name, %arg ) = @_; 359 | my $content; 360 | 361 | $name = quotemeta($name) 362 | unless $arg{regex}; 363 | 364 | # content is thing from name to end of line... 365 | if( $$log_ref =~ m{ ^($name)\: [[:blank:]]* (.*?) $ }mgx ) { 366 | $content = $2; 367 | $name = $1; 368 | 369 | # or thing after that line. 370 | if($arg{multiline}) { 371 | $content = $1 if( $$log_ref =~ m{ 372 | \G\n # from end of last thing... 373 | (.*?) 374 | (?:\n\s*\n|$) # until next blank line or the end 375 | }sgx ); 376 | } 377 | } 378 | 379 | pos($$log_ref) = 0 380 | unless $arg{continuous}; 381 | 382 | return ($name,$content) if wantarray; 383 | return $content; 384 | } 385 | 386 | # convenience method over above 387 | sub parse_sections { 388 | my ($log_ref,$re,%arg) = @_; 389 | 390 | my ($name,$content); 391 | my %sections = (); 392 | 393 | while(1) { 394 | ($name,$content) = parse_section($log_ref,$re, regex=>1,continuous=>1,%arg); 395 | last unless defined $content; 396 | $sections{$name} = $content; 397 | } 398 | 399 | pos($$log_ref) = 0; 400 | return \%sections; 401 | } 402 | 403 | sub parse_images { 404 | my ($log_ref, $report_version) = @_; 405 | 406 | my $section = parse_section($log_ref,'Binary Images Description',multiline=>1); 407 | if (!defined($section)) { 408 | $section = parse_section($log_ref,'Binary Images',multiline=>1); # new format 409 | } 410 | if (!defined($section)) { 411 | die "Error: Can't find \"Binary Images\" section in log file"; 412 | } 413 | 414 | my @lines = split /\n/, $section; 415 | scalar @lines or die "Can't find binary images list: $$log_ref"; 416 | 417 | my %images = (); 418 | my ($pat, $app, %captures); 419 | 420 | # FIXME: This should probably be passed in as an argument 421 | my $default_arch = 'armv6'; 422 | 423 | #To get all the architectures for string matching. 424 | my $arch_flattened = join('|', values(%architectures)); 425 | 426 | # Once Perl 5.10 becomes the default in Mac OS X, named regexp 427 | # capture buffers of the style (?pattern) would make this 428 | # code much more sane. 429 | if($report_version == 102 || $report_version == 103) { # Leopard GM 430 | $pat = ' 431 | ^\s* (\w+) \s* \- \s* (\w+) \s* (?# the range base and extent [1,2] ) 432 | (\+)? (?# the application may have a + in front of the name [3] ) 433 | (.+) (?# bundle name [4] ) 434 | \s+ .+ \(.+\) \s* (?# the versions--generally "??? [???]" ) 435 | \? (?# possible UUID [5] ) 436 | \s* (\/.*)\s*$ (?# first fwdslash to end we hope is path [6] ) 437 | '; 438 | %captures = ( 'base' => \$1, 'extent' => \$2, 'plus' => \$3, 439 | 'bundlename' => \$4, 'uuid' => \$5, 'path' => \$6); 440 | } 441 | elsif($report_version == 104) { # Kirkwood 442 | $pat = ' 443 | ^\s* (\w+) \s* \- \s* (\w+) \s* (?# the range base and extent [1,2] ) 444 | (\+)? (?# the application may have a + in front of the name [3] ) 445 | (.+) (?# bundle name [4] ) 446 | \s+ ('.$arch_flattened.') \s+ (?# the image arch [5] ) 447 | \? (?# possible UUID [6] ) 448 | \s* (\/.*)\s*$ (?# first fwdslash to end we hope is path [7] ) 449 | '; 450 | %captures = ( 'base' => \$1, 'extent' => \$2, 'plus' => \$3, 451 | 'bundlename' => \$4, 'arch' => \$5, 'uuid' => \$6, 452 | 'path' => \$7); 453 | } 454 | elsif($report_version == 6) { # TheRealKerni 455 | $default_arch = 'i386'; 456 | $pat = ' 457 | ^\s* (\w+) \s* \- \s* (\w+) \s* (?# the range base and extent [1,2] ) 458 | (\+)? (?# the application may have a + in front of the name [3] ) 459 | (.+) (?# bundle name [4] ) 460 | \s+ .+ \(.+\) \s* (?# the versions--generally "??? [???]" ) 461 | \? (?# possible UUID [5] ) 462 | \s* (\/.*)\s*$ (?# first fwdslash to end we hope is path [6] ) 463 | '; 464 | %captures = ( 'base' => \$1, 'extent' => \$2, 'plus' => \$3, 465 | 'bundlename' => \$4, 'uuid' => \$5, 'path' => \$6); 466 | } 467 | 468 | for my $line (@lines) { 469 | next if $line =~ /PEF binary:/; # ignore these 470 | 471 | $line =~ s/(&(\w+);?)/$entity2char{$2} || $1/eg; 472 | 473 | if ($line =~ /$pat/ox) { 474 | # Dereference references 475 | my %image; 476 | while((my $key, my $val) = each(%captures)) { 477 | $image{$key} = ${$captures{$key}} || ''; 478 | #print "image{$key} = $image{$key}\n"; 479 | } 480 | 481 | if ($report_version == 6) { # TheRealKerni 482 | $image{uuid} =~ /(.{8})[-](.{4})[-](.{4})[-](.{4})[-](.{12})/; 483 | $image{uuid} = "$1$2$3$4$5"; 484 | } 485 | 486 | $image{uuid} = lc $image{uuid}; 487 | $image{arch} = $image{arch} || $default_arch; 488 | 489 | # Just take the first instance. That tends to be the app. 490 | my $bundlename = $image{bundlename}; 491 | $app = $bundlename if (!defined $app && defined $image{plus} && length $image{plus}); 492 | 493 | # frameworks and apps (and whatever) may share the same name, so disambiguate 494 | if ( defined($images{$bundlename}) ) { 495 | # follow the chain of hash items until the end 496 | my $nextIDKey = $bundlename; 497 | while ( length($nextIDKey) ) { 498 | last if ( !length($images{$nextIDKey}{nextID}) ); 499 | $nextIDKey = $images{$nextIDKey}{nextID}; 500 | } 501 | 502 | # add ourselves to that chain 503 | $images{$nextIDKey}{nextID} = $image{base}; 504 | 505 | # and store under the key we just recorded 506 | $bundlename = $bundlename . $image{base}; 507 | } 508 | 509 | # we are the end of the nextID chain 510 | $image{nextID} = ""; 511 | 512 | $images{$bundlename} = \%image; 513 | } 514 | } 515 | 516 | return (\%images, $app); 517 | } 518 | 519 | # if this is actually a partial binary identifier we know about, then 520 | # return the full name. else return undef. 521 | my %_partial_cache = (); 522 | sub resolve_partial_id { 523 | my ($bundle,$images) = @_; 524 | # is this partial? note: also stripping elipsis here 525 | return undef unless $bundle =~ s/^\.\.\.//; 526 | return $_partial_cache{$bundle} if exists $_partial_cache{$bundle}; 527 | 528 | my $re = qr/\Q$bundle\E$/; 529 | for (keys %$images) { 530 | if( /$re/ ) { 531 | $_partial_cache{$bundle} = $_; 532 | return $_; 533 | } 534 | } 535 | return undef; 536 | } 537 | 538 | # returns an oddly-constructed hash: 539 | # 'string-to-replace' => { bundle=>..., address=>... } 540 | sub parse_backtrace { 541 | my ($backtrace,$images) = @_; 542 | my @lines = split /\n/,$backtrace; 543 | 544 | my %frames = (); 545 | for my $line (@lines) { 546 | if( $line =~ m{ 547 | ^\d+ \s+ # stack frame number 548 | (\S.*?) \s+ # bundle id (1) 549 | ((0x\w+) \s+ # address (3) 550 | .*) \s* $ # current description, to be replaced (2) 551 | }x ) { 552 | my($bundle,$replace,$address) = ($1,$2,$3); 553 | #print STDERR "Parse_bt: $bundle,$replace,$address\n" if ($opt{v}); 554 | 555 | # disambiguate within our hash of binaries 556 | $bundle = findImageByNameAndAddress($images, $bundle, $address); 557 | 558 | # skip unless we know about the image of this frame 559 | next unless 560 | $$images{$bundle} or 561 | $bundle = resolve_partial_id($bundle,$images); 562 | 563 | $frames{$replace} = { 564 | 'address' => $address, 565 | 'bundle' => $bundle, 566 | }; 567 | 568 | } 569 | # else { print "unable to parse backtrace line $line\n" } 570 | } 571 | 572 | return \%frames; 573 | } 574 | 575 | sub slurp_file { 576 | my ($file) = @_; 577 | my $data; 578 | my $fh; 579 | my $readingFromStdin = 0; 580 | 581 | local $/ = undef; 582 | 583 | # - or "" mean read from stdin, otherwise use the given filename 584 | if($file && $file ne '-') { 585 | open $fh,"<",$file or die "while reading $file, $! : "; 586 | } else { 587 | open $fh,"<&STDIN" or die "while readin STDIN, $! : "; 588 | $readingFromStdin = 1; 589 | } 590 | 591 | $data = <$fh>; 592 | 593 | # Replace carriage returns 594 | $data =~ s/\r/\n/g; 595 | 596 | # Crash logs copied and pasted from Safari have a UTF-8 597 | # non-breaking space wherever they had an   character 598 | # in their HTML. This doesn't work out well when parsing 599 | # so we'll translate those characters to spaces. 600 | for ($data) { 601 | $_ =~ s/\xc2\xa0/ /g; 602 | } 603 | 604 | close $fh or die $!; 605 | return \$data; 606 | } 607 | 608 | sub parse_build { 609 | my ($log_ref) = @_; 610 | my $os = parse_section($log_ref,'OS Version'); 611 | $os =~ /\(Build (\w+)/ 612 | || $os =~ /\((\w+)\)/; # new format 613 | return $1; 614 | } 615 | 616 | # Map from the "Code Type" field of the crash log, to a Mac OS X 617 | # architecture name that can be understood by otool. 618 | sub parse_arch { 619 | my ($log_ref) = @_; 620 | my $codeType = parse_section($log_ref,'Code Type'); 621 | $codeType =~ /(\w+)/; 622 | my $arch = $architectures{$1}; 623 | die "Error: Unknown architecture $1" unless defined $arch; 624 | return $arch; 625 | } 626 | 627 | sub parse_report_version { 628 | my ($log_ref) = @_; 629 | my $version = parse_section($log_ref,'Report Version'); 630 | $version or return undef; 631 | $version =~ /(\d+)/; 632 | return $1; 633 | } 634 | 635 | sub findImageByNameAndAddress 636 | { 637 | my ($images,$bundle,$address) = @_; 638 | my $key = $bundle; 639 | 640 | #print STDERR "findImageByNameAndAddress($bundle,$address) ... "; 641 | 642 | my $binary = $$images{$bundle}; 643 | 644 | while( length($$binary{nextID}) ) { 645 | last if ( hex($address) >= hex($$binary{base}) && hex($address) <= hex($$binary{extent}) ); 646 | 647 | $key = $key . $$binary{nextID}; 648 | $binary = $$images{$key}; 649 | } 650 | 651 | #print STDERR "$key\n"; 652 | return $key; 653 | } 654 | 655 | sub prune_used_images { 656 | my ($images,$bt) = @_; 657 | 658 | # make a list of images actually used in backtrace 659 | my $images_used = {}; 660 | for(values %$bt) { 661 | #print STDERR "Pruning: $images, $$_{bundle}, $$_{address}\n" if ($opt{v}); 662 | my $imagename = findImageByNameAndAddress($images, $$_{bundle}, $$_{address}); 663 | $$images_used{$imagename} = $$images{$imagename}; 664 | } 665 | 666 | # overwrite the incoming image list with that; 667 | %$images = %$images_used; 668 | } 669 | 670 | # fetch symbolled binaries 671 | # array of binary image ranges and names 672 | # the OS build 673 | # the name of the crashed program 674 | # undef 675 | # array of possible directories to locate symboled files in 676 | sub fetch_symbolled_binaries { 677 | 678 | print STDERR "Finding Symbols:\n" if $opt{v}; 679 | 680 | my $pre = "."; # used in formatting progress output 681 | my $post = sprintf "\033[K"; # vt100 code to clear from cursor to end of line 682 | 683 | my ($images,$build,$bundle,@extra_search_paths) = @_; 684 | 685 | # fetch paths to symbolled binaries. or ignore that lib if we can't 686 | # find it 687 | for my $b (keys %$images) { 688 | my $lib = $$images{$b}; 689 | 690 | print STDERR "\r${pre}fetching symbol file for $b$post" if $opt{v}; 691 | $pre .= "."; 692 | 693 | 694 | my $symbol = $$lib{symbol}; 695 | unless($symbol) { 696 | ($symbol) = getSymbolPathFor($$lib{path},$build,$$lib{uuid},$$lib{arch},@extra_search_paths); 697 | if($symbol) { 698 | $$lib{symbol} = $symbol; 699 | } 700 | else { 701 | delete $$images{$b}; 702 | next; 703 | } 704 | } 705 | 706 | # app can't slide 707 | next if $b eq $bundle; 708 | 709 | print STDERR "\r${pre}checking address range for $b$post" if $opt{v}; 710 | $pre .= "."; 711 | 712 | # check for sliding. set slide offset if so 713 | if (-e '/usr/bin/size') { 714 | open my($ph),"-|",'size','-m','-l','-x',$symbol or die $!; 715 | my $real_base = ( 716 | grep { $_ } 717 | map { (/_TEXT.*vmaddr\s+(\w+)/)[0] } <$ph> 718 | )[0]; 719 | close $ph; 720 | if ($?) { 721 | # call to size failed. Don't use this image in symbolication; don't die 722 | delete $$images{$b}; 723 | print STDOUT "Error in symbol file for $symbol\n"; # tell the user 724 | print STDERR "Error in symbol file for $symbol\n"; # and log it 725 | next; 726 | } 727 | 728 | if($$lib{base} ne $real_base) { 729 | $$lib{slide} = hex($real_base) - hex($$lib{base}); 730 | } 731 | } 732 | } 733 | print STDERR "\rdone.$post\n" if $opt{v}; 734 | print STDERR "\r$post" if $opt{v}; 735 | print STDERR keys(%$images) . " binary images were found.\n" if $opt{v}; 736 | } 737 | 738 | # run atos 739 | sub symbolize_frames { 740 | my ($images,$bt) = @_; 741 | 742 | # create mapping of framework => address => bt frame (adjust for slid) 743 | # and for framework => arch 744 | my %frames_to_lookup = (); 745 | my %arch_map = (); 746 | 747 | for my $k (keys %$bt) { 748 | my $frame = $$bt{$k}; 749 | my $lib = $$images{$$frame{bundle}}; 750 | unless($lib) { 751 | # don't know about it, can't symbol 752 | # should have already been warned about this! 753 | # print "Skipping unknown $$frame{bundle}\n"; 754 | delete $$bt{$k}; 755 | next; 756 | } 757 | 758 | # adjust address for sliding 759 | my $address = $$frame{address}; 760 | if($$lib{slide}) { 761 | $address = sprintf "0x%08x", hex($$frame{address}) + $$lib{slide}; 762 | $$frame{address} = $address; 763 | } 764 | 765 | # list of address to lookup, mapped to the frame object, for 766 | # each library 767 | $frames_to_lookup{$$lib{symbol}}{$address} = $frame; 768 | $arch_map{$$lib{symbol}} = $$lib{arch}; 769 | } 770 | 771 | # run atos for each library 772 | while(my($symbol,$frames) = each(%frames_to_lookup)) { 773 | # escape the symbol path if it contains single quotes 774 | my $escapedSymbol = $symbol; 775 | $escapedSymbol =~ s/\'/\'\\'\'/g; 776 | 777 | # run atos with the addresses and binary files we just gathered 778 | my $arch = $arch_map{$symbol}; 779 | my $cmd = "$atos -arch $arch -o '$escapedSymbol' @{[ keys %$frames ]} | "; 780 | 781 | print STDERR "Running $cmd\n" if $opt{v}; 782 | 783 | open my($ph),$cmd or die $!; 784 | my @symbolled_frames = map { chomp; $_ } <$ph>; 785 | close $ph or die $!; 786 | 787 | my $references = 0; 788 | 789 | foreach my $symbolled_frame (@symbolled_frames) { 790 | 791 | $symbolled_frame =~ s/\s*\(in .*?\)//; # clean up -- don't need to repeat the lib here 792 | 793 | # find the correct frame -- the order should match since we got the address list with keys 794 | my ($k,$frame) = each(%$frames); 795 | 796 | if ( $symbolled_frame !~ /^\d/ ) { 797 | # only symbolicate if we fetched something other than an address 798 | $$frame{symbolled} = $symbolled_frame; 799 | $references++; 800 | } 801 | 802 | } 803 | 804 | if ( $references == 0 ) { 805 | print STDERR "## Warning: Unable to symbolicate from required binary: $symbol\n"; 806 | } 807 | } 808 | 809 | # just run through and remove elements for which we didn't find a 810 | # new mapping: 811 | while(my($k,$v) = each(%$bt)) { 812 | delete $$bt{$k} unless defined $$v{symbolled}; 813 | } 814 | } 815 | 816 | # run the final regex to symbolize the log 817 | sub replace_symbolized_frames { 818 | my ($log_ref,$bt) = @_; 819 | my $re = join "|" , map { quotemeta } keys %$bt; 820 | 821 | my $log = $$log_ref; 822 | $log =~ s#$re# 823 | my $frame = $$bt{$&}; 824 | $$frame{address} ." ". $$frame{symbolled}; 825 | #esg; 826 | 827 | $log =~ s/(&(\w+);?)/$entity2char{$2} || $1/eg; 828 | 829 | return \$log; 830 | } 831 | 832 | ############# 833 | 834 | sub output_log($) { 835 | my ($log_ref) = @_; 836 | 837 | if($opt{'o'}) { 838 | close STDOUT; 839 | open STDOUT, '>', $opt{'o'}; 840 | } 841 | 842 | print $$log_ref; 843 | } 844 | 845 | ############# 846 | 847 | sub symbolicate_log { 848 | my ($file,@extra_search_paths) = @_; 849 | 850 | print STDERR "Symbolicating...\n" if ( $opt{v} ); 851 | 852 | my $log_ref = slurp_file($file); 853 | 854 | print STDERR length($$log_ref)." characters read.\n" if ( $opt{v} ); 855 | 856 | # get the version number 857 | my $report_version = parse_report_version($log_ref); 858 | $report_version or die "No crash report version in $file"; 859 | 860 | # read the binary images 861 | my ($images,$first_bundle) = parse_images($log_ref, $report_version); 862 | 863 | # -A option: just lookup app symbols 864 | $images = { $first_bundle => $$images{$first_bundle} } if $opt{A}; 865 | 866 | if ( $opt{v} ) { 867 | print STDERR keys(%$images) . " binary images referenced:\n"; 868 | foreach (keys(%$images)) { 869 | print STDERR $_; 870 | print STDERR "\t\t("; 871 | print STDERR $$images{$_}{path}; 872 | print STDERR ")\n"; 873 | } 874 | print "\n"; 875 | } 876 | 877 | # just parse out crashing thread 878 | my $bt = {}; 879 | if($opt{t}) { 880 | # just do crashing logs 881 | my $crashing = parse_section($log_ref,'Thread') 882 | || parse_section($log_ref,'Crashed Thread'); # new format 883 | my $thread = parse_section($log_ref,"Thread $crashing Crashed",multiline=>1); 884 | 885 | die "Can't locate crashed thread in log file. Try using -a option\n" unless defined $thread; 886 | 887 | $bt = parse_backtrace($thread,$images); 888 | } else { 889 | my $threads = parse_sections($log_ref,'Thread\s+\d+\s?(Highlighted|Crashed)?',multiline=>1); 890 | for my $thread (values %$threads) { 891 | # merge all of the frames from all backtraces into one 892 | # collection 893 | my $b = parse_backtrace($thread,$images); 894 | @$bt{keys %$b} = values %$b; 895 | } 896 | } 897 | 898 | # extract build 899 | my $build = parse_build($log_ref); 900 | print STDERR "OS Version $build\n" if $opt{v}; 901 | # extract arch -- this doesn't really mean much now that we can mulitple archs in a backtrace. Manage the arch in each stack frame. 902 | #my $arch = parse_arch($log_ref); 903 | #print STDERR "Arch of Logfile: $arch\n" if $opt{v}; 904 | 905 | # sort out just the images needed for this backtrace 906 | prune_used_images($images,$bt); 907 | if ( $opt{v} ) { 908 | print STDERR keys(%$images) . " binary images remain after pruning:\n"; 909 | foreach my $junk (keys(%$images)) { 910 | print STDERR $junk; 911 | print STDERR ", "; 912 | } 913 | print STDERR "\n"; 914 | } 915 | 916 | @extra_search_paths = (@extra_search_paths, getSymbolDirPaths($build)); 917 | 918 | fetch_symbolled_binaries($images,$build,$first_bundle,@extra_search_paths); 919 | 920 | # If we didn't get *any* symbolled binaries, just print out the original crash log. 921 | my $imageCount = keys(%$images); 922 | if ($imageCount == 0) { 923 | output_log($log_ref); 924 | return; 925 | } 926 | 927 | # run atos 928 | symbolize_frames($images,$bt); 929 | 930 | # run our fancy regex 931 | my $new_log = replace_symbolized_frames($log_ref,$bt); 932 | output_log($new_log); 933 | } --------------------------------------------------------------------------------