From 246361479aee7e4c8808f5b81af89c87eea4a888 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Fri, 21 Aug 2020 10:31:41 -0400 Subject: [PATCH] limit event, screen, and param names to 40 chars https://firebase.google.com/docs/reference/ios/firebaseanalytics/api/reference/Classes/FIRAnalytics#+logeventwithname:parameters --- Example/Tests/Tests.m | 16 ++++- .../Classes/SEGFirebaseIntegration.m | 64 +++++++++---------- 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/Example/Tests/Tests.m b/Example/Tests/Tests.m index 2914a5c..d4e9cfe 100644 --- a/Example/Tests/Tests.m +++ b/Example/Tests/Tests.m @@ -66,6 +66,20 @@ }]; }); + it(@"track with event name and prop name > 40 chars", ^{ + SEGTrackPayload *payload = [[SEGTrackPayload alloc] initWithEvent:@"ufddxsblvtujywadkmohvddqnpbginxozqjffhjyy" + properties:@{ + @"ufddxsblvtujywadkmohvddqnpbginxozqjffhjyy" : @"Death Star" + } + context:@{} + integrations:@{}]; + + [integration track:payload]; + [verify(mockFirebase) logEventWithName:@"ufddxsblvtujywadkmohvddqnpbginxozqjffhjy" parameters:@{ + @"ufddxsblvtujywadkmohvddqnpbginxozqjffhjy" : @"Death Star" + }]; + }); + it(@"track with event name and parmas separated by periods", ^{ SEGTrackPayload *payload = [[SEGTrackPayload alloc] initWithEvent:@"Starship.Ordered" properties:@{ @@ -575,7 +589,7 @@ context:@{} integrations:@{}]; [integration screen:payload]; - [verify(mockFirebase) setScreenName:@"Home screen" screenClass:nil]; + [verify(mockFirebase) setScreenName:@"Home_screen" screenClass:nil]; }); }); diff --git a/Segment-Firebase/Classes/SEGFirebaseIntegration.m b/Segment-Firebase/Classes/SEGFirebaseIntegration.m index 85db2e1..3318ddf 100644 --- a/Segment-Firebase/Classes/SEGFirebaseIntegration.m +++ b/Segment-Firebase/Classes/SEGFirebaseIntegration.m @@ -66,16 +66,38 @@ - (void)track:(SEGTrackPayload *)payload - (void)screen:(SEGScreenPayload *)payload { - [self.firebaseClass setScreenName:payload.name screenClass:nil]; + NSString *name = [SEGFirebaseIntegration formatFirebaseNameString:payload.name]; + + [self.firebaseClass setScreenName:name screenClass:nil]; SEGLog(@"[FIRAnalytics setScreenName:%@]", payload.name); } #pragma mark - Utilities -// Event names can be up to 32 characters long, may only contain alphanumeric -// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_" -// prefix is reserved and should not be used. +// Formats the following types of strings to match the Firebase requirements: +// +// Event Names: https://firebase.google.com/docs/reference/ios/firebaseanalytics/api/reference/Classes/FIRAnalytics#+logeventwithname:parameters: +// Should contain 1 to 40 alphanumeric characters or underscores. +// +// Parameter Names: https://firebase.google.com/docs/reference/ios/firebaseanalytics/api/reference/Classes/FIRAnalytics#/c:objc(cs)FIRAnalytics(cm)logEventWithName:parameters: +// Should contain 1 to 40 alphanumeric characters or underscores. +// +// Screen Names: https://firebase.google.com/docs/reference/ios/firebaseanalytics/api/reference/Classes/FIRAnalytics#setscreennamescreenclass +// Should contain 1 to 40 alphanumeric characters or underscores. + ++ (NSString *)formatFirebaseNameString:(NSString *)name +{ + NSError *error = nil; + + NSString *trimmed = [name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"([^a-zA-Z0-9_])" options:0 error:&error]; + NSString *formatted = [regex stringByReplacingMatchesInString:trimmed options:0 range:NSMakeRange(0, [trimmed length]) withTemplate:@"_"]; + + NSLog(@"Output: %@", formatted); + return [formatted substringToIndex:MIN(40, [formatted length])]; +} + // Maps Segment Spec to Firebase Constants // https://firebase.google.com/docs/reference/ios/firebaseanalytics/api/reference/Constants#/c:FIRParameterNames.h@kFIRParameterCampaign @@ -99,37 +121,19 @@ - (NSString *)formatFirebaseEventNames:(NSString *)event kFIREventSearch, @"Products Searched", nil]; NSString *mappedEvent = [mapper objectForKey:event]; - NSArray *periodSeparatedEvent = [event componentsSeparatedByString:@"."]; - NSString *regexString = @"^[a-zA-Z0-9_]+$"; - NSError *error = NULL; - NSRegularExpression *regex = - [NSRegularExpression regularExpressionWithPattern:regexString - options:0 - error:&error]; - NSUInteger numberOfMatches = [regex numberOfMatchesInString:event - options:0 - range:NSMakeRange(0, [event length])]; if (mappedEvent) { return mappedEvent; - } else if (numberOfMatches == 0) { - NSString *trimmedEvent = [event stringByTrimmingCharactersInSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet]]; - if ([periodSeparatedEvent count] > 1) { - return [trimmedEvent stringByReplacingOccurrencesOfString:@"." withString:@"_"]; - } else { - return [[trimmedEvent stringByReplacingOccurrencesOfString:@" " withString:@"_"] stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; - } } else { - return event; + return [SEGFirebaseIntegration formatFirebaseNameString:event]; } } /// Params supply information that contextualize Events. You can associate up to 25 unique Params /// with each Event type. Some Params are suggested below for certain common Events, but you are /// not limited to these. You may supply extra Params for suggested Events or custom Params for -/// Custom events. Param names can be up to 24 characters long, may only contain alphanumeric +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric /// characters and underscores ("_"), and must start with an alphabetic character. Param values can -/// be up to 36 characters long. The "firebase_" prefix is reserved and should not be used. +/// be up to 100 characters long. The "firebase_" prefix is reserved and should not be used. - (NSDictionary *)returnMappedFirebaseParameters:(NSDictionary *)properties { @@ -170,14 +174,8 @@ + (NSDictionary *)mapToFirebaseParameters:(NSDictionary *)properties withMap:(NS NSMutableDictionary *output = [NSMutableDictionary dictionaryWithCapacity:dictionary.count]; [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id data, BOOL *stop) { [output removeObjectForKey:key]; - NSArray *periodSeparatedKey = [key componentsSeparatedByString:@"."]; - NSString *trimmedKey = [key stringByTrimmingCharactersInSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet]]; - if ([periodSeparatedKey count] > 1) { - key = [trimmedKey stringByReplacingOccurrencesOfString:@"." withString:@"_"]; - } else { - key = [[trimmedKey stringByReplacingOccurrencesOfString:@" " withString:@"_"] stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; - } + key = [SEGFirebaseIntegration formatFirebaseNameString:key]; + if ([data isKindOfClass:[NSNumber class]]) { data = [NSNumber numberWithDouble:[data doubleValue]]; [output setObject:data forKey:key];