ios 无码统计埋点

ios无码统计埋点总结 一

 第一种方式就是业务代码与统计代码相分离,利用runTime的特性,具体操作如下

定义工具类

@interface WHookUtility : NSObject

+ (void)swizzlingInClass:(Class)cls originalSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector;

@end

 

#import  

+ (void)swizzlingInClass:(Class)cls originalSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector

{

    Class class = cls;

    Method originalMethod = class_getInstanceMethod(class, originalSelector);

    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

    

    BOOL didAddMethod =

    class_addMethod(class,

                    originalSelector,

                    method_getImplementation(swizzledMethod),

                    method_getTypeEncoding(swizzledMethod));

    

    if (didAddMethod) {

        class_replaceMethod(class,

                            swizzledSelector,

                            method_getImplementation(originalMethod),

                            method_getTypeEncoding(originalMethod));

    } else {

        method_exchangeImplementations(originalMethod, swizzledMethod);

    }

}

对于以上的函数需要有以下说明:

1 上面的函数主要作用就是交换两个方法的实现,主要的三句代码是:

    Method originalMethod = class_getInstanceMethod(class, originalSelector);

    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

    method_exchangeImplementations(originalMethod, swizzledMethod);

让我举个栗子��:比如你需要统计一个viewController的生命周期开始和结束,那一搬情况下是不是需要在它的

viewWillAppear viewDidDisappear里面写上一句监听的代码[UMXXXX trackEvent:@"EventName"]

如果在每个页面里面都这样写,那么统计这一块的代码耦合很高,这样很不好。现在有一个解决方法,利用RunTime特性Hook住

viewWillAppear viewDidDisappear 这两个函数。具体实现原理看以下UIViewController+userStatics.h

的demo。

2 除了函数的主要作用的三句代码那class_addMethod class_replaceMethod 的作用是什么呢

  假如你hook的函数并不存在比如随意一个函数viewWillShow 那么这两句代码就稍微有点有作用了,至少你在你hook的

  那个类里面执行[self performSelector:@selector(viewWillShow) withObject:nil]不会崩溃。

  (前提是你已经定义好了交换的函数哦)。总的来说只要你不莫名其妙的写出hook不存在的函数,这两个函数是没用的。

   即使hook了不存在的函数也不会崩溃的。如果你发现这两句代码还有其它的作用,可以交流一下~

 

 现在我们来使用一下以上的类

建一个基于UIViewController的类别

#import "UIViewController+userStatics.h"

#import "WHookUtility.h"

@implementation UIViewController (userStatics)



+ (void)load {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        SEL originalSelector = @selector(viewWillAppear:);

        SEL swizzledSelector = @selector(swiz_viewWillAppear:);

        [WHookUtility swizzlingInClass:[self classoriginalSelector:originalSelector swizzledSelector:swizzledSelector];

        

        SEL originalSelectorDis = @selector(viewWillDisappear:);

        SEL swizzledSelectorDis = @selector(swiz_viewWillDisappear:);

        [WHookUtility swizzlingInClass:[self classoriginalSelector:originalSelectorDis swizzledSelector:swizzledSelectorDis];

        

        


    });

}

 

#pragma mark - Method Swizzling


swiz_viewWillAppear:(BOOL)animated  swiz_viewWillDisappear:(BOOL)animated 是我自己在类别里面定义的函数,

在以上的load函数里面我将它们与 viewWillAppear: viewWillDisappear: 交换了。所以当一个类里面执行viewWillAppear:

它事实上执行的是函数swiz_viewWillAppear:(BOOL)animated 你会发现在函数swiz_viewWillAppear:(BOOL)animated

里面有句代码 [self swiz_viewWillAppear:animated]; 由于交换的原因它事实上执行的是函数viewWillAppear:。


- (void)swiz_viewWillAppear:(BOOL)animated

{

    //插入需要执行的代码

    NSLog(@"我在viewWillAppear执行前偷偷插入了一段代码%@",[self class]);

    

    //不能干扰原来的代码流程,插入代码结束后要让本来该执行的代码继续执行

    [self swiz_viewWillAppear:animated];

}



- (void)swiz_viewWillDisappear:(BOOL)animated

{

    //插入需要执行的代码

    NSString *pageName=NSStringFromClass([self class]);

   

    NSLog(@"结束监听%@",pageName);

    //不能干扰原来的代码流程,插入代码结束后要让本来该执行的代码继续执行

    [self swiz_viewWillDisappear:animated];

}


这种runTime方法也可以用在其它的类比如监听整个app的按钮点击:

#import "UIControl+userStatics.h"

#import "WHookUtility.h"


@implementation UIControl (userStatics)



+ (void)load {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        SEL originalSelector = @selector(sendAction:to:forEvent:);

        SEL swizzledSelector = @selector(swiz_sendAction:to:forEvent:);

        [WHookUtility swizzlingInClass:[self classoriginalSelector:originalSelector swizzledSelector:swizzledSelector];

    });

}


#pragma mark - Method Swizzling

- (void)swiz_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event;

{

    //插入埋点代码

    [self performUserStastisticsAction:action to:target forEvent:event];

    

    [self swiz_sendAction:action to:target forEvent:event];

}


- (void)performUserStastisticsAction:(SEL)action to:(id)target forEvent:(UIEvent *)event;

{

    NSLog(@"\n***hook success.\n[1]action:%@\n[2]target:%@ \n[3]event:%ld"NSStringFromSelector(action), target, (long)event);

}


但是这种方法有一个突出的问题解决不了:无法交换代理函数

你如果想要监听webview的代理函数,tableView的代理函数那就无法用这种方法了。









你可能感兴趣的:(IOS)