-
Notifications
You must be signed in to change notification settings - Fork 332
/
SEGAnalyticsUtils.m
198 lines (173 loc) · 6.3 KB
/
SEGAnalyticsUtils.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#import "SEGAnalyticsUtils.h"
#import <AdSupport/ASIdentifierManager.h>
static BOOL kAnalyticsLoggerShowLogs = NO;
NSURL *SEGAnalyticsURLForFilename(NSString *filename)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *supportPath = [paths firstObject];
if (![[NSFileManager defaultManager] fileExistsAtPath:supportPath
isDirectory:NULL]) {
NSError *error = nil;
if (![[NSFileManager defaultManager] createDirectoryAtPath:supportPath
withIntermediateDirectories:YES
attributes:nil
error:&error]) {
SEGLog(@"error: %@", error.localizedDescription);
}
}
return [[NSURL alloc] initFileURLWithPath:[supportPath stringByAppendingPathComponent:filename]];
}
NSString *GenerateUUIDString()
{
CFUUIDRef theUUID = CFUUIDCreate(NULL);
NSString *UUIDString = (__bridge_transfer NSString *)CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
return UUIDString;
}
// Date Utils
NSString *iso8601FormattedString(NSDate *date)
{
static NSDateFormatter *dateFormatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSZ";
});
return [dateFormatter stringFromDate:date];
}
// Async Utils
dispatch_queue_t
seg_dispatch_queue_create_specific(const char *label,
dispatch_queue_attr_t attr)
{
dispatch_queue_t queue = dispatch_queue_create(label, attr);
dispatch_queue_set_specific(queue, (__bridge const void *)queue,
(__bridge void *)queue, NULL);
return queue;
}
BOOL seg_dispatch_is_on_specific_queue(dispatch_queue_t queue)
{
return dispatch_get_specific((__bridge const void *)queue) != NULL;
}
void seg_dispatch_specific(dispatch_queue_t queue, dispatch_block_t block,
BOOL waitForCompletion)
{
if (dispatch_get_specific((__bridge const void *)queue)) {
block();
} else if (waitForCompletion) {
dispatch_sync(queue, block);
} else {
dispatch_async(queue, block);
}
}
void seg_dispatch_specific_async(dispatch_queue_t queue,
dispatch_block_t block)
{
seg_dispatch_specific(queue, block, NO);
}
void seg_dispatch_specific_sync(dispatch_queue_t queue,
dispatch_block_t block)
{
seg_dispatch_specific(queue, block, YES);
}
// Logging
void SEGSetShowDebugLogs(BOOL showDebugLogs)
{
kAnalyticsLoggerShowLogs = showDebugLogs;
}
void SEGLog(NSString *format, ...)
{
if (!kAnalyticsLoggerShowLogs)
return;
va_list args;
va_start(args, format);
NSLogv(format, args);
va_end(args);
}
// JSON Utils
static id SEGCoerceJSONObject(id obj)
{
// if the object is a NSString, NSNumber or NSNull
// then we're good
if ([obj isKindOfClass:[NSString class]] ||
[obj isKindOfClass:[NSNumber class]] ||
[obj isKindOfClass:[NSNull class]]) {
return obj;
}
if ([obj isKindOfClass:[NSArray class]]) {
NSMutableArray *array = [NSMutableArray array];
for (id i in obj)
[array addObject:SEGCoerceJSONObject(i)];
return array;
}
if ([obj isKindOfClass:[NSDictionary class]]) {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (NSString *key in obj) {
if (![key isKindOfClass:[NSString class]])
SEGLog(@"warning: dictionary keys should be strings. got: %@. coercing "
@"to: %@",
[key class], [key description]);
dict[key.description] = SEGCoerceJSONObject(obj[key]);
}
return dict;
}
if ([obj isKindOfClass:[NSDate class]])
return iso8601FormattedString(obj);
if ([obj isKindOfClass:[NSURL class]])
return [obj absoluteString];
// default to sending the object's description
SEGLog(@"warning: dictionary values should be valid json types. got: %@. "
@"coercing to: %@",
[obj class], [obj description]);
return [obj description];
}
static void AssertDictionaryTypes(id dict)
{
assert([dict isKindOfClass:[NSDictionary class]]);
for (id key in dict) {
assert([key isKindOfClass:[NSString class]]);
id value = dict[key];
assert([value isKindOfClass:[NSString class]] ||
[value isKindOfClass:[NSNumber class]] ||
[value isKindOfClass:[NSNull class]] ||
[value isKindOfClass:[NSArray class]] ||
[value isKindOfClass:[NSDictionary class]] ||
[value isKindOfClass:[NSDate class]] ||
[value isKindOfClass:[NSURL class]]);
}
}
NSDictionary *SEGCoerceDictionary(NSDictionary *dict)
{
// make sure that a new dictionary exists even if the input is null
dict = dict ?: @{};
// assert that the proper types are in the dictionary
AssertDictionaryTypes(dict);
// coerce urls, and dates to the proper format
return SEGCoerceJSONObject(dict);
}
NSString *SEGIDFA()
{
NSString *idForAdvertiser = nil;
Class identifierManager = NSClassFromString(@"ASIdentifierManager");
if (identifierManager) {
SEL sharedManagerSelector = NSSelectorFromString(@"sharedManager");
id sharedManager =
((id (*)(id, SEL))
[identifierManager methodForSelector:sharedManagerSelector])(
identifierManager, sharedManagerSelector);
SEL advertisingIdentifierSelector =
NSSelectorFromString(@"advertisingIdentifier");
NSUUID *uuid =
((NSUUID * (*)(id, SEL))
[sharedManager methodForSelector:advertisingIdentifierSelector])(
sharedManager, advertisingIdentifierSelector);
idForAdvertiser = [uuid UUIDString];
}
return idForAdvertiser;
}
NSString *SEGEventNameForScreenTitle(NSString *title)
{
return [[NSString alloc] initWithFormat:@"Viewed %@ Screen", title];
}