Authored by 孙凯

add UIGestureRecognizer time review by hongmo

... ... @@ -46,6 +46,7 @@
B17F61DB1F6678CD009D1606 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B17F61DA1F6678CD009D1606 /* UserNotifications.framework */; };
B188D2051F692DB600FFBEDF /* SDWebImageDownloaderOperation+AutoTrack.m in Sources */ = {isa = PBXBuildFile; fileRef = B188D2041F692DB600FFBEDF /* SDWebImageDownloaderOperation+AutoTrack.m */; };
B1A393141F7B4E04009700D9 /* UIControl+AutoTrack.m in Sources */ = {isa = PBXBuildFile; fileRef = B1A393131F7B4E04009700D9 /* UIControl+AutoTrack.m */; };
B1A393171F7C918C009700D9 /* UIGestureRecognizer+AutoTrack.m in Sources */ = {isa = PBXBuildFile; fileRef = B1A393161F7C918C009700D9 /* UIGestureRecognizer+AutoTrack.m */; };
B1A9387C1F6A8AF600D6582C /* NSString+ER_URL.m in Sources */ = {isa = PBXBuildFile; fileRef = B1A9387B1F6A8AF600D6582C /* NSString+ER_URL.m */; };
B1B6C3A01F74AD3100627DF3 /* README.md in Sources */ = {isa = PBXBuildFile; fileRef = B1B6C3951F74AD3100627DF3 /* README.md */; };
B1B6C3A11F74AD3100627DF3 /* UIScrollView+YHExposure.m in Sources */ = {isa = PBXBuildFile; fileRef = B1B6C3991F74AD3100627DF3 /* UIScrollView+YHExposure.m */; };
... ... @@ -163,6 +164,8 @@
B188D2041F692DB600FFBEDF /* SDWebImageDownloaderOperation+AutoTrack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SDWebImageDownloaderOperation+AutoTrack.m"; sourceTree = "<group>"; };
B1A393121F7B4E04009700D9 /* UIControl+AutoTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIControl+AutoTrack.h"; sourceTree = "<group>"; };
B1A393131F7B4E04009700D9 /* UIControl+AutoTrack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIControl+AutoTrack.m"; sourceTree = "<group>"; };
B1A393151F7C918C009700D9 /* UIGestureRecognizer+AutoTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIGestureRecognizer+AutoTrack.h"; sourceTree = "<group>"; };
B1A393161F7C918C009700D9 /* UIGestureRecognizer+AutoTrack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIGestureRecognizer+AutoTrack.m"; sourceTree = "<group>"; };
B1A9387A1F6A8AF600D6582C /* NSString+ER_URL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSString+ER_URL.h"; sourceTree = "<group>"; };
B1A9387B1F6A8AF600D6582C /* NSString+ER_URL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSString+ER_URL.m"; sourceTree = "<group>"; };
B1B6C3951F74AD3100627DF3 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
... ... @@ -308,6 +311,8 @@
29CDB4B01F6FA5A500AAD350 /* PowerfulBannerView+AutoTrack.m */,
B1A393121F7B4E04009700D9 /* UIControl+AutoTrack.h */,
B1A393131F7B4E04009700D9 /* UIControl+AutoTrack.m */,
B1A393151F7C918C009700D9 /* UIGestureRecognizer+AutoTrack.h */,
B1A393161F7C918C009700D9 /* UIGestureRecognizer+AutoTrack.m */,
);
path = YH_AOP;
sourceTree = "<group>";
... ... @@ -719,6 +724,7 @@
5255C2C11F5D25F400A8FC5F /* YHEventReport.m in Sources */,
529A004B1F564E8500A83F63 /* main.m in Sources */,
B1C419021F616187005E0729 /* OpenUDID.m in Sources */,
B1A393171F7C918C009700D9 /* UIGestureRecognizer+AutoTrack.m in Sources */,
B1D774A51F62A37E00BA89C3 /* SDWebImageDownloader.m in Sources */,
52878C0D1F5FEE4C000A1597 /* YH_EventDataFactory.m in Sources */,
B1D774AC1F62A37E00BA89C3 /* UIImage+MultiFormat.m in Sources */,
... ...
... ... @@ -20,6 +20,7 @@
#import "UIViewController+AutoTrack.h"
#import "UITabBar+AutoTrack.h"
#import "UIControl+AutoTrack.h"
#import "UIGestureRecognizer+AutoTrack.h"
#define kYHEventReportIgnoredViewController @"YHEventReportQueue"
... ... @@ -147,6 +148,8 @@ static NSArray *kYHEventReportIgnoredViewControllerArray;
[UIViewController startTrack];
[UITabBar startTrack];
[UIControl startTrack];
[UIGestureRecognizer startTrack];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIWebView startTrack];
[SDWebImageDownloaderOperation startTrack];
... ...
//
// UIGestureRecognizer+AutoTrack.h
// YHEventReport
//
// Created by 孙凯 on 2017/9/28.
// Copyright © 2017年 YOHO. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIGestureRecognizer (AutoTrack)
@property(nonatomic,copy)NSString *yh_viewId;//唯一ID
+(void)startTrack;
@end
... ...
//
// UIGestureRecognizer+AutoTrack.m
// YHEventReport
//
// Created by 孙凯 on 2017/9/28.
// Copyright © 2017年 YOHO. All rights reserved.
//
#import "UIGestureRecognizer+AutoTrack.h"
#import "YHSwizzle.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import "YHLog.h"
#import "YHEventReport.h"
#import "YH_EventCollector.h"
@interface UIGestureRecognizer ()<UIGestureRecognizerDelegate>
@property(nullable,nonatomic,weak) id <UIGestureRecognizerDelegate> my_delegate;
@end
@implementation UIGestureRecognizer (AutoTrack)
#pragma mark - 属性
- (void)setYh_viewId:(NSString *)yh_viewId{
objc_setAssociatedObject(self,@selector(yh_viewId),yh_viewId,OBJC_ASSOCIATION_RETAIN);
}
- (NSString *)yh_viewId{
return objc_getAssociatedObject(self, @selector(yh_viewId));
}
- (id)my_delegate
{
return objc_getAssociatedObject(self, _cmd);
}
- (void)setMy_delegate:(id)my_delegate
{
objc_setAssociatedObject(self, @selector(my_delegate), my_delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma mark - load
+ (void)startTrack{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
@try {
SEL selectors[] = {
@selector(initWithTarget:action:),
@selector(addTarget:action:),
@selector(setDelegate:),
};
for (NSUInteger index = 0; index < sizeof(selectors) / sizeof(SEL); ++index) {
SEL originalSelector = selectors[index];
SEL swizzledSelector = NSSelectorFromString([@"yher_" stringByAppendingString:NSStringFromSelector(originalSelector)]);
NSError *error = NULL;
[[self class] yh_swizzleMethod:originalSelector
withMethod:swizzledSelector
error:&error];
if (error) {
YHLog(@"Failed to swizzle: on UIControl. Details: %@", error);
error = NULL;
}
}
} @catch (NSException *exception) {
YHLog(@"%@ error: %@", self, exception);
}
});
}
#pragma mark - hook API
-(void)yher_setDelegate:(id<UIGestureRecognizerDelegate>)delegate
{
[self yher_setDelegate:self];
if (![delegate isKindOfClass:[self class]]) {
[self setMy_delegate:delegate];
}
}
- (instancetype)yher_initWithTarget:(nullable id)target action:(nullable SEL)action
{
[UIGestureRecognizer yher_exchangeSelector:action target:target toSelector:@selector(yher_gestureRecognizerDidTouch_cmd:)];
[self setDelegate:target];
return [self yher_initWithTarget:target action:action];
}
- (void)yher_addTarget:(id)target action:(SEL)action
{
[UIGestureRecognizer yher_exchangeSelector:action target:target toSelector:@selector(yher_gestureRecognizerDidTouch_cmd:)];
[self setDelegate:target];
[self yher_addTarget:target action:action];
}
#pragma mark - action
- (void)yher_gestureRecognizerDidTouch_cmd:(UIGestureRecognizer*)sender
{
if ([YHEventReport sharedInstance].isPerformanceTrackEnabled && [YHEventReport sharedInstance].buttonPerformanceTrackEnable) {
[[YH_EventCollector sharedInstance] timeEventEndWithUIGestureRecognizer:sender];
}
[self yher_gestureRecognizerDidTouch_cmd:sender];
}
#pragma mark - hook func
+ (void)yher_exchangeSelector:(SEL)originSel target:(nullable id)target toSelector:(SEL)replazSel
{
Class originalClass = object_getClass(target);
Class swizzledClass = [self class];
SEL originalSelector = originSel;
SEL swizzledSelector = replazSel;
Method originalMethod = class_getInstanceMethod(originalClass, originalSelector);
Method swizzledMethod = class_getInstanceMethod(swizzledClass, swizzledSelector);
IMP originalIMP = method_getImplementation(originalMethod);
IMP swizzledIMP = method_getImplementation(swizzledMethod);
const char *originalType = method_getTypeEncoding(originalMethod);
const char *swizzledType = method_getTypeEncoding(swizzledMethod);
class_replaceMethod(originalClass,swizzledSelector,originalIMP,originalType);
class_replaceMethod(originalClass,originalSelector,swizzledIMP,swizzledType);
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if ([YHEventReport sharedInstance].isPerformanceTrackEnabled && [YHEventReport sharedInstance].buttonPerformanceTrackEnable) {
[[YH_EventCollector sharedInstance] timeEventStartWithUIGestureRecognizer:self];
}
if (self.my_delegate && [self.my_delegate respondsToSelector:@selector(gestureRecognizerShouldBegin:)]) {
return [self.my_delegate gestureRecognizerShouldBegin:gestureRecognizer];
}
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if (self.my_delegate && [self.my_delegate respondsToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)]) {
return [self.my_delegate gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer];
}
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if (self.my_delegate && [self.my_delegate respondsToSelector:@selector(gestureRecognizer:shouldRequireFailureOfGestureRecognizer:)]) {
return [self.my_delegate gestureRecognizer:gestureRecognizer shouldRequireFailureOfGestureRecognizer:otherGestureRecognizer];
}
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if (self.my_delegate && [self.my_delegate respondsToSelector:@selector(gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:)]) {
return [self.my_delegate gestureRecognizer:gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:otherGestureRecognizer];
}
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (self.my_delegate && [self.my_delegate respondsToSelector:@selector(gestureRecognizer:shouldReceiveTouch:)]) {
return [self.my_delegate gestureRecognizer:gestureRecognizer shouldReceiveTouch:touch];
}
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePress:(UIPress *)press
{
if (self.my_delegate && [self.my_delegate respondsToSelector:@selector(gestureRecognizer:shouldReceivePress:)]) {
return [self.my_delegate gestureRecognizer:gestureRecognizer shouldReceivePress:press];
}
return YES;
}
@end
... ...
... ... @@ -238,7 +238,9 @@
case YHPN_BUTTON:
str = @"BUTTON";
break;
case YHPN_GESTURERECOGNIZER:
str = @"GESTURERECOGNIZER";
break;
default:
break;
}
... ...
... ... @@ -27,6 +27,8 @@
- (void)timeEventStartWithUIControl:(UIControl *)control;
- (void)timeEventEndWithUIControl:(UIControl *)control;
- (void)timeEventStartWithUIGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer;
- (void)timeEventEndWithUIGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer;
+ (void)trackAppClickWithView:(id)targetView UITableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
... ...
... ... @@ -18,6 +18,7 @@
#import "UIWebView+AutoTrack.h"
#import "UITabBarItem+Yoho.h"
#import "UIControl+AutoTrack.h"
#import "UIGestureRecognizer+AutoTrack.h"
#define kYHEventReportQueue @"YHEventReportQueue"
#define kYHEventReporrH5StartKey @"YHEventReporrH5StartKey"
... ... @@ -343,10 +344,55 @@
NSDictionary *param = [YH_EventDataFactory factoryTimeEventDataWithUIControl:control ElapsedTime:elapsedTime];
if (param) {
//[[YH_EventCacheManager sharedInstance] pushPerformanceData:param pointName:YHPN_BUTTON];
[[YH_EventCacheManager sharedInstance] pushPerformanceData:param pointName:YHPN_BUTTON];
}
}
#pragma mark - UIGestureRecognizer performance
- (void)timeEventStartWithUIGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
NSNumber *startTime = @([[NSDate date] timeIntervalSince1970]);
NSString *viewId = [NSString stringWithFormat:@"%@%@",NSStringFromClass([gestureRecognizer class]),startTime];
NSLog(@"startTime = %f",[[NSDate date] timeIntervalSince1970]);
if (startTime==0||IsStrEmpty(viewId)) {
return;
}
if (!gestureRecognizer) {
return;
}
gestureRecognizer.yh_viewId=viewId;
dispatch_async(self.serialQueue, ^{
self.timedEvents[viewId] = startTime;
});
}
- (void)timeEventEndWithUIGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
NSTimeInterval elapsedTime = [self eventElapsedTime:gestureRecognizer.yh_viewId];
//NSLog(@"end = %f",[[NSDate date] timeIntervalSince1970]);
if (elapsedTime==0) {
return;
}
if (!IsStrEmpty(gestureRecognizer.yh_viewId)) {
dispatch_async(self.serialQueue, ^{
[self.timedEvents removeObjectForKey:gestureRecognizer.yh_viewId];
});
}
NSDictionary *param = [YH_EventDataFactory factoryTimeEventDataWithUIGestureRecognizer:gestureRecognizer ElapsedTime:elapsedTime];
//NSLog(@"%@",param);
if (param) {
[[YH_EventCacheManager sharedInstance] pushPerformanceData:param pointName:YHPN_GESTURERECOGNIZER];
}
}
@end
... ...
... ... @@ -91,6 +91,7 @@ typedef NS_ENUM(NSInteger, YHEventReportPointName) {
YHPN_WEBVIEW,//UIWebView 加载时间 // @"WEBVIEW"
YHPN_IMAGEVIEW,//Image (SDWebImage) 加载时间 // @"IMAGE"
YHPN_BUTTON,//Button 响应时间 // @"BUTTON"
YHPN_GESTURERECOGNIZER //UIGestureRecognizer响应时间// @"GESTURERECOGNIZER"
};
typedef NS_ENUM(NSInteger, YHEventReportType) {
... ...
... ... @@ -21,6 +21,8 @@
+(NSDictionary *)factoryTimeEventDataWithUIControl:(UIControl *)control ElapsedTime:(NSTimeInterval)elapsedTime;
+(NSDictionary *)factoryTimeEventDataWithUIGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer ElapsedTime:(NSTimeInterval)elapsedTime;
+ (NSDictionary *)factoryEventAppInfo:(YH_PerformanceAppInfo*)appInfo;
@end
... ...
... ... @@ -66,6 +66,19 @@
return dict;
}
+(NSDictionary *)factoryTimeEventDataWithUIGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer ElapsedTime:(NSTimeInterval)elapsedTime {
NSString *className = NSStringFromClass([gestureRecognizer class]);
if (IsStrEmpty(className)) {
return nil;
}
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[className er_encodedString],kYHEventReportTimeURL,[NSString stringWithFormat:@"%.0f",elapsedTime*1000],kYHEventReportTimeElapsed,@"",kYHEventReportTimeTitle,nil];
return dict;
}
+ (NSDictionary *)factoryEventAppInfo:(YH_PerformanceAppInfo*)appInfo
{
NSDictionary *commonInfo = [NSDictionary dictionaryWithObjectsAndKeys:
... ...