Tag screens in Localytics + email fix + psc fix
[FIXED] Sending email with no recipient caused a crash. [FIXED] Duplicate persistence coordinator. [UPDATED] Crashlytics and Localytics SDKs. [UPDATED] Don't continue the Localytics session when device locked. [UPDATED] Put Localytics communication on HTTPS for confidentiality. [ADDED] Tagging screens in Localytics.
This commit is contained in:
parent
6f82cf7f15
commit
bce6b96417
Binary file not shown.
@ -148,6 +148,26 @@ OBJC_EXTERN void CLSNSLog(NSString *format, ...);
|
|||||||
|
|
||||||
@end
|
@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>
|
||||||
|
@optional
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* The CrashlyticsDelegate protocol provides a mechanism for your application to take
|
||||||
@ -169,4 +189,15 @@ OBJC_EXTERN void CLSNSLog(NSString *format, ...);
|
|||||||
**/
|
**/
|
||||||
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics;
|
- (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
|
@end
|
||||||
|
Binary file not shown.
BIN
Crashlytics/Crashlytics.framework/run
vendored
BIN
Crashlytics/Crashlytics.framework/run
vendored
Binary file not shown.
2
External/Pearl
vendored
2
External/Pearl
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 4ceb992dc59e9d085b241239b63df4754da90de7
|
Subproject commit b8cf787af604299c5363846c5b2fcbd9e3083253
|
@ -1,57 +1,70 @@
|
|||||||
//
|
//
|
||||||
// LocalyticsDatabase.h
|
// LocalyticsDatabase.h
|
||||||
// LocalyticsDemo
|
// Copyright (C) 2012 Char Software Inc., DBA Localytics
|
||||||
//
|
//
|
||||||
// Created by jkaufman on 5/26/11.
|
// This code is provided under the Localytics Modified BSD License.
|
||||||
// Copyright 2011 Localytics. All rights reserved.
|
// A copy of this license has been distributed in a file called LICENSE
|
||||||
//
|
// with this source code.
|
||||||
|
//
|
||||||
#import <Foundation/Foundation.h>
|
// Please visit www.localytics.com for more information.
|
||||||
#import <sqlite3.h>
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
#define MAX_DATABASE_SIZE 500000 // The maximum allowed disk size of the primary database file at open, in bytes
|
#import <sqlite3.h>
|
||||||
#define VACUUM_THRESHOLD 0.8 // The database is vacuumed after its size exceeds this proportion of the maximum.
|
|
||||||
|
#define MAX_DATABASE_SIZE 500000 // The maximum allowed disk size of the primary database file at open, in bytes
|
||||||
@interface LocalyticsDatabase : NSObject {
|
#define VACUUM_THRESHOLD 0.8 // The database is vacuumed after its size exceeds this proportion of the maximum.
|
||||||
sqlite3 *_databaseConnection;
|
|
||||||
}
|
@interface LocalyticsDatabase : NSObject {
|
||||||
|
sqlite3 *_databaseConnection;
|
||||||
+ (LocalyticsDatabase *)sharedLocalyticsDatabase;
|
}
|
||||||
|
|
||||||
- (NSUInteger)databaseSize;
|
+ (LocalyticsDatabase *)sharedLocalyticsDatabase;
|
||||||
- (int)eventCount;
|
|
||||||
- (NSTimeInterval)createdTimestamp;
|
- (NSUInteger)databaseSize;
|
||||||
|
- (int)eventCount;
|
||||||
- (BOOL)beginTransaction:(NSString *)name;
|
- (NSTimeInterval)createdTimestamp;
|
||||||
- (BOOL)releaseTransaction:(NSString *)name;
|
|
||||||
- (BOOL)rollbackTransaction:(NSString *)name;
|
- (BOOL)beginTransaction:(NSString *)name;
|
||||||
|
- (BOOL)releaseTransaction:(NSString *)name;
|
||||||
- (BOOL)incrementLastUploadNumber:(int *)uploadNumber;
|
- (BOOL)rollbackTransaction:(NSString *)name;
|
||||||
- (BOOL)incrementLastSessionNumber:(int *)sessionNumber;
|
|
||||||
|
- (BOOL)incrementLastUploadNumber:(int *)uploadNumber;
|
||||||
- (BOOL)addEventWithBlobString:(NSString *)blob;
|
- (BOOL)incrementLastSessionNumber:(int *)sessionNumber;
|
||||||
- (BOOL)addCloseEventWithBlobString:(NSString *)blob;
|
|
||||||
- (BOOL)addFlowEventWithBlobString:(NSString *)blob;
|
- (BOOL)addEventWithBlobString:(NSString *)blob;
|
||||||
- (BOOL)removeLastCloseAndFlowEvents;
|
- (BOOL)addCloseEventWithBlobString:(NSString *)blob;
|
||||||
|
- (BOOL)queueCloseEventWithBlobString:(NSString *)blob;
|
||||||
- (BOOL)addHeaderWithSequenceNumber:(int)number blobString:(NSString *)blob rowId:(sqlite3_int64 *)insertedRowId;
|
- (NSString *)dequeueCloseEventBlobString;
|
||||||
- (int)unstagedEventCount;
|
- (BOOL)addFlowEventWithBlobString:(NSString *)blob;
|
||||||
- (BOOL)stageEventsForUpload:(sqlite3_int64)headerId;
|
- (BOOL)removeLastCloseAndFlowEvents;
|
||||||
- (BOOL)updateAppKey:(NSString *)appKey;
|
|
||||||
- (NSString *)uploadBlobString;
|
- (BOOL)addHeaderWithSequenceNumber:(int)number blobString:(NSString *)blob rowId:(sqlite3_int64 *)insertedRowId;
|
||||||
- (BOOL)deleteUploadedData;
|
- (int)unstagedEventCount;
|
||||||
- (BOOL)resetAnalyticsData;
|
- (BOOL)stageEventsForUpload:(sqlite3_int64)headerId;
|
||||||
- (BOOL)vacuumIfRequired;
|
- (BOOL)updateAppKey:(NSString *)appKey;
|
||||||
|
- (NSString *)uploadBlobString;
|
||||||
- (NSTimeInterval)lastSessionStartTimestamp;
|
- (BOOL)deleteUploadedData;
|
||||||
- (BOOL)setLastsessionStartTimestamp:(NSTimeInterval)timestamp;
|
- (BOOL)resetAnalyticsData;
|
||||||
|
- (BOOL)vacuumIfRequired;
|
||||||
- (BOOL)isOptedOut;
|
|
||||||
- (BOOL)setOptedOut:(BOOL)optOut;
|
- (NSTimeInterval)lastSessionStartTimestamp;
|
||||||
- (NSString *)installId;
|
- (BOOL)setLastsessionStartTimestamp:(NSTimeInterval)timestamp;
|
||||||
- (NSString *)appKey; // Most recent app key-- may not be that used to open the session.
|
|
||||||
|
- (BOOL)isOptedOut;
|
||||||
- (NSString *)customDimension:(int)dimension;
|
- (BOOL)setOptedOut:(BOOL)optOut;
|
||||||
- (BOOL)setCustomDimension:(int)dimension value:(NSString *)value;
|
- (NSString *)installId;
|
||||||
|
- (NSString *)appKey; // Most recent app key-- may not be that used to open the session.
|
||||||
@end
|
|
||||||
|
- (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
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,216 +1,251 @@
|
|||||||
// LocalyticsSession.h
|
// LocalyticsSession.h
|
||||||
// Copyright (C) 2009 Char Software Inc., DBA Localytics
|
// Copyright (C) 2012 Char Software Inc., DBA Localytics
|
||||||
//
|
//
|
||||||
// This code is provided under the Localytics Modified BSD License.
|
// This code is provided under the Localytics Modified BSD License.
|
||||||
// A copy of this license has been distributed in a file called LICENSE
|
// A copy of this license has been distributed in a file called LICENSE
|
||||||
// with this source code.
|
// with this source code.
|
||||||
//
|
//
|
||||||
// Please visit www.localytics.com for more information.
|
// Please visit www.localytics.com for more information.
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <CoreLocation/CoreLocation.h>
|
||||||
// Set this to true to enable localytics traces (useful for debugging)
|
|
||||||
#define DO_LOCALYTICS_LOGGING false
|
// 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.
|
@class LocalyticsSession
|
||||||
Please see the following guides for information on how to best use this
|
@discussion The class which manages creating, collecting, & uploading a Localytics session.
|
||||||
library, sample code, and other useful information:
|
Please see the following guides for information on how to best use this
|
||||||
<ul>
|
library, sample code, and other useful information:
|
||||||
<li><a href="http://wiki.localytics.com/index.php?title=Developer's_Integration_Guide">Main Developer's Integration Guide</a></li>
|
<ul>
|
||||||
</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>
|
<strong>Best Practices</strong>
|
||||||
<li>Instantiate the LocalyticsSession object in applicationDidFinishLaunching.</li>
|
<ul>
|
||||||
<li>Open your session and begin your uploads in applicationDidFinishLaunching. This way the
|
<li>Instantiate the LocalyticsSession object in applicationDidFinishLaunching.</li>
|
||||||
upload has time to complete and it all happens before your users have a
|
<li>Open your session and begin your uploads in applicationDidFinishLaunching. This way the
|
||||||
chance to begin any data intensive actions of their own.</li>
|
upload has time to complete and it all happens before your users have a
|
||||||
<li>Close the session in applicationWillTerminate, and in applicationDidEnterBackground.</li>
|
chance to begin any data intensive actions of their own.</li>
|
||||||
<li>Resume the session in applicationWillEnterForeground.</li>
|
<li>Close the session in applicationWillTerminate, and in applicationDidEnterBackground.</li>
|
||||||
<li>Do not call any Localytics functions inside a loop. Instead, calls
|
<li>Resume the session in applicationWillEnterForeground.</li>
|
||||||
such as <code>tagEvent</code> should follow user actions. This limits the
|
<li>Do not call any Localytics functions inside a loop. Instead, calls
|
||||||
amount of data which is stored and uploaded.</li>
|
such as <code>tagEvent</code> should follow user actions. This limits the
|
||||||
<li>Do not use multiple LocalticsSession objects to upload data with
|
amount of data which is stored and uploaded.</li>
|
||||||
multiple application keys. This can cause invalid state.</li>
|
<li>Do not use multiple LocalticsSession objects to upload data with
|
||||||
</ul>
|
multiple application keys. This can cause invalid state.</li>
|
||||||
|
</ul>
|
||||||
@author Localytics
|
|
||||||
*/
|
@author Localytics
|
||||||
@interface LocalyticsSession : NSObject {
|
*/
|
||||||
|
|
||||||
BOOL _hasInitialized; // Whether or not the session object has been initialized.
|
@interface LocalyticsSession : NSObject {
|
||||||
BOOL _isSessionOpen; // Whether or not this session has been opened.
|
|
||||||
float _backgroundSessionTimeout; // If an App stays in the background for more
|
BOOL _hasInitialized; // Whether or not the session object has been initialized.
|
||||||
// than this many seconds, start a new session
|
BOOL _isSessionOpen; // Whether or not this session has been opened.
|
||||||
// when it returns to foreground.
|
float _backgroundSessionTimeout; // If an App stays in the background for more
|
||||||
@private
|
// than this many seconds, start a new session
|
||||||
#pragma mark Member Variables
|
// when it returns to foreground.
|
||||||
dispatch_queue_t _queue; // Queue of Localytics block objects.
|
@private
|
||||||
dispatch_group_t _criticalGroup; // Group of blocks the must complete before backgrounding.
|
#pragma mark Member Variables
|
||||||
NSString *_sessionUUID; // Unique identifier for this session.
|
dispatch_queue_t _queue; // Queue of Localytics block objects.
|
||||||
NSString *_applicationKey; // Unique identifier for the instrumented application
|
dispatch_group_t _criticalGroup; // Group of blocks the must complete before backgrounding.
|
||||||
NSTimeInterval _lastSessionStartTimestamp; // The start time of the most recent session.
|
NSString *_sessionUUID; // Unique identifier for this session.
|
||||||
NSDate *_sessionResumeTime; // Time session was started or resumed.
|
NSString *_applicationKey; // Unique identifier for the instrumented application
|
||||||
NSDate *_sessionCloseTime; // Time session was closed.
|
NSTimeInterval _lastSessionStartTimestamp; // The start time of the most recent session.
|
||||||
NSMutableString *_unstagedFlowEvents; // Comma-delimited list of app screens and events tagged during this
|
NSDate *_sessionResumeTime; // Time session was started or resumed.
|
||||||
// session that have NOT been staged for upload.
|
NSDate *_sessionCloseTime; // Time session was closed.
|
||||||
NSMutableString *_stagedFlowEvents; // App screens and events tagged during this session that HAVE been staged
|
NSMutableString *_unstagedFlowEvents; // Comma-delimited list of app screens and events tagged during this
|
||||||
// for upload.
|
// session that have NOT been staged for upload.
|
||||||
NSMutableString *_screens; // Comma-delimited list of screens tagged during this session.
|
NSMutableString *_stagedFlowEvents; // App screens and events tagged during this session that HAVE been staged
|
||||||
NSTimeInterval _sessionActiveDuration; // Duration that session open.
|
// for upload.
|
||||||
BOOL _sessionHasBeenOpen; // Whether or not this session has ever been open.
|
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 dispatch_queue_t queue;
|
}
|
||||||
@property dispatch_group_t criticalGroup;
|
|
||||||
@property BOOL isSessionOpen;
|
@property (nonatomic,readonly) dispatch_queue_t queue;
|
||||||
@property BOOL hasInitialized;
|
@property (nonatomic,readonly) dispatch_group_t criticalGroup;
|
||||||
@property float backgroundSessionTimeout;
|
@property BOOL isSessionOpen;
|
||||||
|
@property BOOL hasInitialized;
|
||||||
#pragma mark Public Methods
|
@property float backgroundSessionTimeout;
|
||||||
/*!
|
|
||||||
@method sharedLocalyticsSession
|
- (void)logMessage:(NSString *)message;
|
||||||
@abstract Accesses the Session object. This is a Singleton class which maintains
|
@property (nonatomic, assign, readonly) NSTimeInterval lastSessionStartTimestamp;
|
||||||
a single session throughout your application. It is possible to manage your own
|
@property (nonatomic, assign, readonly) NSInteger sessionNumber;
|
||||||
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:
|
@property enableHTTPS
|
||||||
[[LocalyticsSession sharedLocalyticsSession] tagEvent:@"MY_EVENT"];
|
@abstract Determines whether or not HTTPS is used when calling the Localytics
|
||||||
*/
|
post URL. The default is NO.
|
||||||
+ (LocalyticsSession *)sharedLocalyticsSession;
|
*/
|
||||||
|
@property (nonatomic, assign) BOOL enableHTTPS; // Defaults to NO.
|
||||||
/*!
|
|
||||||
@method LocalyticsSession
|
#pragma mark Public Methods
|
||||||
@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
|
@method sharedLocalyticsSession
|
||||||
*/
|
@abstract Accesses the Session object. This is a Singleton class which maintains
|
||||||
- (void)LocalyticsSession:(NSString *)appKey;
|
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:
|
||||||
@method startSession
|
[[LocalyticsSession sharedLocalyticsSession] functionHere]
|
||||||
@abstract An optional convenience initialize method that also calls the LocalyticsSession, open &
|
So, to tag an event, all that is necessary, anywhere in the code is:
|
||||||
upload methods. Best Practice is to call open & upload immediately after Localytics Session when loading an app,
|
[[LocalyticsSession sharedLocalyticsSession] tagEvent:@"MY_EVENT"];
|
||||||
this method fascilitates that behavior.
|
*/
|
||||||
It is recommended that this call be placed in <code>applicationDidFinishLaunching</code>.
|
+ (LocalyticsSession *)sharedLocalyticsSession;
|
||||||
@param applicationKey The key unique for each application generated
|
|
||||||
at www.localytics.com
|
/*!
|
||||||
*/
|
@method LocalyticsSession
|
||||||
- (void)startSession:(NSString *)appKey;
|
@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
|
||||||
/*!
|
*/
|
||||||
@method setOptIn
|
- (void)LocalyticsSession:(NSString *)appKey;
|
||||||
@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
|
@method startSession
|
||||||
server this user has opted out.
|
@abstract An optional convenience initialize method that also calls the LocalyticsSession, open &
|
||||||
@param optedIn True if the user is opted in, false otherwise.
|
upload methods. Best Practice is to call open & upload immediately after Localytics Session when loading an app,
|
||||||
*/
|
this method fascilitates that behavior.
|
||||||
- (void)setOptIn:(BOOL)optedIn;
|
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
|
||||||
@method isOptedIn
|
*/
|
||||||
@abstract (OPTIONAL) Whether or not this user has is opted in or out. The only way they can be
|
- (void)startSession:(NSString *)appKey;
|
||||||
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
|
@method setOptIn
|
||||||
the app is opted out, all subsequent Localytics calls will return immediately.
|
@abstract (OPTIONAL) Allows the application to control whether or not it will collect user data.
|
||||||
@result true if the user is opted in, false otherwise.
|
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
|
||||||
- (BOOL)isOptedIn;
|
server this user has opted out.
|
||||||
|
@param optedIn True if the user is opted in, false otherwise.
|
||||||
/*!
|
*/
|
||||||
@method open
|
- (void)setOptIn:(BOOL)optedIn;
|
||||||
@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
|
@method isOptedIn
|
||||||
it at the last moment. The session must be opened before any tags can
|
@abstract (OPTIONAL) Whether or not this user has is opted in or out. The only way they can be
|
||||||
be written. It is recommended that this call be placed in <code>applicationDidFinishLaunching</code>.
|
opted out is if setOptIn(false) has been called before this. This function should only be
|
||||||
<br>
|
used to pre-populate a checkbox in an options menu. It is not recommended that an application
|
||||||
If for any reason this is called more than once every subsequent open call
|
branch based on Localytics instrumentation because this creates an additional test case. If
|
||||||
will be ignored.
|
the app is opted out, all subsequent Localytics calls will return immediately.
|
||||||
*/
|
@result true if the user is opted in, false otherwise.
|
||||||
- (void)open;
|
*/
|
||||||
|
- (BOOL)isOptedIn;
|
||||||
/*!
|
|
||||||
@method resume
|
/*!
|
||||||
@abstract Resumes the Localytics session. When the App enters the background, the session is
|
@method open
|
||||||
closed and the time of closing is recorded. When the app returns to the foreground, the session
|
@abstract Opens the Localytics session. Not necessary if you choose to use startSession.
|
||||||
is resumed. If the time since closing is greater than BACKGROUND_SESSION_TIMEOUT, (15 seconds
|
The session time as presented on the website is the time between <code>open</code> and the
|
||||||
by default) a new session is created, and uploading is triggered. Otherwise, the previous session
|
final <code>close</code> so it is recommended to open the session as early as possible, and close
|
||||||
is reopened.
|
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>.
|
||||||
- (void)resume;
|
<br>
|
||||||
|
If for any reason this is called more than once every subsequent open call
|
||||||
/*!
|
will be ignored.
|
||||||
@method close
|
*/
|
||||||
@abstract Closes the Localytics session. This should be called in
|
- (void)open;
|
||||||
<code>applicationWillTerminate</code>.
|
|
||||||
<br>
|
/*!
|
||||||
If close is not called, the session will still be uploaded but no
|
@method resume
|
||||||
events will be processed and the session time will not appear. This is
|
@abstract Resumes the Localytics session. When the App enters the background, the session is
|
||||||
because the session is not yet closed so it should not be used in
|
closed and the time of closing is recorded. When the app returns to the foreground, the session
|
||||||
comparison with sessions which are closed.
|
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
|
||||||
- (void)close;
|
is reopened. It is possible to use the return value to determine whether or not a session was resumed.
|
||||||
|
This may be useful to some customers looking to do conditional instrumentation at the close of a session.
|
||||||
/*!
|
It is perfectly reasonable to ignore the return value.
|
||||||
@method tagEvent
|
@result YES if the sesion was resumed NO if it wasn't (suggesting a new session was created instead).*/
|
||||||
@abstract Allows a session to tag a particular event as having occurred. For
|
- (BOOL)resume;
|
||||||
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
|
@method close
|
||||||
to create a new tag every time the user gets to a new level in order
|
@abstract Closes the Localytics session. This should be called in
|
||||||
to determine how far the average user is progressing in the game.
|
<code>applicationWillTerminate</code>.
|
||||||
<br>
|
<br>
|
||||||
<strong>Tagging Best Practices</strong>
|
If close is not called, the session will still be uploaded but no
|
||||||
<ul>
|
events will be processed and the session time will not appear. This is
|
||||||
<li>DO NOT use tags to record personally identifiable information.</li>
|
because the session is not yet closed so it should not be used in
|
||||||
<li>The best way to use tags is to create all the tag strings as predefined
|
comparison with sessions which are closed.
|
||||||
constants and only use those. This is more efficient and removes the risk of
|
*/
|
||||||
collecting personal information.</li>
|
- (void)close;
|
||||||
<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>
|
@method tagEvent
|
||||||
<br>
|
@abstract Allows a session to tag a particular event as having occurred. For
|
||||||
See the tagging guide at: http://wiki.localytics.com/
|
example, if a view has three buttons, it might make sense to tag
|
||||||
@param event The name of the event which occurred.
|
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
|
||||||
- (void)tagEvent:(NSString *)event;
|
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.
|
||||||
- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes;
|
<br>
|
||||||
|
<strong>Tagging Best Practices</strong>
|
||||||
- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes reportAttributes:(NSDictionary *)reportAttributes;
|
<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
|
||||||
@method tagScreen
|
constants and only use those. This is more efficient and removes the risk of
|
||||||
@abstract Allows tagging the flow of screens encountered during the session.
|
collecting personal information.</li>
|
||||||
@param screen The name of the screen
|
<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>
|
||||||
- (void)tagScreen:(NSString *)screen;
|
</ul>
|
||||||
|
<br>
|
||||||
/*!
|
See the tagging guide at: http://wiki.localytics.com/
|
||||||
@method upload
|
@param event The name of the event which occurred.
|
||||||
@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
|
- (void)tagEvent:(NSString *)event;
|
||||||
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
|
- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes;
|
||||||
will just get uploaded the next time the app comes up.
|
|
||||||
*/
|
- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes reportAttributes:(NSDictionary *)reportAttributes;
|
||||||
- (void)upload;
|
|
||||||
|
/*!
|
||||||
/*!
|
@method tagScreen
|
||||||
@method setCustomDimension
|
@abstract Allows tagging the flow of screens encountered during the session.
|
||||||
@abstract (ENTERPRISE ONLY) Sets the value of a custom dimension. Custom dimensions are dimensions
|
@param screen The name of the screen
|
||||||
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
|
- (void)tagScreen:(NSString *)screen;
|
||||||
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
|
@method upload
|
||||||
never be changed without changing the App Key otherwise old installs of the application will pollute new data.
|
@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
|
||||||
- (void)setCustomDimension:(int)dimension value:(NSString *)value;
|
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
|
||||||
@end
|
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
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
// LocalyticsUploader.h
|
// LocalyticsUploader.h
|
||||||
// Copyright (C) 2009 Char Software Inc., DBA Localytics
|
// Copyright (C) 2012 Char Software Inc., DBA Localytics
|
||||||
//
|
//
|
||||||
// This code is provided under the Localytics Modified BSD License.
|
// This code is provided under the Localytics Modified BSD License.
|
||||||
// A copy of this license has been distributed in a file called LICENSE
|
// A copy of this license has been distributed in a file called LICENSE
|
||||||
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
extern NSString * const kLocalyticsKeyResponseBody;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@class LocalyticsUploader
|
@class LocalyticsUploader
|
||||||
@discussion Singleton class to handle data uploads
|
@discussion Singleton class to handle data uploads
|
||||||
@ -35,8 +37,28 @@
|
|||||||
writing data regardless of whether or not the upload succeeds. Files
|
writing data regardless of whether or not the upload succeeds. Files
|
||||||
which have been renamed still count towards the total number of Localytics
|
which have been renamed still count towards the total number of Localytics
|
||||||
files which can be stored on the disk.
|
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 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;
|
- (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
|
@end
|
@ -1,5 +1,5 @@
|
|||||||
// LocalyticsUploader.m
|
// LocalyticsUploader.m
|
||||||
// Copyright (C) 2009 Char Software Inc., DBA Localytics
|
// Copyright (C) 2012 Char Software Inc., DBA Localytics
|
||||||
//
|
//
|
||||||
// This code is provided under the Localytics Modified BSD License.
|
// This code is provided under the Localytics Modified BSD License.
|
||||||
// A copy of this license has been distributed in a file called LICENSE
|
// A copy of this license has been distributed in a file called LICENSE
|
||||||
@ -10,16 +10,25 @@
|
|||||||
#import "LocalyticsUploader.h"
|
#import "LocalyticsUploader.h"
|
||||||
#import "LocalyticsSession.h"
|
#import "LocalyticsSession.h"
|
||||||
#import "LocalyticsDatabase.h"
|
#import "LocalyticsDatabase.h"
|
||||||
|
#import "WebserviceConstants.h"
|
||||||
#import <zlib.h>
|
#import <zlib.h>
|
||||||
|
|
||||||
#define LOCALYTICS_URL @"http://analytics.localytics.com/api/v2/applications/%@/uploads"
|
#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;
|
static LocalyticsUploader *_sharedUploader = nil;
|
||||||
|
|
||||||
|
NSString * const kLocalyticsKeyResponseBody = @"localytics.key.responseBody";
|
||||||
|
|
||||||
@interface LocalyticsUploader ()
|
@interface LocalyticsUploader ()
|
||||||
- (void)finishUpload;
|
- (void)finishUpload;
|
||||||
- (NSData *)gzipDeflatedDataWithData:(NSData *)data;
|
- (NSData *)gzipDeflatedDataWithData:(NSData *)data;
|
||||||
- (void)logMessage:(NSString *)message;
|
- (void)logMessage:(NSString *)message;
|
||||||
|
- (NSString *)uploadTimeStamp;
|
||||||
|
|
||||||
@property (readwrite) BOOL isUploading;
|
@property (readwrite) BOOL isUploading;
|
||||||
|
|
||||||
@ -40,7 +49,13 @@ static LocalyticsUploader *_sharedUploader = nil;
|
|||||||
|
|
||||||
#pragma mark - Class Methods
|
#pragma mark - Class Methods
|
||||||
|
|
||||||
- (void)uploaderWithApplicationKey:(NSString *)localyticsApplicationKey {
|
- (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.
|
// Do nothing if already uploading.
|
||||||
if (self.isUploading == true)
|
if (self.isUploading == true)
|
||||||
@ -77,17 +92,26 @@ static LocalyticsUploader *_sharedUploader = nil;
|
|||||||
NSData *requestData = [blobString dataUsingEncoding:NSUTF8StringEncoding];
|
NSData *requestData = [blobString dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
NSString *myString = [[[NSString alloc] initWithData:requestData encoding:NSUTF8StringEncoding] autorelease];
|
NSString *myString = [[[NSString alloc] initWithData:requestData encoding:NSUTF8StringEncoding] autorelease];
|
||||||
[self logMessage:[NSString stringWithFormat:@"Uploading data (length: %u)", [myString length]]];
|
[self logMessage:[NSString stringWithFormat:@"Uploading data (length: %u)", [myString length]]];
|
||||||
|
[self logMessage:myString];
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
NSData *deflatedRequestData = [[self gzipDeflatedDataWithData:requestData] retain];
|
NSData *deflatedRequestData = [[self gzipDeflatedDataWithData:requestData] retain];
|
||||||
|
|
||||||
[pool drain];
|
[pool drain];
|
||||||
|
|
||||||
NSString *apiUrlString = [NSString stringWithFormat:LOCALYTICS_URL, [localyticsApplicationKey stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
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]
|
NSMutableURLRequest *submitRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiUrlString]
|
||||||
cachePolicy:NSURLRequestReloadIgnoringCacheData
|
cachePolicy:NSURLRequestReloadIgnoringCacheData
|
||||||
timeoutInterval:60.0];
|
timeoutInterval:60.0];
|
||||||
[submitRequest setHTTPMethod:@"POST"];
|
[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:@"application/x-gzip" forHTTPHeaderField:@"Content-Type"];
|
||||||
[submitRequest setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
|
[submitRequest setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
|
||||||
[submitRequest setValue:[NSString stringWithFormat:@"%d", [deflatedRequestData length]] forHTTPHeaderField:@"Content-Length"];
|
[submitRequest setValue:[NSString stringWithFormat:@"%d", [deflatedRequestData length]] forHTTPHeaderField:@"Content-Length"];
|
||||||
@ -100,7 +124,7 @@ static LocalyticsUploader *_sharedUploader = nil;
|
|||||||
@try {
|
@try {
|
||||||
NSURLResponse *response = nil;
|
NSURLResponse *response = nil;
|
||||||
NSError *responseError = nil;
|
NSError *responseError = nil;
|
||||||
[NSURLConnection sendSynchronousRequest:submitRequest returningResponse:&response error:&responseError];
|
NSData *responseData = [NSURLConnection sendSynchronousRequest:submitRequest returningResponse:&response error:&responseError];
|
||||||
NSInteger responseStatusCode = [(NSHTTPURLResponse *)response statusCode];
|
NSInteger responseStatusCode = [(NSHTTPURLResponse *)response statusCode];
|
||||||
|
|
||||||
if (responseError) {
|
if (responseError) {
|
||||||
@ -123,6 +147,18 @@ static LocalyticsUploader *_sharedUploader = nil;
|
|||||||
[[LocalyticsDatabase sharedLocalyticsDatabase] deleteUploadedData];
|
[[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) {}
|
@catch (NSException * e) {}
|
||||||
|
|
||||||
@ -195,6 +231,15 @@ static LocalyticsUploader *_sharedUploader = nil;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@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
|
#pragma mark - System Functions
|
||||||
+ (id)allocWithZone:(NSZone *)zone {
|
+ (id)allocWithZone:(NSZone *)zone {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
|
@ -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
|
|
@ -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
|
|
@ -1,5 +1,5 @@
|
|||||||
// WebserviceConstants.h
|
// WebserviceConstants.h
|
||||||
// Copyright (C) 2009 Char Software Inc., DBA Localytics
|
// Copyright (C) 2012 Char Software Inc., DBA Localytics
|
||||||
//
|
//
|
||||||
// This code is provided under the Localytics Modified BSD License.
|
// This code is provided under the Localytics Modified BSD License.
|
||||||
// A copy of this license has been distributed in a file called LICENSE
|
// A copy of this license has been distributed in a file called LICENSE
|
||||||
@ -11,6 +11,12 @@
|
|||||||
// To save disk space and network bandwidth all the keywords have been
|
// To save disk space and network bandwidth all the keywords have been
|
||||||
// abbreviated and are exploded by the server.
|
// 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 *
|
* Shared Attributes *
|
||||||
*********************/
|
*********************/
|
||||||
@ -22,6 +28,7 @@
|
|||||||
#define PARAM_SESSION_UUID @"su" // UUID for an existing session
|
#define PARAM_SESSION_UUID @"su" // UUID for an existing session
|
||||||
#define PARAM_NEW_SESSION_UUID @"u" // UUID for a new session
|
#define PARAM_NEW_SESSION_UUID @"u" // UUID for a new session
|
||||||
#define PARAM_ATTRIBUTES @"attrs" // Attributes (dictionary)
|
#define PARAM_ATTRIBUTES @"attrs" // Attributes (dictionary)
|
||||||
|
#define PARAM_SESSION_ELAPSE_TIME @"sl" // Number of seconds since the previous session start
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
* Blob Header *
|
* Blob Header *
|
||||||
@ -42,9 +49,8 @@
|
|||||||
|
|
||||||
// PARAM_DATA_TYPE
|
// PARAM_DATA_TYPE
|
||||||
#define PARAM_APP_KEY @"au" // Localytics Application ID
|
#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_UUID_HASHED @"udid" // Hashed version of the UUID
|
||||||
#define PARAM_DEVICE_MAC @"wmac" // Hashed version of the device Mac
|
#define PARAM_DEVICE_ADID @"adid" // Advertising Identifier
|
||||||
#define PARAM_INSTALL_ID @"iu" // Install ID
|
#define PARAM_INSTALL_ID @"iu" // Install ID
|
||||||
#define PARAM_JAILBROKEN @"j" // Jailbroken (boolean)
|
#define PARAM_JAILBROKEN @"j" // Jailbroken (boolean)
|
||||||
#define PARAM_LIBRARY_VERSION @"lv" // Client Version
|
#define PARAM_LIBRARY_VERSION @"lv" // Client Version
|
||||||
@ -52,14 +58,11 @@
|
|||||||
#define PARAM_DEVICE_PLATFORM @"dp" // Device Platform
|
#define PARAM_DEVICE_PLATFORM @"dp" // Device Platform
|
||||||
#define PARAM_LOCALE_LANGUAGE @"dll" // Locale Language
|
#define PARAM_LOCALE_LANGUAGE @"dll" // Locale Language
|
||||||
#define PARAM_LOCALE_COUNTRY @"dlc" // Locale Country
|
#define PARAM_LOCALE_COUNTRY @"dlc" // Locale Country
|
||||||
#define PARAM_NETWORK_COUNTRY @"nc" // Network Country (iso code) // ???: Never used on iPhone.
|
|
||||||
#define PARAM_DEVICE_COUNTRY @"dc" // Device Country (iso code)
|
#define PARAM_DEVICE_COUNTRY @"dc" // Device Country (iso code)
|
||||||
#define PARAM_DEVICE_MANUFACTURER @"dma" // Device Manufacturer // ???: Never used on iPhone. Used to be "Device Make".
|
|
||||||
#define PARAM_DEVICE_MODEL @"dmo" // Device Model
|
#define PARAM_DEVICE_MODEL @"dmo" // Device Model
|
||||||
#define PARAM_DEVICE_OS_VERSION @"dov" // Device OS Version
|
#define PARAM_DEVICE_OS_VERSION @"dov" // Device OS Version
|
||||||
#define PARAM_NETWORK_CARRIER @"nca" // Network Carrier
|
#define PARAM_NETWORK_CARRIER @"nca" // Network Carrier
|
||||||
#define PARAM_DATA_CONNECTION @"dac" // Data Connection Type // ???: Never used on iPhone.
|
#define PARAM_OPT_VALUE @"out" // Opt Out (boolean)
|
||||||
#define PARAM_OPT_VALUE @"optin" // Opt In (boolean)
|
|
||||||
#define PARAM_DEVICE_MEMORY @"dmem" // Device Memory
|
#define PARAM_DEVICE_MEMORY @"dmem" // Device Memory
|
||||||
|
|
||||||
/*****************
|
/*****************
|
||||||
|
@ -46,11 +46,7 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (![managedObjectContext.persistentStoreCoordinator.persistentStores count])
|
[[self storeManager] persistentStoreCoordinator];
|
||||||
[managedObjectContext performBlockAndWait:^{
|
|
||||||
managedObjectContext.persistentStoreCoordinator = [self storeManager].persistentStoreCoordinator;
|
|
||||||
}];
|
|
||||||
|
|
||||||
if (![self storeManager].isReady)
|
if (![self storeManager].isReady)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
|
@ -116,6 +116,7 @@
|
|||||||
NSString *localyticsKey = [self localyticsKey];
|
NSString *localyticsKey = [self localyticsKey];
|
||||||
if ([localyticsKey length]) {
|
if ([localyticsKey length]) {
|
||||||
inf(@"Initializing Localytics");
|
inf(@"Initializing Localytics");
|
||||||
|
[LocalyticsSession sharedLocalyticsSession].enableHTTPS = YES;
|
||||||
[[LocalyticsSession sharedLocalyticsSession] startSession:localyticsKey];
|
[[LocalyticsSession sharedLocalyticsSession] startSession:localyticsKey];
|
||||||
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
||||||
if (message.level >= PearlLogLevelWarn)
|
if (message.level >= PearlLogLevelWarn)
|
||||||
@ -321,23 +322,11 @@
|
|||||||
|
|
||||||
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
|
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
|
||||||
|
|
||||||
wrn(@"Received memory warning.");
|
inf(@"Received memory warning.");
|
||||||
|
|
||||||
[super applicationDidReceiveMemoryWarning:application];
|
[super applicationDidReceiveMemoryWarning:application];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
|
||||||
|
|
||||||
inf(@"Re-activated");
|
|
||||||
[[MPAppDelegate get] checkConfig];
|
|
||||||
|
|
||||||
if (FBSession.activeSession.state == FBSessionStateCreatedOpening)
|
|
||||||
// An old Facebook Login session that wasn't finished. Clean it up.
|
|
||||||
[FBSession.activeSession close];
|
|
||||||
|
|
||||||
[super applicationDidBecomeActive:application];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
||||||
|
|
||||||
[[LocalyticsSession sharedLocalyticsSession] close];
|
[[LocalyticsSession sharedLocalyticsSession] close];
|
||||||
@ -369,10 +358,31 @@
|
|||||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||||
|
|
||||||
inf(@"Will deactivate");
|
inf(@"Will deactivate");
|
||||||
|
|
||||||
[self saveContext];
|
[self saveContext];
|
||||||
|
|
||||||
if (![[MPiOSConfig get].rememberLogin boolValue])
|
if (![[MPiOSConfig get].rememberLogin boolValue])
|
||||||
[self signOutAnimated:NO];
|
[self signOutAnimated:NO];
|
||||||
|
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] close];
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] upload];
|
||||||
|
|
||||||
|
[super applicationWillResignActive:application];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||||
|
|
||||||
|
inf(@"Re-activated");
|
||||||
|
[[MPAppDelegate get] checkConfig];
|
||||||
|
|
||||||
|
if (FBSession.activeSession.state == FBSessionStateCreatedOpening)
|
||||||
|
// An old Facebook Login session that wasn't finished. Clean it up.
|
||||||
|
[FBSession.activeSession close];
|
||||||
|
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] resume];
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] upload];
|
||||||
|
|
||||||
|
[super applicationDidBecomeActive:application];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Behavior
|
#pragma mark - Behavior
|
||||||
|
@ -77,6 +77,13 @@
|
|||||||
[super viewWillAppear:animated];
|
[super viewWillAppear:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)viewDidAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] tagScreen:@"Apps"];
|
||||||
|
|
||||||
|
[super viewDidAppear:animated];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)viewWillDisappear:(BOOL)animated {
|
- (void)viewWillDisappear:(BOOL)animated {
|
||||||
|
|
||||||
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
|
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPGuideViewController.h"
|
#import "MPGuideViewController.h"
|
||||||
|
#import "LocalyticsSession.h"
|
||||||
|
|
||||||
|
|
||||||
@implementation MPGuideViewController
|
@implementation MPGuideViewController
|
||||||
@ -35,6 +36,8 @@
|
|||||||
|
|
||||||
- (void)viewDidAppear:(BOOL)animated {
|
- (void)viewDidAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] tagScreen:@"Guide"];
|
||||||
|
|
||||||
[super viewDidAppear:animated];
|
[super viewDidAppear:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@
|
|||||||
inf(@"Main will appear");
|
inf(@"Main will appear");
|
||||||
|
|
||||||
// Sometimes, the search bar gets stuck in some sort of first-responder mode that it can't get out of...
|
// Sometimes, the search bar gets stuck in some sort of first-responder mode that it can't get out of...
|
||||||
[self.searchDisplayController.searchBar resignFirstResponder];
|
[[self.view.window findFirstResponderInHierarchy] resignFirstResponder];
|
||||||
|
|
||||||
// Needed for when we appear after a modal VC dismisses:
|
// Needed for when we appear after a modal VC dismisses:
|
||||||
// We can't present until the other modal VC has been fully dismissed and presenting in viewDidAppear will fail.
|
// We can't present until the other modal VC has been fully dismissed and presenting in viewDidAppear will fail.
|
||||||
@ -204,6 +204,8 @@
|
|||||||
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] tagScreen:@"Main"];
|
||||||
|
|
||||||
[super viewDidAppear:animated];
|
[super viewDidAppear:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,7 +678,7 @@
|
|||||||
|
|
||||||
- (IBAction)action:(id)sender {
|
- (IBAction)action:(id)sender {
|
||||||
|
|
||||||
[PearlSheet showSheetWithTitle:nil message:nil viewStyle:UIActionSheetStyleAutomatic
|
[PearlSheet showSheetWithTitle:nil viewStyle:UIActionSheetStyleAutomatic
|
||||||
initSheet:nil
|
initSheet:nil
|
||||||
tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
|
tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
|
||||||
if (buttonIndex == [sheet cancelButtonIndex])
|
if (buttonIndex == [sheet cancelButtonIndex])
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#import "MPAppDelegate.h"
|
#import "MPAppDelegate.h"
|
||||||
#import "MPAppDelegate_Key.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
#import "MPAppDelegate_Store.h"
|
#import "MPAppDelegate_Store.h"
|
||||||
|
#import "LocalyticsSession.h"
|
||||||
|
|
||||||
@interface MPPreferencesViewController ()
|
@interface MPPreferencesViewController ()
|
||||||
|
|
||||||
@ -80,6 +81,13 @@
|
|||||||
[super viewWillAppear:animated];
|
[super viewWillAppear:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)viewDidAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] tagScreen:@"Preferences"];
|
||||||
|
|
||||||
|
[super viewDidAppear:animated];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)viewWillDisappear:(BOOL)animated {
|
- (void)viewWillDisappear:(BOOL)animated {
|
||||||
|
|
||||||
inf(@"Preferences will disappear");
|
inf(@"Preferences will disappear");
|
||||||
@ -152,6 +160,7 @@
|
|||||||
vc.showDoneButton = NO;
|
vc.showDoneButton = NO;
|
||||||
|
|
||||||
[self.navigationController pushViewController:vc animated:YES];
|
[self.navigationController pushViewController:vc animated:YES];
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] tagScreen:@"Settings"];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MPTypeViewController.h"
|
#import "MPTypeViewController.h"
|
||||||
|
#import "LocalyticsSession.h"
|
||||||
|
|
||||||
|
|
||||||
@interface MPTypeViewController ()
|
@interface MPTypeViewController ()
|
||||||
@ -44,6 +45,8 @@
|
|||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] tagScreen:@"Type Selection"];
|
||||||
|
|
||||||
[super viewDidAppear:animated];
|
[super viewDidAppear:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#import "MPAppDelegate.h"
|
#import "MPAppDelegate.h"
|
||||||
#import "MPAppDelegate_Key.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
#import "MPAppDelegate_Store.h"
|
#import "MPAppDelegate_Store.h"
|
||||||
|
#import "LocalyticsSession.h"
|
||||||
|
|
||||||
@interface MPUnlockViewController ()
|
@interface MPUnlockViewController ()
|
||||||
|
|
||||||
@ -193,6 +194,8 @@
|
|||||||
self.uiContainer.alpha = 1;
|
self.uiContainer.alpha = 1;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] tagScreen:@"Unlock"];
|
||||||
|
|
||||||
[super viewDidAppear:animated];
|
[super viewDidAppear:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -749,7 +752,7 @@
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
[PearlSheet showSheetWithTitle:targetedUser.name
|
[PearlSheet showSheetWithTitle:targetedUser.name
|
||||||
message:nil viewStyle:UIActionSheetStyleBlackTranslucent
|
viewStyle:UIActionSheetStyleBlackTranslucent
|
||||||
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
|
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
|
||||||
if (buttonIndex == [sheet cancelButtonIndex])
|
if (buttonIndex == [sheet cancelButtonIndex])
|
||||||
return;
|
return;
|
||||||
@ -823,7 +826,7 @@
|
|||||||
|
|
||||||
- (IBAction)add:(UIButton *)sender {
|
- (IBAction)add:(UIButton *)sender {
|
||||||
|
|
||||||
[PearlSheet showSheetWithTitle:@"Follow Master Password" message:nil viewStyle:UIActionSheetStyleBlackTranslucent
|
[PearlSheet showSheetWithTitle:@"Follow Master Password" viewStyle:UIActionSheetStyleBlackTranslucent
|
||||||
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
|
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
|
||||||
if (buttonIndex == [sheet cancelButtonIndex])
|
if (buttonIndex == [sheet cancelButtonIndex])
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user