美文网首页iOS开发知识小集
ios -无埋点用户行为数据收集

ios -无埋点用户行为数据收集

作者: child_cool | 来源:发表于2018-11-19 10:21 被阅读45次
    af 的方法交换处理
    static inline void af_swizzleSelector(Class class, SEL originalSelector, SEL swizzledSelector) {
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        if (class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
            class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    
    }
    
    

    数据采集

    • uiviewcontroller的生命周期,用于测算页面停留时间加载时间等

    1.viewDidAppear上报页面进入事件。
    2.viewDidDisappear上报页面退出事件
    即可得出用户访问页面路径,两个事件时间戳之差即为用户在页面停留的时间。

    统计数据字段
    1.PAGE_ID,当前页面的标识。 【一般用类名】
    2.SOURCE_ID,当前页面的前一个页面的标识。【获取上一个页面的类名】
    3.TYPE_ID,当前页面一些关键信息。
    4.TIMESTAMP,当前事件生成的时间戳。
    5.页面进入和退出的事件,均上报上述的数据结构。
    6.跟进上面的记录通过计算可以获得VC的路径

    + (void)install {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            [Tool replaceImplementationOfKnownSelector:@selector(viewDidAppear:) onClass:[self class]];
            [Tool replaceImplementationOfKnownSelector:@selector(viewDidDisappear:) onClass:[self class]];
        });
    }
    
    - (void)br_viewDidAppear:(BOOL)animated {
        NSLog(@"[%@--%@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
        [self br_viewDidAppear:animated];
    }
    
    
    - (void)br_viewDidDisappear:(BOOL)animated {
        NSLog(@"[%@--%@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
        [self br_viewDidDisappear:animated];
    }
    
    • UIControl(UISwitch,UIStepper,UISegmentedControl, UINavigationButton,UISlider,UIButton)类控件的点击事件
    + (void)install {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            [Tool replaceImplementationOfKnownSelector:@selector(sendAction:to:from:forEvent:) onClass:[self class]];
        });
    }
    
    - (BOOL)br_sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event {
        
        NSLog(@"=====");
        
        return [self br_sendAction:action to:target from:sender forEvent:event];
    }
    
    • UIView上的GestureRecognizer触摸事件
     在uiview的分类中添加target
    #import <objc/runtime.h>
    + (void)startTracker {
        Method addGestureRecognizerMethod = class_getInstanceMethod(self, @selector(addGestureRecognizer:));
        Method ddAddGestureRecognizerMethod = class_getInstanceMethod(self, @selector(dd_addGestureRecognizer:));
        method_exchangeImplementations(addGestureRecognizerMethod, ddAddGestureRecognizerMethod);
    }
    
    - (void)test:(UIGestureRecognizer *)gest {
        
    }
    
    - (void)dd_addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
        
        [gestureRecognizer addTarget:self action:@selector(test:)];
        
        [self dd_addGestureRecognizer:gestureRecognizer];
    
    
    • UICollectionView和UITableView的cell点击事件
    @implementation UITableView (DDAutoTracker)
    
    + (void)startTracker {
        Method setDelegateMethod = class_getInstanceMethod(self, @selector(setDelegate:));
        Method ddSetDelegateMethod = class_getInstanceMethod(self, @selector(dd_setDelegate:));
        method_exchangeImplementations(setDelegateMethod, ddSetDelegateMethod);
    }
    
    - (void)dd_setDelegate:(id <UITableViewDelegate>)delegate {
        
        //只监听UITableView
        if (![self isMemberOfClass:[UITableView class]]) {
            return;
        }
        
        [self dd_setDelegate:delegate];
        
        if (delegate) {
            Class class = [delegate class];
            SEL originSelector = @selector(tableView:didSelectRowAtIndexPath:);
            SEL swizzlSelector = NSSelectorFromString(@"dd_didSelectRowAtIndexPath");
            BOOL didAddMethod = class_addMethod(class, swizzlSelector, (IMP)dd_didSelectRowAtIndexPath, "v@:@@");
            if (didAddMethod) {
                Method originMethod = class_getInstanceMethod(class, swizzlSelector);
                Method swizzlMethod = class_getInstanceMethod(class, originSelector);
                method_exchangeImplementations(originMethod, swizzlMethod);
            }
        }
    }
    
    void dd_didSelectRowAtIndexPath(id self, SEL _cmd, id tableView, NSIndexPath *indexpath) {
        SEL selector = NSSelectorFromString(@"dd_didSelectRowAtIndexPath");
        ((void(*)(id, SEL,id, NSIndexPath *))objc_msgSend)(self, selector, tableView, indexpath);
        
        UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexpath];
        
        NSString *targetString = NSStringFromClass([self class]);
        NSString *actionString = NSStringFromSelector(_cmd);
        
        NSString *eventId = [NSString stringWithFormat:@"%@&&%@",targetString,actionString];
        NSDictionary *infoDictionary = [cell ddInfoDictionary];
        
        [[DDAutoTrackerOperation sharedInstance] sendTrackerData:eventId
                                                            info:infoDictionary];
    }
    
    @end
    
    @implementation UICollectionView (DDAutoTracker)
    
    + (void)startTracker {
        Method setDelegateMethod = class_getInstanceMethod(self, @selector(setDelegate:));
        Method ddSetDelegateMethod = class_getInstanceMethod(self, @selector(dd_setDelegate:));
        method_exchangeImplementations(setDelegateMethod, ddSetDelegateMethod);
    }
    
    - (void)dd_setDelegate:(id <UICollectionViewDelegate>)delegate {
        
        //只监听UICollectionView
        if (![self isMemberOfClass:[UICollectionView class]]) {
            return;
        }
        
        [self dd_setDelegate:delegate];
        if (delegate) {
            Class class = [delegate class];
            SEL originSelector = @selector(collectionView:didSelectItemAtIndexPath:);
            SEL swizzlSelector = NSSelectorFromString(@"dd_didSelectItemAtIndexPath");
            BOOL didAddMethod = class_addMethod(class, swizzlSelector, (IMP)dd_didSelectItemAtIndexPath, "v@:@@");
            if (didAddMethod) {
                Method originMethod = class_getInstanceMethod(class, swizzlSelector);
                Method swizzlMethod = class_getInstanceMethod(class, originSelector);
                method_exchangeImplementations(originMethod, swizzlMethod);
            }
        }
    }
    
    void dd_didSelectItemAtIndexPath(id self, SEL _cmd, id collectionView, NSIndexPath *indexpath) {
        SEL selector = NSSelectorFromString(@"dd_didSelectItemAtIndexPath");
        ((void(*)(id, SEL,id, NSIndexPath *))objc_msgSend)(self, selector, collectionView, indexpath);
        
        UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexpath];
        
        NSString *targetString = NSStringFromClass([self class]);
        NSString *actionString = NSStringFromSelector(_cmd);
        
        NSString *eventId = [NSString stringWithFormat:@"%@&&%@",targetString,actionString];
        NSDictionary *infoDictionary = [cell ddInfoDictionary];
        
        [[DDAutoTrackerOperation sharedInstance] sendTrackerData:eventId
                                                            info:infoDictionary];
    }
    
    @end
    
    • UITabBar、UIAlertView、UIActionSheet等的点击事件
    hook delegate 然后hook点击事件的代理方法
    唯一标识 使用title message 按钮内容 再加上路径
    
    ios 9
    if ([NSStringFromClass([view class]) isEqualToString:@"_UIAlertControllerView"]) {
        Ivar ivar = class_getInstanceVariable([view class], "_actionViews");
        NSMutableArray *actionviews =  object_getIvar(view, ivar);
        for (UIView *actionview in actionviews) {
            CGPoint point = [gesture locationInView:actionview];
            if ([NSStringFromClass([actionview class]) isEqualToString:@"_UIAlertControllerActionView"] &&
                point.x > 0 && point.x < CGRectGetWidth(actionview.bounds) &&
                point.y > 0 && point.y < CGRectGetHeight(actionview.bounds) &&
                gesture.state == UIGestureRecognizerStateBegan) {
               .........  //进行埋点操作
            }
        }
    }
    
    ios 10
    if ([NSStringFromClass([view class]) isEqualToString:@"_UIAlertControllerInterfaceActionGroupView"]) {
        NSMutableArray *targets = [gesture valueForKey:@"_targets"];
        id targetContainer = targets[0];
        id targetOfGesture = [targetContainer valueForKey:@"_target"];
        if ([targetOfGesture isKindOfClass:[NSClassFromString(@"UIInterfaceActionSelectionTrackingController") class]]) {
            Ivar ivar = class_getInstanceVariable([targetOfGesture class], "_representationViews");
            NSMutableArray *representationViews =  object_getIvar(targetOfGesture, ivar);
            for (UIView *representationView in representationViews) {
                CGPoint point = [gesture locationInView:representationView];
                if ([NSStringFromClass([representationView class]) isEqualToString:@"_UIInterfaceActionCustomViewRepresentationView"] &&
                    point.x > 0 && point.x < CGRectGetWidth(representationView.bounds) &&
                    point.y > 0 && point.y < CGRectGetHeight(representationView.bounds) &&
                    gesture.state == UIGestureRecognizerStateBegan) {
                    .........  //进行埋点操作
                    }
                }
        }
    }
    
    #import <objc/runtime.h>
    #import <objc/message.h>
    #import "DDAutoTrackerOperation.h"
    #import "NSObject+DDAutoTracker.h"
    
    @implementation UIAlertView (test)
    
    + (void)load {
        [self startTracker];
    }
    
    + (void)startTracker {
        Method setDelegateMethod = class_getInstanceMethod(self, @selector(setDelegate:));
        Method ddSetDelegateMethod = class_getInstanceMethod(self, @selector(dd_setDelegate:));
        method_exchangeImplementations(setDelegateMethod, ddSetDelegateMethod);
    }
    
    - (void)dd_setDelegate:(id <UIAlertViewDelegate>)delegate {
        
        //只监听UICollectionView
        if (![self isMemberOfClass:[UIAlertView class]]) {
            return;
        }
        
        [self dd_setDelegate:delegate];
        if (delegate) {
            Class class = [delegate class];
            SEL originSelector = @selector(alertView:clickedButtonAtIndex:);
            SEL swizzlSelector = NSSelectorFromString(@"br_clickedButtonAtIndex");
            BOOL didAddMethod = class_addMethod(class, swizzlSelector, (IMP)br_clickedButtonAtIndex, "v@:@@");
            if (didAddMethod) {
                Method originMethod = class_getInstanceMethod(class, swizzlSelector);
                Method swizzlMethod = class_getInstanceMethod(class, originSelector);
                method_exchangeImplementations(originMethod, swizzlMethod);
            }
        }
    }
    
    
    
    void br_clickedButtonAtIndex(id self, SEL _cmd, id alertView, NSInteger buttonIndex) {
        SEL selector = NSSelectorFromString(@"br_clickedButtonAtIndex");
        ((void(*)(id, SEL,id, NSInteger))objc_msgSend)(self, selector, alertView, buttonIndex);
    
        NSLog(@"hook 点击的第几个 %ld", buttonIndex);
     }
    
    
    @end
    
    • RN采集

    • app内OpenURL 主要是应用直接的跳转回调等

    hook UIApplicationDelegate协议对象,直接hook appdelegate或者写它的分类,可能会失败(原因:某些用户可能会自定义文件名,默认加前缀,XXAppdelegate)
    还有其生命周期方法一并hook
    
    需要判断方法是否实现,未实现添加实现(本人一直操作失败),已实现进行交换
    
    application:handleOpenURL:
    application:openURL:options:
    
    • UItextview uitextfiled uisearchbar
      根据代理处理

    数据缓存

    • 默认的存储模式【个人想法内存】
    • 考虑用户杀掉程序或者崩溃时数据如何持久化存储
    • 持久化保存方式【json?plist?db?】哪种性能更好?
    • 文件量限制,时间限制 【记录10条数据就开始上传一次,或者1分钟一次】
    • 缓存格式?

    构建json协议

    传输数据

    相关文章

      网友评论

        本文标题:ios -无埋点用户行为数据收集

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