iOS 使用AOP统计打点

作者: 来宝 | 来源:发表于2016-09-21 23:12 被阅读1812次

统计打点是 App 开发里很重要的一个环节,App 的运行状态、用户的各种行为等都需要打点,有不少关于统计的第三方库(如友盟统计)。但是,如果要求在整个项目的所有button里统计用户的点击事件,假如一个项目里面有1000个button,你就要设1000个地方设置统计代码,显然不科学。
有没有一种办法在一个地方进行统计打点,检测整个应用的点击事件?

方案一:使用Runtime的方式追踪点击的按钮

特点:需要对每个button进行tag编号,对手势点击、tableView的点击要单独配置,比较繁琐

方案二:使用面向切面编程AOP对按钮或者页面进行追踪(无需在任何详情页面中做相应配置)

特点:

1、在不修改源代码的情况下,通过运行时给程序添加统一功能的技术,可以用作日志记录,性能统计等
2、无需对每个button进行tag编号,创建button后只需在新建的plist中配置button对应的方法名和对应的事件 ID就行
3、适用于Tap点击手势,使用时设置事件ID,和button的使用方法一样
4、button不支持直接在block里面写事件的方式,但可以在block里面调用方法或者需要统一写成下面的方式

[button addTarget:self  action:@selector(click)forControlEvents:UIControlEventTouchUpInside];

5、适用于tableview的didSelectRowAtIndexPath点击事件,可获取tableView对应的类名、section和row
6、如果是统计tableview的点击事件,根据需要在获取到section和row后加个判断埋点统计

if (section == 0 && row == 1) {
   [MobClick event:eventID];
}

7、如果有特殊需求:某个按钮登录前和登录后记录的事件不一样,需要加判断

if ([eventID isEqualToString:@"xxx"]) {
    [EJServiceUserInfo isLogin]?[MobClick event:eventID]:[MobClick event:@"???"];
   }else{
   [MobClick event:eventID];
 }

以下是具体代码:

(不得不吐槽一下,网上很多博客文章都是转载的,很少有能直接运行的,研究了一整天才弄出来)

这里用到了第三方库:Aspects,用cocoaPods进行集成 pod 'Aspects'

1、创建一个继承与NSObject的EJAspectManager类

EJAspectManager.h

@interface EJAspectManager : NSObject
+(void)trackAspectHooks;
@end

EJAspectManager.m

#import "EJAspectManager.h"
#import "Aspects/Aspects.h"
@implementation EJAspectManager

+(void)trackAspectHooks{

    [EJAspectManager trackViewAppear];
    [EJAspectManager trackBttonEvent];
}


#pragma mark -- 监控统计用户进入此界面的时长,频率等信息
+ (void)trackViewAppear{
    
    [UIViewController aspect_hookSelector:@selector(viewWillAppear:)
                              withOptions:AspectPositionBefore
                               usingBlock:^(id<AspectInfo> info){
                                   
                                   //用户统计代码写在此处
                                   DDLogDebug(@"[打点统计]:%@ viewWillAppear",NSStringFromClass([info.instance class]));
                                   NSString *className = NSStringFromClass([info.instance class]);
                                   DLog(@"className-->%@",className);
                                   [MobClick beginLogPageView:className];//(className为页面名称
                                   
                               }
                                    error:NULL];
    
    
    [UIViewController aspect_hookSelector:@selector(viewWillDisappear:)
                              withOptions:AspectPositionBefore
                               usingBlock:^(id<AspectInfo> info){
                                   
                                   //用户统计代码写在此处
                                   DDLogDebug(@"[打点统计]:%@ viewWillDisappear",NSStringFromClass([info.instance class]));
                                   NSString *className = NSStringFromClass([info.instance class]);
                                   DLog(@"className-->%@",className);
                                   [MobClick endLogPageView:className];
                                   
                               }
                                    error:NULL];
    
    //other hooks ... goes here
    //...
}

#pragma mark --- 监控button的点击事件
+ (void)trackBttonEvent{
    
    __weak typeof(self) ws = self;

    //设置事件统计
    //放到异步线程去执行
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //读取配置文件,获取需要统计的事件列表
        NSString *path = [[NSBundle mainBundle] pathForResource:@"EventList" ofType:@"plist"];
        NSDictionary *eventStatisticsDict = [[NSDictionary alloc] initWithContentsOfFile:path];
        for (NSString *classNameString in eventStatisticsDict.allKeys) {
            //使用运行时创建类对象
            const char * className = [classNameString UTF8String];
            //从一个字串返回一个类
            Class newClass = objc_getClass(className);
            
            NSArray *pageEventList = [eventStatisticsDict objectForKey:classNameString];
            for (NSDictionary *eventDict in pageEventList) {
                //事件方法名称
                NSString *eventMethodName = eventDict[@"MethodName"];
                SEL seletor = NSSelectorFromString(eventMethodName);
                NSString *eventId = eventDict[@"EventId"];
                
                [ws trackEventWithClass:object_getClass(newClass) selector:seletor eventID:eventId];
                [ws trackTableViewEventWithClass:object_getClass(newClass) selector:seletor eventID:eventId];
                [ws trackParameterEventWithClass:object_getClass(newClass) selector:seletor eventID:eventId];
            }
        }
    });
}

#pragma mark -- 监控button和tap点击事件(不带参数)
+ (void)trackEventWithClass:(Class)klass selector:(SEL)selector eventID:(NSString*)eventID{
    
    [klass aspect_hookSelector:selector withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
        
        NSString *className = NSStringFromClass([aspectInfo.instance class]);
        NSLog(@"className--->%@",className);
        NSLog(@"event----->%@",eventID);
        if ([eventID isEqualToString:@"xxx"]) {
            [EJServiceUserInfo isLogin]?[MobClick event:eventID]:[MobClick event:@"???"];
        }else{
            [MobClick event:eventID];
        }
    } error:NULL];
}


#pragma mark -- 监控button和tap点击事件(带参数)
+ (void)trackParameterEventWithClass:(Class)klass selector:(SEL)selector eventID:(NSString*)eventID{
    
    [klass aspect_hookSelector:selector withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo,UIButton *button) {
        
        NSLog(@"button---->%@",button);
        NSString *className = NSStringFromClass([aspectInfo.instance class]);
        NSLog(@"className--->%@",className);
        NSLog(@"event----->%@",eventID);
        
    } error:NULL];
}


#pragma mark -- 监控tableView的点击事件
+ (void)trackTableViewEventWithClass:(Class)klass selector:(SEL)selector eventID:(NSString*)eventID{
    
    [klass aspect_hookSelector:selector withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo,NSSet *touches, UIEvent *event) {
        
        NSString *className = NSStringFromClass([aspectInfo.instance class]);
        NSLog(@"className--->%@",className);
        NSLog(@"event----->%@",eventID);
        NSLog(@"section---->%@",[event valueForKeyPath:@"section"]);
        NSLog(@"row---->%@",[event valueForKeyPath:@"row"]);
        NSInteger section = [[event valueForKeyPath:@"section"]integerValue];
        NSInteger row = [[event valueForKeyPath:@"row"]integerValue];
        
        //统计事件
        if (section == 0 && row == 1) {
            [MobClick event:eventID];
        }
        
    } error:NULL];
}
@end

2、这样我们在appDelegate里面直接调用下面的代码就可以达到全局统计的目的了!

[EJAspectManager trackAspectHooks];

3、上面涉及到的EventPlist是新创建的plist文件,设置方式如下:

B091368F-0F17-4671-9A5E-F6527BA5CD31.png

需要demo的同学麻烦打个赏(金额随便给),留个邮箱,我会发到你们邮箱里,谢谢支持!

相关文章

  • iOS使用AOP统计打点

    文章来源 方案一:使用Runtime的方式追踪点击的按钮 特点:需要对每个button进行tag编号,对手势点击、...

  • iOS 使用AOP统计打点

    统计打点是 App 开发里很重要的一个环节,App 的运行状态、用户的各种行为等都需要打点,有不少关于统计的第三方...

  • iOS打点

    1.iOS 关于统计打点2.使用runtime 实现iOS自动打点统计3.iOS 统计打点那些事4.Aspects

  • iOS 下的AOP编程之打点统计

    概念 AOP编程也叫面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的...

  • 前端iOS打点统计的AOP技术实践

    前言 近期前端移动组因项目需求,需要在用户行为上进行打点统计,但由于部分早期SDK在初始设计时并未考虑到日志记录这...

  • iOS 关于统计打点

    之前到别人的一篇博客上评论了下他的打点统计方法,后来很多人来问我,,所以还是决定写下这篇文章。第一次写博客,不...

  • iOS 统计打点工作记录

    iOS 统计打点记录 统计打点,意思就是在某个点击事件,或者函数调用上做一个记录,看一下这个函数调用的情况,简单的...

  • 打点统计

    打点 百度统计后台 PV/UV PV(Page View):页面的访问次数,就算是刷新一次都会计算在内 UV(Un...

  • 统计打点

    http://www.cocoachina.com/ios/20150911/13410.html

  • iOS AOP简单实现日志打点[Aspects]

    前言:本文简述简单使用Aspects实现自动日志打点,仅是简单使用,深层次需要大神来深究 一、知名AOP库 Asp...

网友评论

  • 小码僧:大佬你好,刚刚打赏完毕!需要这个Demo,谢谢,发我邮箱: cimain@qq.com
    小码僧:@来宝 没有收到 难道发错了:joy: 邮箱是 cimain@qq.com
    来宝:已发邮箱
  • zhlv:大赞,最近在做这方面的需求,方便发我个demo么 347303844@qq.com
    来宝:@梦回蓝桥 你牛逼你别看啊
    梦回蓝桥:打个屁赏,这种文章来骗小白的吗?基本照抄别人的还好意思要赏金,要点碧莲
    来宝:@无赖_V 给个打赏先
  • zhlv:求个demo.谢谢 347303844@qq.com
    来宝:@小召95 打赏发demo
  • Stone_熊小叔:大神,最近在做这方面的需求,方便发我个demo么 847677085@qq.com
  • CJ_NeverStop:您好,求个 demo hrlkw@163.com 谢谢谢谢~~:relaxed: :relaxed:
  • 小Jerry:874659527@qq.com:smile:
  • 072fc8deeb7e:为什么点击事件获取不到呢?都是提示Unable to find selector
  • 84f6f5b32b75:怎么传递参数啊? 有点懵了
  • 噜噜土豆:求demo,最近在做这个,灰常感谢 614125682@qq.com
  • 97ca5136172a:Aspects: Unable to find selector -[ViewController redBtnClick]. 这个是什么原因呢?
    072fc8deeb7e:把[ws trackEventWithClass:object_getClass(newClass) selector:seletor eventID:eventId];改成[ws trackTableViewEventWithClass:newClass selector:seletor eventID:eventId];
  • zhou某某:714930878@qq.com我的邮箱 能给我一份demo吗 谢谢
  • 79770bd43632:想请教下更复杂的情况下埋点,比如页面有个轮播图,我在点击时添加统计并将,点击后跳转页面的id和轮播图的顺序一起传给统计后台,甚至整段数据都传过去,如何做到统一处理这样的逻辑,[Track trackEvent:eventName label:data parameters:@{@"key":@"value"}];
  • 紫荆秋雪_文:正在做这个,大神来一发demo吧,zjqx1991@163.com
  • huanghy:你好有demo,可以提供一下吗?邮箱turn__back@163.com
  • 03a336dff0ec:跪求demo啊,492843636@qq.com
  • e0cc624d3b51:能否发一下DEMO,谢谢。767043152@qq.com
  • _Miyo:最近在做这个需求,能否给个demo?谢了

    675026851@qq.com
  • 一个人的思考: 你好,我尝试集成一下,页面打印正常,按钮触发事件没有相应的回调:grin:
  • 邹邹_ZZ:599052444@qq.com 求demo :pray:
  • 奋斗的郅博:有demo吗来一个 邮箱1791141072@qq.com
  • 949f31d32f50:可以给个demo吗,正在做这个... bxlook@outlook.com
  • 891811bcc4fd:大赞,最近在做这方面的需求,方便发我个demo么 905578301@qq.com
  • 狼叔妹:好东西,能提供个demo?
    zhou某某:@来宝 714930878@qq.com我的邮箱 能给我一份demo吗 谢谢
    狼叔妹:463803387@qq.com我的qq邮箱!非常谢谢啊!
    来宝:@978e7829c0ce 给个邮箱,回去发给你

本文标题:iOS 使用AOP统计打点

本文链接:https://www.haomeiwen.com/subject/dyxpettx.html