Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Removed analytics libraries since they are almost always perpetually …

…out of date
  • Loading branch information...
commit 6d57e3bad840a03cbed3ffdc0c631874014547d9 1 parent 72b4e1f
@thuss thuss authored
View
66 providers/ApSalar/Apsalar.h
@@ -1,66 +0,0 @@
-//
-// Apsalar.h
-// Apsalar SDK for iPhone/iOS public API
-//
-// Copyright © 2010-2011 Apsalar Inc. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#import <UIKit/UIKit.h>
-
-typedef enum { // APTIMIZER
- AP_TRIGGER_SUCCESS, // An overlay was loaded
- AP_TRIGGER_NOT_SHOWN, // Overlay not shown, unknown reason
- AP_TRIGGER_NOT_READY, // Apsalar session not started
- AP_TRIGGER_NO_CONNECTIVITY, // No connectivity needed to do overlay
- AP_TRIGGER_NO_RULE, // No rules connected to this trigger
- AP_TRIGGER_UNKNOWN, // New trigger, not yet registered
- AP_TRIGGER_CURRENTLY_ACTIVE // A trigger is already active
-} AP_TRIGGER_RESULT;
-
-@interface Apsalar : NSObject
-+ (void) startSession:(NSString *)apiKey withKey:(NSString *)apiSecret ;
-+ (void) startSession:(NSString *)apiKey // APTIMIZER
- withKey:(NSString *)apiSecret // APTIMIZER
- andLaunchOptions:(NSDictionary *)launchOptions; // APTIMIZER
-+ (void) reStartSession:(NSString *)apiKey withKey:(NSString *)apiSecret;
-+ (BOOL) sessionStarted;
-+ (void) endSession;
-+ (void) event:(NSString *)name;
-+ (void) event:(NSString *)name withArgs:(NSDictionary *)args;
-+ (void) eventWithArgs:(NSString *)name, ...; // use only subclasses of
- // NSObject, not primitive types
- // like int
-+ (void) catchExceptions;
-+ (Apsalar *) shared;
-+ (void) registerCallback:(NSString *)signature // APTIMIZER
- obj:(NSObject *)obj // APTIMIZER
- selector:(SEL)selector; // APTIMIZER
-+ (NSInteger) trigger:(NSString *)name; // APTIMIZER
-+ (void) callback:(NSString *)url; // APTIMIZER
-+ (NSTimeInterval) sessionDuration;
-+ (NSDate *) sessionStartDate;
-+ (NSString *) sessionID;
-+ (NSString *) version;
-+ (void) setBufferLimit:(int)size;
-@property(nonatomic, readonly) NSString *applicationName;
-@property(nonatomic, readonly) NSString *applicationIdentifier;
-@property(nonatomic) int contentDisplayTimeout;
-+ (void) setContentDisplayTimeout:(int)seconds;
-@property(nonatomic) BOOL triggerActive; // APTIMIZER
-+ (BOOL) triggerActive; // APTIMIZER
-@end
-
-@interface ApButton: UIButton {
- @private
- int ap_flags;
-}
-@property(nonatomic, retain) UIButton *actual;
-@property(nonatomic, retain) NSString *name;
-@property(nonatomic, retain) NSString *title;
-@property(nonatomic, retain) NSString *btnType;
-@property(nonatomic) BOOL connected;
-@end
-
-@interface ApFeedbackButton: ApButton
-@end
View
BIN  providers/ApSalar/libApsalar.a
Binary file not shown
View
90 providers/FlurryAnalytics/FlurryAnalytics.h
@@ -1,90 +0,0 @@
-//
-// FlurryAnalytics.h
-// Flurry iOS Analytics Agent
-//
-// Copyright 2009-2011 Flurry, Inc. All rights reserved.
-//
-// Methods in this header file are for use with Flurry Analytics
-
-#import <UIKit/UIKit.h>
-
-/*!
- * \brief Provides all available methods for defining and reporting Analytics from use
- * of your app.
- *
- * Set of methods that allow developers to capture detailed, aggregate information
- * regarding the use of their app by end users.
- * \author 2009 - 2011 Flurry, Inc. All Rights Reserved.
- */
-
-/*!
- * @class FlurryAnalytics
- * @abstract Provides all available methods for defining and reporting Analytics from use
- * of your app.
- * @discussion Set of methods that allow developers to capture detailed, aggregate information
- * regarding the use of their app by end users.
- * @helps This class provides methods necessary for correct function of FlurryAppCircle.h.
- * For information on how to use Flurry's AppCircle SDK to
- * attract high-quality users and monetize your user base see http://wiki.flurry.com/index.php?title=AppCircle.
- *
- */
-
-@interface FlurryAnalytics : NSObject {
-}
-
-/*
- optional sdk settings that should be called before start session
- */
-+ (void)setAppVersion:(NSString *)version; // override the app version
-+ (NSString *)getFlurryAgentVersion; // get the Flurry Agent version number
-+ (void)setShowErrorInLogEnabled:(BOOL)value; // default is NO
-+ (void)setDebugLogEnabled:(BOOL)value; // generate debug logs for Flurry support, default is NO
-+ (void)setSessionContinueSeconds:(int)seconds; // default is 10 seconds
-+ (void)setSecureTransportEnabled:(BOOL)value; // set data to be sent over SSL, default is NO
-
-/*
- start session, attempt to send saved sessions to server
- */
-+ (void)startSession:(NSString *)apiKey;
-
-/*
- log events or errors after session has started
- */
-+ (void)logEvent:(NSString *)eventName;
-+ (void)logEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters;
-+ (void)logError:(NSString *)errorID message:(NSString *)message exception:(NSException *)exception;
-+ (void)logError:(NSString *)errorID message:(NSString *)message error:(NSError *)error;
-
-/*
- start or end timed events
- */
-+ (void)logEvent:(NSString *)eventName timed:(BOOL)timed;
-+ (void)logEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters timed:(BOOL)timed;
-+ (void)endTimedEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters; // non-nil parameters will update the parameters
-
-/*
- count page views
- */
-+ (void)logAllPageViews:(id)target; // automatically track page view on UINavigationController or UITabBarController
-+ (void)logPageView; // manually increment page view by 1
-
-/*
- set user info
- */
-+ (void)setUserID:(NSString *)userID; // user's id in your system
-+ (void)setAge:(int)age; // user's age in years
-+ (void)setGender:(NSString *)gender; // user's gender m or f
-
-/*
- set location information
- */
-+ (void)setLatitude:(double)latitude longitude:(double)longitude horizontalAccuracy:(float)horizontalAccuracy verticalAccuracy:(float)verticalAccuracy;
-
-/*
- optional session settings that can be changed after start session
- */
-+ (void)setSessionReportsOnCloseEnabled:(BOOL)sendSessionReportsOnClose; // default is YES
-+ (void)setSessionReportsOnPauseEnabled:(BOOL)setSessionReportsOnPauseEnabled; // default is NO
-+ (void)setEventLoggingEnabled:(BOOL)value; // default is YES
-
-@end
View
BIN  providers/FlurryAnalytics/libFlurryAnalytics.a
Binary file not shown
View
52 providers/Localytics/LocalyticsDatabase.h
@@ -1,52 +0,0 @@
-//
-// LocalyticsDatabase.h
-// LocalyticsDemo
-//
-// Created by jkaufman on 5/26/11.
-// Copyright 2011 Localytics. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#import <sqlite3.h>
-
-@interface LocalyticsDatabase : NSObject {
- sqlite3 *_databaseConnection;
- NSRecursiveLock *_dbLock;
- NSRecursiveLock *_transactionLock;
-}
-
-+ (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)addFlowEventWithBlobString:(NSString *)blob;
-- (BOOL)removeLastCloseAndFlowEvents;
-
-- (BOOL)addHeaderWithSequenceNumber:(int)number blobString:(NSString *)blob rowId:(sqlite3_int64 *)insertedRowId;
-- (int)unstagedEventCount;
-- (BOOL)stageEventsForUpload:(sqlite3_int64)headerId;
-- (NSString *)uploadBlobString;
-- (BOOL)deleteUploadData;
-
-- (NSTimeInterval)lastSessionStartTimestamp;
-- (BOOL)setLastsessionStartTimestamp:(NSTimeInterval)timestamp;
-
-- (BOOL)isOptedOut;
-- (BOOL)setOptedOut:(BOOL)optOut;
-- (NSString *) installId;
-
-- (NSString *)customDimension:(int)dimension;
-- (BOOL)setCustomDimension:(int)dimension value:(NSString *)value;
-
-@end
View
740 providers/Localytics/LocalyticsDatabase.m
@@ -1,740 +0,0 @@
-//
-// LocalyticsDatabase.m
-// LocalyticsDemo
-//
-// Created by jkaufman on 5/26/11.
-// Copyright 2011 Localytics. All rights reserved.
-//
-
-#import "LocalyticsDatabase.h"
-
-#define LOCALYTICS_DIR @".localytics" // Name for the directory in which Localytics database is stored
-#define LOCALYTICS_DB @"localytics" // File name for the database (without extension)
-#define BUSY_TIMEOUT 30 // Maximum time SQlite will busy-wait for the database to unlock before returning SQLITE_BUSY
-
-@interface LocalyticsDatabase ()
- - (int)schemaVersion;
- - (void)createSchema;
- - (void)upgradeToSchemaV2;
- - (void)moveDbToCaches;
-@end
-
-@implementation LocalyticsDatabase
-
-// The singleton database object.
-static LocalyticsDatabase *_sharedLocalyticsDatabase = nil;
-
-+ (NSString *)localyticsDirectoryPath {
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
- return [[paths objectAtIndex:0] stringByAppendingPathComponent:LOCALYTICS_DIR];
-}
-
-+ (NSString *)localyticsDatabasePath {
- NSString *path = [[LocalyticsDatabase localyticsDirectoryPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.sqlite", LOCALYTICS_DB]];
- return path;
-}
-
-#pragma mark Singleton Class
-+ (LocalyticsDatabase *)sharedLocalyticsDatabase {
- @synchronized(self) {
- if (_sharedLocalyticsDatabase == nil) {
- _sharedLocalyticsDatabase = [[self alloc] init];
- }
- }
- return _sharedLocalyticsDatabase;
-}
-
-- (LocalyticsDatabase *)init {
- if((self = [super init])) {
-
- // Ensure that database access is not concurrent and that only one thread has an open
- // transaction at any given time.
- _dbLock = [[NSRecursiveLock alloc] init];
- _transactionLock = [[NSRecursiveLock alloc] init];
-
- // Mover any data that a previous library may have left in the documents directory
- [self moveDbToCaches];
-
- // Create directory structure for Localytics.
- NSString *directoryPath = [LocalyticsDatabase localyticsDirectoryPath];
- if (![[NSFileManager defaultManager] fileExistsAtPath:directoryPath]) {
- [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:nil];
- }
-
- // Attempt to open database. It will be created if it does not exist, already.
- [_dbLock lock];
- NSString *dbPath = [LocalyticsDatabase localyticsDatabasePath];
- int code = sqlite3_open([dbPath UTF8String], &_databaseConnection);
-
- // If we were unable to open the database, it is likely corrupted. Clobber it and move on.
- if (code != SQLITE_OK) {
- [[NSFileManager defaultManager] removeItemAtPath:dbPath error:nil];
- code = sqlite3_open([dbPath UTF8String], &_databaseConnection);
- }
- [_dbLock unlock];
-
- // Check db connection, creating schema if necessary.
- if (code == SQLITE_OK) {
- sqlite3_busy_timeout(_databaseConnection, BUSY_TIMEOUT); // Defaults to 0, otherwise.
- if ([self schemaVersion] == 0) {
- [self createSchema];
- }
- }
-
- // Perform any Migrations if necessary
- if ([self schemaVersion] < 2) {
- [self upgradeToSchemaV2];
- }
- }
-
- return self;
-}
-
-#pragma mark - Database
-
-- (BOOL)beginTransaction:(NSString *)name {
- [_dbLock lock];
- [_transactionLock lock];
- const char *sql = [[NSString stringWithFormat:@"SAVEPOINT %@", name] cStringUsingEncoding:NSUTF8StringEncoding];
- int code = sqlite3_exec(_databaseConnection, sql, NULL, NULL, NULL);
- [_dbLock unlock];
- return code == SQLITE_OK;
-}
-
-- (BOOL)releaseTransaction:(NSString *)name {
- [_dbLock lock];
- const char *sql = [[NSString stringWithFormat:@"RELEASE SAVEPOINT %@", name] cStringUsingEncoding:NSUTF8StringEncoding];
- int code = sqlite3_exec(_databaseConnection, sql, NULL, NULL, NULL);
- [_transactionLock unlock];
- [_dbLock unlock];
- return code == SQLITE_OK;
-}
-
-- (BOOL)rollbackTransaction:(NSString *)name {
- [_dbLock lock];
- const char *sql = [[NSString stringWithFormat:@"ROLLBACK SAVEPOINT %@", name] cStringUsingEncoding:NSUTF8StringEncoding];
- int code = sqlite3_exec(_databaseConnection, sql, NULL, NULL, NULL);
- [_transactionLock unlock];
- [_dbLock unlock];
- return code == SQLITE_OK;
-}
-
-- (int)schemaVersion {
- [_dbLock lock];
- int version = 0;
- const char *sql = "SELECT MAX(schema_version) FROM localytics_info";
- sqlite3_stmt *selectSchemaVersion;
- if(sqlite3_prepare_v2(_databaseConnection, sql, -1, &selectSchemaVersion, NULL) == SQLITE_OK) {
- if(sqlite3_step(selectSchemaVersion) == SQLITE_ROW) {
- version = sqlite3_column_int(selectSchemaVersion, 0);
- }
- }
- sqlite3_finalize(selectSchemaVersion);
- [_dbLock unlock];
- return version;
-}
-
-- (NSString *) installId {
- [_dbLock lock];
-
- NSString *installId = nil;
-
- sqlite3_stmt *selectInstallId;
- sqlite3_prepare_v2(_databaseConnection, "SELECT install_id FROM localytics_info", -1, &selectInstallId, NULL);
- int code = sqlite3_step(selectInstallId);
- if (code == SQLITE_ROW && sqlite3_column_text(selectInstallId, 0)) {
- installId = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectInstallId, 0)];
- }
- sqlite3_finalize(selectInstallId);
-
- [_dbLock unlock];
- return installId;
-}
-
-// Due to the new iOS storage guidelines it is necessary to move the database out of the documents directory
-// and into the /library/caches directory
-- (void)moveDbToCaches {
- NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *localyticsDocumentsDirectory = [[documentPaths objectAtIndex:0] stringByAppendingPathComponent:LOCALYTICS_DIR];
- NSArray *cachesPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
- NSString *localyticsCachesDirectory = [[cachesPaths objectAtIndex:0] stringByAppendingPathComponent:LOCALYTICS_DIR];
-
- // If the old directory doesn't exist, there is nothing else to do here
- if([[NSFileManager defaultManager] fileExistsAtPath:localyticsDocumentsDirectory] == NO)
- {
- return;
- }
-
- // Try to move the directory
- if(NO == [[NSFileManager defaultManager] moveItemAtPath:localyticsDocumentsDirectory
- toPath:localyticsCachesDirectory
- error:nil])
- {
- // If the move failed try and, delete the old directory
- [ [NSFileManager defaultManager] removeItemAtPath:localyticsDocumentsDirectory error:nil];
- }
-}
-
-- (void)createSchema {
- int code = SQLITE_OK;
-
- [_dbLock lock];
- [_transactionLock lock];
-
- // Execute schema creation within a single transaction.
- code = sqlite3_exec(_databaseConnection, "BEGIN", NULL, NULL, NULL);
-
- if (code == SQLITE_OK) {
- code = sqlite3_exec(_databaseConnection,
- "CREATE TABLE upload_headers ("
- "sequence_number INTEGER PRIMARY KEY, "
- "blob_string TEXT)",
- NULL, NULL, NULL);
- }
-
- if (code == SQLITE_OK) {
- code = sqlite3_exec(_databaseConnection,
- "CREATE TABLE events ("
- "event_id INTEGER PRIMARY KEY AUTOINCREMENT, " // In case foreign key constraints are reintroduced.
- "upload_header INTEGER, "
- "blob_string TEXT NOT NULL)",
- NULL, NULL, NULL);
- }
-
- if (code == SQLITE_OK) {
- code = sqlite3_exec(_databaseConnection,
- "CREATE TABLE localytics_info ("
- "schema_version INTEGER PRIMARY KEY, "
- "last_upload_number INTEGER, "
- "last_session_number INTEGER, "
- "opt_out BOOLEAN, "
- "last_close_event INTEGER, "
- "last_flow_event INTEGER, "
- "last_session_start REAL, "
- "install_id CHAR(40), "
- "custom_d0 CHAR(64), "
- "custom_d1 CHAR(64), "
- "custom_d2 CHAR(64), "
- "custom_d3 CHAR(64) "
- ")",
- NULL, NULL, NULL);
- }
-
- if (code == SQLITE_OK) {
- code = sqlite3_exec(_databaseConnection,
- "INSERT INTO localytics_info (schema_version, last_upload_number, last_session_number, opt_out) "
- "VALUES (2, 0, 0, 0)",
- NULL, NULL, NULL);
- }
-
- // Commit transaction.
- if (code == SQLITE_OK || code == SQLITE_DONE) {
- sqlite3_exec(_databaseConnection, "COMMIT", NULL, NULL, NULL);
- } else {
- sqlite3_exec(_databaseConnection, "ROLLBACK", NULL, NULL, NULL);
- }
- [_transactionLock unlock];
- [_dbLock unlock];
-}
-
-// V2 adds a unique identifier for each installation
-// This identifier has been moved to user preferences so the database an live in the caches directory
-// Also adds storage for custom dimensions
-- (void)upgradeToSchemaV2 {
- int code = SQLITE_OK;
-
- [_dbLock lock];
- [_transactionLock lock];
- code = sqlite3_exec(_databaseConnection, "BEGIN", NULL, NULL, NULL);
-
- if (code == SQLITE_OK) {
- code = sqlite3_exec(_databaseConnection,
- "ALTER TABLE localytics_info ADD install_id CHAR(40)",
- NULL, NULL, NULL);
- }
-
- if (code == SQLITE_OK) {
- code = sqlite3_exec(_databaseConnection,
- "ALTER TABLE localytics_info ADD custom_d0 CHAR(64)",
- NULL, NULL, NULL);
- }
-
- if (code == SQLITE_OK) {
- code = sqlite3_exec(_databaseConnection,
- "ALTER TABLE localytics_info ADD custom_d1 CHAR(64)",
- NULL, NULL, NULL);
- }
-
- if (code == SQLITE_OK) {
- code = sqlite3_exec(_databaseConnection,
- "ALTER TABLE localytics_info ADD custom_d2 CHAR(64)",
- NULL, NULL, NULL);
- }
-
- if (code == SQLITE_OK) {
- code = sqlite3_exec(_databaseConnection,
- "ALTER TABLE localytics_info ADD custom_d3 CHAR(64)",
- NULL, NULL, NULL);
- }
-
- // Commit transaction.
- if (code == SQLITE_OK || code == SQLITE_DONE) {
- sqlite3_exec(_databaseConnection, "COMMIT", NULL, NULL, NULL);
- } else {
- sqlite3_exec(_databaseConnection, "ROLLBACK", NULL, NULL, NULL);
- }
- [_transactionLock unlock];
- [_dbLock unlock];
-}
-
-- (NSUInteger)databaseSize {
- NSUInteger size = 0;
- NSDictionary *fileAttributes = [[NSFileManager defaultManager]
- attributesOfItemAtPath:[LocalyticsDatabase localyticsDatabasePath]
- error:nil];
- size = [fileAttributes fileSize];
- return size;
-}
-
-- (int) eventCount {
- [_dbLock lock];
- int count = 0;
- const char *sql = "SELECT count(*) FROM events";
- sqlite3_stmt *selectEventCount;
-
- if(sqlite3_prepare_v2(_databaseConnection, sql, -1, &selectEventCount, NULL) == SQLITE_OK)
- {
- if(sqlite3_step(selectEventCount) == SQLITE_ROW) {
- count = sqlite3_column_int(selectEventCount, 0);
- }
- }
- sqlite3_finalize(selectEventCount);
- [_dbLock unlock];
-
- return count;
-}
-
-- (NSTimeInterval)createdTimestamp {
- NSTimeInterval timestamp = 0;
- NSDictionary *fileAttributes = [[NSFileManager defaultManager]
- attributesOfItemAtPath:[LocalyticsDatabase localyticsDatabasePath]
- error:nil];
- timestamp = [[fileAttributes fileCreationDate] timeIntervalSince1970];
- return timestamp;
-}
-
-- (NSTimeInterval)lastSessionStartTimestamp {
- [_dbLock lock];
-
- NSTimeInterval lastSessionStart = 0;
-
- sqlite3_stmt *selectLastSessionStart;
- sqlite3_prepare_v2(_databaseConnection, "SELECT last_session_start FROM localytics_info", -1, &selectLastSessionStart, NULL);
- int code = sqlite3_step(selectLastSessionStart);
- if (code == SQLITE_ROW) {
- lastSessionStart = sqlite3_column_double(selectLastSessionStart, 0) == 1;
- }
- sqlite3_finalize(selectLastSessionStart);
-
- [_dbLock unlock];
-
- return lastSessionStart;
-}
-
-- (BOOL)setLastsessionStartTimestamp:(NSTimeInterval)timestamp {
- [_dbLock lock];
-
- sqlite3_stmt *updateLastSessionStart;
- sqlite3_prepare_v2(_databaseConnection, "UPDATE localytics_info SET last_session_start = ?", -1, &updateLastSessionStart, NULL);
- sqlite3_bind_double(updateLastSessionStart, 1, timestamp);
- int code = sqlite3_step(updateLastSessionStart);
- sqlite3_finalize(updateLastSessionStart);
-
- [_dbLock unlock];
-
- return code == SQLITE_DONE;
-}
-
-- (BOOL)isOptedOut {
- [_dbLock lock];
-
- BOOL optedOut = NO;
-
- sqlite3_stmt *selectOptOut;
- sqlite3_prepare_v2(_databaseConnection, "SELECT opt_out FROM localytics_info", -1, &selectOptOut, NULL);
- int code = sqlite3_step(selectOptOut);
- if (code == SQLITE_ROW) {
- optedOut = sqlite3_column_int(selectOptOut, 0) == 1;
- }
- sqlite3_finalize(selectOptOut);
-
- [_dbLock unlock];
-
- return optedOut;
-}
-
-- (BOOL)setOptedOut:(BOOL)optOut {
- [_dbLock lock];
-
- sqlite3_stmt *updateOptedOut;
- sqlite3_prepare_v2(_databaseConnection, "UPDATE localytics_info SET opt_out = ?", -1, &updateOptedOut, NULL);
- sqlite3_bind_int(updateOptedOut, 1, optOut);
- int code = sqlite3_step(updateOptedOut);
- sqlite3_finalize(updateOptedOut);
-
- [_dbLock unlock];
-
- return code == SQLITE_OK;
-}
-
-- (NSString *)customDimension:(int)dimension {
- if(dimension < 0 || dimension > 3) {
- return nil;
- }
-
- NSString *value = nil;
- NSString *query = [NSString stringWithFormat:@"select custom_d%i from localytics_info", dimension];
-
- [_dbLock lock];
- sqlite3_stmt *selectCustomDim;
- sqlite3_prepare_v2(_databaseConnection, [query UTF8String], -1, &selectCustomDim, NULL);
- int code = sqlite3_step(selectCustomDim);
- if (code == SQLITE_ROW && sqlite3_column_text(selectCustomDim, 0)) {
- value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectCustomDim, 0)];
- }
- sqlite3_finalize(selectCustomDim);
- [_dbLock unlock];
-
- return value;
-}
-
-- (BOOL)setCustomDimension:(int)dimension value:(NSString *)value {
- if(dimension < 0 || dimension > 3) {
- return false;
- }
-
- NSString *query = [NSString stringWithFormat:@"update localytics_info SET custom_d%i = %@",
- dimension,
- (value == nil) ? @"null" : [NSString stringWithFormat:@"\"%@\"", value]];
-
- [_dbLock lock];
- int code = sqlite3_exec(_databaseConnection, [query UTF8String], NULL, NULL, NULL);
- [_dbLock unlock];
-
- return code == SQLITE_OK;
-}
-
-- (BOOL)incrementLastUploadNumber:(int *)uploadNumber {
- NSString *t = @"increment_upload_number";
- int code = SQLITE_OK;
-
- code = [self beginTransaction:t] ? SQLITE_OK : SQLITE_ERROR;
-
- [_dbLock lock];
-
- if(code == SQLITE_OK) {
- // Increment value
- code = sqlite3_exec(_databaseConnection,
- "UPDATE localytics_info "
- "SET last_upload_number = (last_upload_number + 1)",
- NULL, NULL, NULL);
- }
-
- if(code == SQLITE_OK) {
- // Retrieve new value
- sqlite3_stmt *selectUploadNumber;
- sqlite3_prepare_v2(_databaseConnection,
- "SELECT last_upload_number FROM localytics_info",
- -1, &selectUploadNumber, NULL);
- code = sqlite3_step(selectUploadNumber);
- if (code == SQLITE_ROW) {
- *uploadNumber = sqlite3_column_int(selectUploadNumber, 0);
- }
- sqlite3_finalize(selectUploadNumber);
- }
-
- [_dbLock unlock];
-
- if(code == SQLITE_ROW) {
- [self releaseTransaction:t];
- } else {
- [self rollbackTransaction:t];
- }
-
- return code == SQLITE_ROW;
-}
-
-- (BOOL)incrementLastSessionNumber:(int *)sessionNumber {
- NSString *t = @"increment_session_number";
- int code = [self beginTransaction:t] ? SQLITE_OK : SQLITE_ERROR;
-
- [_dbLock lock];
-
- if(code == SQLITE_OK) {
- // Increment value
- code = sqlite3_exec(_databaseConnection,
- "UPDATE localytics_info "
- "SET last_session_number = (last_session_number + 1)",
- NULL, NULL, NULL);
- }
-
- if(code == SQLITE_OK) {
- // Retrieve new value
- sqlite3_stmt *selectSessionNumber;
- sqlite3_prepare_v2(_databaseConnection,
- "SELECT last_session_number FROM localytics_info",
- -1, &selectSessionNumber, NULL);
- code = sqlite3_step(selectSessionNumber);
- if (code == SQLITE_ROW && sessionNumber != NULL) {
- *sessionNumber = sqlite3_column_int(selectSessionNumber, 0);
- }
- sqlite3_finalize(selectSessionNumber);
- }
-
- [_dbLock unlock];
-
- if(code == SQLITE_ROW) {
- [self releaseTransaction:t];
- } else {
- [self rollbackTransaction:t];
- }
-
- return code == SQLITE_ROW;
-}
-
-- (BOOL)addEventWithBlobString:(NSString *)blob {
- [_dbLock lock];
-
- int code = SQLITE_OK;
- sqlite3_stmt *insertEvent;
- sqlite3_prepare_v2(_databaseConnection, "INSERT INTO events (blob_string) VALUES (?)", -1, &insertEvent, NULL);
- sqlite3_bind_text(insertEvent, 1, [blob UTF8String], -1, SQLITE_TRANSIENT);
- code = sqlite3_step(insertEvent);
- sqlite3_finalize(insertEvent);
-
- [_dbLock unlock];
-
- return code == SQLITE_DONE;
-}
-
-- (BOOL)addCloseEventWithBlobString:(NSString *)blob {
- NSString *t = @"add_close_event";
- BOOL success = [self beginTransaction:t];
-
- // Add close event.
- if (success) {
- success = [self addEventWithBlobString:blob];
- }
-
- // Record row id to localytics_info so that it can be removed if the session resumes.
- if (success) {
- [_dbLock lock];
- sqlite3_stmt *updateCloseEvent;
- sqlite3_prepare_v2(_databaseConnection, "UPDATE localytics_info SET last_close_event = (SELECT event_id FROM events WHERE rowid = ?)", -1, &updateCloseEvent, NULL);
- sqlite3_int64 lastRow = sqlite3_last_insert_rowid(_databaseConnection);
- sqlite3_bind_int64(updateCloseEvent, 1, lastRow);
- int code = sqlite3_step(updateCloseEvent);
- sqlite3_finalize(updateCloseEvent);
- success = code == SQLITE_DONE;
- [_dbLock unlock];
- }
-
- if (success) {
- [self releaseTransaction:t];
- } else {
- [self rollbackTransaction:t];
- }
- return success;
-}
-
-- (BOOL)addFlowEventWithBlobString:(NSString *)blob {
- NSString *t = @"add_flow_event";
- BOOL success = [self beginTransaction:t];
-
- // Add flow event.
- if (success) {
- success = [self addEventWithBlobString:blob];
- }
-
- // Record row id to localytics_info so that it can be removed if the session resumes.
- if (success) {
- [_dbLock lock];
- sqlite3_stmt *updateFlowEvent;
- sqlite3_prepare_v2(_databaseConnection, "UPDATE localytics_info SET last_flow_event = (SELECT event_id FROM events WHERE rowid = ?)", -1, &updateFlowEvent, NULL);
- sqlite3_int64 lastRow = sqlite3_last_insert_rowid(_databaseConnection);
- sqlite3_bind_int64(updateFlowEvent, 1, lastRow);
- int code = sqlite3_step(updateFlowEvent);
- sqlite3_finalize(updateFlowEvent);
- success = code == SQLITE_DONE;
- [_dbLock unlock];
- }
-
- if (success) {
- [self releaseTransaction:t];
- } else {
- [self rollbackTransaction:t];
- }
- return success;
-}
-
-- (BOOL)removeLastCloseAndFlowEvents {
- [_dbLock lock];
-
- // Attempt to remove the last recorded close event.
- // Fail quietly if none was saved or it was previously removed.
- int code = sqlite3_exec(_databaseConnection, "DELETE FROM events WHERE event_id = (SELECT last_close_event FROM localytics_info) OR event_id = (SELECT last_flow_event FROM localytics_info)", NULL, NULL, NULL);
-
- [_dbLock unlock];
-
- return code == SQLITE_OK;
-}
-
-- (BOOL)addHeaderWithSequenceNumber:(int)number blobString:(NSString *)blob rowId:(sqlite3_int64 *)insertedRowId {
- [_dbLock lock];
-
- sqlite3_stmt *insertHeader;
- sqlite3_prepare_v2(_databaseConnection, "INSERT INTO upload_headers (sequence_number, blob_string) VALUES (?, ?)", -1, &insertHeader, NULL);
- sqlite3_bind_int(insertHeader, 1, number);
- sqlite3_bind_text(insertHeader, 2, [blob UTF8String], -1, SQLITE_TRANSIENT);
- int code = sqlite3_step(insertHeader);
- sqlite3_finalize(insertHeader);
-
- if (code == SQLITE_DONE && insertedRowId != NULL) {
- *insertedRowId = sqlite3_last_insert_rowid(_databaseConnection);
- }
-
- [_dbLock unlock];
-
- return code == SQLITE_DONE;
-}
-
-- (int)unstagedEventCount {
- [_dbLock lock];
-
- int rowCount = 0;
- sqlite3_stmt *selectEventCount;
- sqlite3_prepare_v2(_databaseConnection, "SELECT COUNT(*) FROM events WHERE UPLOAD_HEADER IS NULL", -1, &selectEventCount, NULL);
- int code = sqlite3_step(selectEventCount);
- if (code == SQLITE_ROW) {
- rowCount = sqlite3_column_int(selectEventCount, 0);
- }
- sqlite3_finalize(selectEventCount);
-
- [_dbLock unlock];
-
- return rowCount;
-}
-
-- (BOOL)stageEventsForUpload:(sqlite3_int64)headerId {
- [_dbLock lock];
-
- // Associate all outstanding events with the given upload header ID.
- NSString *stageEvents = [NSString stringWithFormat:@"UPDATE events SET upload_header = ? WHERE upload_header IS NULL"];
- sqlite3_stmt *updateEvents;
- sqlite3_prepare_v2(_databaseConnection, [stageEvents UTF8String], -1, &updateEvents, NULL);
- sqlite3_bind_int(updateEvents, 1, headerId);
- int code = sqlite3_step(updateEvents);
- sqlite3_finalize(updateEvents);
- BOOL success = (code == SQLITE_DONE);
-
- [_dbLock unlock];
-
- return success;
-}
-
-- (NSString *)uploadBlobString {
- [_dbLock lock];
-
- // Retrieve the blob strings of each upload header and its child events, in order.
- const char *sql = "SELECT * FROM ( "
- " SELECT h.blob_string AS 'blob', h.sequence_number as 'seq', 0 FROM upload_headers h"
- " UNION ALL "
- " SELECT e.blob_string AS 'blob', e.upload_header as 'seq', 1 FROM events e"
- ") "
- "ORDER BY 2, 3";
- sqlite3_stmt *selectBlobs;
- sqlite3_prepare_v2(_databaseConnection, sql, -1, &selectBlobs, NULL);
- NSMutableString *uploadBlobString = [NSMutableString string];
- while (sqlite3_step(selectBlobs) == SQLITE_ROW) {
- const char *blob = (const char *)sqlite3_column_text(selectBlobs, 0);
- if (blob != NULL) {
- NSString *blobString = [[NSString alloc] initWithCString:blob encoding:NSUTF8StringEncoding];
- [uploadBlobString appendString:blobString];
- [blobString release];
- }
- }
- sqlite3_finalize(selectBlobs);
-
- [_dbLock unlock];
-
- return [[uploadBlobString copy] autorelease];
-}
-
-- (BOOL)deleteUploadData {
- // Delete all headers and staged events.
- NSString *t = @"delete_upload_data";
- int code = [self beginTransaction:t] ? SQLITE_OK : SQLITE_ERROR;
-
- [_dbLock lock];
-
- if (code == SQLITE_OK) {
- code = sqlite3_exec(_databaseConnection, "DELETE FROM events WHERE upload_header IS NOT NULL", NULL, NULL, NULL);
- }
-
- if (code == SQLITE_OK) {
- code = sqlite3_exec(_databaseConnection, "DELETE FROM upload_headers", NULL, NULL, NULL);
- }
-
- [_dbLock unlock];
-
- if (code == SQLITE_OK) {
- [self releaseTransaction:t];
- } else {
- [self rollbackTransaction:t];
- }
-
- return code == SQLITE_OK;
-}
-
-#pragma mark - Lifecycle
-
-+ (id)allocWithZone:(NSZone *)zone {
- @synchronized(self) {
- if (_sharedLocalyticsDatabase == nil) {
- _sharedLocalyticsDatabase = [super allocWithZone:zone];
- return _sharedLocalyticsDatabase;
- }
- }
- // 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 {
- sqlite3_close(_databaseConnection);
- [_transactionLock release];
- [_dbLock release];
- [super dealloc];
-}
-
-@end
View
212 providers/Localytics/LocalyticsSession.h
@@ -1,212 +0,0 @@
-// LocalyticsSession.h
-// Copyright (C) 2009 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>
-
-// 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
- 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 BOOL isSessionOpen;
-@property BOOL hasInitialized;
-@property float backgroundSessionTimeout;
-
-#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 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.
-*/
-- (void)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;
-
-@end
View
1,076 providers/Localytics/LocalyticsSession.m
@@ -1,1076 +0,0 @@
-// LocalyticsSession.m
-// Copyright (C) 2009 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 "LocalyticsSession.h"
-#import "WebserviceConstants.h"
-#import "UploaderThread.h"
-#import "LocalyticsDatabase.h"
-
-#include <sys/types.h>
-#include <sys/sysctl.h>
-#include <mach/mach.h>
-#include <sys/socket.h>
-#include <net/if_dl.h>
-#include <ifaddrs.h>
-#include <CommonCrypto/CommonDigest.h>
-
-#pragma mark Constants
-#define PREFERENCES_KEY @"_localytics_install_id" // The randomly generated ID for each install of the app
-#define CLIENT_VERSION @"iOS_2.5" // The version of this library
-#define LOCALYTICS_DIR @".localytics" // The directory in which the Localytics database is stored
-#define MAX_DATABASE_SIZE 500000 // The maximum allowed disk size of the primary database file at open, in bytes
-#define MAX_STORED_EVENTS 1000 // The maximum alowed events to be stored in the database.
-#define IFT_ETHER 0x6 // Ethernet CSMACD
-#define PATH_TO_APT @"/private/var/lib/apt/"
-
-#define DEFAULT_BACKGROUND_SESSION_TIMEOUT 15 // Default value for how many seconds a session persists when App shifts to the background.
-
-// The singleton session object.
-static LocalyticsSession *_sharedLocalyticsSession = nil;
-
-@interface LocalyticsSession()
-
-#pragma mark @property Member Variables
-@property (nonatomic, retain) NSString *sessionUUID;
-@property (nonatomic, retain) NSString *applicationKey;
-@property (nonatomic, assign) NSTimeInterval lastSessionStartTimestamp;
-@property (nonatomic, retain) NSDate *sessionResumeTime;
-@property (nonatomic, retain) NSDate *sessionCloseTime;
-@property (nonatomic, retain) NSMutableString *unstagedFlowEvents;
-@property (nonatomic, retain) NSMutableString *stagedFlowEvents;
-@property (nonatomic, retain) NSMutableString *screens;
-@property (nonatomic, assign) NSTimeInterval sessionActiveDuration;
-@property (nonatomic, assign) BOOL sessionHasBeenOpen;
-
-#pragma mark Private Methods
-- (NSString *)blobHeaderStringWithSequenceNumber:(int)nextSequenceNumber;
-- (BOOL)createOptEvent:(BOOL)optState;
-- (void)logMessage:(NSString *)message;
-- (NSString *)getRandomUUID;
-- (void)addFlowEventWithName:(NSString *)name type:(NSString *)eventType;
-- (void)addScreenWithName:(NSString *)name;
-- (BOOL)saveApplicationFlowAndRemoveOnResume:(BOOL)removeOnResume;
-- (NSString *)customDimensions;
-- (NSString *)hashString:(NSString *)input;
-- (NSString *)macAddress;
-- (NSString *)formatAttributeWithName:(NSString *)paramName value:(NSString *)paramValue first:(BOOL)firstAttribute;
-- (NSString *)formatAttributeWithName:(NSString *)paramName value:(NSString *)paramValue;
-- (NSString *)escapeString:(NSString *)input;
-- (NSString *)uniqueDeviceIdentifier;
-- (NSString *) installationId;
-- (NSString *)getAppVersion;
-- (NSTimeInterval)getTimestamp;
-- (BOOL)isDeviceJailbroken;
-- (NSString *)getDeviceModel;
-- (NSString *)modelSizeString;
-- (double)availableMemory;
-- (void)reopenPreviousSession;
-@end
-
-@implementation LocalyticsSession
-
-#pragma mark synthesis
-@synthesize sessionUUID = _sessionUUID;
-@synthesize applicationKey = _applicationKey;
-@synthesize lastSessionStartTimestamp = _lastSessionStartTimestamp;
-@synthesize sessionResumeTime = _sessionResumeTime;
-@synthesize sessionCloseTime = _sessionCloseTime;
-@synthesize isSessionOpen = _isSessionOpen;
-@synthesize hasInitialized = _hasInitialized;
-@synthesize backgroundSessionTimeout = _backgroundSessionTimeout;
-@synthesize unstagedFlowEvents = _unstagedFlowEvents;
-@synthesize stagedFlowEvents = _stagedFlowEvents;
-@synthesize screens = _screens;
-@synthesize sessionActiveDuration = _sessionActiveDuration;
-@synthesize sessionHasBeenOpen = _sessionHasBeenOpen;
-
-#pragma mark Singleton Class
-+ (LocalyticsSession *)sharedLocalyticsSession {
- @synchronized(self) {
- if (_sharedLocalyticsSession == nil) {
- _sharedLocalyticsSession = [[self alloc] init];
- }
- }
- return _sharedLocalyticsSession;
-}
-
-#pragma mark Object Initialization
-- (LocalyticsSession *)init {
- if((self = [super init])) {
- _isSessionOpen = NO;
- _hasInitialized = NO;
- _backgroundSessionTimeout = DEFAULT_BACKGROUND_SESSION_TIMEOUT;
- _sessionHasBeenOpen = NO;
- [LocalyticsDatabase sharedLocalyticsDatabase];
- }
-
- return self;
-}
-
-#pragma mark Public Methods
-- (void)LocalyticsSession:(NSString *)appKey {
- // If the session has already initialized, don't bother doing it again.
- if(self.hasInitialized)
- {
- [self logMessage:@"Object has already been initialized."];
- return;
- }
-
- @try {
-
- if(appKey == (id)[NSNull null] || appKey.length == 0) {
- [self logMessage:@"App key is null or empty."];
- self.hasInitialized = NO;
- return;
- }
-
- // App key should only be alphanumeric chars and dashes.
- NSString *trimmedAppKey = [appKey stringByReplacingOccurrencesOfString:@"-" withString:@""];
- if([[trimmedAppKey stringByTrimmingCharactersInSet:[NSCharacterSet alphanumericCharacterSet]] isEqualToString:@""] == false) {
- [self logMessage:@"App key may only contain dashes and alphanumeric characters."];
- self.hasInitialized = NO;
- return;
- }
-
- if ([LocalyticsDatabase sharedLocalyticsDatabase]) {
- self.applicationKey = appKey;
- self.hasInitialized = YES;
- [self logMessage:[@"Object Initialized. Application's key is: " stringByAppendingString:self.applicationKey]];
- }
- }
- @catch (NSException * e) {}
-}
-
-- (void)startSession:(NSString *)appKey {
- [self LocalyticsSession:appKey];
- [self open];
- [self upload];
-}
-
-- (void)open {
- // There are a number of conditions in which nothing should be done:
- if (self.hasInitialized == NO || // the session object has not yet initialized
- self.isSessionOpen == YES) // session has already been opened
- {
- [self logMessage:@"Unable to open session."];
- return;
- }
-
- if([self isOptedIn] == false) {
- [self logMessage:@"Can't open session because user is opted out."];
- return;
- }
-
- @try {
- // If there is too much data on the disk, don't bother collecting any more.
- LocalyticsDatabase *db = [LocalyticsDatabase sharedLocalyticsDatabase];
- if([db eventCount] >= MAX_STORED_EVENTS) {
- [self logMessage:@"Maximum number of events stored in database. Session not opened."];
- self.isSessionOpen = NO;
- return;
- }
-
- self.sessionActiveDuration = 0;
- self.sessionResumeTime = [NSDate date];
- self.unstagedFlowEvents = [NSMutableString string];
- self.stagedFlowEvents = [NSMutableString string];
- self.screens = [NSMutableString string];
-
- // Begin transaction for session open.
- NSString *t = @"open_session";
- BOOL success = [db beginTransaction:t];
-
- // Save session start time.
- self.lastSessionStartTimestamp = [self.sessionResumeTime timeIntervalSince1970];
- if (success) {
- success = [db setLastsessionStartTimestamp:self.lastSessionStartTimestamp];
- }
-
- // Retrieve next session number.
- int sessionNumber = 0;
- if (success) {
- success = [db incrementLastSessionNumber:&sessionNumber];
- }
-
- if (success) {
- // Prepare session open event.
- self.sessionUUID = [self getRandomUUID];
-
- // Store event.
- NSMutableString *openEventString = [NSMutableString string];
- [openEventString appendString:@"{"];
- [openEventString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE value:@"s" first:YES]];
- [openEventString appendString:[self formatAttributeWithName:PARAM_NEW_SESSION_UUID value:self.sessionUUID]];
- [openEventString appendFormat:@",\"%@\":%u", PARAM_CLIENT_TIME, (long)self.lastSessionStartTimestamp];
- [openEventString appendFormat:@",\"%@\":%d", PARAM_SESSION_NUMBER, sessionNumber];
-
- [openEventString appendString:[self customDimensions]];
-
- [openEventString appendString:@"}\n"];
-
- [self customDimensions];
-
- success = [db addEventWithBlobString:[[openEventString copy] autorelease]];
- }
-
- if (success) {
- [db releaseTransaction:t];
- self.isSessionOpen = YES;
- self.sessionHasBeenOpen = YES;
- [self logMessage:[@"Succesfully opened session. UUID is: " stringByAppendingString:self.sessionUUID]];
- } else {
- [db rollbackTransaction:t];
- self.isSessionOpen = NO;
- [self logMessage:@"Failed to open session."];
- }
- }
- @catch (NSException * e) {}
-}
-
-- (void)resume {
- // Do nothing if session is already open
- if(self.isSessionOpen == YES)
- return;
-
- if([self isOptedIn] == false) {
- [self logMessage:@"Can't resume session because user is opted out."];
- return;
- }
-
- // conditions for resuming previous session
- if(self.sessionHasBeenOpen &&
- (!self.sessionCloseTime ||
- [self.sessionCloseTime timeIntervalSinceNow]*-1 <= self.backgroundSessionTimeout)) {
- // Note that we allow the session to be resumed even if the database size exceeds the
- // maximum. This is because we don't want to create incomplete sessions. If the DB was large
- // enough that the previous session could not be opened, there will be nothing to resume. But
- // if this session caused it to go over it is better to let it complete and stop the next one
- // from being created.
- [self logMessage:@"Resume called - Resuming previous session."];
- [self reopenPreviousSession];
- } else {
- // otherwise open new session and upload
- [self logMessage:@"Resume called - Opening a new session."];
- [self open];
- }
- self.sessionCloseTime = nil;
-}
-
-- (void)close {
- // Do nothing if the session is not open
- if (self.isSessionOpen == NO)
- {
- [self logMessage:@"Unable to close session"];
- return;
- }
-
- // Save time of close
- self.sessionCloseTime = [NSDate date];
-
- // Update active session duration.
- self.sessionActiveDuration += [self.sessionCloseTime timeIntervalSinceDate:self.sessionResumeTime];
-
- int sessionLength = (int)[[NSDate date] timeIntervalSince1970] - self.lastSessionStartTimestamp;
-
- @try {
- // Create the JSON representing the close blob
- NSMutableString *closeEventString = [NSMutableString string];
- [closeEventString appendString:@"{"];
- [closeEventString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE value:@"c" first:YES]];
- [closeEventString appendString:[self formatAttributeWithName:PARAM_SESSION_UUID value:self.sessionUUID]];
- [closeEventString appendString:[self formatAttributeWithName:PARAM_UUID value:[self getRandomUUID] ]];
- [closeEventString appendFormat:@",\"%@\":%u", PARAM_SESSION_START, (long)self.lastSessionStartTimestamp];
- [closeEventString appendFormat:@",\"%@\":%u", PARAM_SESSION_ACTIVE, (long)self.sessionActiveDuration];
- [closeEventString appendFormat:@",\"%@\":%u", PARAM_CLIENT_TIME, (long)[self getTimestamp]];
-
- // Avoid recording session lengths of users with unreasonable client times (usually caused by developers testing clock change attacks)
- if(sessionLength > 0 && sessionLength < 400000) {
- [closeEventString appendFormat:@",\"%@\":%u", PARAM_SESSION_TOTAL, sessionLength];
- }
-
- // Open second level - screen flow
- [closeEventString appendFormat:@",\"%@\":[", PARAM_SESSION_SCREENFLOW];
- [closeEventString appendString:self.screens];
-
- // Close second level - screen flow
- [closeEventString appendString:@"]"];
-
- // Append the custom dimensions
- [closeEventString appendString:[self customDimensions]];
-
- // Close first level - close blob
- [closeEventString appendString:@"}\n"];
-
- BOOL success = [[LocalyticsDatabase sharedLocalyticsDatabase] addCloseEventWithBlobString:[[closeEventString copy] autorelease]];
-
- self.isSessionOpen = NO; // Session is no longer open.
-
- if (success) {
- // Record final session flow, opting to remove it from the database if the session happens to resume.
- // This is safe now that the session has closed because no new events can be added.
- success = [self saveApplicationFlowAndRemoveOnResume:YES];
- }
-
- if (success) {
- [self logMessage:@"Session succesfully closed."];
- } else {
- [self logMessage:@"Failed to record session close."];
- }
- }
- @catch (NSException * e) {}
-}
-
-- (void)setOptIn:(BOOL)optedIn {
- if([self isOptedIn] == optedIn) {
- [self logMessage:@"Opt status unchanged."];
- return;
- }
-
- @try {
- LocalyticsDatabase *db = [LocalyticsDatabase sharedLocalyticsDatabase];
- NSString *t = @"set_opt";
- BOOL success = [db beginTransaction:t];
-
- // Write out opt event.
- if (success) {
- success = [self createOptEvent:optedIn];
- }
-
- // Update database with the option (stored internally as an opt-out).
- if (success) {
- [db setOptedOut:optedIn == NO];
- }
-
- if (success && optedIn == NO) {
- // Disable all further Localytics calls for this and future sessions
- // This should not be flipped when the session is opted back in because that
- // would create an incomplete session
- self.isSessionOpen = NO;
- }
-
- if (success) {
- [db releaseTransaction:t];
- [self logMessage:[NSString stringWithFormat:@"Application opted %@", optedIn ? @"in" : @"out"]];
- } else {
- [db rollbackTransaction:t];
- [self logMessage:@"Failed to update opt state."];
- }
- }
- @catch (NSException * e) {}
-}
-
-- (BOOL)isOptedIn {
- return [[LocalyticsDatabase sharedLocalyticsDatabase] isOptedOut] == NO;
-}
-
-// A convenience function for users who don't wish to add attributes.
-- (void)tagEvent:(NSString *)event {
- [self tagEvent:event attributes:nil reportAttributes:nil];
-}
-
-// Most users should use this tagEvent call.
-- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes {
- [self tagEvent:event attributes:attributes reportAttributes:nil];
-}
-
-- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes reportAttributes:(NSDictionary *)reportAttributes {
- @try {
- // Do nothing if the session is not open.
- if (self.isSessionOpen == NO)
- {
- [self logMessage:@"Cannot tag an event because the session is not open."];
- return;
- }
-
- if(event == (id)[NSNull null] || event.length == 0)
- {
- [self logMessage:@"Event tagged without a name. Skipping."];
- return;
- }
-
- // Create the JSON for the event
- NSMutableString *eventString = [[[NSMutableString alloc] init] autorelease];
- [eventString appendString:@"{"];
- [eventString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE value:@"e" first:YES]];
- [eventString appendString:[self formatAttributeWithName:PARAM_UUID value:[self getRandomUUID] ]];
- [eventString appendString:[self formatAttributeWithName:PARAM_APP_KEY value:self.applicationKey ]];
- [eventString appendString:[self formatAttributeWithName:PARAM_SESSION_UUID value:self.sessionUUID ]];
- [eventString appendString:[self formatAttributeWithName:PARAM_EVENT_NAME value:[self escapeString:event] ]];
- [eventString appendFormat:@",\"%@\":%u", PARAM_CLIENT_TIME, (long)[self getTimestamp]];
-
- // Append the custom dimensions
- [eventString appendString:[self customDimensions]];
-
- // If there are any attributes for this event, add them as a hash
- int attrIndex = 0;
- if(attributes != nil)
- {
- // Open second level - attributes
- [eventString appendString:[NSString stringWithFormat:@",\"%@\":{", PARAM_ATTRIBUTES]];
- for (id key in [attributes allKeys])
- {
- // Have to escape paramName and paramValue because they user-defined.
- [eventString appendString:
- [self formatAttributeWithName:[self escapeString:[key description]]
- value:[self escapeString:[[attributes valueForKey:key] description]]
- first:(attrIndex == 0)]];
- attrIndex++;
- }
-
- // Close second level - attributes
- [eventString appendString:@"}"];
- }
-
- // If there are any report attributes for this event, add them as above
- attrIndex = 0;
- if(reportAttributes != nil)
- {
- [eventString appendString:[NSString stringWithFormat:@",\"%@\":{", PARAM_REPORT_ATTRIBUTES]];
- for(id key in [reportAttributes allKeys]) {
- [eventString appendString:
- [self formatAttributeWithName:[self escapeString:[key description]]
- value:[self escapeString:[[reportAttributes valueForKey:key] description]]
- first:(attrIndex == 0)]];
- attrIndex++;
- }
- [eventString appendString:@"}"];
- }
-
- // Close first level - Event information
- [eventString appendString:@"}\n"];
-
- BOOL success = [[LocalyticsDatabase sharedLocalyticsDatabase] addEventWithBlobString:[[eventString copy] autorelease]];
- if (success) {
- // User-originated events should be tracked as application flow.
- [self addFlowEventWithName:event type:@"e"]; // "e" for Event.
-
- [self logMessage:[@"Tagged event: " stringByAppendingString:event]];
- } else {
- [self logMessage:@"Failed to tag event."];
- }
- }
- @catch (NSException * e) {}
-}
-
-- (void)tagScreen:(NSString *)screen {
- // Do nothing if the session is not open.
- if (self.isSessionOpen == NO)
- {
- [self logMessage:@"Cannot tag a screen because the session is not open."];
- return;
- }
-
- // Tag screen with description to enforce string type and avoid retaining objects passed by clients in lieu of a
- // screen name.
- NSString *screenName = [screen description];
- [self addFlowEventWithName:screenName type:@"s"]; // "s" for Screen.
-
- // Maintain a parallel list of only screen names. This is submitted in the session close event.
- // This may be removed in a future version of the client library.
- [self addScreenWithName:screenName];
-
- [self logMessage:[@"Tagged screen: " stringByAppendingString:screenName]];
-}
-
-- (void)setCustomDimension:(int)dimension value:(NSString *)value {
- if(dimension < 0 || dimension > 3) {
- [self logMessage:@"Only valid dimensions are 0 - 3"];
- return;
- }
-
- if(false == [[LocalyticsDatabase sharedLocalyticsDatabase] setCustomDimension:dimension value:value]) {
- [self logMessage:@"Unable to set custom dimensions."];
- }
-}
-
-/*
- @method saveApplicationFlowAndRemoveOnResume:
- @abstract Constructs an application flow blob string and writes it to the database, optionally flagging it for deletion
- if the session is resumed.
- @param removeOnResume YES if the application flow blob should be deleted if the session is resumed.
- @return YES if the application flow event was written to the database successfully.
-*/
-- (BOOL)saveApplicationFlowAndRemoveOnResume:(BOOL)removeOnResume {
- BOOL success = YES;
-
- // If there are no new events, then there is nothing additional to save.
- if (self.unstagedFlowEvents.length) {
- // Flows are uploaded as a distinct blob type containing arrays of new and previously-uploaded event and
- // screen names. Write a flow event to the database.
- NSMutableString *flowEventString = [[[NSMutableString alloc] init] autorelease];
-
- // Open first level - flow blob event
- [flowEventString appendString:@"{"];
- [flowEventString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE value:@"f" first:YES]];
- [flowEventString appendString:[self formatAttributeWithName:PARAM_UUID value:[self getRandomUUID] ]];
- [flowEventString appendFormat:@",\"%@\":%u", PARAM_SESSION_START, (long)self.lastSessionStartTimestamp];
-
- // Open second level - new flow events
- [flowEventString appendFormat:@",\"%@\":[", PARAM_NEW_FLOW_EVENTS];
- [flowEventString appendString:self.unstagedFlowEvents]; // Flow events are escaped in |-addFlowEventWithName:|
- // Close second level - new flow events
- [flowEventString appendString:@"]"];
-
- // Open second level - old flow events
- [flowEventString appendFormat:@",\"%@\":[", PARAM_OLD_FLOW_EVENTS];
- [flowEventString appendString:self.stagedFlowEvents];
- // Close second level - old flow events
- [flowEventString appendString:@"]"];
-
- // Close first level - flow blob event
- [flowEventString appendString:@"}\n"];
-
- success = [[LocalyticsDatabase sharedLocalyticsDatabase] addFlowEventWithBlobString:[[flowEventString copy] autorelease]];
- }
- return success;
-}
-
-- (void)upload {
- @try {
- if ([[UploaderThread sharedUploaderThread] isUploading]) {
- [self logMessage:@"An upload is already in progress. Aborting."];
- return;
- }
-
- NSString *t = @"stage_upload";
- LocalyticsDatabase *db = [LocalyticsDatabase sharedLocalyticsDatabase];
- BOOL success = [db beginTransaction:t];
-
- // Lock on new flow events to ensure that:
- // - The event list for the current session is not modified while an upload is in progress.
- // - New flow events are only transitioned to the "old" list if the upload is staged successfully.
- @synchronized (_unstagedFlowEvents) {
- if (success) {
- // Write flow blob to database. This is for a session in progress and should not be removed upon resume.
- success = [self saveApplicationFlowAndRemoveOnResume:NO];
- }
-
- if (success && [db unstagedEventCount] > 0) {
- // Increment upload sequence number.
- int sequenceNumber = 0;
- success = [db incrementLastUploadNumber:&sequenceNumber];
-
- // Write out header to database.
- sqlite3_int64 headerRowId = 0;
- if (success) {
- NSString *headerBlob = [self blobHeaderStringWithSequenceNumber:sequenceNumber];
- success = [db addHeaderWithSequenceNumber:sequenceNumber blobString:headerBlob rowId:&headerRowId];
- }
-
- // Associate unstaged events.
- if (success) {
- success = [db stageEventsForUpload:headerRowId];
- }
- }
-
- if (success) {
- // Complete transaction
- [db releaseTransaction:t];
-
- // Move new flow events to the old flow event array.
- if (self.unstagedFlowEvents.length) {
- if (self.stagedFlowEvents.length) {
- [self.stagedFlowEvents appendFormat:@",%@", self.unstagedFlowEvents];
- } else {
- self.stagedFlowEvents = [[self.unstagedFlowEvents mutableCopy] autorelease];
- }
- self.unstagedFlowEvents = [NSMutableString string];
- }
-
- // Begin upload.
- [[UploaderThread sharedUploaderThread] uploaderThreadwithApplicationKey:self.applicationKey];
- } else {
- [db rollbackTransaction:t];
- [self logMessage:@"Failed to start upload."];
- }
- }
- }
- @catch (NSException * e) { }
-}
-
-#pragma mark Private Methods
-/*!
- @method reopenPreviousSession
- @abstract Reopens the previous session, using previous session variables. If there was no previous session, do nothing.
-*/
-- (void)reopenPreviousSession {
- if(self.sessionHasBeenOpen == NO){
- [self logMessage:@"Unable to reopen previous session, because a previous session was never opened."];
- return;
- }
-
- // Record session resume time.
- self.sessionResumeTime = [NSDate date];
-
- //Remove close and flow events if they exist.
- [[LocalyticsDatabase sharedLocalyticsDatabase] removeLastCloseAndFlowEvents];
-
- self.isSessionOpen = YES;
-}
-
-/*!
- @method addFlowEventWithName:type:
- @abstract Adds a simple key-value pair to the list of events tagged during this session.
- @param name The name of the tagged event.
- @param eventType A key representing the type of the tagged event. Either "s" for Screen or "e" for Event.
- */
-- (void)addFlowEventWithName:(NSString *)name type:(NSString *)eventType {
- if (!name || !eventType)
- return;
-
- // Format new event as simple key-value dictionary.
- NSString *eventString = [self formatAttributeWithName:eventType value:[self escapeString:name] first:YES];
-
- // Flow events are uploaded as a sequence of key-value pairs. Wrap the above in braces and append to the list.
- // Lock to avoid adding events while an upload is being prepared.
- @synchronized(_unstagedFlowEvents) {
- BOOL previousFlowEvents = self.unstagedFlowEvents.length > 0;
- if (previousFlowEvents) {
- [self.unstagedFlowEvents appendString:@","];
- }
- [self.unstagedFlowEvents appendFormat:@"{%@}", eventString];
- }
-}
-
-/*!
- @method addScreenWithName:
- @abstract Adds a name to list of screens encountered during this session.
- @discussion The complete list of names is sent with the session close event. Screen names are stored in parallel to the
- screen flow events list and may be removed in future versions of this library.
- @param name The name of the tagged screen.
- */
-- (void)addScreenWithName:(NSString *)name {
- if (self.screens.length > 0) {
- [self.screens appendString:@","];
- }
- [self.screens appendFormat:@"\"%@\"", [self escapeString:name]];
-}
-
-/*!
- @method blobHeaderStringWithSequenceNumber:
- @abstract Creates the JSON string for the upload blob header, substituting in the given upload sequence number.
- @param nextSequenceNumber The sequence number for the current upload attempt.
- @return The upload header JSON blob.
- */
-- (NSString *)blobHeaderStringWithSequenceNumber:(int)nextSequenceNumber {
-
- NSMutableString *headerString = [[[NSMutableString alloc] init] autorelease];
-
- // Common header information.
- UIDevice *thisDevice = [UIDevice currentDevice];
- NSLocale *locale = [NSLocale currentLocale];
- NSLocale *english = [[[NSLocale alloc] initWithLocaleIdentifier: @"en_US"] autorelease];
- NSLocale *device_locale = [[NSLocale preferredLanguages] objectAtIndex:0];
- NSString *device_language = [english displayNameForKey:NSLocaleIdentifier value:device_locale];
- NSString *locale_country = [english displayNameForKey:NSLocaleCountryCode value:[locale objectForKey:NSLocaleCountryCode]];
- NSString *uuid = [self getRandomUUID];
- NSString *device_uuid = [self uniqueDeviceIdentifier];
-
- // Open first level - blob information
- [headerString appendString:@"{"];
- [headerString appendFormat:@"\"%@\":%d", PARAM_SEQUENCE_NUMBER, nextSequenceNumber];
- [headerString appendFormat:@",\"%@\":%u", PARAM_PERSISTED_AT, (long)[[LocalyticsDatabase sharedLocalyticsDatabase] createdTimestamp]];
- [headerString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE value:@"h" ]];
- [headerString appendString:[self formatAttributeWithName:PARAM_UUID value:uuid ]];
-
- // Open second level - blob header attributes
- [headerString appendString:[NSString stringWithFormat:@",\"%@\":{", PARAM_ATTRIBUTES]];
- [headerString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE value:@"a" first:YES]];
-
- // >> Application and session information
- [headerString appendString:[self formatAttributeWithName:PARAM_INSTALL_ID value:[self installationId] ]];
- [headerString appendString:[self formatAttributeWithName:PARAM_APP_KEY value:self.applicationKey ]];
- [headerString appendString:[self formatAttributeWithName:PARAM_APP_VERSION value:[self getAppVersion] ]];
- [headerString appendString:[self formatAttributeWithName:PARAM_LIBRARY_VERSION value:CLIENT_VERSION ]];
-
- // >> Device Information
- [headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_UUID value:device_uuid ]];
- [headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_UUID_HASHED value:[self hashString:device_uuid] ]];
- [headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_PLATFORM value:[thisDevice model] ]];
- [headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_OS_VERSION value:[thisDevice systemVersion] ]];
- [headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_MODEL value:[self getDeviceModel] ]];
-
-// MAC Address collection. Uncomment the following line to add Mac address to the mix of collected identifiers
-// [headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_MAC value:[self hashString:[self macAddress]] ]];
- [headerString appendString:[NSString stringWithFormat:@",\"%@\":%d", PARAM_DEVICE_MEMORY, (long)[self availableMemory] ]];
- [headerString appendString:[self formatAttributeWithName:PARAM_LOCALE_LANGUAGE value:device_language]];
- [headerString appendString:[self formatAttributeWithName:PARAM_LOCALE_COUNTRY value:locale_country]];
- [headerString appendString:[self formatAttributeWithName:PARAM_DEVICE_COUNTRY value:[locale objectForKey:NSLocaleCountryCode]]];
- [headerString appendString:[NSString stringWithFormat:@",\"%@\":%@", PARAM_JAILBROKEN, [self isDeviceJailbroken] ? @"true" : @"false"]];
-
- // Close second level - attributes
- [headerString appendString:@"}"];
-
- // Close first level - blob information
- [headerString appendString:@"}\n"];
-
- return [[headerString copy] autorelease];
-}
-
-/*!
- @method createOptEvent:
- @abstract Generates the JSON for an opt event (user opting in or out) and writes it to the database.
- @return YES if the event was written to the database, NO otherwise
- */
-- (BOOL)createOptEvent:(BOOL)optState {
- NSMutableString *optEventString = [NSMutableString string];
- [optEventString appendString:@"{"];
- [optEventString appendString:[self formatAttributeWithName:PARAM_DATA_TYPE value:@"o" first:YES]];
- [optEventString appendString:[self formatAttributeWithName:PARAM_APP_KEY value:self.applicationKey first:NO]];
- [optEventString appendString:[NSString stringWithFormat:@",\"%@\":%@", PARAM_OPT_VALUE, (optState ? @"true" : @"false") ]];
- [optEventString appendFormat:@",\"%@\":%u", PARAM_CLIENT_TIME, (long)[self getTimestamp]];
- [optEventString appendString:@"}\n"];
-
- BOOL success = [[LocalyticsDatabase sharedLocalyticsDatabase] addEventWithBlobString:[[optEventString copy] autorelease]];
- return success;
-}
-
-/*!
- @method logMessage
- @abstract Logs a message with (localytics) prepended to it.
- @param message The message to log
- */
-- (void)logMessage:(NSString *)message
-{
- if(DO_LOCALYTICS_LOGGING) {
- NSLog(@"(localytics) %s\n", [message UTF8String]);
- }
-}
-
-#pragma mark Datapoint Functions
-/*!
- @method customDimensions
- @abstract Returns the json blob containing the custom dimensions. Assumes this will be appended
- to an existing blob and as a result prepends the results with a comma.
- */
-- (NSString *)customDimensions
-{
- NSMutableString *dimensions = [[[NSMutableString alloc] init] autorelease];
-
- for(int i=0; i <4; i++) {
- NSString *dimension = [[LocalyticsDatabase sharedLocalyticsDatabase] customDimension:i];
- if(dimension) {
- [dimensions appendFormat:@",\"c%i\":\"%@\"", i, dimension];
- }
- }
-
- return [[dimensions copy] autorelease];
-}
-
-/*!
- @method macAddress
- @abstract Returns the macAddress of this device.
- */
-- (NSString *)macAddress
-{
- NSMutableString* result = [NSMutableString string];
-
- BOOL success;
- struct ifaddrs* addrs;
- const struct ifaddrs* cursor;
- const struct sockaddr_dl* dlAddr;
- const uint8_t * base;
- int i;
-
- success = (getifaddrs(&addrs) == 0);
- if(success)
- {
- cursor = addrs;
- while(cursor != NULL)
- {
- if((cursor->ifa_addr->sa_family == AF_LINK) && (((const struct sockaddr_dl *) cursor->ifa_addr)->sdl_type == IFT_ETHER))
- {
- dlAddr = (const struct sockaddr_dl *) cursor->ifa_addr;
- base = (const uint8_t *) &dlAddr->sdl_data[dlAddr->sdl_nlen];
-
- for(i=0; i<dlAddr->sdl_alen; i++)
- {
- if(i != 0) {
- [result appendString:@":"];
- }
- [result appendFormat:@"%02x", base[i]];
- }
- break;
- }
- cursor = cursor->ifa_next;
- }
- freeifaddrs(addrs);
- }
-
- return result;
-}
-
-/*!
- @method hashString
- @abstract SHA1 Hashes a string
- */
-- (NSString *)hashString:(NSString *)input
-{
- NSData *stringBytes = [input dataUsingEncoding: NSUTF8StringEncoding];
- unsigned char digest[CC_SHA1_DIGEST_LENGTH];
-
- if (CC_SHA1([stringBytes bytes], [stringBytes length], digest)) {
- NSMutableString* hashedUUID = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
- for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
- [hashedUUID appendFormat:@"%02x", digest[i]];
- }
- return hashedUUID;
- }
-
- return nil;
-}
-
-/*!
- @method getRandomUUID
- @abstract Generates a random UUID
- @return NSString containing the new UUID
- */
-- (NSString *)getRandomUUID {
- CFUUIDRef theUUID = CFUUIDCreate(NULL);
- CFStringRef stringUUID = CFUUIDCreateString(NULL, theUUID);
- CFRelease(theUUID);
- return [(NSString *)stringUUID autorelease];
-}
-
-/*!
- @method formatAttributeWithName:value:firstAttribute:
- @abstract Returns the given string key/value pair as a JSON string.
- @param paramName The name of the parameter
- @param paramValue The value of the parameter
- @param firstAttribute YES if this attribute is first in an attribute list
- @return a JSON string which can be dumped to the JSON file
- */
-- (NSString *)formatAttributeWithName:(NSString *)paramName value:(NSString *)paramValue first:(BOOL)firstAttribute {
- // The expected result is one of:
- // "paramname":"paramvalue"
- // "paramname":null
- NSMutableString *formattedString = [NSMutableString string];
- if (!firstAttribute) {
- [formattedString appendString:@","];
- }
-
- NSString *quotedString = @"\"%@\"";
- paramName = [NSString stringWithFormat:quotedString, paramName];
- paramValue = paramValue ? [NSString stringWithFormat:quotedString, paramValue] : @"null";
- [formattedString appendFormat:@"%@:%@", paramName, paramValue];
- return [[formattedString copy] autorelease];
-}
-
-// Convenience method for formatAttributeWithName which sets firstAttribute to NO since
-// this is the most common way to call it.
-- (NSString *)formatAttributeWithName:(NSString *)paramName value:(NSString *)paramValue {
- return [self formatAttributeWithName:paramName value:paramValue first:NO];
-}
-
-/*!
- @method escapeString
- @abstract Formats the input string so it fits nicely in a JSON document. This includes
- escaping double quote and slash characters.
- @return The escaped version of the input string
- */
-- (NSString *) escapeString:(NSString *)input
-{
- NSString *output = [input stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
- output = [output stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
- output = [output stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
- return output;
-}
-
-/*!
- @method installationId
- @abstract Looks in user preferences for an ID unique to this installation. If one is not
- found it checks if one happens to be in the database (carroyover from older version of the db)
- if not, it generates one.
- @return A string uniquely identifying this installation of this app
- */
-- (NSString *) installationId {
- NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
- NSString *installId = [prefs stringForKey:PREFERENCES_KEY];
-
- if(installId == nil)
- {
- [self logMessage:@"Install ID not found in preferences, checking DB"];
- installId = [[LocalyticsDatabase sharedLocalyticsDatabase] installId];
- }
-
- // If it hasn't been found yet, generate a new one.
- if(installId == nil)
- {
- [self logMessage:@"Install ID not find one in database, generating a new one."];
- installId = [self getRandomUUID];
- }
-
- // Store the newly generated installId
- [prefs setObject:installId forKey:PREFERENCES_KEY];
- [[NSUserDefaults standardUserDefaults] synchronize];
-
- return installId;
-}
-
-/*!
- @method uniqueDeviceIdentifier
- @abstract A unique device identifier is a hash value composed from various hardware identifiers such
- as the device’s serial number. It is guaranteed to be unique for every device but cannot
- be tied to a user account. [UIDevice Class Reference]
- @return An 1-way hashed identifier unique to this device.
- */
-- (NSString *)uniqueDeviceIdentifier {
-
-// Supress the warning for uniqueIdentifier being deprecated.
-// We collect it as long as it is available along with a randomly generated ID.
-// This way, when this becomes unavailable we can map existing users so the
-// new vs returning counts do not break. This will be removed before it causes grief.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- NSString *systemId = [[UIDevice currentDevice] uniqueIdentifier];
-#pragma clang diagnostic pop
-
- return systemId;
-}
-
-/*!
- @method getAppVersion
- @abstract Gets the pretty string for this application's version.
- @return The application's version as a pretty string
- */
-- (NSString *)getAppVersion {
- return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
-}
-
-/*!
- @method getTimestamp
- @abstract Gets the current time as seconds since Unix epoch.
- @return an NSTimeInterval time.
- */
-- (NSTimeInterval)getTimestamp {
- return [[NSDate date] timeIntervalSince1970];
-}
-
-/*!
- @method isDeviceJailbroken
- @abstract checks for the existance of apt to determine whether the user is running any
- of the jailbroken app sources.
- @return whether or not the device is jailbroken.
- */
-- (BOOL) isDeviceJailbroken {
- NSFileManager *sessionFileManager = [NSFileManager defaultManager];
- return [sessionFileManager fileExistsAtPath:PATH_TO_APT];
-}
-
-/*!
- @method getDeviceModel
- @abstract Gets the device model string.
- @return a platform string identifying the device
- */
-- (NSString *)getDeviceModel {
- char *buffer[256] = { 0 };
- size_t size = sizeof(buffer);
- sysctlbyname("hw.machine", buffer, &size, NULL, 0);
- NSString *platform = [NSString stringWithCString:(const char*)buffer
- encoding:NSUTF8StringEncoding];
- return platform;
-}
-
-/*!
- @method modelSizeString
- @abstract Checks how much disk space is reported and uses that to determine the model
- @return A string identifying the model, e.g. 8GB, 16GB, etc
- */
-- (NSString *) modelSizeString {
-
-#if TARGET_IPHONE_SIMULATOR
- return @"simulator";
-#endif
-
- // User partition
- NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSDictionary *stats = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[path lastObject] error:nil];
- uint64_t user = [[stats objectForKey:NSFileSystemSize] longLongValue];
-
- // System partition
- path = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSSystemDomainMask, YES);
- stats = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[path lastObject] error:nil];
- uint64_t system = [[stats objectForKey:NSFileSystemSize] longLongValue];
-
- // Add up and convert to gigabytes
- // TODO: seem to be missing a system partiton or two...
- NSInteger size = (user + system) >> 30;
-
- // Find nearest power of 2 (eg, 1,2,4,8,16,32,etc). Over 64 and we return 0
- for (NSInteger gig = 1; gig < 257; gig = gig << 1) {
- if (size < gig)
- return [NSString stringWithFormat:@"%dGB", gig];
- }
- return nil;
-}
-
-/*!
- @method availableMemory
- @abstract Reports how much memory is available
- @return A double containing the available free memory
- */
-- (double)availableMemory {
- double result = NSNotFound;
- vm_statistics_data_t stats;
- mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
- if (!host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&stats, &count))
- result = vm_page_size * stats.free_count;
-
- return result;
-}
-
-
-#pragma mark System Functions
-+ (id)allocWithZone:(NSZone *)zone {
- @synchronized(self) {
- if (_sharedLocalyticsSession == nil) {
- _sharedLocalyticsSession = [super allocWithZone:zone];
- return _sharedLocalyticsSession;
- }
- }
- // 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 {
- // Remove self for notifications added in this class, only.
-
- [_sessionUUID release];
- [_applicationKey release];
- [_sessionCloseTime release];
- [_unstagedFlowEvents release];
- [_stagedFlowEvents release];
- [_screens release];
- [_sharedLocalyticsSession release];
-
- [super dealloc];
-}
-
-@end
View
48 providers/Localytics/UploaderThread.h
@@ -1,48 +0,0 @@
-// UploaderThread.h
-// Copyright (C) 2009 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>
-
-/*!
- @class UploaderThread
- @discussion Singleton class to handle data uploads
- */
-
-@interface UploaderThread : NSObject {
- NSURLConnection *_uploadConnection; // The connection which uploads the bits
- NSInteger _responseStatusCode; // The HTTP response status code for the current connection
-
- BOOL _isUploading; // A flag to gaurantee only one uploader instance can happen at once
-}
-
-@property (nonatomic, retain) NSURLConnection *uploadConnection;
-
-@property BOOL isUploading;
-
-/*!
- @method sharedUploaderThread
- @abstract Establishes this as a Singleton Class allowing for data persistence.
- The class is accessed within the code using the following syntax:
- [[UploaderThread sharedUploaderThread] functionHere]
- */
-+ (UploaderThread *)sharedUploaderThread;
-
-/*!
- @method UploaderThread
- @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
- */
-- (void)uploaderThreadwithApplicationKey:(NSString *)localyticsApplicationKey;
-
-@end
View
260 providers/Localytics/UploaderThread.m
@@ -1,260 +0,0 @@
-// UploaderThread.m
-// Copyright (C) 2009 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 "UploaderThread.h"
-#import "LocalyticsSession.h"
-#import "LocalyticsDatabase.h"
-#import <zlib.h>
-
-#define LOCALYTICS_URL @"http://analytics.localytics.com/api/v2/applications/%@/uploads" // url to send the
-
-static UploaderThread *_sharedUploaderThread = nil;
-
-@interface UploaderThread ()
-- (void)complete;
-- (NSData *)gzipDeflatedDataWithData:(NSData *)data;
-- (void)logMessage:(NSString *)message;
-@end
-
-@implementation UploaderThread
-
-@synthesize uploadConnection = _uploadConnection;
-@synthesize isUploading = _isUploading;
-
-#pragma mark Singleton Class
-+ (UploaderThread *)sharedUploaderThread {
- @synchronized(self) {
- if (_sharedUploaderThread == nil)
- {
- _sharedUploaderThread = [[self alloc] init];
- }
- }
- return _sharedUploaderThread;
-}
-
-#pragma mark Class Methods
-- (void)uploaderThreadwithApplicationKey:(NSString *)localyticsApplicationKey {
-
- // Do nothing if already uploading.
- if (self.uploadConnection != nil || 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 complete];
- return;
- }
-
- NSData *requestData = [blobString dataUsingEncoding:NSUTF8StringEncoding];
- NSString *myString = [[[NSString alloc] initWithData:requestData encoding:NSUTF8StringEncoding] autorelease];
- [self logMessage:@"Upload data:"];
- [self logMessage:myString];
-
- // Step 2
- NSData *deflatedRequestData = [[self gzipDeflatedDataWithData:requestData] retain];
-
- [pool drain];
-
- NSString *apiUrlString = [NSString stringWithFormat:LOCALYTICS_URL, [localyticsApplicationKey stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
- NSMutableURLRequest *submitRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiUrlString]
- cachePolicy:NSURLRequestReloadIgnoringCacheData
- timeoutInterval:60.0];
- [submitRequest setHTTPMethod:@"POST"];
- [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];
-
- // The NSURLConnection Object automatically spawns its own thread as a default behavior.
- @try
- {
- [self logMessage:@"Spawning new thread for upload"];
- self.uploadConnection = [NSURLConnection connectionWithRequest:submitRequest delegate:self];
-
- // Step 3 is handled by connectionDidFinishLoading.
- }
- @catch (NSException * e)
- {
- [self complete];
- }
-}
-
-#pragma mark **** NSURLConnection FUNCTIONS ****
-
-- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
- // Used to gather response data from server - Not utilized in this version
-}
-
-- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
- // Could receive multiple response callbacks, likely due to redirection.
- // Record status and act only when connection completes load.
- _responseStatusCode = [(NSHTTPURLResponse *)response statusCode];
-}
-
-- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
- // If the connection finished loading, the files should be deleted. 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
- {
- // The connection finished loading and uploaded data should be deleted. 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] deleteUploadData];
- }
-
- // Close upload session
- [self complete];
-}
-
-- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
- // 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: %s",
- [error code],
- [error localizedDescription]]];
-
- [self complete];
-}
-
-/*!
- @method complete
- @abstract closes the upload connection and reports back to the session that the upload is complete
- */
-- (void)complete {
- _responseStatusCode = 0;
- self.uploadConnection = nil;
- self.isUploading = false;
-}
-
-/*!
- @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]);
- }
-}
-
-#pragma mark System Functions
-+ (id)allocWithZone:(NSZone *)zone {
- @synchronized(self) {
- if (_sharedUploaderThread == nil) {
- _sharedUploaderThread = [super allocWithZone:zone];
- return _sharedUploaderThread;
- }
- }
- // 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 {
- [_uploadConnection release];
- [_sharedUploaderThread release];
- [super dealloc];
-}
-
-@end
View
111 providers/Localytics/WebserviceConstants.h
@@ -1,111 +0,0 @@
-// WebserviceConstants.h
-// Copyright (C) 2009 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.
-
-/*********************
- * 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)
-
-/***************
- * 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 @"du" // Device UUID
-#define PARAM_DEVICE_UUID_HASHED @"udid" // Hashed version of the UUID
-#define PARAM_DEVICE_MAC @"wmac" // Hashed version of the device Mac
-#define PARAM_INSTALL_ID @"iu" // Install ID
-#define PARAM_JAILBROKEN @"j" // Jailbroken (boolean)
-#define PARAM_LIBRARY_VERSION @"lv"