diff options
author | Brad Leege <bleege@gmail.com> | 2015-03-20 16:01:52 -0500 |
---|---|---|
committer | Brad Leege <bleege@gmail.com> | 2015-03-20 16:01:52 -0500 |
commit | ec304d37ac0fd03f3cf96ab9a5466b6a8f689674 (patch) | |
tree | 49416410efbf8a6e5e565c822a55fd7552dc1736 | |
parent | 253643f57d055a7e90ddea17374d706ef2c18ed4 (diff) | |
download | qtlocation-mapboxgl-ec304d37ac0fd03f3cf96ab9a5466b6a8f689674.tar.gz |
#1033 - Integrating MapboxEvents class.
-rw-r--r-- | gyp/platform-ios.gypi | 6 | ||||
-rw-r--r-- | include/mbgl/ios/MGLMapboxEvents.h | 24 | ||||
-rw-r--r-- | platform/ios/MGLMapboxEvents.m | 250 |
3 files changed, 278 insertions, 2 deletions
diff --git a/gyp/platform-ios.gypi b/gyp/platform-ios.gypi index 43c51d61b9..738a4afa5e 100644 --- a/gyp/platform-ios.gypi +++ b/gyp/platform-ios.gypi @@ -16,10 +16,12 @@ '../platform/darwin/asset_root.mm', '../platform/darwin/image.mm', '../platform/darwin/reachability.m', - '../include/mbgl/ios/MGLMetricsLocationManager.h', - '../platform/ios/MGLMetricsLocationManager.m', + '../include/mbgl/ios/MGLMapboxEvents.h', + '../platform/ios/MGLMapboxEvents.m', '../include/mbgl/ios/MGLMapView.h', '../platform/ios/MGLMapView.mm', + '../include/mbgl/ios/MGLMetricsLocationManager.h', + '../platform/ios/MGLMetricsLocationManager.m', '../include/mbgl/ios/MGLStyleFunctionValue.h', '../platform/ios/MGLStyleFunctionValue.m', '../include/mbgl/ios/MGLTypes.h', diff --git a/include/mbgl/ios/MGLMapboxEvents.h b/include/mbgl/ios/MGLMapboxEvents.h new file mode 100644 index 0000000000..c0cff7c2b7 --- /dev/null +++ b/include/mbgl/ios/MGLMapboxEvents.h @@ -0,0 +1,24 @@ +// +// MapboxEvents.h +// MapboxEvents +// +// Created by Brad Leege on 3/5/15. +// Copyright (c) 2015 Mapbox. All rights reserved. +// + +#import <Foundation/Foundation.h> + +@interface MGLMapboxEvents : NSObject + +@property (atomic) NSInteger flushAt; +@property (atomic) NSInteger flushAfter; +@property (atomic) NSString *api; +@property (atomic) NSString *token; +@property (atomic) NSString *appName; +@property (atomic) NSString *appVersion; + ++ (id)sharedManager; + +- (void) pushEvent:(NSString *)event withAttributes:(NSDictionary *)attributeDictionary; + +@end
\ No newline at end of file diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m new file mode 100644 index 0000000000..cd6ecbd0ab --- /dev/null +++ b/platform/ios/MGLMapboxEvents.m @@ -0,0 +1,250 @@ +// +// MapboxEvents.m +// MapboxEvents +// +// Dynamic detection of ASIdentifierManager from Mixpanel +// https://github.com/mixpanel/mixpanel-iphone/blob/master/LICENSE +// +// Created by Brad Leege on 3/5/15. +// Copyright (c) 2015 Mapbox. All rights reserved. +// + +#import "MGLMapboxEvents.h" +#import <UIKit/UIKit.h> +#import <CoreTelephony/CTTelephonyNetworkInfo.h> +#import <CoreTelephony/CTCarrier.h> +#include <sys/sysctl.h> + +@interface MGLMapboxEvents() + +@property (atomic) NSMutableArray *queue; +@property (atomic) NSString *instance; +@property (atomic) NSString *anonid; +@property (atomic) NSTimer *timer; +@property (atomic) NSString *userAgent; + +@end + +@implementation MGLMapboxEvents + +static MGLMapboxEvents *sharedManager = nil; + +NSString *anonId = nil; +NSDateFormatter *rfc3339DateFormatter = nil; +NSString *model; +NSString *iOSVersion; +NSString *carrier; +NSNumber *scale; + +- (id) init { + self = [super init]; + if (self) { + _queue = [[NSMutableArray alloc] init]; + _flushAt = 20; + _flushAfter = 10000; + _api = @"https://api.tiles.mapbox.com"; + _token = nil; + _instance = [[NSUUID UUID] UUIDString]; + Class ASIdentifierManagerClass = NSClassFromString(@"ASIdentifierManager"); + if (ASIdentifierManagerClass) { + SEL sharedManagerSelector = NSSelectorFromString(@"sharedManager"); + id sharedManager = ((id (*)(id, SEL))[ASIdentifierManagerClass methodForSelector:sharedManagerSelector])(ASIdentifierManagerClass, sharedManagerSelector); + // Add check here + SEL isAdvertisingTrackingEnabledSelector = NSSelectorFromString(@"isAdvertisingTrackingEnabled"); + BOOL trackingEnabled = ((BOOL (*)(id, SEL))[sharedManager methodForSelector:isAdvertisingTrackingEnabledSelector])(sharedManager, isAdvertisingTrackingEnabledSelector); + if (trackingEnabled) { + SEL advertisingIdentifierSelector = NSSelectorFromString(@"advertisingIdentifier"); + NSUUID *uuid = ((NSUUID* (*)(id, SEL))[sharedManager methodForSelector:advertisingIdentifierSelector])(sharedManager, advertisingIdentifierSelector); + _anonid = [uuid UUIDString]; + } else { + _anonid = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + } + } else { + _anonid = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + } + + + // Get Vendor ID + anonId = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + model = [self getSysInfoByName:"hw.machine"]; + iOSVersion = [NSString stringWithFormat:@"%@ %@", [UIDevice currentDevice].systemName, [UIDevice currentDevice].systemVersion]; + if ([UIScreen instancesRespondToSelector:@selector(nativeScale)]) { + scale = [[NSNumber alloc] initWithFloat:[UIScreen mainScreen].nativeScale]; + } else { + scale = [[NSNumber alloc] initWithFloat:[UIScreen mainScreen].scale]; + } + CTCarrier *carrierVendor = [[[CTTelephonyNetworkInfo alloc] init] subscriberCellularProvider]; + carrier = [carrierVendor carrierName]; + + _userAgent = @"MapboxEventsiOS/1.0"; + + // Setup Date Format + rfc3339DateFormatter = [[NSDateFormatter alloc] init]; + NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + + [rfc3339DateFormatter setLocale:enUSPOSIXLocale]; + [rfc3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"]; + [rfc3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; + } + return self; +} + ++ (id)sharedManager { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedManager = [[self alloc] init]; + }); + return sharedManager; +} + +- (void) pushEvent:(NSString *)event withAttributes:(NSDictionary *)attributeDictionary { + + if (!event) { + return; + } + + NSMutableDictionary *evt = [[NSMutableDictionary alloc] init]; + // mapbox-events stock attributes + [evt setObject:event forKey:@"event"]; + [evt setObject:[NSNumber numberWithInt:1] forKey:@"version"]; + [evt setObject:[self formatDate:[NSDate date]] forKey:@"created"]; + [evt setObject:self.instance forKey:@"instance"]; + [evt setObject:self.anonid forKey:@"anonid"]; + + // mapbox-events-ios stock attributes + [evt setValue:[rfc3339DateFormatter stringFromDate:[NSDate date]] forKey:@"deviceTimestamp"]; + [evt setValue:model forKey:@"model"]; + [evt setValue:iOSVersion forKey:@"operatingSystem"]; + [evt setValue:[self getDeviceOrientation] forKey:@"orientation"]; + [evt setValue:[[NSNumber alloc] initWithFloat:(100 * [UIDevice currentDevice].batteryLevel)] forKey:@"batteryLevel"]; + [evt setValue:scale forKey:@"resolution"]; + [evt setValue:carrier forKey:@"carrier"]; + + for (NSString *key in [attributeDictionary allKeys]) { + [evt setObject:[attributeDictionary valueForKey:key] forKey:key]; + } + + // Make Immutable Version + NSDictionary *finalEvent = [NSDictionary dictionaryWithDictionary:evt]; + + // Put On The Queue + [self.queue addObject:finalEvent]; + + // Has Flush Limit Been Reached? + if ((int)_queue.count >= (int)_flushAt) { + [self flush]; + } + + // Reset Timer (Initial Starting of Timer after first event is pushed) + [self startTimer]; +} + +- (void) flush { + if (_token == nil) { + NSLog(@"token hasn't been set yet, so no events can be sent. return"); + return; + } + + if (_flushAt > [_queue count]) { + NSLog(@"flush() flushAt (%lu) is greater than current queue count (%lu) so just return", _flushAt, [_queue count]); + return; + } + + // Create Array of Events to push to the Server + NSRange theRange = NSMakeRange(0, (int)_flushAt); + NSArray *events = [_queue subarrayWithRange:theRange]; + + // Update Queue to remove events sent to server + [_queue removeObjectsInRange:theRange]; + + // Send Array of Events to Server + [self postEvents:events]; + +} + +- (void) postEvents:(NSArray *)events { + // Setup URL Request + NSString *url = [NSString stringWithFormat:@"%@/events/v1?access_token=%@", _api, _token]; + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]]; + [request setValue:[self getUserAgent] forHTTPHeaderField:@"User-Agent"]; + [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; + [request setHTTPMethod:@"POST"]; + + // Convert Array of Dictionaries to JSON + if ([NSJSONSerialization isValidJSONObject:events]) { + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:events options:NSJSONWritingPrettyPrinted error:nil]; + [request setHTTPBody:jsonData]; + + // Send non blocking HTTP Request to server + [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:nil]; + } +} + +- (void) startTimer { + // Stop Timer if it already exists + if (_timer) { + [_timer invalidate]; + _timer = nil; + } + + // Start New Timer + NSTimeInterval interval = (double)((NSInteger)_flushAfter); + _timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(flush) userInfo:nil repeats:YES]; +} + +- (NSString *) getUserAgent { + + if (_appName != nil && _appVersion != nil && ([_userAgent rangeOfString:_appName].location == NSNotFound)) { + _userAgent = [NSString stringWithFormat:@"%@/%@ %@", _appName, _appVersion, _userAgent]; + } + return _userAgent; +} + +- (NSString *) formatDate:(NSDate *)date { + return [rfc3339DateFormatter stringFromDate:date]; +} + +- (NSString *) getDeviceOrientation { + switch ([UIDevice currentDevice].orientation) { + case UIDeviceOrientationUnknown: + return @"Unknown"; + break; + case UIDeviceOrientationPortrait: + return @"Portrait"; + break; + case UIDeviceOrientationPortraitUpsideDown: + return @"PortraitUpsideDown"; + break; + case UIDeviceOrientationLandscapeLeft: + return @"LandscapeLeft"; + break; + case UIDeviceOrientationLandscapeRight: + return @"LandscapeRight"; + break; + case UIDeviceOrientationFaceUp: + return @"FaceUp"; + break; + case UIDeviceOrientationFaceDown: + return @"FaceDown"; + break; + default: + return @"Default - Unknown"; + break; + } +} + +- (NSString *)getSysInfoByName:(char *)typeSpecifier +{ + size_t size; + sysctlbyname(typeSpecifier, NULL, &size, NULL, 0); + + char *answer = malloc(size); + sysctlbyname(typeSpecifier, answer, &size, NULL, 0); + + NSString *results = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding]; + + free(answer); + return results; +} + +@end
\ No newline at end of file |