Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

update count.ly sdk and expose suspend resume functions

  • Loading branch information...
commit 41efcfaeb7b14540fc3119518e01ea5e215a8a81 1 parent 1909862
@euforic authored
View
1  Classes/CountLyModule.h
@@ -5,6 +5,7 @@
* and licensed under the Apache Public License (version 2)
*/
#import "TiModule.h"
+#import "Countly.h"
@interface CountLyModule : TiModule
{
View
104 Classes/CountLyModule.m
@@ -8,7 +8,59 @@
#import "TiBase.h"
#import "TiHost.h"
#import "TiUtils.h"
-#import "Countly.h"
+
+
+/// Tool to decoded urld encoded string that Count.ly uses to send metrics
+/// Utilities for encoding and decoding URL arguments.
+/// This code is from the project google-toolbox-for-mac
+@interface NSString (GTMNSStringURLArgumentsAdditions)
+
+/// Returns a string that is escaped properly to be a URL argument.
+//
+/// This differs from stringByAddingPercentEscapesUsingEncoding: in that it
+/// will escape all the reserved characters (per RFC 3986
+/// <http://www.ietf.org/rfc/rfc3986.txt>) which
+/// stringByAddingPercentEscapesUsingEncoding would leave.
+///
+/// This will also escape '%', so this should not be used on a string that has
+/// already been escaped unless double-escaping is the desired result.
+- (NSString*)gtm_stringByEscapingForURLArgument;
+
+/// Returns the unescaped version of a URL argument
+//
+/// This has the same behavior as stringByReplacingPercentEscapesUsingEncoding:,
+/// except that it will also convert '+' to space.
+- (NSString*)gtm_stringByUnescapingFromURLArgument;
+
+@end
+
+#define GTMNSMakeCollectable(cf) ((id)(cf))
+#define GTMCFAutorelease(cf) ([GTMNSMakeCollectable(cf) autorelease])
+
+@implementation NSString (GTMNSStringURLArgumentsAdditions)
+
+- (NSString*)gtm_stringByEscapingForURLArgument {
+ // Encode all the reserved characters, per RFC 3986
+ // (<http://www.ietf.org/rfc/rfc3986.txt>)
+ CFStringRef escaped =
+ CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
+ (CFStringRef)self,
+ NULL,
+ (CFStringRef)@"!*'();:@&=+$,/?%#[]",
+ kCFStringEncodingUTF8);
+ return GTMCFAutorelease(escaped);
+}
+
+- (NSString*)gtm_stringByUnescapingFromURLArgument {
+ NSMutableString *resultString = [NSMutableString stringWithString:self];
+ [resultString replaceOccurrencesOfString:@"+"
+ withString:@" "
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [resultString length])];
+ return [resultString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+}
+
+@end
@implementation CountLyModule
@@ -41,12 +93,12 @@ -(void)shutdown:(id)sender
// this method is called when the module is being unloaded
// typically this is during shutdown. make sure you don't do too
// much processing here or the app will be quit forceably
-
+
// you *must* call the superclass
[super shutdown:sender];
}
-#pragma mark Cleanup
+#pragma mark Cleanup
-(void)dealloc
{
@@ -69,7 +121,7 @@ -(void)_listenerAdded:(NSString *)type count:(int)count
{
if (count == 1 && [type isEqualToString:@"my_event"])
{
- // the first (of potentially many) listener is being added
+ // the first (of potentially many) listener is being added
// for event named 'my_event'
}
}
@@ -94,31 +146,53 @@ -(void)start:(id)args
TiThreadPerformOnMainThread(^{[[Countly sharedInstance] start:apikey withHost:apiHost];}, NO);
}
--(id)udid
+-(void)resume:(id)args
+{
+ [[Countly sharedInstance] resume];
+}
+
+-(void)suspend:(id)args
+{
+ [[Countly sharedInstance] suspend];
+
+}
+
+-(void)exit:(id)args
+{
+ [[Countly sharedInstance] exit];
+
+}
+
+-(NSNumber*)isSuspended
+{
+ return NUMBOOL([[Countly sharedInstance] isSuspended]);
+}
+
+-(NSString*)udid
{
NSString *udid = [DeviceInfo udid];
return udid;
}
--(id)device
+-(NSString*)device
{
NSString *device = [DeviceInfo device];
return device;
}
--(id)osVersion
+-(NSString*)osVersion
{
NSString *osVersion = [DeviceInfo osVersion];
return osVersion;
}
--(id)carrier
+-(NSString*)carrier
{
NSString *carrier = [DeviceInfo carrier];
return carrier;
}
--(id)resolution
+-(NSString*)resolution
{
NSString *resolution = [DeviceInfo resolution];
return resolution;
@@ -126,19 +200,13 @@ -(id)resolution
-(id)locale
{
- NSString *locale = [DeviceInfo locale];
+ NSLocale *locale = [DeviceInfo locale];
return locale;
}
--(id)platform
-{
- NSString *platform = [DeviceInfo platform];
- return platform;
-}
-
--(id)metrics
+-(NSString*)metrics
{
- NSString *metrics = [DeviceInfo platform];
+ NSString *metrics = [[DeviceInfo metrics] gtm_stringByUnescapingFromURLArgument];
return metrics;
}
View
23 LICENSE
@@ -1 +1,22 @@
-TODO: place your license here and we'll include it in the module distribution
+(The MIT License)
+
+Copyright (c) 2012 Christian Sullivan &lt;cs@euforic.co&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
43 README.md
@@ -10,6 +10,24 @@ Other Countly SDK repositories;
- [Countly Android SDK (countly-sdk-android)](https://github.com/Countly/countly-sdk-android)
+# Install
+
+```
+$ git clone https://github.com/euforic/Ti-Count.ly.git
+$ cd Ti-Count.ly
+$ cp count.ly-iphone-0.1.1.zip /Library/Application Support/Titanium/
+```
+Register your module with your application by editing `tiapp.xml` and adding your module.
+```
+<modules>
+ <module version="0.1.1">count.ly</module>
+</modules>
+```
+Require you module in whatever js file you plan to use it in
+```
+var my_module = require('count.ly');
+```
+
## Usage
```
@@ -28,6 +46,27 @@ Ti.API.info(countly.platform);
Ti.API.info(countly.metrics);
```
-## TODO
+## License
+
+(The MIT License)
+
+Copyright (c) 2012 Christian Sullivan &lt;cs@euforic.co&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
-Write a real readme
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
BIN  ...odeproj/project.xcworkspace/xcuserdata/euforic.xcuserdatad/UserInterfaceState.xcuserstate
Binary file not shown
View
8 example/app.js
@@ -16,7 +16,12 @@ win.open();
var countly = require('count.ly');
countly.start('APP_KEY','http://API_HOST.com');
-label.text = JSON.parse(countly.metrics);
+var metrics = JSON.parse(countly.metrics);
+
+metrics.udid = countly.udid;
+metrics.carrier = countly.carrier || 'Simulator';
+metrics.isSuspended = countly.isSuspended;
+label.text = metrics;
Ti.API.info(countly.udid);
Ti.API.info(countly.device);
@@ -24,5 +29,4 @@ Ti.API.info(countly.osVersion);
Ti.API.info(countly.carrier);
Ti.API.info(countly.resolution);
Ti.API.info(countly.locale);
-Ti.API.info(countly.platform);
Ti.API.info(countly.metrics);
View
4 manifest
@@ -2,7 +2,7 @@
# this is your module manifest and used by Titanium
# during compilation, packaging, distribution, etc.
#
-version: 0.1
+version: 0.1.1
apiversion: 2
description: Count.ly SDK Module
author: Christian Sullivan <cs@euforic.co>
@@ -15,4 +15,4 @@ name: count.ly
moduleid: count.ly
guid: ad1ce2b6-9511-403b-b5de-50c40542c433
platform: iphone
-minsdk: 2.1.0.v20120604151821
+minsdk: 2.1.1.GA
View
36 sdk/Countly.h
@@ -1,26 +1,12 @@
// Countly.h
-//
+//
// This code is provided under the MIT License.
-//
+//
// Please visit www.count.ly for more information.
#import <Foundation/Foundation.h>
-#import <UIKit/UIKit.h>
-@interface DeviceInfo : NSObject {
-
-}
-
-+ (NSString *)udid;
-+ (NSString *)device;
-+ (NSString *)osVersion;
-+ (NSString *)carrier;
-+ (NSString *)resolution;
-+ (NSString *)locale;
-+ (NSString *)platform;
-
-@end
@interface Countly : NSObject {
double unsentSessionLength;
@@ -30,8 +16,22 @@
}
+ (Countly *)sharedInstance;
-
- (void)start:(NSString *)appKey withHost:(NSString *)appHost;
+- (BOOL)isSuspended;
+- (void)resume;
+- (void)suspend;
+- (void)exit;
+@end
+@interface DeviceInfo : NSObject{
+}
-@end
++ (NSString *)udid;
++ (NSString *)device;
++ (NSString *)osVersion;
++ (NSString *)carrier;
++ (NSString *)resolution;
++ (NSLocale *)locale;
++ (NSString *)appVersion;
++ (NSString *)metrics;
+@end
View
194 sdk/Countly.m
@@ -1,7 +1,7 @@
// Countly.m
-//
+//
// This code is provided under the MIT License.
-//
+//
// Please visit www.count.ly for more information.
@@ -19,10 +19,63 @@
#import "Countly_OpenUDID.h"
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <CoreTelephony/CTCarrier.h>
+#import <UIKit/UIKit.h>
#include <sys/types.h>
#include <sys/sysctl.h>
+
+/// Utilities for encoding and decoding URL arguments.
+/// This code is from the project google-toolbox-for-mac
+@interface NSString (GTMNSStringURLArgumentsAdditions)
+
+/// Returns a string that is escaped properly to be a URL argument.
+//
+/// This differs from stringByAddingPercentEscapesUsingEncoding: in that it
+/// will escape all the reserved characters (per RFC 3986
+/// <http://www.ietf.org/rfc/rfc3986.txt>) which
+/// stringByAddingPercentEscapesUsingEncoding would leave.
+///
+/// This will also escape '%', so this should not be used on a string that has
+/// already been escaped unless double-escaping is the desired result.
+- (NSString*)gtm_stringByEscapingForURLArgument;
+
+/// Returns the unescaped version of a URL argument
+//
+/// This has the same behavior as stringByReplacingPercentEscapesUsingEncoding:,
+/// except that it will also convert '+' to space.
+- (NSString*)gtm_stringByUnescapingFromURLArgument;
+
+@end
+
+#define GTMNSMakeCollectable(cf) ((id)(cf))
+#define GTMCFAutorelease(cf) ([GTMNSMakeCollectable(cf) autorelease])
+
+@implementation NSString (GTMNSStringURLArgumentsAdditions)
+
+- (NSString*)gtm_stringByEscapingForURLArgument {
+ // Encode all the reserved characters, per RFC 3986
+ // (<http://www.ietf.org/rfc/rfc3986.txt>)
+ CFStringRef escaped =
+ CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
+ (CFStringRef)self,
+ NULL,
+ (CFStringRef)@"!*'();:@&=+$,/?%#[]",
+ kCFStringEncodingUTF8);
+ return GTMCFAutorelease(escaped);
+}
+
+- (NSString*)gtm_stringByUnescapingFromURLArgument {
+ NSMutableString *resultString = [NSMutableString stringWithString:self];
+ [resultString replaceOccurrencesOfString:@"+"
+ withString:@" "
+ options:NSLiteralSearch
+ range:NSMakeRange(0, [resultString length])];
+ return [resultString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+}
+
+@end
+
@implementation DeviceInfo
+ (NSString *)udid
@@ -47,7 +100,7 @@ + (NSString *)osVersion
}
+ (NSString *)carrier
-{
+{
if (NSClassFromString(@"CTTelephonyNetworkInfo"))
{
CTTelephonyNetworkInfo *netinfo = [[[CTTelephonyNetworkInfo alloc] init] autorelease];
@@ -64,7 +117,7 @@ + (NSString *)resolution
CGFloat scale = [[UIScreen mainScreen] respondsToSelector:@selector(scale)] ? [[UIScreen mainScreen] scale] : 1.f;
CGSize res = CGSizeMake(bounds.size.width * scale, bounds.size.height * scale);
NSString *result = [NSString stringWithFormat:@"%gx%g", res.width, res.height];
-
+
return result;
}
@@ -73,51 +126,35 @@ + (NSString *)locale
return [[NSLocale currentLocale] localeIdentifier];
}
++ (NSString *)appVersion
+{
+ return [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey];
+}
+
+ (NSString *)metrics
-{
+{
NSString *result = @"{";
-
+
result = [result stringByAppendingFormat:@"\"%@\":\"%@\"", @"_device", [DeviceInfo device]];
-
+
result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"_os", @"iOS"];
-
- result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"_os_version", [DeviceInfo osVersion]];
+
+ result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"_os_version", [DeviceInfo osVersion]];
NSString *carrier = [DeviceInfo carrier];
if (carrier != nil)
result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"_carrier", carrier];
-
+
result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"_resolution", [DeviceInfo resolution]];
result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"_locale", [DeviceInfo locale]];
-
- result = [result stringByAppendingString:@"}"];
-
- result = [result stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- return result;
-}
+ result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"_app_version", [DeviceInfo appVersion]];
-+ (NSString *)platform
-{
- NSString *result = @"{";
-
- result = [result stringByAppendingFormat:@"\"%@\":\"%@\"", @"device", [DeviceInfo device]];
-
- result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"os", @"iOS"];
-
- result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"os_version", [DeviceInfo osVersion]];
-
- NSString *carrier = [DeviceInfo carrier];
- if (carrier != nil)
- result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"carrier", carrier];
-
- result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"resolution", [DeviceInfo resolution]];
-
- result = [result stringByAppendingFormat:@",\"%@\":\"%@\"", @"locale", [DeviceInfo locale]];
-
result = [result stringByAppendingString:@"}"];
-
+
+ result = [result gtm_stringByEscapingForURLArgument];
+
return result;
}
@@ -127,9 +164,9 @@ @interface ConnectionQueue : NSObject
{
NSMutableArray *queue_;
NSURLConnection *connection_;
- UIBackgroundTaskIdentifier bgTask_;
+ UIBackgroundTaskIdentifier bgTask_;
NSString *appKey;
- NSString *appHost;
+ NSString *appHost;
}
@property (nonatomic, copy) NSString *appKey;
@@ -148,7 +185,7 @@ + (ConnectionQueue *)sharedInstance
{
if (s_sharedConnectionQueue == nil)
s_sharedConnectionQueue = [[ConnectionQueue alloc] init];
-
+
return s_sharedConnectionQueue;
}
@@ -170,23 +207,24 @@ - (void) tick
if (connection_ != nil || bgTask_ != UIBackgroundTaskInvalid || [queue_ count] == 0)
return;
- UIApplication *app = [UIApplication sharedApplication];
- bgTask_ = [app beginBackgroundTaskWithExpirationHandler:^{
- [app endBackgroundTask:bgTask_];
- bgTask_ = UIBackgroundTaskInvalid;
+ UIApplication *app = [UIApplication sharedApplication];
+ bgTask_ = [app beginBackgroundTaskWithExpirationHandler:^{
+ [app endBackgroundTask:bgTask_];
+ bgTask_ = UIBackgroundTaskInvalid;
}];
NSString *data = [queue_ objectAtIndex:0];
- NSString *urlString = [NSString stringWithFormat:@"%@/i?%@", appHost, data];
+ NSString *urlString = [NSString stringWithFormat:@"%@/i?%@", self.appHost, data];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
- connection_ = [NSURLConnection connectionWithRequest:request delegate:self];
+ connection_ = [NSURLConnection connectionWithRequest:request delegate:self];
}
- (void)beginSession
{
- NSString *data = [NSString stringWithFormat:@"app_key=%@&device_id=%@&sdk_version="COUNTLY_VERSION"&begin_session=1&metrics=%@",
- appKey,
+ NSString *data = [NSString stringWithFormat:@"app_key=%@&device_id=%@&timestamp=%ld&sdk_version="COUNTLY_VERSION"&begin_session=1&metrics=%@",
+ appKey,
[DeviceInfo udid],
+ time(NULL),
[DeviceInfo metrics]];
[queue_ addObject:data];
[self tick];
@@ -194,14 +232,22 @@ - (void)beginSession
- (void)updateSessionWithDuration:(int)duration
{
- NSString *data = [NSString stringWithFormat:@"app_key=%@&device_id=%@&session_duration=%d", appKey, [DeviceInfo udid], duration];
+ NSString *data = [NSString stringWithFormat:@"app_key=%@&device_id=%@&timestamp=%ld&session_duration=%d",
+ appKey,
+ [DeviceInfo udid],
+ time(NULL),
+ duration];
[queue_ addObject:data];
[self tick];
}
- (void)endSessionWithDuration:(int)duration
{
- NSString *data = [NSString stringWithFormat:@"app_key=%@&device_id=%@&end_session=1&session_duration=%d", appKey, [DeviceInfo udid], duration];
+ NSString *data = [NSString stringWithFormat:@"app_key=%@&device_id=%@&timestamp=%ld&end_session=1&session_duration=%d",
+ appKey,
+ [DeviceInfo udid],
+ time(NULL),
+ duration];
[queue_ addObject:data];
[self tick];
}
@@ -213,14 +259,14 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection
UIApplication *app = [UIApplication sharedApplication];
if (bgTask_ != UIBackgroundTaskInvalid)
{
- [app endBackgroundTask:bgTask_];
+ [app endBackgroundTask:bgTask_];
bgTask_ = UIBackgroundTaskInvalid;
}
-
+
connection_ = nil;
-
+
[queue_ removeObjectAtIndex:0];
-
+
[self tick];
}
@@ -231,19 +277,24 @@ - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)err
UIApplication *app = [UIApplication sharedApplication];
if (bgTask_ != UIBackgroundTaskInvalid)
{
- [app endBackgroundTask:bgTask_];
+ [app endBackgroundTask:bgTask_];
bgTask_ = UIBackgroundTaskInvalid;
}
-
+
connection_ = nil;
}
- (void)dealloc
{
[super dealloc];
+
if (connection_)
[connection_ cancel];
+
[queue_ release];
+
+ self.appKey = nil;
+ self.appHost = nil;
}
@end
@@ -257,7 +308,6 @@ + (Countly *)sharedInstance
if (s_sharedCountly == nil)
s_sharedCountly = [[Countly alloc] init];
-
return s_sharedCountly;
}
@@ -265,11 +315,22 @@ - (id)init
{
if (self = [super init])
{
+ timer = nil;
isSuspended = NO;
unsentSessionLength = 0;
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackgroundCallBack:) name:UIApplicationDidEnterBackgroundNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterForegroundCallBack:) name:UIApplicationWillEnterForegroundNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willTerminateCallBack:) name:UIApplicationWillTerminateNotification object:nil];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(didEnterBackgroundCallBack:)
+ name:UIApplicationDidEnterBackgroundNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(willEnterForegroundCallBack:)
+ name:UIApplicationWillEnterForegroundNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(willTerminateCallBack:)
+ name:UIApplicationWillTerminateNotification
+ object:nil];
}
return self;
}
@@ -296,7 +357,7 @@ - (void)onTimer:(NSTimer *)timer
double currTime = CFAbsoluteTimeGetCurrent();
unsentSessionLength += currTime - lastTime;
lastTime = currTime;
-
+
int duration = unsentSessionLength;
[[ConnectionQueue sharedInstance] updateSessionWithDuration:duration];
unsentSessionLength -= duration;
@@ -305,7 +366,7 @@ - (void)onTimer:(NSTimer *)timer
- (void)suspend
{
isSuspended = YES;
-
+
double currTime = CFAbsoluteTimeGetCurrent();
unsentSessionLength += currTime - lastTime;
@@ -323,6 +384,11 @@ - (void)resume
isSuspended = NO;
}
+- (BOOL)isSuspended
+{
+ return isSuspended;
+}
+
- (void)exit
{
}
@@ -333,6 +399,12 @@ - (void)dealloc
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillTerminateNotification object:nil];
+ if (timer)
+ {
+ [timer invalidate];
+ timer = nil;
+ }
+
[super dealloc];
}
@@ -355,4 +427,4 @@ - (void)willTerminateCallBack:(NSNotification *)notification
[self exit];
}
-@end
+@end
View
14 sdk/Countly_OpenUDID.h
@@ -15,7 +15,7 @@
IF YOU ARE GOING TO INTEGRATE OpenUDID INSIDE A (STATIC) LIBRARY,
PLEASE MAKE SURE YOU REFACTOR THE OpenUDID CLASS WITH A PREFIX OF YOUR OWN,
E.G. ACME_OpenUDID. THIS WILL AVOID CONFUSION BY DEVELOPERS WHO ARE ALSO
- USING OpenUDID IN THEIR OWN CODE.
+ USING OpenUDID IN THEIR OWN CODE.
!!! IMPORTANT !!!
@@ -23,23 +23,23 @@
/*
http://en.wikipedia.org/wiki/Zlib_License
-
+
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
-
+
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
-
+
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
-
+
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
-
+
3. This notice may not be removed or altered from any source
distribution.
*/
@@ -62,4 +62,4 @@
+ (NSString*) valueWithError:(NSError**)error;
+ (void) setOptOut:(BOOL)optOutValue;
-@end
+@end
View
105 sdk/Countly_OpenUDID.m
@@ -15,31 +15,31 @@
/*
http://en.wikipedia.org/wiki/Zlib_License
-
+
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
-
+
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
-
+
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
-
+
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
-
+
3. This notice may not be removed or altered from any source
distribution.
*/
#if __has_feature(objc_arc)
-#error This file uses the classic non-ARC retain/release model; hints below...
+#error This file uses the classic non-ARC retain/release model; hints below...
// to selectively compile this file as non-ARC, do as follows:
- // https://img.skitch.com/20120411-bcku69k1uw528cwh9frh5px8ya.png
+ // https://img.skitch.com/20120717-g3ag5h9a6ehkgpmpjiuen3qpwp.png
#endif
#import "Countly_OpenUDID.h"
@@ -77,7 +77,7 @@ @implementation Countly_OpenUDID
// Convenience method to support iOS & Mac OS X
//
+ (void) _setDict:(id)dict forPasteboard:(id)pboard {
-#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
+#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
[pboard setData:[NSKeyedArchiver archivedDataWithRootObject:dict] forPasteboardType:kOpenUDIDDomain];
#else
[pboard setData:[NSKeyedArchiver archivedDataWithRootObject:dict] forType:kOpenUDIDDomain];
@@ -88,11 +88,11 @@ + (void) _setDict:(id)dict forPasteboard:(id)pboard {
// Convenience method to support iOS & Mac OS X
//
+ (NSMutableDictionary*) _getDictFromPasteboard:(id)pboard {
-#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
+#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
id item = [pboard dataForPasteboardType:kOpenUDIDDomain];
#else
- id item = [pboard dataForType:kOpenUDIDDomain];
-#endif
+ id item = [pboard dataForType:kOpenUDIDDomain];
+#endif
if (item) {
@try{
item = [NSKeyedUnarchiver unarchiveObjectWithData:item];
@@ -101,8 +101,8 @@ + (NSMutableDictionary*) _getDictFromPasteboard:(id)pboard {
item = nil;
}
}
-
- // return an instance of a MutableDictionary
+
+ // return an instance of a MutableDictionary
return [NSMutableDictionary dictionaryWithDictionary:(item == nil || [item isKindOfClass:[NSDictionary class]]) ? item : nil];
}
@@ -111,39 +111,48 @@ + (NSMutableDictionary*) _getDictFromPasteboard:(id)pboard {
// After that, the caching/pasteboard/redundancy mechanism inside [OpenUDID value] returns a persistent and cross application OpenUDID
//
+ (NSString*) _generateFreshOpenUDID {
-
+
NSString* _openUDID = nil;
-
+
// August 2011: One day, this may no longer be allowed in iOS. When that is, just comment this line out.
- // March 25th 2012: this day has come, let's remove this "outlawed" call...
-#if TARGET_OS_IPHONE
+ // March 25th 2012: this day has come, let's remove this "outlawed" call...
+#if TARGET_OS_IPHONE
// if([UIDevice instancesRespondToSelector:@selector(uniqueIdentifier)]){
// _openUDID = [[UIDevice currentDevice] uniqueIdentifier];
// }
#endif
- // Next we try to use an alternative method which uses the host name, process ID, and a time stamp
- // We then hash it with md5 to get 32 bytes, and then add 4 extra random bytes
- // Collision is possible of course, but unlikely and suitable for most industry needs (e.g.. aggregate tracking)
+ // Next we generate a UUID.
+ // UUIDs (Universally Unique Identifiers), also known as GUIDs (Globally Unique Identifiers) or IIDs
+ // (Interface Identifiers), are 128-bit values guaranteed to be unique. A UUID is made unique over
+ // both space and time by combining a value unique to the computer on which it was generated—usually the
+ // Ethernet hardware address—and a value representing the number of 100-nanosecond intervals since
+ // October 15, 1582 at 00:00:00.
+ // We then hash this UUID with md5 to get 32 bytes, and then add 4 extra random bytes
+ // Collision is possible of course, but unlikely and suitable for most industry needs (e.g. aggregate tracking)
//
if (_openUDID==nil) {
+ CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
+ CFStringRef cfstring = CFUUIDCreateString(kCFAllocatorDefault, uuid);
+ const char *cStr = CFStringGetCStringPtr(cfstring,CFStringGetFastestEncoding(cfstring));
unsigned char result[16];
- const char *cStr = [[[NSProcessInfo processInfo] globallyUniqueString] UTF8String];
CC_MD5( cStr, strlen(cStr), result );
+ CFRelease(uuid);
+
_openUDID = [NSString stringWithFormat:
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%08x",
- result[0], result[1], result[2], result[3],
+ result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15],
- arc4random() % 4294967295];
+ (NSUInteger)(arc4random() % NSUIntegerMax)];
}
-
+
// Call to other developers in the Open Source community:
//
// feel free to suggest better or alternative "UDID" generation code above.
// NOTE that the goal is NOT to find a better hash method, but rather, find a decentralized (i.e. not web-based)
// 160 bits / 20 bytes random string generator with the fewest possible collisions.
- //
+ //
return _openUDID;
}
@@ -167,9 +176,9 @@ + (NSString*) valueWithError:(NSError **)error {
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"OpenUDID in cache from first call",@"description", nil]];
return kOpenUDIDSessionCache;
}
-
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
-
+
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+
// The AppUID will uniquely identify this app within the pastebins
//
NSString * appUID = (NSString *) [defaults objectForKey:kOpenUDIDAppUIDKey];
@@ -180,14 +189,14 @@ + (NSString*) valueWithError:(NSError **)error {
appUID = (NSString *) CFUUIDCreateString(NULL, uuid);
CFRelease(uuid);
}
-
+
NSString* openUDID = nil;
NSString* myRedundancySlotPBid = nil;
NSDate* optedOutDate = nil;
BOOL optedOut = NO;
BOOL saveLocalDictToDefaults = NO;
BOOL isCompromised = NO;
-
+
// Do we have a local copy of the OpenUDID dictionary?
// This local copy contains a copy of the openUDID, myRedundancySlotPBid (and unused in this block, the local bundleid, and the timestamp)
//
@@ -200,7 +209,7 @@ + (NSString*) valueWithError:(NSError **)error {
optedOut = optedOutDate!=nil;
OpenUDIDLog(@"localDict = %@",localDict);
}
-
+
// Here we go through a sequence of slots, each of which being a UIPasteboard created by each participating app
// The idea behind this is to both multiple and redundant representations of OpenUDIDs, as well as serve as placeholder for potential opt-out
//
@@ -237,22 +246,22 @@ + (NSString*) valueWithError:(NSError **)error {
// the local dictionary is prime on the opt-out subject, so ignore if already opted-out locally
if (optedOut) {
optedOutDate = [dict objectForKey:kOpenUDIDOOTSKey];
- optedOut = optedOutDate!=nil;
+ optedOut = optedOutDate!=nil;
}
}
}
}
-
+
// sort the Frequency dict with highest occurence count of the same OpenUDID (redundancy, failsafe)
// highest is last in the list
//
NSArray* arrayOfUDIDs = [frequencyDict keysSortedByValueUsingSelector:@selector(compare:)];
NSString* mostReliableOpenUDID = (arrayOfUDIDs!=nil && [arrayOfUDIDs count]>0)? [arrayOfUDIDs lastObject] : nil;
OpenUDIDLog(@"Freq Dict = %@\nMost reliable %@",frequencyDict,mostReliableOpenUDID);
-
+
// if openUDID was not retrieved from the local preferences, then let's try to get it from the frequency dictionary above
//
- if (openUDID==nil) {
+ if (openUDID==nil) {
if (mostReliableOpenUDID==nil) {
// this is the case where this app instance is likely to be the first one to use OpenUDID on this device
// we create the OpenUDID, legacy or semi-random (i.e. most certainly unique)
@@ -260,12 +269,12 @@ + (NSString*) valueWithError:(NSError **)error {
openUDID = [Countly_OpenUDID _generateFreshOpenUDID];
} else {
// or we leverage the OpenUDID shared by other apps that have already gone through the process
- //
+ //
openUDID = mostReliableOpenUDID;
}
// then we create a local representation
//
- if (localDict==nil) {
+ if (localDict==nil) {
localDict = [NSMutableDictionary dictionaryWithCapacity:4];
[localDict setObject:openUDID forKey:kOpenUDIDKey];
[localDict setObject:appUID forKey:kOpenUDIDAppUIDKey];
@@ -280,7 +289,7 @@ + (NSString*) valueWithError:(NSError **)error {
if (mostReliableOpenUDID!=nil && ![mostReliableOpenUDID isEqualToString:openUDID])
isCompromised = YES;
}
-
+
// Here we store in the available PB slot, if applicable
//
OpenUDIDLog(@"Available Slot %@ Existing Slot %@",availableSlotPBid,myRedundancySlotPBid);
@@ -291,14 +300,14 @@ + (NSString*) valueWithError:(NSError **)error {
#else
NSPasteboard* slotPB = [NSPasteboard pasteboardWithName:availableSlotPBid];
#endif
-
+
// save slotPBid to the defaults, and remember to save later
//
if (localDict) {
[localDict setObject:availableSlotPBid forKey:kOpenUDIDSlotKey];
saveLocalDictToDefaults = YES;
}
-
+
// Save the local dictionary to the corresponding UIPasteboard slot
//
if (openUDID && localDict)
@@ -319,7 +328,7 @@ + (NSString*) valueWithError:(NSError **)error {
if (error!=nil) *error = [NSError errorWithDomain:kOpenUDIDDomain
code:kOpenUDIDErrorOptedOut
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Application with unique id %@ is opted-out from OpenUDID as of %@",appUID,optedOutDate],@"description", nil]];
-
+
kOpenUDIDSessionCache = [[NSString stringWithFormat:@"%040x",0] retain];
return kOpenUDIDSessionCache;
}
@@ -344,7 +353,7 @@ + (void) setOptOut:(BOOL)optOutValue {
// init call
[Countly_OpenUDID value];
-
+
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// load the dictionary from local cache or create one
@@ -361,14 +370,14 @@ + (void) setOptOut:(BOOL)optOutValue {
else
[dict removeObjectForKey:kOpenUDIDOOTSKey];
- // store the dictionary locally
+ // store the dictionary locally
[defaults setObject:dict forKey:kOpenUDIDKey];
-
+
OpenUDIDLog(@"Local dict after opt-out = %@",dict);
-
- // reset memory cache
+
+ // reset memory cache
kOpenUDIDSessionCache = nil;
-
+
}
-@end
+@end
View
4 titanium.xcconfig
@@ -4,10 +4,10 @@
// OF YOUR TITANIUM SDK YOU'RE BUILDING FOR
//
//
-TITANIUM_SDK_VERSION = 2.1.0.v20120607000247
+TITANIUM_SDK_VERSION = 2.1.1.GA
-//
+//
// THESE SHOULD BE OK GENERALLY AS-IS
//
TITANIUM_SDK = /Library/Application Support/Titanium/mobilesdk/osx/$(TITANIUM_SDK_VERSION)
Please sign in to comment.
Something went wrong with that request. Please try again.