Showing
4 changed files
with
114 additions
and
23 deletions
@@ -707,6 +707,7 @@ | @@ -707,6 +707,7 @@ | ||
707 | TargetAttributes = { | 707 | TargetAttributes = { |
708 | 529A00451F564E8500A83F63 = { | 708 | 529A00451F564E8500A83F63 = { |
709 | CreatedOnToolsVersion = 8.3; | 709 | CreatedOnToolsVersion = 8.3; |
710 | + DevelopmentTeam = LUM7XZ8Q2G; | ||
710 | ProvisioningStyle = Automatic; | 711 | ProvisioningStyle = Automatic; |
711 | }; | 712 | }; |
712 | }; | 713 | }; |
@@ -947,6 +948,7 @@ | @@ -947,6 +948,7 @@ | ||
947 | isa = XCBuildConfiguration; | 948 | isa = XCBuildConfiguration; |
948 | buildSettings = { | 949 | buildSettings = { |
949 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | 950 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; |
951 | + DEVELOPMENT_TEAM = LUM7XZ8Q2G; | ||
950 | FRAMEWORK_SEARCH_PATHS = ( | 952 | FRAMEWORK_SEARCH_PATHS = ( |
951 | "$(inherited)", | 953 | "$(inherited)", |
952 | "$(PROJECT_DIR)/YHEventReport/Utils/SDWebImage/Vendors", | 954 | "$(PROJECT_DIR)/YHEventReport/Utils/SDWebImage/Vendors", |
@@ -965,6 +967,7 @@ | @@ -965,6 +967,7 @@ | ||
965 | isa = XCBuildConfiguration; | 967 | isa = XCBuildConfiguration; |
966 | buildSettings = { | 968 | buildSettings = { |
967 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | 969 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; |
970 | + DEVELOPMENT_TEAM = LUM7XZ8Q2G; | ||
968 | FRAMEWORK_SEARCH_PATHS = ( | 971 | FRAMEWORK_SEARCH_PATHS = ( |
969 | "$(inherited)", | 972 | "$(inherited)", |
970 | "$(PROJECT_DIR)/YHEventReport/Utils/SDWebImage/Vendors", | 973 | "$(PROJECT_DIR)/YHEventReport/Utils/SDWebImage/Vendors", |
@@ -8,6 +8,13 @@ | @@ -8,6 +8,13 @@ | ||
8 | 8 | ||
9 | #import <UIKit/UIKit.h> | 9 | #import <UIKit/UIKit.h> |
10 | 10 | ||
11 | +@protocol UIViewControllerPerformanceTrack <NSObject> | ||
12 | + | ||
13 | +@optional | ||
14 | +- (BOOL)shouldNotTrackFirstPageLoadPerformance; | ||
15 | + | ||
16 | +@end | ||
17 | + | ||
11 | @interface UIViewController (AutoTrack) | 18 | @interface UIViewController (AutoTrack) |
12 | 19 | ||
13 | @property(nonatomic,copy)NSString *yh_viewId;//该页面唯一ID | 20 | @property(nonatomic,copy)NSString *yh_viewId;//该页面唯一ID |
@@ -16,7 +23,7 @@ | @@ -16,7 +23,7 @@ | ||
16 | 23 | ||
17 | - (UITabBarController *)yher_tabBarController; | 24 | - (UITabBarController *)yher_tabBarController; |
18 | 25 | ||
19 | -@property(nonatomic,copy)NSString* yher_hasReported;//tab VC 已经统计过 @"0" @"1" | 26 | +@property(nonatomic,assign) BOOL yher_hasReported; |
20 | 27 | ||
21 | +(void)startTrack; | 28 | +(void)startTrack; |
22 | 29 |
@@ -14,6 +14,44 @@ | @@ -14,6 +14,44 @@ | ||
14 | #import "YH_EventCollector.h" | 14 | #import "YH_EventCollector.h" |
15 | #import "YHEventReport.h" | 15 | #import "YHEventReport.h" |
16 | 16 | ||
17 | +@interface UIViewController (AutoTrackPrivate) | ||
18 | + | ||
19 | +@property (nonatomic, assign, readonly) BOOL shouldTrack; | ||
20 | +@property (nonatomic, assign) BOOL shouldResetStartLoadDate; | ||
21 | + | ||
22 | +@end | ||
23 | + | ||
24 | +@implementation UIViewController (AutoTrackPrivate) | ||
25 | + | ||
26 | +- (BOOL)shouldTrack { | ||
27 | + return ![self isSystemContainerController] && | ||
28 | + ![self shouldNotTrackByProtocol] && | ||
29 | + [YHEventReport sharedInstance].isPerformanceTrackEnabled && | ||
30 | + [YHEventReport sharedInstance].isControllerPerformanceTrackEnable && | ||
31 | + ![[YHEventReport sharedInstance] isPerformanceViewControllerStringIgnored:NSStringFromClass([self class])]; | ||
32 | +} | ||
33 | + | ||
34 | +- (BOOL)shouldNotTrackByProtocol { | ||
35 | + return [self conformsToProtocol:@protocol(UIViewControllerPerformanceTrack)] && | ||
36 | + [(id<UIViewControllerPerformanceTrack>)self shouldNotTrackFirstPageLoadPerformance]; | ||
37 | +} | ||
38 | + | ||
39 | +- (void)setShouldResetStartLoadDate:(BOOL)shouldResetStartLoadDate { | ||
40 | + objc_setAssociatedObject(self, @selector(shouldResetStartLoadDate), @(shouldResetStartLoadDate), OBJC_ASSOCIATION_COPY_NONATOMIC); | ||
41 | +} | ||
42 | + | ||
43 | +- (BOOL)shouldResetStartLoadDate { | ||
44 | + return [objc_getAssociatedObject(self, _cmd) boolValue]; | ||
45 | +} | ||
46 | + | ||
47 | +- (BOOL)isSystemContainerController { | ||
48 | + return [self isKindOfClass:[UINavigationController class]] || | ||
49 | + [self isKindOfClass:[UITabBarController class]] || | ||
50 | + [self isKindOfClass:[UISplitViewController class]] || | ||
51 | + [self isKindOfClass:[UIPageViewController class]]; | ||
52 | +} | ||
53 | + | ||
54 | +@end | ||
17 | 55 | ||
18 | @implementation UIViewController (AutoTrack) | 56 | @implementation UIViewController (AutoTrack) |
19 | 57 | ||
@@ -39,6 +77,15 @@ | @@ -39,6 +77,15 @@ | ||
39 | viewdidappearError = NULL; | 77 | viewdidappearError = NULL; |
40 | } | 78 | } |
41 | 79 | ||
80 | + NSError *viewwillappearError = NULL; | ||
81 | + [[self class] yh_swizzleMethod:@selector(viewWillAppear:) | ||
82 | + withMethod:@selector(yher_viewWillAppear:) | ||
83 | + error:&viewwillappearError]; | ||
84 | + if (viewwillappearError) { | ||
85 | + YHLog(@"Failed to swizzle viewWillAppear: on UIViewController. Details: %@", viewwillappearError); | ||
86 | + viewdidappearError = NULL; | ||
87 | + } | ||
88 | + | ||
42 | } @catch (NSException *exception) { | 89 | } @catch (NSException *exception) { |
43 | YHLog(@"%@ error: %@", self, exception); | 90 | YHLog(@"%@ error: %@", self, exception); |
44 | } | 91 | } |
@@ -48,19 +95,30 @@ | @@ -48,19 +95,30 @@ | ||
48 | 95 | ||
49 | - (void)yher_viewDidLoad{ | 96 | - (void)yher_viewDidLoad{ |
50 | @try { | 97 | @try { |
51 | - if ([YHEventReport sharedInstance].isPerformanceTrackEnabled && [YHEventReport sharedInstance].isControllerPerformanceTrackEnable && ![[YHEventReport sharedInstance] isPerformanceViewControllerStringIgnored:NSStringFromClass([self class])]) { | 98 | + if (self.shouldTrack) { |
52 | [[YH_EventCollector sharedInstance] timeEventStartWithViewController:self]; | 99 | [[YH_EventCollector sharedInstance] timeEventStartWithViewController:self]; |
100 | + [self performSelector:@selector(yher_checkVisiable) withObject:nil afterDelay:0]; | ||
53 | } | 101 | } |
54 | } @catch (NSException *exception) { | 102 | } @catch (NSException *exception) { |
55 | YHLog(@"%@ error: %@", self, exception); | 103 | YHLog(@"%@ error: %@", self, exception); |
56 | } | 104 | } |
57 | - | ||
58 | [self yher_viewDidLoad]; | 105 | [self yher_viewDidLoad]; |
59 | } | 106 | } |
60 | 107 | ||
108 | +-(void)yher_viewWillAppear:(BOOL)animated { | ||
109 | + @try { | ||
110 | + if (self.shouldTrack && self.shouldResetStartLoadDate && !self.yher_hasReported) { | ||
111 | + [[YH_EventCollector sharedInstance] timeEventStartWithViewController:self]; | ||
112 | + } | ||
113 | + } @catch (NSException *exception) { | ||
114 | + YHLog(@"%@ error: %@", self, exception); | ||
115 | + } | ||
116 | + [self yher_viewWillAppear:animated]; | ||
117 | +} | ||
118 | + | ||
61 | -(void)yher_viewDidAppear:(BOOL)animated { | 119 | -(void)yher_viewDidAppear:(BOOL)animated { |
62 | @try { | 120 | @try { |
63 | - if ([YHEventReport sharedInstance].isPerformanceTrackEnabled && [YHEventReport sharedInstance].isControllerPerformanceTrackEnable && ![[YHEventReport sharedInstance] isPerformanceViewControllerStringIgnored:NSStringFromClass([self class])]) { | 121 | + if (self.shouldTrack && !self.yher_hasReported) { |
64 | [[YH_EventCollector sharedInstance] timeEventEndWithViewController:self]; | 122 | [[YH_EventCollector sharedInstance] timeEventEndWithViewController:self]; |
65 | } | 123 | } |
66 | if ([YHEventReport sharedInstance].isAppCrashReportEnable && [YHEventReport sharedInstance].isAutoTrackEnabled) { | 124 | if ([YHEventReport sharedInstance].isAppCrashReportEnable && [YHEventReport sharedInstance].isAutoTrackEnabled) { |
@@ -86,12 +144,18 @@ | @@ -86,12 +144,18 @@ | ||
86 | [self yher_viewDidAppear:animated]; | 144 | [self yher_viewDidAppear:animated]; |
87 | } | 145 | } |
88 | 146 | ||
147 | +- (void)yher_checkVisiable { | ||
148 | + if (!self.view.window) { | ||
149 | + self.shouldResetStartLoadDate = YES; | ||
150 | + } | ||
151 | +} | ||
152 | + | ||
89 | - (void)setYh_viewId:(NSString *)yh_viewId{ | 153 | - (void)setYh_viewId:(NSString *)yh_viewId{ |
90 | objc_setAssociatedObject(self,@selector(yh_viewId),yh_viewId,OBJC_ASSOCIATION_RETAIN); | 154 | objc_setAssociatedObject(self,@selector(yh_viewId),yh_viewId,OBJC_ASSOCIATION_RETAIN); |
91 | } | 155 | } |
92 | 156 | ||
93 | - (NSString *)yh_viewId{ | 157 | - (NSString *)yh_viewId{ |
94 | - return objc_getAssociatedObject(self, @selector(yh_viewId)); | 158 | + return objc_getAssociatedObject(self, _cmd); |
95 | } | 159 | } |
96 | 160 | ||
97 | 161 | ||
@@ -100,15 +164,15 @@ | @@ -100,15 +164,15 @@ | ||
100 | } | 164 | } |
101 | 165 | ||
102 | - (NSString *)yh_Alias{ | 166 | - (NSString *)yh_Alias{ |
103 | - return objc_getAssociatedObject(self, @selector(yh_Alias)); | 167 | + return objc_getAssociatedObject(self, _cmd); |
104 | } | 168 | } |
105 | 169 | ||
106 | -- (void)setYher_hasReported:(NSString *)yher_hasReported{ | ||
107 | - objc_setAssociatedObject(self,@selector(yher_hasReported),yher_hasReported,OBJC_ASSOCIATION_RETAIN); | 170 | +- (void)setYher_hasReported:(BOOL)yher_hasReported{ |
171 | + objc_setAssociatedObject(self,@selector(yher_hasReported),@(yher_hasReported),OBJC_ASSOCIATION_COPY_NONATOMIC); | ||
108 | } | 172 | } |
109 | 173 | ||
110 | -- (NSString *)yher_hasReported{ | ||
111 | - return objc_getAssociatedObject(self, @selector(yher_hasReported)); | 174 | +- (BOOL)yher_hasReported{ |
175 | + return [objc_getAssociatedObject(self, _cmd) boolValue]; | ||
112 | } | 176 | } |
113 | 177 | ||
114 | - (UITabBarController *)yher_tabBarController | 178 | - (UITabBarController *)yher_tabBarController |
@@ -28,6 +28,16 @@ | @@ -28,6 +28,16 @@ | ||
28 | #define kYHEventReportQueue @"YHEventReportQueue" | 28 | #define kYHEventReportQueue @"YHEventReportQueue" |
29 | #define kYHEventReporrH5StartKey @"YHEventReporrH5StartKey" | 29 | #define kYHEventReporrH5StartKey @"YHEventReporrH5StartKey" |
30 | 30 | ||
31 | +NS_INLINE NSString *YH_Objectkey(id anyObject) { | ||
32 | + NSCParameterAssert(anyObject); | ||
33 | + if (!anyObject) { | ||
34 | + return NSStringFromClass(NSNull.class); | ||
35 | + } | ||
36 | + uintptr_t intPoint = (uintptr_t)anyObject; | ||
37 | + NSString *keyPart1 = NSStringFromClass([anyObject class]); | ||
38 | + NSString *keyPart2 = @(intPoint).description; | ||
39 | + return [keyPart1 stringByAppendingString:keyPart2]; | ||
40 | +} | ||
31 | 41 | ||
32 | @interface YH_EventCollector() | 42 | @interface YH_EventCollector() |
33 | 43 | ||
@@ -182,16 +192,12 @@ | @@ -182,16 +192,12 @@ | ||
182 | 192 | ||
183 | #pragma mark - viewcontroller performance | 193 | #pragma mark - viewcontroller performance |
184 | - (void)timeEventStartWithViewController:(UIViewController *)viewController{ | 194 | - (void)timeEventStartWithViewController:(UIViewController *)viewController{ |
185 | - NSNumber *startTime = @([[NSDate date] timeIntervalSince1970]); | ||
186 | - NSString *viewId = [NSString stringWithFormat:@"%@%@",NSStringFromClass([viewController class]),startTime]; | ||
187 | - | ||
188 | - if (startTime==0||IsStrEmpty(viewId)) { | ||
189 | - return; | ||
190 | - } | ||
191 | - | 195 | + NSParameterAssert(viewController); |
192 | if (!viewController) { | 196 | if (!viewController) { |
193 | return; | 197 | return; |
194 | } | 198 | } |
199 | + NSNumber *startTime = @([[NSDate date] timeIntervalSince1970]); | ||
200 | + NSString *viewId = YH_Objectkey(viewController); | ||
195 | 201 | ||
196 | if ([viewController isKindOfClass:NSClassFromString(@"YH_H5ViewController")]) { | 202 | if ([viewController isKindOfClass:NSClassFromString(@"YH_H5ViewController")]) { |
197 | dispatch_async(self.serialQueue, ^{ | 203 | dispatch_async(self.serialQueue, ^{ |
@@ -206,20 +212,22 @@ | @@ -206,20 +212,22 @@ | ||
206 | } | 212 | } |
207 | 213 | ||
208 | - (void)timeEventEndWithViewController:(UIViewController *)viewController{ | 214 | - (void)timeEventEndWithViewController:(UIViewController *)viewController{ |
209 | - | 215 | + NSParameterAssert(viewController); |
216 | + if (!viewController || !viewController.yh_viewId || viewController.yher_hasReported) { | ||
217 | + return; | ||
218 | + } | ||
210 | NSTimeInterval elapsedTime = 0; | 219 | NSTimeInterval elapsedTime = 0; |
211 | - | ||
212 | if ([self isTabViewControllerString:NSStringFromClass([viewController class])]) { | 220 | if ([self isTabViewControllerString:NSStringFromClass([viewController class])]) { |
213 | UITabBarController *tabBarVC = [viewController yher_tabBarController]; | 221 | UITabBarController *tabBarVC = [viewController yher_tabBarController]; |
214 | double didSelectTime = [tabBarVC.tabBar.selectedItem.yh_didSelectTime doubleValue]; | 222 | double didSelectTime = [tabBarVC.tabBar.selectedItem.yh_didSelectTime doubleValue]; |
215 | - if ([viewController.yher_hasReported isEqualToString:@"1"]) { | 223 | + if (viewController.yher_hasReported) { |
216 | return; | 224 | return; |
217 | } | 225 | } |
218 | if (didSelectTime==0) { | 226 | if (didSelectTime==0) { |
219 | elapsedTime = [self eventElapsedTime:viewController.yh_viewId]; | 227 | elapsedTime = [self eventElapsedTime:viewController.yh_viewId]; |
220 | }else{ | 228 | }else{ |
221 | elapsedTime = [[NSDate date] timeIntervalSince1970] - didSelectTime; | 229 | elapsedTime = [[NSDate date] timeIntervalSince1970] - didSelectTime; |
222 | - viewController.yher_hasReported = @"1"; | 230 | + viewController.yher_hasReported = YES; |
223 | } | 231 | } |
224 | }else{ | 232 | }else{ |
225 | elapsedTime = [self eventElapsedTime:viewController.yh_viewId]; | 233 | elapsedTime = [self eventElapsedTime:viewController.yh_viewId]; |
@@ -233,13 +241,22 @@ | @@ -233,13 +241,22 @@ | ||
233 | [self.timedEvents removeObjectForKey:viewController.yh_viewId]; | 241 | [self.timedEvents removeObjectForKey:viewController.yh_viewId]; |
234 | }); | 242 | }); |
235 | } | 243 | } |
236 | - | ||
237 | NSDictionary *param = [YH_EventDataFactory factoryTimeEventDataWithViewController:viewController ElapsedTime:elapsedTime]; | 244 | NSDictionary *param = [YH_EventDataFactory factoryTimeEventDataWithViewController:viewController ElapsedTime:elapsedTime]; |
238 | - | ||
239 | if (param) { | 245 | if (param) { |
240 | [[YH_EventCacheManager sharedInstance] pushPerformanceData:param pointName:YHPN_VIEWCONTROLLER]; | 246 | [[YH_EventCacheManager sharedInstance] pushPerformanceData:param pointName:YHPN_VIEWCONTROLLER]; |
241 | } | 247 | } |
248 | + viewController.yher_hasReported = YES; | ||
249 | + [self printDebugLoadElapsedTime:elapsedTime controller:viewController info:param]; | ||
250 | +} | ||
242 | 251 | ||
252 | +- (void)printDebugLoadElapsedTime:(NSTimeInterval)elapsedTime controller:(UIViewController *)viewController info:(NSDictionary *)info { | ||
253 | +#ifdef DEBUG | ||
254 | + NSLog(@"🤬🤬🤬 \n %@:%@ \n 🤬🤬🤬",NSStringFromClass(viewController.class) ,info); | ||
255 | + //优化目标:1秒内展现 | ||
256 | + if (elapsedTime >= 1.f) { | ||
257 | + NSLog(@"🥀🥀🥀 FBI warning:加载速度过慢,急需优化 🥀🥀🥀"); | ||
258 | + } | ||
259 | +#endif | ||
243 | } | 260 | } |
244 | 261 | ||
245 | #pragma mark - webview performance | 262 | #pragma mark - webview performance |
-
Please register or login to post a comment