iOS 全埋點-頁面瀏覽事件(2)

語言: CN / TW / HK

小知識,大挑戰!本文正在參與“程式設計師必備小知識”創作活動。

寫在前面

傳送門: iOS 全埋點-應用程式退出和啟動(1)
本章節主要是介紹 iOS全埋點序列文章(2)頁面瀏覽事件的埋點分析

UIViewController生命週期

UIViewController在不同的顯示狀態時會回撥不同的方法。如下圖所示:

ViewController生命週期.png

通過UIViewController的整個生命週期可知, 當執行到-viewDidAppear:方法時,表示檢視已經 在螢幕上渲染完成,即頁面已經顯示出來,正等 待使用者進行下一步操作。因此,執行到- viewDidAppear:方法的時間點是觸發頁面瀏覽事件的最佳時機。如果想要實現頁面瀏覽事件的全埋點,就需要使用 iOS的“黑魔法”——Method Swizzling分析的相關技術

定義一個NSObject的分類Swizzler如下所示: ```

import "NSObject+Swizzler.h"

import

@implementation NSObject (Swizzler)

  • (BOOL)sensorsdata_swizzleMethod:(SEL)originalSEL withMethod:(SEL)alternateSEL {

    //獲取原始的方法 Method originalMethod = class_getInstanceMethod(self, originalSEL); if (!originalMethod) { return NO; } //獲取將要交換的方法 Method alternateMethod = class_getInstanceMethod(self, alternateSEL); if (!alternateMethod) { return NO; } //互動兩個方法的實現 method_exchangeImplementations(originalMethod, alternateMethod); //返回yes,方法交換成功 return YES; }

@end

`` 新建一個UIViewController的類別CountData`

``` + (void)load {

[UIViewController sensorsdata_swizzleMethod:@selector(viewDidAppear:) withMethod:@selector(CountData_viewDidAppear:)];

}

//觸發$AppViewScreen事件 - (void)CountData_viewDidAppear:(BOOL)animated {

[self CountData_viewDidAppear:animated];
//首先去判斷當前的黑名單設定中是否包含有(特別需求就是可能某一個頁面不需要統計的情況)
if ([self shouldTrackAppViewScreen]) {

    NSMutableDictionary *prams = [[NSMutableDictionary alloc]init];
    [prams setValue:NSStringFromClass([self class]) forKey:@"$screen_name"];      
    //navigationItem.titleView的優先順序高於navigationItem.title
    NSString *title = [self contentTiltleFromView:self.navigationItem.titleView];
    if (title.length == 0) {
        title = self.navigationItem.title;
    }
    [prams setValue:title forKey:@"$title"];
    [[SensorsAnalyticsSDK sharedInstance]track:@"$AppViewScreen" properties:prams];
}

} ```

遮蔽採集頁面

針對特別需求就是可能某一個頁面不需要統計的情況,這個時候可以配置一個黑名單的plist檔案

黑名單plist.png

```

pragma mark - 檢查黑名單中是否包含目前UIViewController

-(BOOL)shouldTrackAppViewScreen {

static NSSet *blackList = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    //獲取檔案的路徑
    NSString *path = [[NSBundle bundleForClass:SensorsAnalyticsSDK.class] pathForResource:KdataBlackListFileName ofType:nil];
    NSArray *classNames = [NSArray arrayWithContentsOfFile:path];
    NSMutableSet *set = [NSMutableSet setWithCapacity:classNames.count];
    for (NSString *str in classNames) {
        if (NSClassFromString(str)) {
            [set addObject:NSClassFromString(str)];
        }   
    }
    blackList = [set copy];
});

for (Class cla in blackList) {
    //判斷當前控制器是否為黑名單中類或子類
    if ([self isKindOfClass:cla]) {
        return NO;
    }
}
return YES;

} ```

捕獲頁面標題

一般設定頁面title的方式 - 方式1: self.title = @"title"; - 方式2: self.navigationItem.title = @"navigationItem.title"; - 方式3: self.navigationItem.titleView = customTitleView;customTitleView 自定義的View

注意:navigationItem.titleView的優先順序要高於 navigationItem.title。

匹配頁面標題方法如下: ``` -(NSString )contentTiltleFromView:(UIView ) view {

if (view.isHidden) {
    return nil;
}
NSMutableString *elementContent = [NSMutableString string];
if ([view isKindOfClass:[UIButton class]]) {
    UIButton *button = (UIButton *)view;
    NSString *title = button.titleLabel.text;
    if (title.length > 0) {
        [elementContent appendString:title];
    }
}
else if ([view isKindOfClass:[UILabel class]]) {
    UILabel *label = (UILabel *)view;
    NSString *title = label.text;
    if (title.length > 0) {
        [elementContent appendString:title];   
    }
}
else if ([view isKindOfClass:[UITextView class]]) {
    UITextView *textView = (UITextView *)view;
    NSString *title = textView.text;
    if (title.length > 0) {
        [elementContent appendString:title];   
    }
}
else {
    NSMutableArray<NSString *> *elementContentArray = [NSMutableArray array];
    for (UIView *subview in view.subviews) {
        NSString *temp = [self contentTiltleFromView:subview];
        if (temp.length > 0) {
            [elementContentArray addObject:temp];
        }
    }
    if (elementContentArray.count > 0) {
        [elementContent appendString:[elementContentArray componentsJoinedByString: @"-"]];
    }
}
return [elementContent copy];

}

```

存在的問題

  • 應用程式熱啟動時(從後臺恢復),第一個頁面沒有觸發$AppViewScreen事件。原因是這個 頁面沒有再次執行-viewDidAppear:方法。
  • 要求UIViewController的子類不重寫- viewDidAppear:方法,一旦重寫必須呼叫[super viewDidAppear:animated],否則不會觸發 $AppViewScreen事件。原因是直接交換了 UIViewController的-viewDidAppear:方法。