前言
隨著科技以及業務的發展,手勢的應用也越來越普及,因此對於資料採集,我們要考慮如果通過全埋點來實現手勢的採集。
一、手勢識別器
蘋果為了降低開發者在手勢事件處理方面的開發難度,定義了一個抽象類 UIGestureRecognizer 來協助開發者。UIGestureRecognizer 是具體手勢識別器的抽象基類,它定義了一組可以為所有具體手勢識別器配置的常見行為。它還可以通過設定委託(即實現了 UIGestureRecognizerDelegate 協議的物件),來支援對某些行為進行更細粒度的定製。
手勢識別器必須被新增在一個特定的檢視上(比如 UILabel、UIImageView 等控制元件),即需要通過呼叫 UIView 類中的 - addGestureRecognizer: 方法進行新增。手勢識別器也是用了 Target-Action 設計模式。當我們為一個手勢識別器新增一個或者多個 Target-Action 後,在檢視上進行觸控操作時,一旦系統識別了該手勢,就會向所有的 Target 物件傳送訊息,並執行 Action 方法。雖然手勢識別器和 UIControl 類一樣,都是使用了 Target-Action 設計模式,但是手勢識別器並不會將訊息交由 UIApplication 物件來進行傳送。因此,我們無法使用與 UIControl 控制元件相同的處理方式,即通過響應者鏈的方式來實現對手勢操作的全埋點。
由於 UIGestureRecognizer 是一個抽象基類,所以它並不會處理具體的手勢。因此,對於輕拍(UITapGestureRecognizer)、長按(UILongPressGestureRecognizer)等具體的手勢觸控事件,需要使用相應的子類即具體的手勢識別器進行處理。
常見的具體手勢識別器有:
- UITapGestureRecognizer:輕拍手勢
- UILongPressGestureRecognizer:長按手勢
- UIPinchGestureRecognizer:捏合(縮放)手勢
- UIRotationGestureRecognizer:旋轉手勢
- UISwipeGestureRecognizer:輕掃手勢
- UIPanGestureRecognizer:平移手勢
- UIScreenEdgePanGestureRecognizer:螢幕邊緣平移手勢
給上面所有的具體手勢識別器新增 Target-Action 的方法都是相同的,常見的主要是通過以下的兩個方法進行新增。
-
initWithTarget:target action:
-
addTarget:action:
詳細的定義參考如下:
/** 指定初始化方法 通過新增一個 Target-Action 進行初始化, 當初始化的手勢識別器物件,識別到觸控手勢時,會向 Target 物件傳送訊息,即呼叫 Action 方法 @param target 需要傳送訊息的 Target 物件 @param action 向 Target 物件傳送的訊息,即方法名 @return 初始化的物件 */ - (instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action NS_DESIGNATED_INITIALIZER; /** 向一個手勢識別器新增一個 Target-Action 可以多次呼叫此方法,給一個手勢識別器物件新增多個 Target-Action 。 如果已經新增了一個 Target-Action,再次新增相同的 Target-Action 時,會被忽略。 @param target 需要傳送訊息的 Target 物件 @param action 向 Target 物件傳送的訊息,即方法名 */ - (void)addTarget:(id)target action:(SEL)action;
在實際的開發過程中,使用比較多的是 UITapGestureRecognizer 和 UILongPressGestureRecognizer 兩個手勢識別器,這兩個手勢識別器分別是處理輕拍手勢和長按手勢。
二、手勢全埋點
在資料採集中,一般只需要採集常見控制元件(UILabel、UIImageView)的輕拍和長按手勢。
所以,我們分別介紹如何實現控制元件輕拍和長按手勢的全埋點。
2.1 UITapGestureRecognizer 全埋點
為了採集控制元件的輕拍手勢,我們可以通過 Method Swizzling 交換 UITapGestureRecognizer 類的新增 Target-Action 的方法,從而可以新增一個新的 Target-Action,並在新新增的 Action 方法中觸發 $AppClick 事件,從而就可以達到採集控制元件輕拍手勢全埋點的效果。
在 UITapGestureRecognizer 類中,用於新增 Target-Action 方法有兩個:
• - initWithTarget:action:
• - addTarget:action:
因此,我們需要對這兩個方法分別進行交換。
第一步:建立 UITapGestureRecognizer 分類 UIGestureRecognizer+SensorsData,並實現 +load 類方法,在 + load方法中,進行 - initWithTarget:action: 和 - addTarget:action: 的方法交換。
#import "UIGestureRecognizer+SensorsData.h"
#import "NSObject+SASwizzler.h"
#import "SensorsAnalyticsSDK+Track.h"
@implementation UITapGestureRecognizer (SensorsData)
+ (void)load {
[UITapGestureRecognizer sensorsdata_swizzleMethod:@selector(sensorsdata_initWithTarget:action:) withMethod:@selector(initWithTarget:action:)];
[UITapGestureRecognizer sensorsdata_swizzleMethod:@selector(addTarget:action:) withMethod:@selector(sensorsdata_addTarget:action:)];
}
- (instancetype)sensorsdata_initWithTarget:(id)target action:(SEL)action {
[self sensorsdata_initWithTarget:target action:action];
[self addTarget:target action:action];
return self;
}
- (void)sensorsdata_addTarget:(id)target action:(SEL)action {
[self sensorsdata_addTarget:target action:action];
// 新增 Target-Action, 用於觸發 $AppClick 事件
[self sensorsdata_addTarget:self action:@selector(sensorsdata_trackTapGestureAction:)];
}
- (void)sensorsdata_trackTapGestureAction:(UITapGestureRecognizer *)sender {
[[SensorsAnalyticsSDK sharedInstance] trackAppClickWithView:view properties:nil];
}
第二步:在 - sensorsdata_trackTapGestureAction: 方法中判斷要採集的控制元件
- (void)sensorsdata_trackTapGestureAction:(UITapGestureRecognizer *)sender {
UIView *view = sender.view;
// 暫定只採集 UILabel 和 UIImageView
BOOL isTrackClass = [view isKindOfClass:UILabel.class] || [view isKindOfClass:UIImageView.class];
if (!isTrackClass) {
return;
}
[[SensorsAnalyticsSDK sharedInstance] trackAppClickWithView:view properties:nil];
}
第三步:測試驗證
{
"event" : "$AppClick",
"time" : 1648892963385,
"propeerties" : {
"$model" : "x86_64",
"$manufacturer" : "Apple",
"$element_type" : "UIImageView",
"$lib_version" : "1.0.0",
"$os" : "iOS",
"$app_version" : "1.0",
"$screen_name" : "ViewController",
"$os_version" : "15.2",
"$lib" : "iOS"
}
}
2.2 UILongPressGestureRecognizer 全埋點
對於 UILongPressGestureRecognizer 來說,其實現邏輯與 UITapGestureRecognizer 基本上是相同的。