|
|
//
|
|
|
// 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 |
...
|
...
|
|