forked from orta/ARAnalytics
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathARDSL.m
140 lines (109 loc) · 5.45 KB
/
ARDSL.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
#import "ARDSL.h"
#import <RSSwizzle/RSSwizzle.h>
#import <ReactiveCocoa/ReactiveCocoa.h>
NSString * const ARAnalyticsTrackedEvents = @"trackedEvents";
NSString * const ARAnalyticsTrackedScreens = @"trackedScreens";
NSString * const ARAnalyticsClass = @"class";
NSString * const ARAnalyticsDetails = @"details";
NSString * const ARAnalyticsPageName = @"pageName";
NSString * const ARAnalyticsPageNameKeyPath = @"keypath";
NSString * const ARAnalyticsEventName = @"event";
NSString * const ARAnalyticsSelectorName = @"selector";
NSString * const ARAnalyticsEventProperties = @"properties";
NSString * const ARAnalyticsShouldFire = @"shouldFire";;
static BOOL ar_shouldFireForInstance (NSDictionary *dictionary, id instance, RACTuple *context) {
ARAnalyticsEventShouldFireBlock shouldFireBlock = dictionary[ARAnalyticsShouldFire];
BOOL shouldFire;
if (shouldFireBlock) {
shouldFire = shouldFireBlock(instance, context.allObjects);
} else {
shouldFire = YES;
}
return shouldFire;
}
static SEL ar_selectorForEventAnalyticsDetails (NSDictionary *detailsDictionary) {
NSString *selectorName = detailsDictionary[ARAnalyticsSelectorName];
SEL selector = NSSelectorFromString(selectorName);
return selector;
}
static SEL ar_selectorForScreenAnalyticsDetails (NSDictionary *dictionary, Class klass) {
SEL selector;
NSString *selectorName = dictionary[ARAnalyticsSelectorName];
if (selectorName) {
selector = NSSelectorFromString(selectorName);
} else {
#if TARGET_OS_IPHONE
selector = @selector(viewDidAppear:);
NSCAssert([klass isSubclassOfClass:UIViewController.class] || klass == UIViewController.class, @"Default selector of viewDidAppear: must only be used on classes extending UIViewController or UIViewController itself.");
#else
NSCAssert(NO, @"You must specify a selector name for page views on OS X.");
#endif
}
return selector;
}
@implementation ARAnalytics (DSL)
+ (void)setupWithAnalytics:(NSDictionary *)analyticsDictionary configuration:(NSDictionary *)configurationDictionary {
[self setupWithAnalytics:analyticsDictionary];
NSArray *trackedScreenClasses = configurationDictionary[ARAnalyticsTrackedScreens];
[trackedScreenClasses enumerateObjectsUsingBlock:^(NSDictionary *screenDictionary, NSUInteger idx, BOOL *stop) {
[self addScreenMonitoringAnalyticsHook:screenDictionary];
}];
NSArray *trackedEventClasses = configurationDictionary[ARAnalyticsTrackedEvents];
[trackedEventClasses enumerateObjectsUsingBlock:^(NSDictionary *eventDictionary, NSUInteger idx, BOOL *stop) {
[self addEventAnalyticsHook:eventDictionary];
}];
}
+ (void)addEventAnalyticsHook:(NSDictionary *)eventDictionary {
Class klass = eventDictionary[ARAnalyticsClass];
RSSwizzleClassMethod(klass, @selector(alloc), RSSWReturnType(id), void, RSSWReplacement({
id instance = RSSWCallOriginal();
[eventDictionary[ARAnalyticsDetails] enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
SEL selector = ar_selectorForEventAnalyticsDetails(object);
NSString *event = object[ARAnalyticsEventName];
__weak __typeof(instance) weakInstance = instance;
[[instance rac_signalForSelector:selector] subscribeNext:^(RACTuple *parameters) {
id instance = weakInstance;
BOOL shouldFire = ar_shouldFireForInstance(object, instance, parameters);
if (shouldFire) {
NSDictionary *properties;
ARAnalyticsEventPropertiesBlock propertiesBlock = object[ARAnalyticsEventProperties];
if (propertiesBlock) {
properties = propertiesBlock(instance, parameters.allObjects);
}
[ARAnalytics event:event withProperties:properties];
}
}];
}];
return instance;
}));
}
+ (void)addScreenMonitoringAnalyticsHook:(NSDictionary *)screenDictionary {
Class klass = screenDictionary[ARAnalyticsClass];
RSSwizzleClassMethod(klass, @selector(alloc), RSSWReturnType(id), void, RSSWReplacement({
id instance = RSSWCallOriginal();
[screenDictionary[ARAnalyticsDetails] enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
SEL selector = ar_selectorForScreenAnalyticsDetails(object, klass);
// Try to grab the page name from the dictionary.
NSString *dictionaryPageName = object[ARAnalyticsPageName];
// If there wasn't one, then try to invoke keypath.
NSString *pageNameKeypath = object[ARAnalyticsPageNameKeyPath];
__weak __typeof(instance) weakInstance = instance;
[[instance rac_signalForSelector:selector] subscribeNext:^(RACTuple *parameters) {
id instance = weakInstance;
BOOL shouldFire = ar_shouldFireForInstance(object, instance, parameters);
if (shouldFire) {
NSString *pageName;
if (dictionaryPageName) {
pageName = dictionaryPageName;
} else {
pageName = [instance valueForKeyPath:pageNameKeypath];
NSAssert(pageName, @"Value for Key on `%@` returned nil.", pageNameKeypath);
}
[ARAnalytics pageView:pageName];
}
}];
}];
return instance;
}));
}
@end