2
0

Serious houskeeping: Better file structure & preparation for Xcode workspace.

This commit is contained in:
Maarten Billemont
2013-03-29 11:58:27 -04:00
parent 02b323d640
commit 1c79545245
846 changed files with 6048 additions and 5771 deletions

View File

@@ -0,0 +1 @@
Versions/Current/Crashlytics

1
External/Crashlytics.framework/Headers vendored Symbolic link
View File

@@ -0,0 +1 @@
Versions/Current/Headers

1
External/Crashlytics.framework/Resources vendored Symbolic link
View File

@@ -0,0 +1 @@
Versions/Current/Resources

Binary file not shown.

View File

@@ -0,0 +1,192 @@
//
// Crashlytics.h
// Crashlytics
//
// Copyright 2012 Crashlytics, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
*
* The CLS_LOG macro provides as easy way to gather more information in your log messages that are
* sent with your crash data. CLS_LOG prepends your custom log message with the function name and
* line number where the macro was used. If your app was built with the DEBUG preprocessor macro
* defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
* If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
*
* Example output:
* -[AppDelegate login:] line 134 $ login start
*
* If you would like to change this macro, create a new header file, unset our define and then define
* your own version. Make sure this new header file is imported after the Crashlytics header file.
*
* #undef CLS_LOG
* #define CLS_LOG(__FORMAT__, ...) CLSNSLog...
*
**/
#ifdef DEBUG
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
/**
*
* Add logging that will be sent with your crash data. This logging will not show up in the system.log
* and will only be visible in your Crashlytics dashboard.
*
**/
OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
/**
*
* Add logging that will be sent with your crash data. This logging will show up in the system.log
* and your Crashlytics dashboard. It is not recommended for Release builds.
*
**/
OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
@protocol CrashlyticsDelegate;
@interface Crashlytics : NSObject
@property (nonatomic, readonly, copy) NSString *apiKey;
@property (nonatomic, readonly, copy) NSString *version;
@property (nonatomic, assign) BOOL debugMode;
@property (nonatomic, assign) NSObject <CrashlyticsDelegate> *delegate;
/**
*
* The recommended way to install Crashlytics into your application is to place a call
* to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method.
*
* This delay defaults to 1 second in order to generally give the application time to
* fully finish launching.
*
**/
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey;
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay;
/**
*
* If you need the functionality provided by the CrashlyticsDelegate protocol, you can use
* these convenience methods to activate the framework and set the delegate in one call.
*
**/
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate;
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate afterDelay:(NSTimeInterval)delay;
/**
*
* Access the singleton Crashlytics instance.
*
**/
+ (Crashlytics *)sharedInstance;
/**
*
* The easiest way to cause a crash - great for testing!
*
**/
- (void)crash;
/**
*
* Many of our customers have requested the ability to tie crashes to specific end-users of their
* application in order to facilitate responses to support requests or permit the ability to reach
* out for more information. We allow you to specify up to three separate values for display within
* the Crashlytics UI - but please be mindful of your end-user's privacy.
*
* We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
* in your system. This could be a database id, hash, or other value that is meaningless to a
* third-party observer but can be indexed and queried by you.
*
* Optionally, you may also specify the end-user's name or username, as well as email address if you
* do not have a system that works well with obscured identifiers.
*
* Pursuant to our EULA, this data is transferred securely throughout our system and we will not
* disseminate end-user data unless required to by law. That said, if you choose to provide end-user
* contact information, we strongly recommend that you disclose this in your application's privacy
* policy. Data privacy is of our utmost concern.
*
**/
- (void)setUserIdentifier:(NSString *)identifier;
- (void)setUserName:(NSString *)name;
- (void)setUserEmail:(NSString *)email;
+ (void)setUserIdentifier:(NSString *)identifier;
+ (void)setUserName:(NSString *)name;
+ (void)setUserEmail:(NSString *)email;
/**
*
* Set a value for a key to be associated with your crash data.
*
**/
- (void)setObjectValue:(id)value forKey:(NSString *)key;
- (void)setIntValue:(int)value forKey:(NSString *)key;
- (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
- (void)setFloatValue:(float)value forKey:(NSString *)key;
+ (void)setObjectValue:(id)value forKey:(NSString *)key;
+ (void)setIntValue:(int)value forKey:(NSString *)key;
+ (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
+ (void)setFloatValue:(float)value forKey:(NSString *)key;
@end
/**
* The CLSCrashReport protocol exposes methods that you can call on crash report objects passed
* to delegate methods. If you want these values or the entire object to stay in memory retain
* them or copy them.
**/
@protocol CLSCrashReport <NSObject>
@required
/**
* Returns the session identifier for the crash report.
**/
- (NSString *)identifier;
/**
* Returns the custom key value data for the crash report.
**/
- (NSDictionary *)customKeys;
@end
/**
*
* The CrashlyticsDelegate protocol provides a mechanism for your application to take
* action on events that occur in the Crashlytics crash reporting system. You can make
* use of these calls by assigning an object to the Crashlytics' delegate property directly,
* or through the convenience startWithAPIKey:delegate:... methods.
*
**/
@protocol CrashlyticsDelegate <NSObject>
@optional
/**
*
* Called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. This is called some time after the crash reporting
* process has begun. If you have specified a delay in one of the
* startWithAPIKey:... calls, this will take at least that long to be invoked.
*
**/
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics;
/**
*
* Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is
* called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. A CLSCrashReport is passed back that contains data about
* the last crash report that was generated. See the CLSCrashReport protocol for method details.
* This method is called after crashlyticsDidDetectCrashDuringPreviousExecution.
*
**/
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash;
@end

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>12C60</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>Crashlytics</string>
<key>CFBundleIdentifier</key>
<string>com.crashlytics.ios</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Crashlytics</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.0.3</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>0200.03.00</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>10A403</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>DTPlatformVersion</key>
<string>6.0</string>
<key>DTSDKBuild</key>
<string>10A403</string>
<key>DTSDKName</key>
<string>iphoneos6.0</string>
<key>DTXcode</key>
<string>0451</string>
<key>DTXcodeBuild</key>
<string>4G1004</string>
<key>MinimumOSVersion</key>
<string>4.0</string>
</dict>
</plist>

View File

@@ -0,0 +1 @@
../../../run

View File

@@ -0,0 +1,15 @@
#!/usr/bin/ruby
#
# WARNING: DO NOT MODIFY THIS FILE.
#
# Crashlytics
# Crashlytics Version: 1.0.0.1
#
# Copyright Crashlytics, Inc. 2012. All rights reserved.
#
require 'pathname'
path = Pathname.new(__FILE__).parent
`#{path}/../../../run`

View File

@@ -0,0 +1 @@
A

BIN
External/Crashlytics.framework/run vendored Executable file

Binary file not shown.

70
External/Localytics/LocalyticsDatabase.h vendored Executable file
View File

@@ -0,0 +1,70 @@
//
// LocalyticsDatabase.h
// Copyright (C) 2012 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#define MAX_DATABASE_SIZE 500000 // The maximum allowed disk size of the primary database file at open, in bytes
#define VACUUM_THRESHOLD 0.8 // The database is vacuumed after its size exceeds this proportion of the maximum.
@interface LocalyticsDatabase : NSObject {
sqlite3 *_databaseConnection;
}
+ (LocalyticsDatabase *)sharedLocalyticsDatabase;
- (NSUInteger)databaseSize;
- (int)eventCount;
- (NSTimeInterval)createdTimestamp;
- (BOOL)beginTransaction:(NSString *)name;
- (BOOL)releaseTransaction:(NSString *)name;
- (BOOL)rollbackTransaction:(NSString *)name;
- (BOOL)incrementLastUploadNumber:(int *)uploadNumber;
- (BOOL)incrementLastSessionNumber:(int *)sessionNumber;
- (BOOL)addEventWithBlobString:(NSString *)blob;
- (BOOL)addCloseEventWithBlobString:(NSString *)blob;
- (BOOL)queueCloseEventWithBlobString:(NSString *)blob;
- (NSString *)dequeueCloseEventBlobString;
- (BOOL)addFlowEventWithBlobString:(NSString *)blob;
- (BOOL)removeLastCloseAndFlowEvents;
- (BOOL)addHeaderWithSequenceNumber:(int)number blobString:(NSString *)blob rowId:(sqlite3_int64 *)insertedRowId;
- (int)unstagedEventCount;
- (BOOL)stageEventsForUpload:(sqlite3_int64)headerId;
- (BOOL)updateAppKey:(NSString *)appKey;
- (NSString *)uploadBlobString;
- (BOOL)deleteUploadedData;
- (BOOL)resetAnalyticsData;
- (BOOL)vacuumIfRequired;
- (NSTimeInterval)lastSessionStartTimestamp;
- (BOOL)setLastsessionStartTimestamp:(NSTimeInterval)timestamp;
- (BOOL)isOptedOut;
- (BOOL)setOptedOut:(BOOL)optOut;
- (NSString *)installId;
- (NSString *)appKey; // Most recent app key-- may not be that used to open the session.
- (NSString *)customDimension:(int)dimension;
- (BOOL)setCustomDimension:(int)dimension value:(NSString *)value;
- (NSString *)customerId;
- (BOOL)setCustomerId:(NSString *)newCustomerId;
- (NSInteger)safeIntegerValueFromDictionary:(NSDictionary *)dict forKey:(NSString *)key;
- (NSString *)safeStringValueFromDictionary:(NSDictionary *)dict forKey:(NSString *)key;
- (NSDictionary *)safeDictionaryFromDictionary:(NSDictionary *)dict forKey:(NSString *)key;
- (NSArray *)safeListFromDictionary:(NSDictionary *)dict forKey:(NSString *)key;
@end

1037
External/Localytics/LocalyticsDatabase.m vendored Executable file

File diff suppressed because it is too large Load Diff

251
External/Localytics/LocalyticsSession.h vendored Executable file
View File

@@ -0,0 +1,251 @@
// LocalyticsSession.h
// Copyright (C) 2012 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
// Set this to true to enable localytics traces (useful for debugging)
#define DO_LOCALYTICS_LOGGING false
/*!
@class LocalyticsSession
@discussion The class which manages creating, collecting, & uploading a Localytics session.
Please see the following guides for information on how to best use this
library, sample code, and other useful information:
<ul>
<li><a href="http://wiki.localytics.com/index.php?title=Developer's_Integration_Guide">Main Developer's Integration Guide</a></li>
</ul>
<strong>Best Practices</strong>
<ul>
<li>Instantiate the LocalyticsSession object in applicationDidFinishLaunching.</li>
<li>Open your session and begin your uploads in applicationDidFinishLaunching. This way the
upload has time to complete and it all happens before your users have a
chance to begin any data intensive actions of their own.</li>
<li>Close the session in applicationWillTerminate, and in applicationDidEnterBackground.</li>
<li>Resume the session in applicationWillEnterForeground.</li>
<li>Do not call any Localytics functions inside a loop. Instead, calls
such as <code>tagEvent</code> should follow user actions. This limits the
amount of data which is stored and uploaded.</li>
<li>Do not use multiple LocalticsSession objects to upload data with
multiple application keys. This can cause invalid state.</li>
</ul>
@author Localytics
*/
@interface LocalyticsSession : NSObject {
BOOL _hasInitialized; // Whether or not the session object has been initialized.
BOOL _isSessionOpen; // Whether or not this session has been opened.
float _backgroundSessionTimeout; // If an App stays in the background for more
// than this many seconds, start a new session
// when it returns to foreground.
@private
#pragma mark Member Variables
dispatch_queue_t _queue; // Queue of Localytics block objects.
dispatch_group_t _criticalGroup; // Group of blocks the must complete before backgrounding.
NSString *_sessionUUID; // Unique identifier for this session.
NSString *_applicationKey; // Unique identifier for the instrumented application
NSTimeInterval _lastSessionStartTimestamp; // The start time of the most recent session.
NSDate *_sessionResumeTime; // Time session was started or resumed.
NSDate *_sessionCloseTime; // Time session was closed.
NSMutableString *_unstagedFlowEvents; // Comma-delimited list of app screens and events tagged during this
// session that have NOT been staged for upload.
NSMutableString *_stagedFlowEvents; // App screens and events tagged during this session that HAVE been staged
// for upload.
NSMutableString *_screens; // Comma-delimited list of screens tagged during this session.
NSTimeInterval _sessionActiveDuration; // Duration that session open.
BOOL _sessionHasBeenOpen; // Whether or not this session has ever been open.
}
@property (nonatomic,readonly) dispatch_queue_t queue;
@property (nonatomic,readonly) dispatch_group_t criticalGroup;
@property BOOL isSessionOpen;
@property BOOL hasInitialized;
@property float backgroundSessionTimeout;
- (void)logMessage:(NSString *)message;
@property (nonatomic, assign, readonly) NSTimeInterval lastSessionStartTimestamp;
@property (nonatomic, assign, readonly) NSInteger sessionNumber;
/*!
@property enableHTTPS
@abstract Determines whether or not HTTPS is used when calling the Localytics
post URL. The default is NO.
*/
@property (nonatomic, assign) BOOL enableHTTPS; // Defaults to NO.
#pragma mark Public Methods
/*!
@method sharedLocalyticsSession
@abstract Accesses the Session object. This is a Singleton class which maintains
a single session throughout your application. It is possible to manage your own
session, but this is the easiest way to access the Localytics object throughout your code.
The class is accessed within the code using the following syntax:
[[LocalyticsSession sharedLocalyticsSession] functionHere]
So, to tag an event, all that is necessary, anywhere in the code is:
[[LocalyticsSession sharedLocalyticsSession] tagEvent:@"MY_EVENT"];
*/
+ (LocalyticsSession *)sharedLocalyticsSession;
/*!
@method LocalyticsSession
@abstract Initializes the Localytics Object. Not necessary if you choose to use startSession.
@param applicationKey The key unique for each application generated at www.localytics.com
*/
- (void)LocalyticsSession:(NSString *)appKey;
/*!
@method startSession
@abstract An optional convenience initialize method that also calls the LocalyticsSession, open &
upload methods. Best Practice is to call open & upload immediately after Localytics Session when loading an app,
this method fascilitates that behavior.
It is recommended that this call be placed in <code>applicationDidFinishLaunching</code>.
@param applicationKey The key unique for each application generated
at www.localytics.com
*/
- (void)startSession:(NSString *)appKey;
/*!
@method setOptIn
@abstract (OPTIONAL) Allows the application to control whether or not it will collect user data.
Even if this call is used, it is necessary to continue calling upload(). No new data will be
collected, so nothing new will be uploaded but it is necessary to upload an event telling the
server this user has opted out.
@param optedIn True if the user is opted in, false otherwise.
*/
- (void)setOptIn:(BOOL)optedIn;
/*!
@method isOptedIn
@abstract (OPTIONAL) Whether or not this user has is opted in or out. The only way they can be
opted out is if setOptIn(false) has been called before this. This function should only be
used to pre-populate a checkbox in an options menu. It is not recommended that an application
branch based on Localytics instrumentation because this creates an additional test case. If
the app is opted out, all subsequent Localytics calls will return immediately.
@result true if the user is opted in, false otherwise.
*/
- (BOOL)isOptedIn;
/*!
@method open
@abstract Opens the Localytics session. Not necessary if you choose to use startSession.
The session time as presented on the website is the time between <code>open</code> and the
final <code>close</code> so it is recommended to open the session as early as possible, and close
it at the last moment. The session must be opened before any tags can
be written. It is recommended that this call be placed in <code>applicationDidFinishLaunching</code>.
<br>
If for any reason this is called more than once every subsequent open call
will be ignored.
*/
- (void)open;
/*!
@method resume
@abstract Resumes the Localytics session. When the App enters the background, the session is
closed and the time of closing is recorded. When the app returns to the foreground, the session
is resumed. If the time since closing is greater than BACKGROUND_SESSION_TIMEOUT, (15 seconds
by default) a new session is created, and uploading is triggered. Otherwise, the previous session
is reopened.
@return Returns whether the session was resumed or a new session was started. If the user has opted
out of analytics then the return from this method is undefined.
*/
- (BOOL)resume;
/*!
@method close
@abstract Closes the Localytics session. This should be called in
<code>applicationWillTerminate</code>.
<br>
If close is not called, the session will still be uploaded but no
events will be processed and the session time will not appear. This is
because the session is not yet closed so it should not be used in
comparison with sessions which are closed.
*/
- (void)close;
/*!
@method tagEvent
@abstract Allows a session to tag a particular event as having occurred. For
example, if a view has three buttons, it might make sense to tag
each button click with the name of the button which was clicked.
For another example, in a game with many levels it might be valuable
to create a new tag every time the user gets to a new level in order
to determine how far the average user is progressing in the game.
<br>
<strong>Tagging Best Practices</strong>
<ul>
<li>DO NOT use tags to record personally identifiable information.</li>
<li>The best way to use tags is to create all the tag strings as predefined
constants and only use those. This is more efficient and removes the risk of
collecting personal information.</li>
<li>Do not set tags inside loops or any other place which gets called
frequently. This can cause a lot of data to be stored and uploaded.</li>
</ul>
<br>
See the tagging guide at: http://wiki.localytics.com/
@param event The name of the event which occurred.
*/
- (void)tagEvent:(NSString *)event;
- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes;
- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes reportAttributes:(NSDictionary *)reportAttributes;
/*!
@method tagScreen
@abstract Allows tagging the flow of screens encountered during the session.
@param screen The name of the screen
*/
- (void)tagScreen:(NSString *)screen;
/*!
@method upload
@abstract Creates a low priority thread which uploads any Localytics data already stored
on the device. This should be done early in the process life in order to
guarantee as much time as possible for slow connections to complete. It is also reasonable
to upload again when the application is exiting because if the upload is cancelled the data
will just get uploaded the next time the app comes up.
*/
- (void)upload;
/*!
@method setCustomDimension
@abstract (ENTERPRISE ONLY) Sets the value of a custom dimension. Custom dimensions are dimensions
which contain user defined data unlike the predefined dimensions such as carrier, model, and country.
Once a value for a custom dimension is set, the device it was set on will continue to upload that value
until the value is changed. To clear a value pass nil as the value.
The proper use of custom dimensions involves defining a dimension with less than ten distinct possible
values and assigning it to one of the four available custom dimensions. Once assigned this definition should
never be changed without changing the App Key otherwise old installs of the application will pollute new data.
*/
- (void)setCustomDimension:(int)dimension value:(NSString *)value;
/*!
@method setLocation
@abstract Stores the user's location. This will be used in all event and session calls.
If your application has already collected the user's location, it may be passed to Localytics
via this function. This will cause all events and the session close to include the locatin
information. It is not required that you call this function.
@param deviceLocation The user's location.
*/
- (void)setLocation:(CLLocationCoordinate2D)deviceLocation;
/*!
@method ampTrigger
@abstract Displays the AMP message for the specific event.
Is a stub implementation here to prevent crashes if this class is accidentally used inplace of
the LocalyticsAmpSession
@param event Name of the event.
*/
- (void)ampTrigger:(NSString *)event;
@end

1285
External/Localytics/LocalyticsSession.m vendored Executable file

File diff suppressed because it is too large Load Diff

64
External/Localytics/LocalyticsUploader.h vendored Executable file
View File

@@ -0,0 +1,64 @@
// LocalyticsUploader.h
// Copyright (C) 2012 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import <UIKit/UIKit.h>
extern NSString * const kLocalyticsKeyResponseBody;
/*!
@class LocalyticsUploader
@discussion Singleton class to handle data uploads
*/
@interface LocalyticsUploader : NSObject {
}
@property (readonly) BOOL isUploading;
/*!
@method sharedLocalyticsUploader
@abstract Establishes this as a Singleton Class allowing for data persistence.
The class is accessed within the code using the following syntax:
[[LocalyticsUploader sharedLocalyticsUploader] functionHere]
*/
+ (LocalyticsUploader *)sharedLocalyticsUploader;
/*!
@method LocalyticsUploader
@abstract Creates a thread which uploads all queued header and event data.
All files starting with sessionFilePrefix are renamed,
uploaded and deleted on upload. This way the sessions can continue
writing data regardless of whether or not the upload succeeds. Files
which have been renamed still count towards the total number of Localytics
files which can be stored on the disk.
This version of the method now just calls the second version of it with a nil target and NULL callback method.
@param localyticsApplicationKey the Localytics application ID
@param useHTTPS Flag determining whether HTTP or HTTPS is used for the post URL.
@param installId Install id passed to the server in the x-install-id header field.
*/
- (void)uploaderWithApplicationKey:(NSString *)localyticsApplicationKey useHTTPS:(BOOL)useHTTPS installId:(NSString *)installId;
/*!
@method LocalyticsUploader
@abstract Creates a thread which uploads all queued header and event data.
All files starting with sessionFilePrefix are renamed,
uploaded and deleted on upload. This way the sessions can continue
writing data regardless of whether or not the upload succeeds. Files
which have been renamed still count towards the total number of Localytics
files which can be stored on the disk.
@param localyticsApplicationKey the Localytics application ID
@param useHTTPS Flag determining whether HTTP or HTTPS is used for the post URL.
@param installId Install id passed to the server in the x-install-id header field.
@param resultTarget Result target is the target for the callback method that knows how to handle response data
@param callback Callback is the method of the target class that is to be called with the data begin returned by an upload
*/
- (void)uploaderWithApplicationKey:(NSString *)localyticsApplicationKey useHTTPS:(BOOL)useHTTPS installId:(NSString *)installId resultTarget:(id)target callback:(SEL)callbackMethod;
@end

281
External/Localytics/LocalyticsUploader.m vendored Executable file
View File

@@ -0,0 +1,281 @@
// LocalyticsUploader.m
// Copyright (C) 2012 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import "LocalyticsUploader.h"
#import "LocalyticsSession.h"
#import "LocalyticsDatabase.h"
#import "WebserviceConstants.h"
#import <zlib.h>
#ifndef LOCALYTICS_URL
#define LOCALYTICS_URL @"http://analytics.localytics.com/api/v2/applications/%@/uploads"
#endif
#ifndef LOCALYTICS_URL_SECURED
#define LOCALYTICS_URL_SECURED @"https://analytics.localytics.com/api/v2/applications/%@/uploads"
#endif
static LocalyticsUploader *_sharedUploader = nil;
NSString * const kLocalyticsKeyResponseBody = @"localytics.key.responseBody";
@interface LocalyticsUploader ()
- (void)finishUpload;
- (NSData *)gzipDeflatedDataWithData:(NSData *)data;
- (void)logMessage:(NSString *)message;
- (NSString *)uploadTimeStamp;
@property (readwrite) BOOL isUploading;
@end
@implementation LocalyticsUploader
@synthesize isUploading = _isUploading;
#pragma mark - Singleton Class
+ (LocalyticsUploader *)sharedLocalyticsUploader {
@synchronized(self) {
if (_sharedUploader == nil) {
_sharedUploader = [[self alloc] init];
}
}
return _sharedUploader;
}
#pragma mark - Class Methods
- (void)uploaderWithApplicationKey:(NSString *)localyticsApplicationKey useHTTPS:(BOOL)useHTTPS installId:(NSString *)installId
{
[self uploaderWithApplicationKey:localyticsApplicationKey useHTTPS:useHTTPS installId:installId resultTarget:nil callback:NULL];
}
- (void)uploaderWithApplicationKey:(NSString *)localyticsApplicationKey useHTTPS:(BOOL)useHTTPS installId:(NSString *)installId resultTarget:(id)target callback:(SEL)callbackMethod;
{
// Do nothing if already uploading.
if (self.isUploading == true)
{
[self logMessage:@"Upload already in progress. Aborting."];
return;
}
[self logMessage:@"Beginning upload process"];
self.isUploading = true;
// Prepare the data for upload. The upload could take a long time, so some effort has to be made to be sure that events
// which get written while the upload is taking place don't get lost or duplicated. To achieve this, the logic is:
// 1) Append every header row blob string and and those of its associated events to the upload string.
// 2) Deflate and upload the data.
// 3) On success, delete all blob headers and staged events. Events added while an upload is in process are not
// deleted because they are not associated a header (and cannot be until the upload completes).
// Step 1
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
LocalyticsDatabase *db = [LocalyticsDatabase sharedLocalyticsDatabase];
NSString *blobString = [db uploadBlobString];
if ([blobString length] == 0) {
// There is nothing outstanding to upload.
[self logMessage:@"Abandoning upload. There are no new events."];
[pool drain];
[self finishUpload];
return;
}
NSData *requestData = [blobString dataUsingEncoding:NSUTF8StringEncoding];
NSString *myString = [[[NSString alloc] initWithData:requestData encoding:NSUTF8StringEncoding] autorelease];
[self logMessage:[NSString stringWithFormat:@"Uploading data (length: %u)", [myString length]]];
[self logMessage:myString];
// Step 2
NSData *deflatedRequestData = [[self gzipDeflatedDataWithData:requestData] retain];
[pool drain];
NSString *urlStringFormat;
if (useHTTPS) {
urlStringFormat = LOCALYTICS_URL_SECURED;
} else {
urlStringFormat = LOCALYTICS_URL;
}
NSString *apiUrlString = [NSString stringWithFormat:urlStringFormat, [localyticsApplicationKey stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *submitRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiUrlString]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60.0];
[submitRequest setHTTPMethod:@"POST"];
[submitRequest setValue:[self uploadTimeStamp] forHTTPHeaderField:HEADER_CLIENT_TIME];
[submitRequest setValue:installId forHTTPHeaderField:HEADER_INSTALL_ID];
[submitRequest setValue:@"application/x-gzip" forHTTPHeaderField:@"Content-Type"];
[submitRequest setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
[submitRequest setValue:[NSString stringWithFormat:@"%d", [deflatedRequestData length]] forHTTPHeaderField:@"Content-Length"];
[submitRequest setHTTPBody:deflatedRequestData];
[deflatedRequestData release];
// Perform synchronous upload in an async dispatch. This is necessary because the calling block will not persist to
// receive the response data.
dispatch_group_async([[LocalyticsSession sharedLocalyticsSession] criticalGroup], [[LocalyticsSession sharedLocalyticsSession] queue], ^{
@try {
NSURLResponse *response = nil;
NSError *responseError = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:submitRequest returningResponse:&response error:&responseError];
NSInteger responseStatusCode = [(NSHTTPURLResponse *)response statusCode];
if (responseError) {
// On error, simply print the error and close the uploader. We have to assume the data was not transmited
// so it is not deleted. In the event that we accidently store data which was succesfully uploaded, the
// duplicate data will be ignored by the server when it is next uploaded.
[self logMessage:[NSString stringWithFormat:
@"Error Uploading. Code: %d, Description: %@",
[responseError code],
[responseError localizedDescription]]];
} else {
// Step 3
// While response status codes in the 5xx range leave upload rows intact, the default case is to delete.
if (responseStatusCode >= 500 && responseStatusCode < 600) {
[self logMessage:[NSString stringWithFormat:@"Upload failed with response status code %d", responseStatusCode]];
} else {
// Because only one instance of the uploader can be running at a time it should not be possible for
// new upload rows to appear so there is no fear of deleting data which has not yet been uploaded.
[self logMessage:[NSString stringWithFormat:@"Upload completed successfully. Response code %d", responseStatusCode]];
[[LocalyticsDatabase sharedLocalyticsDatabase] deleteUploadedData];
}
}
if ([responseData length] > 0) {
if (DO_LOCALYTICS_LOGGING) {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[self logMessage:[NSString stringWithFormat:@"Response body: %@", responseString]];
[responseString release];
}
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:responseData forKey:kLocalyticsKeyResponseBody];
if (target) {
[target performSelector:callbackMethod withObject:userInfo];
}
}
}
@catch (NSException * e) {}
[self finishUpload];
});
}
- (void)finishUpload
{
self.isUploading = false;
// Upload data has been deleted. Recover the disk space if necessary.
[[LocalyticsDatabase sharedLocalyticsDatabase] vacuumIfRequired];
}
/*!
@method gzipDeflatedDataWithData
@abstract Deflates the provided data using gzip at the default compression level (6). Complete NSData gzip category available on CocoaDev. http://www.cocoadev.com/index.pl?NSDataCategory.
@return the deflated data
*/
- (NSData *)gzipDeflatedDataWithData:(NSData *)data
{
if ([data length] == 0) return data;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.total_out = 0;
strm.next_in=(Bytef *)[data bytes];
strm.avail_in = [data length];
// Compresssion Levels:
// Z_NO_COMPRESSION
// Z_BEST_SPEED
// Z_BEST_COMPRESSION
// Z_DEFAULT_COMPRESSION
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil;
NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chunks for expansion
do {
if (strm.total_out >= [compressed length])
[compressed increaseLengthBy: 16384];
strm.next_out = [compressed mutableBytes] + strm.total_out;
strm.avail_out = [compressed length] - strm.total_out;
deflate(&strm, Z_FINISH);
} while (strm.avail_out == 0);
deflateEnd(&strm);
[compressed setLength: strm.total_out];
return [NSData dataWithData:compressed];
}
/*!
@method logMessage
@abstract Logs a message with (localytics uploader) prepended to it
@param message The message to log
*/
- (void) logMessage:(NSString *)message {
if(DO_LOCALYTICS_LOGGING) {
NSLog(@"(localytics uploader) %s\n", [message UTF8String]);
}
}
/*!
@method uploadTimeStamp
@abstract Gets the current time, along with local timezone, formatted as a DateTime for the webservice.
@return a DateTime of the current local time and timezone.
*/
- (NSString *)uploadTimeStamp {
return [ NSString stringWithFormat:@"%ld", (long)[[NSDate date] timeIntervalSince1970] ];
}
#pragma mark - System Functions
+ (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if (_sharedUploader == nil) {
_sharedUploader = [super allocWithZone:zone];
return _sharedUploader;
}
}
// returns nil on subsequent allocations
return nil;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
// maximum value of an unsigned int - prevents additional retains for the class
return UINT_MAX;
}
- (oneway void)release {
// ignore release commands
}
- (id)autorelease {
return self;
}
- (void)dealloc {
[_sharedUploader release];
[super dealloc];
}
@end

114
External/Localytics/WebserviceConstants.h vendored Executable file
View File

@@ -0,0 +1,114 @@
// WebserviceConstants.h
// Copyright (C) 2012 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
// The constants which are used to make up the JSON blob
// To save disk space and network bandwidth all the keywords have been
// abbreviated and are exploded by the server.
/*****************
* Upload Header *
*****************/
#define HEADER_CLIENT_TIME @"x-upload-time"
#define HEADER_INSTALL_ID @"x-install-id"
/*********************
* Shared Attributes *
*********************/
#define PARAM_UUID @"u" // UUID for JSON document
#define PARAM_DATA_TYPE @"dt" // Data Type
#define PARAM_CLIENT_TIME @"ct" // Client Time, seconds from Unix epoch (int)
#define PARAM_LATITUDE @"lat" // Latitude - if available
#define PARAM_LONGITUDE @"lon" // Longitude - if available
#define PARAM_SESSION_UUID @"su" // UUID for an existing session
#define PARAM_NEW_SESSION_UUID @"u" // UUID for a new session
#define PARAM_ATTRIBUTES @"attrs" // Attributes (dictionary)
#define PARAM_SESSION_ELAPSE_TIME @"sl" // Number of seconds since the previous session start
/***************
* Blob Header *
***************/
// PARAM_UUID
// PARAM_DATA_TYPE => "h" for Header
// PARAM_ATTRIBUTES => dictionary containing Header Common Attributes
#define PARAM_PERSISTED_AT @"pa" // Persistent Storage Created At. A timestamp created when the app was
// first launched and the persistent storage was created. Stores as
// seconds from Unix epoch. (int)
#define PARAM_SEQUENCE_NUMBER @"seq" // Sequence number - an increasing count for each blob, stored in the
// persistent store Consistent across app starts. (int)
/****************************
* Header Common Attributes *
****************************/
// PARAM_DATA_TYPE
#define PARAM_APP_KEY @"au" // Localytics Application ID
#define PARAM_DEVICE_UUID_HASHED @"udid" // Hashed version of the UUID
#define PARAM_DEVICE_ADID @"adid" // Advertising Identifier
#define PARAM_INSTALL_ID @"iu" // Install ID
#define PARAM_JAILBROKEN @"j" // Jailbroken (boolean)
#define PARAM_LIBRARY_VERSION @"lv" // Client Version
#define PARAM_APP_VERSION @"av" // Application Version
#define PARAM_DEVICE_PLATFORM @"dp" // Device Platform
#define PARAM_LOCALE_LANGUAGE @"dll" // Locale Language
#define PARAM_LOCALE_COUNTRY @"dlc" // Locale Country
#define PARAM_DEVICE_COUNTRY @"dc" // Device Country (iso code)
#define PARAM_DEVICE_MODEL @"dmo" // Device Model
#define PARAM_DEVICE_OS_VERSION @"dov" // Device OS Version
#define PARAM_NETWORK_CARRIER @"nca" // Network Carrier
#define PARAM_OPT_VALUE @"out" // Opt Out (boolean)
#define PARAM_DEVICE_MEMORY @"dmem" // Device Memory
/*****************
* Session Start *
*****************/
// PARAM_UUID
// PARAM_DATA_TYPE => "s" for Start
// PARAM_CLIENT_TIME
#define PARAM_SESSION_NUMBER @"nth" // This is the nth session on the device, 1-indexed (int)
/****************
* Session Stop *
****************/
// PARAM_UUID
// PARAM_DATA_TYPE => "c" for Close
// PARAM_CLIENT_TIME
// PARAM_LATITUDE
// PARAM_LONGITUDE
// PARAM_SESSION_UUID => UUID of session being closed
#define PARAM_SESSION_ACTIVE @"cta" // Active time in seconds (time app was active)
#define PARAM_SESSION_TOTAL @"ctl" // Total session length
#define PARAM_SESSION_SCREENFLOW @"fl" // Screens encountered during this session, in order
/*********************
* Application Event *
*********************/
// PARAM_UUID
// PARAM_DATA_TYPE => "e" for Event
// PARAM_CLIENT_TIME
// PARAM_LATITUDE
// PARAM_LONGITUDE
// PARAM_SESSION_UUID => UUID of session event occured in
// PARAM_ATTRIBUTES => dictionary containing attributes for this event as key-value string pairs
#define PARAM_EVENT_NAME @"n" // Event Name, (eg. 'Button Click')
#define PARAM_REPORT_ATTRIBUTES @"rattrs" // Attributes used in custom reports
/********************
* Application flow *
********************/
// PARAM_UUID
// PARAM_DATA_TYPE => "f" for Flow
// PARAM_CLIENT_TIME
#define PARAM_SESSION_START @"ss" // Start time for the current session.
#define PARAM_NEW_FLOW_EVENTS @"nw" // Events and screens encountered during this session that have NOT been staged for upload.
#define PARAM_OLD_FLOW_EVENTS @"od" // Events and screens encountered during this session that HAVE been staged for upload.

2
External/Pearl vendored

225
External/TestFlight/README.md vendored Normal file
View File

@@ -0,0 +1,225 @@
##Introduction
The TestFlight SDK allows you to track how beta testers are testing your application. Out of the box we track simple usage information, such as which tester is using your application, their device model/OS, how long they used the application, logs of their test session, and automatic recording of any crashes they encounter.
To get the most out of the SDK we have provided the Checkpoint API.
The Checkpoint API is used to help you track exactly how your testers are using your application. Curious about which users passed level 5 in your game, or posted their high score to Twitter, or found that obscure feature? With a single line of code you can finally gather all this information. Wondering how many times your app has crashed? Wondering who your power testers are? We've got you covered. See more information on the Checkpoint API in section 4.
Alongside the Checkpoint API is the Questions interface. The Questions interface is managed on a per build basis on the TestFlight website. Find out more about the Questions Interface in section 6.
For more detailed debugging we have a remote logging solution. Find out more about our logging system with TFLog in the Remote Logging section.
##Considerations
Information gathered by the SDK is sent to the website in real time. When an application is put into the background (iOS 4.x) or terminated (iOS 3.x) we try to send the finalizing information for the session during the time allowed for finalizing the application. Should all of the data not get sent the remaining data will be sent the next time the application is launched. As such, to get the most out of the SDK we recommend your application support iOS 4.0 and higher.
This SDK can be run from both the iPhone Simulator and Device and has been tested using Xcode 4.0.
##Integration
1. Add the files to your project: File -&gt; Add Files to " "
1. Find and select the folder that contains the SDK
2. Make sure that "Copy items into destination folder (if needed)" is checked
3. Set Folders to "Create groups for any added folders"
4. Select all targets that you want to add the SDK to
2. Verify that libTestFlight.a has been added to the Link Binary With Libraries Build Phase for the targets you want to use the SDK with
1. Select your Project in the Project Navigator
2. Select the target you want to enable the SDK for
3. Select the Build Phases tab
4. Open the Link Binary With Libraries Phase
5. If libTestFlight.a is not listed, drag and drop the library from your Project Navigator to the Link Binary With Libraries area
6. Repeat Steps 2 - 5 until all targets you want to use the SDK with have the SDK linked
3. Add libz to your Link Binary With Libraries Build Phase
1. Select your Project in the Project Navigator
2. Select the target you want to enable the SDK for
3. Select the Build Phases tab
4. Open the Link Binary With Libraries Phase
5. Click the + to add a new library
6. Find libz.dylib in the list and add it
7. Repeat Steps 2 - 6 until all targets you want to use the SDK with have libz.dylib
4. In your Application Delegate:
1. Import TestFlight: `#import "TestFlight.h"`
***NOTE:*** Rather than importing `TestFlight.h` in every file you may add the above line into you pre-compiled header (`<projectname>_Prefix.pch`) file inside of the
#ifdef __OBJC__
section. This will give you access to the SDK across all files.
2. Get your Team Token which you can find at [http://testflightapp.com/dashboard/team/](http://testflightapp.com/dashboard/team/) select the team you are using from the team selection drop down list on the top of the page and then select Team Info.
3. Launch TestFlight with your Team Token
-(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// start of your application:didFinishLaunchingWithOptions
// ...
[TestFlight takeOff:@"Insert your Team Token here"];
// The rest of your application:didFinishLaunchingWithOptions method
// ...
}
4. To report crashes to you we install our own uncaught exception handler. If you are not currently using an exception handler of your own then all you need to do is go to the next step. If you currently use an Exception Handler, or you use another framework that does please go to the section on advanced exception handling.
5. To enable the best crash reporting possible we recommend setting the following project build settings in Xcode to NO for all targets that you want to have live crash reporting for. You can find build settings by opening the Project Navigator (default command+1 or command+shift+j) then clicking on the project you are configuring (usually the first selection in the list). From there you can choose to either change the global project settings or settings on an individual project basis. All settings below are in the Deployment Section.
1. Deployment Post Processing
2. Strip Debug Symbols During Copy
3. Strip Linked Product
##Beta Testing and Release Differentiation
In order to provide more information about your testers while beta testing you will need to provide the device's unique identifier. This identifier is not something that the SDK will collect from the device and we do not recommend using this in production. To send the device identifier to us put the following code before your call to takeOff.
#define TESTING 1
#ifdef TESTING
[TestFlight setDeviceIdentifier:[[UIDevice currentDevice] uniqueIdentifier]];
#endif
This will allow you to have the best possible information during testing, but disable getting and sending of the device unique identifier when you release your application. When it is time to release simply comment out #define TESTING 1. If you decide to not include the device's unique identifier during your testing phase TestFlight will still collect all of the information that you send but it may be anonymized.
##Checkpoint API
When a tester does something you care about in your app you can pass a checkpoint. For example completing a level, adding a todo item, etc. The checkpoint progress is used to provide insight into how your testers are testing your apps. The passed checkpoints are also attached to crashes, which can help when creating steps to replicate.
`[TestFlight passCheckpoint:@"CHECKPOINT_NAME"];` Use `passCheckpoint:` to track when a user performs certain tasks in your application. This can be useful for making sure testers are hitting all parts of your application, as well as tracking which testers are being thorough.
##Feedback API
To launch unguided feedback call the openFeedbackView method. We recommend that you call this from a GUI element.
-(IBAction)launchFeedback {
[TestFlight openFeedbackView];
}
If you want to create your own feedback form you can use the submitCustomFeedback method to submit the feedback that the user has entered.
-(IBAction)submitFeedbackPressed:(id)sender {
NSString *feedback = [self getUserFeedback];
[TestFlight submitFeedback:feedback];
}
The above sample assumes that [self getUserFeedback] is implemented such that it obtains the users feedback from the GUI element you have created and that submitFeedbackPressed is the action for your submit button.
Once users have submitted feedback from inside of the application you can view it in the feedback area of your build page.
##Upload your build
After you have integrated the SDK into your application you need to upload your build to TestFlight. You can upload from your dashboard or or using the Upload API, full documentation at [https://testflightapp.com/api/doc/](https://testflightapp.com/api/doc/)
##Questions Interface
In order to ask a question, you'll need to associate it with a checkpoint. Make sure your checkpoints are initialized by running your app and hitting them all yourself before you start adding questions.
There are three question types available: Yes/No, Multiple Choice, and Long Answer.
To create questions, visit your builds Questions page and click on 'Add Question'. If you choose Multiple Choice, you'll need to enter a list of possible answers for your testers to choose from — otherwise, you'll only need to enter your question's, well, question. If your build has no questions, you can also choose to migrate questions from another build (because seriously — who wants to do all that typing again)?
After restarting your application on an approved device, when you pass the checkpoint associated with your questions a TestFlight modal question form will appear on the screen asking the beta tester to answer your question.
After you upload a new build to TestFlight you will need to associate questions once again. However if your checkpoints and questions have remained the same you can choose "copy questions from an older build" and choose which build to copy the questions from.
##View the results
As testers install your build and start to test it you will see their session data on the web on the build report page for the build you've uploaded.
##Advanced Exception Handling
An uncaught exception means that your application is in an unknown state and there is not much that you can do but try and exit gracefully. Our SDK does its best to get the data we collect in this situation to you while it is crashing, but it is designed in such a way that the important act of saving the data occurs in as safe way a way as possible before trying to send anything. If you do use uncaught exception or signal handlers install your handlers before calling `takeOff`. Our SDK will then call your handler while ours is running. For example:
/*
My Apps Custom uncaught exception catcher, we do special stuff here, and TestFlight takes care of the rest
*/
void HandleExceptions(NSException *exception) {
NSLog(@"This is where we save the application data during a exception");
// Save application data on crash
}
/*
My Apps Custom signal catcher, we do special stuff here, and TestFlight takes care of the rest
*/
void SignalHandler(int sig) {
NSLog(@"This is where we save the application data during a signal");
// Save application data on crash
}
-(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// installs HandleExceptions as the Uncaught Exception Handler
NSSetUncaughtExceptionHandler(&HandleExceptions);
// create the signal action structure
struct sigaction newSignalAction;
// initialize the signal action structure
memset(&newSignalAction, 0, sizeof(newSignalAction));
// set SignalHandler as the handler in the signal action structure
newSignalAction.sa_handler = &SignalHandler;
// set SignalHandler as the handlers for SIGABRT, SIGILL and SIGBUS
sigaction(SIGABRT, &newSignalAction, NULL);
sigaction(SIGILL, &newSignalAction, NULL);
sigaction(SIGBUS, &newSignalAction, NULL);
// Call takeOff after install your own unhandled exception and signal handlers
[TestFlight takeOff:@"Insert your Team Token here"];
// continue with your application initialization
}
You do not need to add the above code if your application does not use exception handling already.
##Remote Logging
To perform remote logging you can use the TFLog method which logs in a few different methods described below. In order to make the transition from NSLog to TFLog easy we have used the same method signature for TFLog as NSLog. You can easily switch over to TFLog by adding the following macro to your header
#define NSLog TFLog
That will do a switch from NSLog to TFLog, if you want more information, such as file name and line number you can use a macro like
#define NSLog(__FORMAT__, ...) TFLog((@"%s [Line %d] " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
Which will produce output that looks like
-[HTFCheckpointsController showYesNoQuestion:] [Line 45] Pressed YES/NO
We have implemented three different loggers.
1. TestFlight logger
2. Apple System Log logger
3. STDERR logger
Each of the loggers log asynchronously and all TFLog calls are non blocking. The TestFlight logger writes its data to a file which is then sent to our servers on Session End events. The Apple System Logger sends its messages to the Apple System Log and are viewable using the Organizer in Xcode when the device is attached to your computer. The ASL logger can be disabled by turning it off in your TestFlight options
[TestFlight setOptions:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:@"logToConsole"]];
The default option is YES.
The STDERR logger sends log messages to STDERR so that you can see your log statements while debugging. The STDERR logger is only active when a debugger is attached to your application. If you do not wish to use the STDERR logger you can disable it by turning it off in your TestFlight options
[TestFlight setOptions:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:@"logToSTDERR"]];
The default option is YES.
## Advanced Remote Logging
For most users we expect using TFLog to provide all of the logging functionality that they need. For the occasion where you need to provide a wrapper around TFLog we provide
void TFLogv(NSString *format, va_list arg_list);
Using TFLogv you can have your method that accepts a variable number of arguments that then passes that format and argument list to TFLog.
##iOS3
We now require that anyone who is writing an application that supports iOS3 add the System.framework as an optional link. In order to provide a better shutdown experience we send any large log files to our servers in the background. To add System.framework as an optional link:
1. Select your Project in the Project Navigator
2. Select the target you want to enable the SDK for
3. Select the Build Phases tab
4. Open the Link Binary With Libraries Phase
5. Click the + to add a new library
6. Find libSystem.dylib in the list and add it
7. To the right of libSystem.dylib in the Link Binary With Libraries pane change "Required" to "Optional"

101
External/TestFlight/TestFlight.h vendored Normal file
View File

@@ -0,0 +1,101 @@
//
// TestFlight.h
// libTestFlight
//
// Created by Jonathan Janzen on 06/11/11.
// Copyright 2011 TestFlight. All rights reserved.
#import <Foundation/Foundation.h>
#define TESTFLIGHT_SDK_VERSION @"1.2beta2"
#undef TFLog
#if __cplusplus
extern "C" {
#endif
void TFLog(NSString *format, ...);
void TFLogv(NSString *format, va_list arg_list);
#if __cplusplus
}
#endif
/**
* TestFlight object
* All methods are class level
*/
@interface TestFlight : NSObject {
}
/**
* Add custom environment information
* If you want to track custom information such as a user name from your application you can add it here
*
* @param information A string containing the environment you are storing
* @param key The key to store the information with
*/
+ (void)addCustomEnvironmentInformation:(NSString *)information forKey:(NSString*)key;
/**
* Starts a TestFlight session
*
* @param teamToken Will be your team token obtained from https://testflightapp.com/dashboard/team/edit/
*/
+ (void)takeOff:(NSString *)teamToken;
/**
* Sets custom options
*
* @param options NSDictionary containing the options you want to set available options are described below
*
* Option Accepted Values Description
* reinstallCrashHandlers [ NSNumber numberWithBool:YES ] Reinstalls crash handlers, to be used if a third party
* library installs crash handlers overtop of the TestFlight Crash Handlers
* logToConsole [ NSNumber numberWithBool:YES ] YES - default, sends log statements to Apple System Log and TestFlight log
* NO - sends log statements to TestFlight log only
* logToSTDERR [ NSNumber numberWithBool:YES ] YES - default, sends log statements to STDERR when debugger is attached
* NO - sends log statements to TestFlight log only
* sendLogOnlyOnCrash [ NSNumber numberWithBool:YES ] NO - default, sends logs to TestFlight at the end of every session
* YES - sends logs statements to TestFlight only if there was a crash
* attachBacktraceToFeedback [ NSNumber numberWithBool:YES ] NO - default, feedback is sent exactly as the user enters it
* YES - attaches the current backtrace, with symbols, to the feedback.
* disableInAppUpdates [ NSNumber numberWithBool:YES ] NO - default, in application updates are allowed
* YES - the in application update screen will not be displayed
*/
+ (void)setOptions:(NSDictionary*)options;
/**
* Track when a user has passed a checkpoint after the flight has taken off. Eg. passed level 1, posted high score
*
* @param checkpointName The name of the checkpoint, this should be a static string
*/
+ (void)passCheckpoint:(NSString *)checkpointName;
/**
* Opens a feedback window that is not attached to a checkpoint
*/
+ (void)openFeedbackView;
/**
* Submits custom feedback to the site. Sends the data in feedback to the site. This is to be used as the method to submit
* feedback from custom feedback forms.
*
* @param feedback Your users feedback, method does nothing if feedback is nil
*/
+ (void)submitFeedback:(NSString*)feedback;
/**
* Sets the Device Identifier.
* The SDK no longer obtains the device unique identifier. This method should only be used during testing so that you can
* identify a testers test data with them. If you do not provide the identifier you will still see all session data, with checkpoints
* and logs, but the data will be anonymized.
* It is recommended that you only use this method during testing. We also recommended that you wrap this method with a pre-processor
* directive that is only active for non-app store builds.
* #ifndef RELEASE
* [TestFlight setDeviceIdentifier:[[UIDevice currentDevice] uniqueIdentifier]];
* #endif
*
* @param deviceIdentifer The current devices device identifier
*/
+ (void)setDeviceIdentifier:(NSString*)deviceIdentifer;
@end

BIN
External/TestFlight/libTestFlight.a vendored Normal file

Binary file not shown.

208
External/TestFlight/release_notes.md vendored Normal file
View File

@@ -0,0 +1,208 @@
##1.2 BETA 2 - October 9, 2012
* Resolved an instance of close_file being called on a bad file descriptor
##1.2 BETA 1 - October 1, 2012
* Removed support for armv6
* Exception handler now returns instead of raising a SIGTRAP
##1.1 - September 13, 2012
* armv7s and iOS 6 support
* Updated for general release
##1.1 BETA 3 - September 12, 2012
* armv7s slice added to library
* fixed typo for in application updates, inAppUdates changed to inAppUpdates
##1.1 BETA 2 - September 6, 2012
* Re-enabled armv6 support
* Added option to disable in application updates
##1.1 BETA 1 - July 13, 2012
* Added TFLogv to allow for log customizations. Check the README or online docs for more information.
* Added option attachBacktraceToFeedback, which attaches a backtrace to feedback sent from the SDK. For users who use feedback in more than one location in the application.
* Resolved issue where other exception handlers would not be called during an exception.
* SDK now sends the device language for a session.
* Documentation fixes.
* Stability fixes.
###1.0 - March 29, 2012
* Resolved occurrences of exceptions with the message "No background task exists with identifier 0"
###1.0 BETA 1 - March 23, 2012
* Privacy Updates
* UDID is no longer collected by the SDK. During testing please use `[TestFlight setDeviceIdentifier:[[UIDevice currentDevice] uniqueIdentifier]];` to send the UDID so you can identify your testers. For release do not set `+setDeviceIdentifier`. See Beta Testing and Release Differentiation in the README or online at [https://testflightapp.com/sdk/doc/1.0beta1/](http://testflightapp.com/sdk/doc/1.0beta1/)
###0.8.3 - February 14, 2012
* Rolled previous beta code into release builds
* No longer allow in application updates to occur in applications that were obtained from the app store.
**Tested compiled library with:**
* Xcode 4.3
* Xcode 4.2
* Xcode 4.1
* Xcode 3.2.6
###0.8.3 BETA 5 - February 10, 2012
* Changed logging from asynchronous to synchronous.
* Resolved crash when looking for a log path failed.
* Added submitFeedback to the TestFlight class to allow for custom feedback forms.
###0.8.3 BETA 4 - January 20, 2012
* Resolved an issue that occured when an application was upgraded from 0.8.3 BETA 1 to 0.8.3 BETA 3+ with unsent data from 0.8.3 BETA 1
###0.8.3 BETA 3 - January 19, 2012
* On crash log files over 64k will not be sent until next launch.
**Known Issues:**
* Logging massive amounts of data at the end of a session may prevent the application from launching in time on next launch
###0.8.3 BETA 2 - January 13, 2012
* libz.dylib is now required to be added to your "Link Binary with Libraries" build phase
* Log file compression, The compression is done on an as needed basis rather than before sending
* Changed all outgoing data from JSON to MessagePack
* Added option `logToSTDERR` to disable the `STDERR` logger
###0.8.3 BETA 1 - December 29, 2011
* In rare occurrences old session data that had not been sent to our server may have been discarded or attached to the wrong build. It is now no longer discarded
* Made sending of Session End events more robust
* Network queuing system does better bursting of unsent data
* Log files that are larger than 64K are now sent sometime after the next launch
* Log files that are larger than 16MB are no longer supported and will be replaced with a message indicating the log file was too large
* Fixed crashes while resuming from background
###0.8.2 - December 20, 2011
* Promoted 0.8.2 BETA 4 to stable
**Known Issues:**
* Under some circumstances Session End events may not be sent until the next launch.
* With large log files Session End events may take a long time to show up.
**Tested compiled library with:**
* Xcode 4.3
* Xcode 4.2
* Xcode 4.1
* Xcode 3.2.6
###0.8.2 BETA 4 - December 12, 2011
* Prevented "The string argument is NULL" from occuring during finishedHandshake in rare cases
* Resolved issue where data recorded while offline may not be sent
###0.8.2 BETA 3 - December 8, 2011
* Added auto-release pools to background setup and tear down
###0.8.2 BETA 2 - December 5, 2011
* Fixed the "pointer being freed was not allocated" bug
###0.8.1 - November 18, 2011
* Implemented TFLog logging system, see README for more information
* Fixed an issue where Session End events may not be sent until next launch
* Fixed an issue where duplicate events could be sent
* Fixed an issue with Session End events not being sent from some iPod touch models
**Tested compiled library with:**
* Xcode 4.2
* Xcode 4.1
* Xcode 3.2.6
###0.8 - November 8, 2011
* Added `SIGTRAP` as a signal type that we catch
* Removed all Objective-c from crash reporting
* Removed the use of non signal safe functions from signal handling
* Created a signal safe way to get symbols from a stack trace
* Changed the keyboardType for Long Answer Questions and Feedback to allow for international character input
* Changed `TESTFLIGHT_SDK_VERSION` string to be an `NSString`
* Changed cache folder from Library/Caches/TestFlight to Library/Caches/com.testflight.testflightsdk
* Fixed issue with saving data when device is offline
* Fixed compability issues with iOS 3
* Added calling into the rootViewController shouldAutorotateToInterfaceOrientation if a rootViewController is set
* Made the comments in TestFlight.h compatible with Appledoc
Tested compiled library with:
* Xcode 4.2
* Xcode 4.1
* Xcode 3.2
###0.7.2 - September 29, 2011
* Changed `TESTFLIGHT_SDK_VERSION` string to be an `NSString`
* Fixed an issue where exiting an application while the SDK is active caused modal views to be dismissed
###0.7.1 - September 22, 2011
* Internal release
* Refactoring
###0.7 - September 21, 2011
* Moved TestFlight images and data to the Library/Caches folder
* Resolved an issue where sometimes the rootViewController could not be found and feedback, questions and upgrade views would not be displayed
* In application upgrade changed to allow skipping until the next version is installed and allows upgrades to be forced
* Fixed a memory leak when launching questions
###0.6 - September 2, 2011
* Renamed base64_encode to testflight_base64_encode to remove a conflict with other third party libraries
* Added ability to reinstall crash handlers when they are overwritten using the setOptions API
* Fixed an issue where crash reports might not get sent under certain circumstances
* Fixed a deadlock when the application is put in the background and then resumed before all information can be sent
* Fixed an issue when attempting to un-install all signal handlers during a signal
* Added support for landscape mode on the iPad to the Questions and Feedback views
* Crash reporting now works in versions of Xcode earlier than 4.2
* Fixed a memory leak during handshake
###0.5 - August 19, 2011
* Feedback that is not attached to a checkpoint [TestFlight openFeedbackView]
* Usability changes to question views
* Removed pause and resume sessions, replaced with sessions being stopped and started
* Added text auto correction to the Long Answer question type
* Crash reports now send on crash instead of next launch
###0.4 - August 15, 2011
* In Application Feedback with Questions
* In application updates
* Custom Environment Information added
* Networking stack reimplementation
* Exception handling fixes
###0.3 - June 15, 2011
* Removed all mention of JSONKit from the README
* Added support for using both the Bundle Version and the Bundle Short Version string
###0.2 - June 14, 2011
* Removed all categories this allows users to use the SDK without having to set -ObjC and -load_all
* Prefixed JSONKit for use in TestFlight to remove reported issues where some users were already using JSONKit
* Added support for armv6 again
###0.1 - June 11, 2011
* Initial Version