ક્લાયન્ટ-સાઇડ ઇવેન્ટ ટ્રેકિંગ મોટેભાગે ત્રણ પ્રકારનું છે:

  • કોડ-આધારિત ટ્રેકિંગ
  • વિઝ્યુઅલ ટ્રેકિંગ
  • સ્વચાલિત ટ્રેકિંગ

આ લેખ મુખ્યત્વે સ્વચાલિત ટ્રેકિંગ પાછળના વિચારો અને અમલની પ્રક્રિયા રજૂ કરે છે.

1. કોડ-આધારિત ટ્રેકિંગ

કોડ-આધારિત ટ્રેકિંગ એટલે ટ્રેક કરવાના દરેક બિંદુએ ઇન્ટરફેસ બોલાવી ઇવેન્ટ ડેટા સીધો અપલોડ કરવો. મોટાભાગની તૃતીય-પક્ષ ઍનલિટિક્સ સેવાઓ અનુકૂળ api આપે છે.

પણ ટ્રેકિંગ કોડ વ્યવસાય તર્કમાં ફેલાય અને તેની સાથે ચુસ્ત રીતે જોડાય છે. સ્ક્રીન કે પ્રવાહ બદલાય ત્યારે જૂની ઇવેન્ટનું શું કરવું અથવા નવી જોઈએ કે નહીં તે અસ્પષ્ટ રહે છે. ઇવેન્ટ વધતાં ફેલાયેલા કોડની જાળવણી દુઃસ્વપ્ન બને છે. મૅક્રો અને ફૅક્ટરી વર્ગ કોડ સરળ કરે, પણ મૂળ સ્થિતિ બદલતા નથી.

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    // 埋点
    APE(kEvent4001);
}

2. વિઝ્યુઅલ ટ્રેકિંગ

વિઝ્યુઅલ ટ્રેકિંગમાં દૃશ્ય સાધનથી સંગ્રહ બિંદુ ગોઠવાય છે. ક્લાયન્ટ ગોઠવણી આપમેળે પાર્સ કરી ઇવેન્ટ મોકલે છે, જેથી કહેવાતું “ચિહ્નવિહોણું ટ્રેકિંગ” બને છે. પ્રતિનિધિ ઓપન-સોર્સ ઉકેલ Mixpanel છે.

3. સ્વચાલિત ટ્રેકિંગ

સ્વચાલિત અથવા ફુલ-ઇવેન્ટ ટ્રેકિંગનો અર્થ ઇન્સ્ટ્રુમેન્ટેશન બિલકુલ નથી એવો નથી. તે બધી ઇવેન્ટ એકત્ર કરીને મોકલે છે અને ઉપયોગી ડેટા સર્વર ગાળે છે.

વધુ સુધારા માટે સર્વર ગોઠવણી ફાઇલ મોકલી શકે, જેથી ક્લાયન્ટ પોતે ઇવેન્ટ ગાળે.

KPI માટે, મેં આ વિચાર પર ચક્ર ફરી બનાવ્યું અને WKTrackingData બનાવ્યું.

અહીં WKTrackingData અમલમાં આવેલી સમસ્યાઓ અને વિચારો નોંધ્યા છે.

અમલનો વિચાર સરળ છે. કોડ આ રીતે ગોઠવાયેલો છે:

મૂળ WKTrackingData સ્થાપત્ય: મૅનેજર, ઇવેન્ટ પાથ અને AOP મોડ્યુલ

અહીં WKTrackingDataManager બધું ડેટા સંચાલન અને ઇવેન્ટ ટ્રેકિંગ ગોઠવણી સંભાળે છે.

ઇવેન્ટ ટ્રેકિંગ ગોઠવણીનું મૂળ ઉપયોગ ઉદાહરણ

WKTrackingDataViewPathHelper બનાવે છે event_path મૂલ્યો.

AOP દરેક ઇવેન્ટ ટ્રેક કરવા જવાબદાર મોડ્યુલ છે.

વિગતવાર ઉપયોગ માટે GitHub જુઓ.

ઇવેન્ટને અનન્ય રીતે કેવી રીતે ઓળખવી?

બે પ્રશ્ન છે: ઇવેન્ટ કેવી રીતે રજૂ કરવી અને તેની અનન્યતા કેવી રીતે સુનિશ્ચિત કરવી?

ઇવેન્ટ રજૂ કરવી

ઇવેન્ટ event_pathથી રજૂ થાય છે. ઇવેન્ટ શરૂ કરનાર responder માટે મૂળ વિચાર તેની રિસ્પોન્ડર શૃંખલા અનુસરી તેનો path બનાવવાનો છે.

બનેલો રિસ્પોન્ડર path આવો છે:

"event_path" = "#buttonClick:#UIButton#UIButton[0]#UIView[0]#ViewController#...#UIApplication#AppDelegate
ઇવેન્ટની અનન્ય ઓળખ

કેટલીક વ્યવસાય પરિસ્થિતિમાં સમાન button કે બીજું નિયંત્રણ તેની ગુણધર્મો બદલાતાં જુદી વ્યવસાય ઇવેન્ટ દર્શાવે છે.

ઉદાહરણ તરીકે, હોમ સ્ક્રીનનું button સાઇન આઉટ હોય ત્યારે સાઇન ઇન કરવા ટૅપ કરો અને સાઇન ઇન પછી ઓળખ ચકાસણી બાકી હોય તો ઓળખ ચકાસો બતાવે.

સમાન buttonનું વ્યૂ વૃક્ષ બદલાયું નથી, તેથી તેનો રિસ્પોન્ડર path સમાન રહે છે.

આવા કિસ્સામાં UISwitchની ચાલુ/બંધ સ્થિતિ, UISegmentedControlનું indexSelect, UIStepper અને UITableView અથવા UICollectionViewના cell ઇન્ટરૅક્શન પણ આવે છે.

આ માટે WKTrackingData નિયંત્રણના પસંદ ગુણધર્મો ઉમેરી event_path બનાવે છે. પરિણામે event_path આવું બને છે:

"event_path" = "#buttonClick:#UIButton#UIButton[0]#UIView[0]#ViewController#...#UIApplication#AppDelegate#currentTitle=Button#state=1#enabled=1#selected=0";
વ્યવસાય-વિશિષ્ટ વિસ્તરણ

બીજી પરિસ્થિતિ વિચારો: હોમ સ્ક્રીન પર banner કેરોઝલ.

દરેક banner સ્થાનની છબી અને ગંતવ્ય url સર્વર આપે છે અને સ્થાન ગોઠવી શકાય છે.

દરેક indexના bannerનું ગંતવ્ય સ્થિર નથી. 0 સ્થાનની ઇવેન્ટ ફક્ત event_pathથી જાણી શકાતી નથી.

અનન્ય ઓળખ માટે url જેવા વ્યવસાય-વિશિષ્ટ પેરામીટર ઉમેરવા પડે.

WKTrackingData વ્યવસાય પેરામીટર વિસ્તરણ આપે છે, જેથી કૉલર પોતાના પેરામીટર ઉમેરી શકે:

વ્યવસાય પેરામીટરથી ઇવેન્ટ વિસ્તરણનું મૂળ કોડ ઉદાહરણ

ટ્રેક ન કરવા જેવાં નિયંત્રણ wk_ignoreTrackingથી બાકાત કરી શકાય:

self.slider.wk_ignoreTracking = YES;

અન્ય સમસ્યાઓ

જુદી ઇવેન્ટ ટ્રેક કરવા WKTrackingData ઍસ્પેક્ટ-ઓરિએન્ટેડ પદ્ધતિથી runtime વડે સીધાં મેથડ swizzle કરે છે.

પણ UIAlertView, UIActionSheet, UITableView અને UICollectionView ટ્રેક કરવા તેમનાં delegate મેથડ swizzle કરવા પડે.

  • જો delegate class મેથડ અમલ કરે તો સીધું swizzle કરો.

  • જો delegate class અમલ ન કરે છતાં ઇવેન્ટ ટ્રેક કરવી હોય તો સંબંધિત delegate methodનો અમલ જાતે ઉમેરવો પડે.

- (void)wk_swizzleInstanceSelector:(SEL)origSel_ fromClass:(Class)fromClass replaceSelector:(SEL)replaceSel_ originNotImp:(SEL)notImpSel_ {
    Method originalMethod = class_getInstanceMethod([self class], origSel_);
    if (originalMethod) {
        [self wk_swizzleInstanceSelector:origSel_ fromClass:fromClass replaceSelector:replaceSel_];
    } else {
        Method notImpMethod = class_getInstanceMethod(fromClass, notImpSel_);
        // 如果delegateClass没有实现 origSel_ 方法
        // 则给delegateClass的 origSel_ 添加 orginReplaceMethod 的实现
        BOOL didAddNotImpMethod =
        class_addMethod([self class],
                        origSel_,
                        method_getImplementation(notImpMethod),
                        method_getTypeEncoding(notImpMethod));
        if (didAddNotImpMethod) {
            NSLog(@"%@ did add not imp method %@" , NSStringFromClass([self class]) , NSStringFromSelector(notImpSel_));
        }
    }
}

અમલ અહીં છે

વ્યવહારમાં UITableView અને UICollectionViewના delegate ઑબ્જેક્ટ મેથડ અમલ ન કરે ત્યારે tableView:didSelectRowAtIndexPath:માં જાતે implementation ઉમેરવાથી પણ તે ચાલતું નહોતું.

પહેલાં સામાન્ય tableView:didSelectRowAtIndexPath: કૉલ સ્ટૅક જુઓ:

ટેબલ-વ્યૂ પંક્તિ પસંદગી માટેનો મૂળ ડિબગર કૉલ સ્ટૅક

અહીં UITableView ટૅપના જવાબમાં ક્રમે ચાર મેથડ બોલાવે છે એક cell માટે:

  • પગલું 1. [UITableView _userSelectRowAtPendingSelectionIndexPath:]
  • પગલું 2. [UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:]
  • પગલું 3. [UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect:]
  • પગલું 4. [TableViewController tableView:didSelectRowAtIndexPath:]

ક્રમ બતાવે છે કે UITableView પહેલાં આ delegate classનું tableView:didSelectRowAtIndexPath: બોલાવતાં પહેલાં પોતાનું _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect: ચલાવે છે.

આ મેથડ પર breakpoint મૂકો: _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect: અને assembly જુઓ:

ડેલિગેટ મેથડ શાખા દર્શાવતું મૂળ assembly દૃશ્ય

જો delegate class અમલ કરે tableView:didSelectRowAtIndexPath:, તો બધું સામાન્ય અને tableView:didSelectRowAtIndexPath: કૉલ પૂર્ણ થાય છે.

પણ જો delegate class અમલ ન કરે tableView:didSelectRowAtIndexPath:, તો જાતે tableView:didSelectRowAtIndexPath:નું implementation ઉમેર્યા છતાં tableView:didSelectRowAtIndexPath:ને જવાબ આપવાનો પ્રયાસ થતો નથી.

assembly અનુસરતાં સીધો બીજા instruction પર jump દેખાય છે.

WKTrackingData અહીં જુદો રસ્તો લઈને સીધું [UITableView _userSelectRowAtPendingSelectionIndexPath:] swizzle કરે છે (UICollectionView માટે સમાન). તેથી UITableView અને UICollectionViewના delegate ઑબ્જેક્ટ સંબંધિત cell ઇવેન્ટ મેથડ અમલ ન કરે ત્યારે પણ ઇન્ટરૅક્શન ટ્રેક થાય છે.

4. અંતિમ વિચાર

સમાન ઇવેન્ટ માટે અનેક event_path

થોડા જુદા સ્ક્રીનવાળી અનેક પ્રકાશિત આવૃત્તિ હોય તો સમાન ઇવેન્ટને અનેક event_path હોઈ શકે.

વ્યવહારમાં આ મૅપિંગ માટે સર્વર-સાઇડ સહકર્મીઓનો સહકાર જોઈએ; તેને બૅકએન્ડમાં ગોઠવી શકાય એવું બનાવી શકાય.

ઇવેન્ટ ઍનલિટિક્સ સુધારવું

અગાઉના વ્યવસાય-વિશિષ્ટ વિસ્તરણ વિભાગે વ્યવસાય પેરામીટર ઉમેરવાનું કહ્યું. WKTrackingData categoriesથી આ કરે છે.

વ્યવહારમાં ફુલ-ઇવેન્ટ ટ્રેકિંગે ઘણો બેન્ડવિડ્થ બગાડ્યો. ઘણી ઇવેન્ટ જરૂરી નહોતી [(ŏ_ŏ)].

વધુ સુધારા માટે સર્વર તેને જોઈતી બધી ઇવેન્ટની ગોઠવણી ફાઇલ મોકલે. ગોઠવણી સાથે મેળ ખાતો event_path જ અપલોડ થાય.

આ તબક્કે વ્યવસાય પેરામીટર માટે WKTrackingData જરૂરી નથી; સીધું kvc વાપરો.

ઉદાહરણ:

key_path = "viewController.banner.url"

અહીં સુધી વાંચ્યું હોય તો WKTrackingData ખોલીને star આપો. પ્રશ્ન હોય તો GitHub પર issue ખોલો અથવા નીચે ટિપ્પણી કરો!