summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorboundsj <jesse@rebounds.net>2016-03-01 17:00:44 -0800
committerJesse Bounds <jesse@rebounds.net>2016-03-03 17:45:10 -0800
commitd10d3eef432ff5a3b161e87e7653bb902b86a32d (patch)
treef140047b56956af9c9c66be7a3d90ae56bac80d6 /platform
parentc6d84f0d71f7f6244ce88c33b35d19e780ee144a (diff)
downloadqtlocation-mapboxgl-d10d3eef432ff5a3b161e87e7653bb902b86a32d.tar.gz
[iOS] #4148 Update event serialization to the V2 specification.
This updates the endpoint for events to "v2" and updates appUserTurnstile, map.load, map.click, map.dragend, and location to the V2 spec.
Diffstat (limited to 'platform')
-rw-r--r--platform/ios/src/MGLAPIClient.m39
-rw-r--r--platform/ios/src/MGLMapView.mm16
-rw-r--r--platform/ios/src/MGLMapboxEvents.h16
-rw-r--r--platform/ios/src/MGLMapboxEvents.m312
4 files changed, 228 insertions, 155 deletions
diff --git a/platform/ios/src/MGLAPIClient.m b/platform/ios/src/MGLAPIClient.m
index b4f85b5631..58f1c70bb9 100644
--- a/platform/ios/src/MGLAPIClient.m
+++ b/platform/ios/src/MGLAPIClient.m
@@ -2,8 +2,10 @@
#import "NSBundle+MGLAdditions.h"
#import "MGLAccountManager.h"
-static NSString * const MGLAPIClientUserAgent = @"MapboxEventsiOS/1.1";
-static NSString * const MGLAPIClientBaseURL = @"https://api.tiles.mapbox.com";
+static NSString * const MGLAPIClientUserAgentBase = @"MapboxEventsiOS";
+static NSString * const MGLAPIClientBaseURL = @"https://api.mapbox.com";
+static NSString * const MGLAPIClientEventsPath = @"events/v2";
+static NSString * const MGLAPIClientDomain = @"com.mapbox.mglnative";
static NSString * const MGLAPIClientHeaderFieldUserAgentKey = @"User-Agent";
static NSString * const MGLAPIClientHeaderFieldContentTypeKey = @"Content-Type";
@@ -41,13 +43,24 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
#pragma mark Public API
- (void)postEvents:(nonnull NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler {
- NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self requestForEvents:events]
- completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
- [self.dataTasks removeObject:dataTask];
- if (completionHandler) {
- completionHandler(error);
- }
- }];
+ __block NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self requestForEvents:events]
+ completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
+ NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
+ NSError *statusError = nil;
+ if (httpResponse.statusCode >= 400) {
+ NSString *description = [NSString stringWithFormat:@"The session data task failed. Original request was: %@", dataTask.originalRequest];
+ NSString *reason = [NSString stringWithFormat:@"The status code was %@", @(httpResponse.statusCode)];
+ NSDictionary *userInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(description, nil),
+ NSLocalizedFailureReasonErrorKey: NSLocalizedString(reason, nil)};
+ statusError = [[NSError alloc] initWithDomain:MGLAPIClientDomain code:1 userInfo:userInfo];
+ }
+ if (completionHandler) {
+ error = error ? error : statusError;
+ completionHandler(error);
+ }
+ [self.dataTasks removeObject:dataTask];
+ dataTask = nil;
+ }];
[dataTask resume];
[self.dataTasks addObject:dataTask];
}
@@ -64,7 +77,7 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
#pragma mark Utilities
- (NSURLRequest *)requestForEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events {
- NSString *url = [NSString stringWithFormat:@"%@/events/v1?access_token=%@", self.baseURL, [MGLAccountManager accessToken]];
+ NSString *url = [NSString stringWithFormat:@"%@/%@?access_token=%@", self.baseURL, MGLAPIClientEventsPath, [MGLAccountManager accessToken]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[request setValue:self.userAgent forHTTPHeaderField:MGLAPIClientHeaderFieldUserAgentKey];
[request setValue:MGLAPIClientHeaderFieldContentTypeValue forHTTPHeaderField:MGLAPIClientHeaderFieldContentTypeKey];
@@ -106,7 +119,10 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSString *appBuildNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
- _userAgent = [NSString stringWithFormat:@"%@/%@/%@ %@", appName, appVersion, appBuildNumber, MGLAPIClientUserAgent];
+ NSString *semanticVersion = [NSBundle mgl_frameworkBundle].infoDictionary[@"MGLSemanticVersionString"];
+ NSString *shortVersion = [NSBundle mgl_frameworkBundle].infoDictionary[@"CFBundleShortVersionString"];
+ NSString *sdkVersion = semanticVersion ? semanticVersion : shortVersion;
+ _userAgent = [NSString stringWithFormat:@"%@/%@/%@ %@/%@", appName, appVersion, appBuildNumber, MGLAPIClientUserAgentBase, sdkVersion];
}
#pragma mark - JSON Serialization
@@ -118,7 +134,6 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
#pragma mark NSURLSessionDelegate
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^) (NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
-
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index ccf8a7bc3d..158228ca2f 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -450,16 +450,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
_pendingLongitude = NAN;
_targetCoordinate = kCLLocationCoordinate2DInvalid;
- // metrics: map load event
- mbgl::LatLng latLng = _mbglMap->getLatLng(padding);
- int zoom = round(_mbglMap->getZoom());
-
- [MGLMapboxEvents pushEvent:MGLEventTypeMapLoad withAttributes:@{
- MGLEventKeyLatitude: @(latLng.latitude),
- MGLEventKeyLongitude: @(latLng.longitude),
- MGLEventKeyZoomLevel: @(zoom),
- MGLEventKeyPushEnabled: @([MGLMapboxEvents checkPushEnabled])
- }];
+ [MGLMapboxEvents pushEvent:MGLEventTypeMapLoad withAttributes:@{}];
}
- (void)createGLView
@@ -1321,12 +1312,9 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
_mbglMap->cancelTransitions();
- if (doubleTap.state == UIGestureRecognizerStateBegan)
+ if (doubleTap.state == UIGestureRecognizerStateEnded)
{
[self trackGestureEvent:MGLEventGestureDoubleTap forRecognizer:doubleTap];
- }
- else if (doubleTap.state == UIGestureRecognizerStateEnded)
- {
CGPoint gesturePoint = [doubleTap locationInView:doubleTap.view];
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
diff --git a/platform/ios/src/MGLMapboxEvents.h b/platform/ios/src/MGLMapboxEvents.h
index 9d90bd967e..98f59ffd3f 100644
--- a/platform/ios/src/MGLMapboxEvents.h
+++ b/platform/ios/src/MGLMapboxEvents.h
@@ -4,29 +4,20 @@
NS_ASSUME_NONNULL_BEGIN
+// Event types
extern NSString *const MGLEventTypeAppUserTurnstile;
extern NSString *const MGLEventTypeMapLoad;
extern NSString *const MGLEventTypeMapTap;
extern NSString *const MGLEventTypeMapDragEnd;
extern NSString *const MGLEventTypeLocation;
-extern NSString *const MGLEventTypeVisit;
-extern NSString *const MGLEventTypeLocalDebug;
+// Event keys
extern NSString *const MGLEventKeyLatitude;
extern NSString *const MGLEventKeyLongitude;
extern NSString *const MGLEventKeyZoomLevel;
-extern NSString *const MGLEventKeySpeed;
-extern NSString *const MGLEventKeyCourse;
-extern NSString *const MGLEventKeyAltitude;
-extern NSString *const MGLEventKeyHorizontalAccuracy;
-extern NSString *const MGLEventKeyVerticalAccuracy;
-extern NSString *const MGLEventKeyPushEnabled;
-extern NSString *const MGLEventKeyEmailEnabled;
extern NSString *const MGLEventKeyGestureID;
-extern NSString *const MGLEventKeyArrivalDate;
-extern NSString *const MGLEventKeyDepartureDate;
-extern NSString *const MGLEventKeyLocalDebugDescription;
+// Gestures
extern NSString *const MGLEventGestureSingleTap;
extern NSString *const MGLEventGestureDoubleTap;
extern NSString *const MGLEventGestureTwoFingerSingleTap;
@@ -48,7 +39,6 @@ typedef NS_MUTABLE_DICTIONARY_OF(NSString *, id) MGLMutableMapboxEventAttributes
+ (void)pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary;
+ (void)ensureMetricsOptoutExists;
+ (void)flush;
-+ (BOOL)checkPushEnabled;
@end
diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m
index 9097c5b10a..35f6327fc5 100644
--- a/platform/ios/src/MGLMapboxEvents.m
+++ b/platform/ios/src/MGLMapboxEvents.m
@@ -11,31 +11,15 @@
#include <mbgl/platform/darwin/reachability.h>
#include <sys/sysctl.h>
-static const NSUInteger version = 1;
-
+// Event types
NSString *const MGLEventTypeAppUserTurnstile = @"appUserTurnstile";
NSString *const MGLEventTypeMapLoad = @"map.load";
NSString *const MGLEventTypeMapTap = @"map.click";
NSString *const MGLEventTypeMapDragEnd = @"map.dragend";
NSString *const MGLEventTypeLocation = @"location";
-NSString *const MGLEventTypeVisit = @"visit";
NSString *const MGLEventTypeLocalDebug = @"debug";
-NSString *const MGLEventKeyLatitude = @"lat";
-NSString *const MGLEventKeyLongitude = @"lng";
-NSString *const MGLEventKeyZoomLevel = @"zoom";
-NSString *const MGLEventKeySpeed = @"speed";
-NSString *const MGLEventKeyCourse = @"course";
-NSString *const MGLEventKeyAltitude = @"altitude";
-NSString *const MGLEventKeyHorizontalAccuracy = @"horizontalAccuracy";
-NSString *const MGLEventKeyVerticalAccuracy = @"verticalAccuracy";
-NSString *const MGLEventKeyPushEnabled = @"enabled.push";
-NSString *const MGLEventKeyEmailEnabled = @"enabled.email";
-NSString *const MGLEventKeyGestureID = @"gesture";
-NSString *const MGLEventKeyArrivalDate = @"arrivalDate";
-NSString *const MGLEventKeyDepartureDate = @"departureDate";
-NSString *const MGLEventKeyLocalDebugDescription = @"debug.description";
-
+// Gestures
NSString *const MGLEventGestureSingleTap = @"SingleTap";
NSString *const MGLEventGestureDoubleTap = @"DoubleTap";
NSString *const MGLEventGestureTwoFingerSingleTap = @"TwoFingerTap";
@@ -45,15 +29,49 @@ NSString *const MGLEventGesturePinchStart = @"Pinch";
NSString *const MGLEventGestureRotateStart = @"Rotation";
NSString *const MGLEventGesturePitchStart = @"Pitch";
-const NSUInteger MGLMaximumEventsPerFlush = 20;
-const NSTimeInterval MGLFlushInterval = 60;
+// Event keys
+NSString *const MGLEventKeyLatitude = @"lat";
+NSString *const MGLEventKeyLongitude = @"lng";
+NSString *const MGLEventKeyZoomLevel = @"zoom";
+NSString *const MGLEventKeySpeed = @"speed";
+NSString *const MGLEventKeyCourse = @"course";
+NSString *const MGLEventKeyGestureID = @"gesture";
+NSString *const MGLEventKeyLocalDebugDescription = @"debug.description";
+
+static NSString *const MGLEventKeyEvent = @"event";
+static NSString *const MGLEventKeyCreated = @"created";
+static NSString *const MGLEventKeyVendorID = @"userId";
+static NSString *const MGLEventKeyModel = @"model";
+static NSString *const MGLEventKeyEnabledTelemetry = @"enabled.telemetry";
+static NSString *const MGLEventKeyOperatingSystem = @"operatingSystem";
+static NSString *const MGLEventKeyResolution = @"resolution";
+static NSString *const MGLEventKeyAccessibilityFontScale = @"accessibilityFontScale";
+static NSString *const MGLEventKeyOrientation = @"orientation";
+static NSString *const MGLEventKeyBatteryLevel = @"batteryLevel";
+static NSString *const MGLEventKeyPluggedIn = @"pluggedIn";
+static NSString *const MGLEventKeyWifi = @"wifi";
+static NSString *const MGLEventKeySource = @"source";
+static NSString *const MGLEventKeySessionId = @"sessionId";
+static NSString *const MGLEventKeyApplicationState = @"applicationState";
+static NSString *const MGLEventKeyAltitude = @"altitude";
+
+// SDK event source
+static NSString *const MGLEventSource = @"mapbox";
+
+// Event application state
+static NSString *const MGLApplicationStateForeground = @"Foreground";
+static NSString *const MGLApplicationStateBackground = @"Background";
+static NSString *const MGLApplicationStateInactive = @"Inactive";
+static NSString *const MGLApplicationStateUnknown = @"Unknown";
+
+const NSUInteger MGLMaximumEventsPerFlush = 180;
+const NSTimeInterval MGLFlushInterval = 180;
@interface MGLMapboxEventsData : NSObject
@property (nonatomic) NSString *vendorId;
@property (nonatomic) NSString *model;
@property (nonatomic) NSString *iOSVersion;
-@property (nonatomic) NSString *carrier;
@property (nonatomic) CGFloat scale;
@end
@@ -63,7 +81,6 @@ const NSTimeInterval MGLFlushInterval = 60;
- (instancetype)init {
if (self = [super init]) {
_vendorId = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
-
_model = [self sysInfoByName:"hw.machine"];
_iOSVersion = [NSString stringWithFormat:@"%@ %@", [UIDevice currentDevice].systemName, [UIDevice currentDevice].systemVersion];
if ([UIScreen instancesRespondToSelector:@selector(nativeScale)]) {
@@ -94,7 +111,7 @@ const NSTimeInterval MGLFlushInterval = 60;
@property (nonatomic) MGLMapboxEventsData *data;
@property (nonatomic, copy) NSString *appBundleId;
-@property (nonatomic, copy) NSString *instanceID;
+@property (nonatomic, readonly) NSString *instanceID;
@property (nonatomic, copy) NSString *dateForDebugLogFile;
@property (nonatomic) NSDateFormatter *rfc3339DateFormatter;
@property (nonatomic) MGLAPIClient *apiClient;
@@ -106,11 +123,13 @@ const NSTimeInterval MGLFlushInterval = 60;
@property (nonatomic) dispatch_queue_t debugLogSerialQueue;
@property (nonatomic) MGLLocationManager *locationManager;
@property (nonatomic) NSTimer *timer;
+@property (nonatomic) NSDate *lastInstanceIDRotationDate;
@end
@implementation MGLMapboxEvents {
id _userDefaultsObserver;
+ NSString *_instanceID;
}
+ (void)initialize {
@@ -139,7 +158,6 @@ const NSTimeInterval MGLFlushInterval = 60;
self = [super init];
if (self) {
_appBundleId = [[NSBundle mainBundle] bundleIdentifier];
- _instanceID = [[NSUUID UUID] UUIDString];
_apiClient = [[MGLAPIClient alloc] init];
NSString *uniqueID = [[NSProcessInfo processInfo] globallyUniqueString];
@@ -216,6 +234,18 @@ const NSTimeInterval MGLFlushInterval = 60;
[self pauseMetricsCollection];
}
+- (NSString *)instanceID {
+ if (self.lastInstanceIDRotationDate && [[NSDate date] timeIntervalSinceDate:self.lastInstanceIDRotationDate] >= 0) {
+ _instanceID = nil;
+ }
+ if (!_instanceID) {
+ _instanceID = [[NSUUID UUID] UUIDString];
+ NSTimeInterval twentyFourHourTimeInterval = 24 * 3600;
+ self.lastInstanceIDRotationDate = [[NSDate date] dateByAddingTimeInterval:twentyFourHourTimeInterval];
+ }
+ return _instanceID;
+}
+
- (void)pauseOrResumeMetricsCollectionIfRequired {
// Prevent blue status bar when host app has `when in use` permission only and it is not in foreground
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse &&
@@ -259,50 +289,30 @@ const NSTimeInterval MGLFlushInterval = 60;
[self.locationManager startUpdatingLocation];
}
-+ (void)pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
- [[MGLMapboxEvents sharedManager] pushEvent:event withAttributes:attributeDictionary];
++ (void)flush {
+ [[MGLMapboxEvents sharedManager] flush];
}
-- (void)pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
- if (!event) {
+- (void)flush {
+ if ([MGLAccountManager accessToken] == nil) {
return;
}
- if ([event isEqualToString:MGLEventTypeMapLoad]) {
- [self pushTurnstileEvent];
- }
-
- if ([self isPaused]) {
+ if ([self.eventQueue count] == 0) {
return;
}
- NSDictionary *stockAttributes = @{@"event": event,
- @"version": @(version),
- @"created": [self.rfc3339DateFormatter stringFromDate:[NSDate date]],
- @"instance": self.instanceID,
- @"vendorId": self.data.vendorId,
- @"appBundleId": self.appBundleId,
- @"model": self.data.model,
- @"operatingSystem": self.data.iOSVersion,
- @"resolution": @(self.data.scale),
- @"wifi": @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi]),
- @"orientation": [self deviceOrientation],
- @"batteryLevel": @([self batteryLevel]),
- @"applicationState": [self applicationState],
- @"accessibilityFontScale": @([self contentSizeScale])};
- MGLMutableMapboxEventAttributes *allEventAttributes = [NSMutableDictionary dictionaryWithDictionary:attributeDictionary];
- [allEventAttributes addEntriesFromDictionary:stockAttributes];
- MGLMapboxEventAttributes *finalEvent = [allEventAttributes copy];
- [self.eventQueue addObject:finalEvent];
- [self writeEventToLocalDebugLog:finalEvent];
+ NSArray *events = [NSArray arrayWithArray:self.eventQueue];
+ [self.eventQueue removeAllObjects];
- // Has Flush Limit Been Reached?
- if (self.eventQueue.count >= MGLMaximumEventsPerFlush) {
- [self flush];
- } else if (self.eventQueue.count == 1) {
- // If this is first new event on queue start timer,
- [self startTimer];
+ [self postEvents:events];
+
+ if (self.timer) {
+ [self.timer invalidate];
+ self.timer = nil;
}
+
+ [self pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription:@"flush"}];
}
- (void)pushTurnstileEvent {
@@ -321,20 +331,18 @@ const NSTimeInterval MGLFlushInterval = 60;
return;
}
- NSDictionary *turnstileEventAttributes = @{@"event" : MGLEventTypeAppUserTurnstile,
- @"created" : [strongSelf.rfc3339DateFormatter stringFromDate:[NSDate date]],
- @"appBundleId" : strongSelf.appBundleId,
- @"vendorId": vendorID,
- @"version": @(version),
- @"instance": strongSelf.instanceID};
-
+ NSDictionary *turnstileEventAttributes = @{MGLEventKeyEvent: MGLEventTypeAppUserTurnstile,
+ MGLEventKeyCreated: [strongSelf.rfc3339DateFormatter stringFromDate:[NSDate date]],
+ MGLEventKeyVendorID: vendorID,
+ MGLEventKeyEnabledTelemetry: @([[strongSelf class] isEnabled])};
+
if ([MGLAccountManager accessToken] == nil) {
return;
}
[strongSelf.apiClient postEvent:turnstileEventAttributes completionHandler:^(NSError * _Nullable error) {
if (error) {
[strongSelf pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription: @"Network error",
- @"error": error}];
+ @"error": error}];
return;
}
[strongSelf writeEventToLocalDebugLog:turnstileEventAttributes];
@@ -342,30 +350,104 @@ const NSTimeInterval MGLFlushInterval = 60;
});
}
-+ (void)flush {
- [[MGLMapboxEvents sharedManager] flush];
++ (void)pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
+ [[MGLMapboxEvents sharedManager] pushEvent:event withAttributes:attributeDictionary];
}
-- (void)flush {
- if ([MGLAccountManager accessToken] == nil) {
+- (void)pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
+ if (!event) {
return;
}
- if ([self.eventQueue count] == 0) {
- return;
+ if ([event isEqualToString:MGLEventTypeMapLoad]) {
+ [self pushTurnstileEvent];
}
- NSArray *events = [NSArray arrayWithArray:self.eventQueue];
- [self.eventQueue removeAllObjects];
-
- [self postEvents:events];
+ if ([self isPaused]) {
+ return;
+ }
- if (self.timer) {
- [self.timer invalidate];
- self.timer = nil;
+ MGLMapboxEventAttributes *fullyFormedEvent = [self fullyFormedEventForEvent:event withAttributes:attributeDictionary];
+ if (fullyFormedEvent) {
+ [self.eventQueue addObject:fullyFormedEvent];
+ [self writeEventToLocalDebugLog:fullyFormedEvent];
+ // Has Flush Limit Been Reached?
+ if (self.eventQueue.count >= MGLMaximumEventsPerFlush) {
+ [self flush];
+ } else if (self.eventQueue.count == 1) {
+ // If this is first new event on queue start timer,
+ [self startTimer];
+ }
+ } else {
+ [self pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription: @"Unknown event",
+ @"eventName": event,
+ @"event.attributes": attributeDictionary}];
}
+}
- [self pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription:@"flush"}];
+#pragma mark Events
+
+- (MGLMapboxEventAttributes *)fullyFormedEventForEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
+ if ([event isEqualToString:MGLEventTypeMapLoad]) {
+ return [self mapLoadEventWithAttributes:attributeDictionary];
+ } else if ([event isEqualToString:MGLEventTypeMapTap]) {
+ return [self mapClickEventWithAttributes:attributeDictionary];
+ } else if ([event isEqualToString:MGLEventTypeMapDragEnd]) {
+ return [self mapDragEndEventWithAttributes:attributeDictionary];
+ } else if ([event isEqualToString:MGLEventTypeLocation]) {
+ return [self locationEventWithAttributes:attributeDictionary];
+ }
+ return nil;
+}
+
+- (MGLMapboxEventAttributes *)locationEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
+ MGLMutableMapboxEventAttributes *attributes = [@{MGLEventKeyEvent: MGLEventTypeLocation,
+ MGLEventKeySource: MGLEventSource,
+ MGLEventKeySessionId: self.instanceID,
+ MGLEventKeyOperatingSystem: self.data.iOSVersion} mutableCopy];
+ [self addApplicationStateToAttributes:attributes];
+ return [self eventForAttributes:attributes attributeDictionary:attributeDictionary];
+}
+
+- (MGLMapboxEventAttributes *)mapLoadEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
+ MGLMutableMapboxEventAttributes *attributes = [@{MGLEventKeyEvent: MGLEventTypeMapLoad,
+ MGLEventKeyCreated: [self.rfc3339DateFormatter stringFromDate:[NSDate date]],
+ MGLEventKeyVendorID: self.data.vendorId,
+ MGLEventKeyModel: self.data.model,
+ MGLEventKeyOperatingSystem: self.data.iOSVersion,
+ MGLEventKeyResolution: @(self.data.scale),
+ MGLEventKeyAccessibilityFontScale: @([self contentSizeScale]),
+ MGLEventKeyOrientation: [self deviceOrientation],
+ MGLEventKeyBatteryLevel: @([self batteryLevel]),
+ MGLEventKeyWifi: @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi])} mutableCopy];
+ [self addBatteryStateToAttributes:attributes];
+ return [self eventForAttributes:attributes attributeDictionary:attributeDictionary];
+}
+
+- (MGLMapboxEventAttributes *)mapClickEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
+ MGLMutableMapboxEventAttributes *attributes = [self interactionEvent];
+ attributes[MGLEventKeyEvent] = MGLEventTypeMapTap;
+ return [self eventForAttributes:attributes attributeDictionary:attributeDictionary];
+}
+
+- (MGLMapboxEventAttributes *)mapDragEndEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
+ MGLMutableMapboxEventAttributes *attributes = [self interactionEvent];
+ attributes[MGLEventKeyEvent] = MGLEventTypeMapDragEnd;
+ return [self eventForAttributes:attributes attributeDictionary:attributeDictionary];
+}
+
+- (MGLMutableMapboxEventAttributes *)interactionEvent {
+ MGLMutableMapboxEventAttributes *attributes = [@{MGLEventKeyCreated: [self.rfc3339DateFormatter stringFromDate:[NSDate date]],
+ MGLEventKeyOrientation: [self deviceOrientation],
+ MGLEventKeyBatteryLevel: @([self batteryLevel]),
+ MGLEventKeyWifi: @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi])} mutableCopy];
+ [self addBatteryStateToAttributes:attributes];
+ return attributes;
+}
+
+- (MGLMapboxEventAttributes *)eventForAttributes:(MGLMutableMapboxEventAttributes *)attributes attributeDictionary:(MGLMapboxEventAttributes *)attributeDictionary {
+ [attributes addEntriesFromDictionary:attributeDictionary];
+ return [attributes copy];
}
// Called implicitly from public use of +flush.
@@ -400,7 +482,7 @@ const NSTimeInterval MGLFlushInterval = 60;
}
- (NSInteger)batteryLevel {
- return [[NSNumber numberWithFloat:100 * [UIDevice currentDevice].batteryLevel] integerValue];
+ return [[NSNumber numberWithFloat:roundf(100 * [UIDevice currentDevice].batteryLevel)] integerValue];
}
- (NSString *)deviceOrientation {
@@ -437,24 +519,16 @@ const NSTimeInterval MGLFlushInterval = 60;
}
- (NSString *)applicationState {
- NSString *result;
-
switch ([UIApplication sharedApplication].applicationState) {
case UIApplicationStateActive:
- result = @"Active";
- break;
+ return MGLApplicationStateForeground;
case UIApplicationStateInactive:
- result = @"Inactive";
- break;
+ return MGLApplicationStateInactive;
case UIApplicationStateBackground:
- result = @"Background";
- break;
+ return MGLApplicationStateBackground;
default:
- result = @"Default - Unknown";
- break;
+ return MGLApplicationStateUnknown;
}
-
- return result;
}
- (NSInteger)contentSizeScale {
@@ -491,20 +565,27 @@ const NSTimeInterval MGLFlushInterval = 60;
return result;
}
-+ (BOOL)checkPushEnabled {
- BOOL blockResult;
- if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
- // iOS 8+
- blockResult = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
- } else {
- // iOS 7
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
- blockResult = (types == UIRemoteNotificationTypeNone) ? NO : YES;
-#pragma clang diagnostic pop
+- (void)addBatteryStateToAttributes:(MGLMutableMapboxEventAttributes *)attributes {
+ UIDeviceBatteryState batteryState = [[UIDevice currentDevice] batteryState];
+ switch (batteryState) {
+ case UIDeviceBatteryStateCharging:
+ case UIDeviceBatteryStateFull:
+ attributes[MGLEventKeyPluggedIn] = @(YES);
+ break;
+ case UIDeviceBatteryStateUnplugged:
+ attributes[MGLEventKeyPluggedIn] = @(NO);
+ break;
+ default:
+ // do nothing
+ break;
+ }
+}
+
+- (void)addApplicationStateToAttributes:(MGLMutableMapboxEventAttributes *)attributes {
+ NSString *currentApplicationState = [self applicationState];
+ if (![currentApplicationState isEqualToString:MGLApplicationStateUnknown]) {
+ attributes[MGLEventKeyApplicationState] = currentApplicationState;
}
- return blockResult;
}
+ (void)ensureMetricsOptoutExists {
@@ -543,14 +624,14 @@ const NSTimeInterval MGLFlushInterval = 60;
- (void)locationManager:(MGLLocationManager *)locationManager didUpdateLocations:(NSArray *)locations {
for (CLLocation *loc in locations) {
- [MGLMapboxEvents pushEvent:MGLEventTypeLocation
- withAttributes:@{MGLEventKeyLatitude: @(loc.coordinate.latitude),
- MGLEventKeyLongitude: @(loc.coordinate.longitude),
- MGLEventKeySpeed: @(loc.speed),
- MGLEventKeyCourse: @(loc.course),
- MGLEventKeyAltitude: @(round(loc.altitude)),
- MGLEventKeyHorizontalAccuracy: @(round(loc.horizontalAccuracy)),
- MGLEventKeyVerticalAccuracy: @(round(loc.verticalAccuracy))}];
+ double accuracy = 10000000;
+ double lat = floor(loc.coordinate.latitude * accuracy) / accuracy;
+ double lng = floor(loc.coordinate.longitude * accuracy) / accuracy;
+ NSString *formattedDate = [self.rfc3339DateFormatter stringFromDate:loc.timestamp];
+ [MGLMapboxEvents pushEvent:MGLEventTypeLocation withAttributes:@{MGLEventKeyCreated: formattedDate,
+ MGLEventKeyLatitude: @(lat),
+ MGLEventKeyLongitude: @(lng),
+ MGLEventKeyAltitude: @(round(loc.altitude))}];
}
}
@@ -634,8 +715,7 @@ const NSTimeInterval MGLFlushInterval = 60;
- (NSString *)stringForDebugEvent:(MGLMapboxEventAttributes *)event {
// redact potentially sensitive location details from system console log
- if ([event[@"event"] isEqualToString:MGLEventTypeLocation] ||
- [event[@"event"] isEqualToString:MGLEventTypeVisit]) {
+ if ([event[@"event"] isEqualToString:MGLEventTypeLocation]) {
MGLMutableMapboxEventAttributes *evt = [MGLMutableMapboxEventAttributes dictionaryWithDictionary:event];
[evt setObject:@"<redacted>" forKey:@"lat"];
[evt setObject:@"<redacted>" forKey:@"lng"];