A kliensoldali eseménykövetés nagyjából három kategóriára osztható:
- Kódalapú követés
- Vizuális követés
- Automatikus követés
Ez a cikk elsősorban az automatikus követés mögötti elképzeléseket és megvalósítási folyamatot mutatja be.
1. Kódalapú követés
A kódalapú követés során minden követni kívánt ponton meghívunk egy interfészt, és közvetlenül feltöltjük az eseményadatokat. A legtöbb külső elemzőszolgáltató kínál kódalapú követési api felületet, ami kényelmes.
Ez azonban problémát okoz: a követőkód szétszóródik az üzleti logikában, és szorosan összekapcsolódik vele. Ha a képernyők vagy az üzleti folyamatok megváltoznak, nem egyértelmű, mi legyen a régi eseményekkel, és kellenek-e újak. Az eseményszám növekedésével a szétszórt követőkód karbantartása rémálommá válik. Makrók és gyárosztályok egyszerűsíthetik a kódot, de a lényeget nem változtatják meg.
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// 埋点
APE(kEvent4001);
}
2. Vizuális követés
A vizuális követés egy vizuális eszközzel állítja be az adatgyűjtési pontokat. A kliens automatikusan feldolgozza a konfigurációt, és jelenti az eseményeket, így jön létre az úgynevezett „nyomtalan követés”. Egy jellemző nyílt forrású megoldás a Mixpanel.
3. Automatikus követés
Az automatikus, más néven teljes eseménykövetés valójában nem jelenti a műszerezés hiányát. Minden eseményt összegyűjt és jelent, a hasznos adatok kiválogatását pedig a szerverre bízza.
További optimalizálásként a szerver konfigurációs fájlt küldhet, hogy a kliens maga szűrje az eseményeket.
A KPI-k kedvéért újra feltaláltam a kereket ezen elképzelés alapján, és elkészítettem a WKTrackingData eszközt.
Itt feljegyzek néhány problémát és ötletet a WKTrackingData megvalósításából.
A megvalósítás alapötlete egyszerű. A kód így épül fel:

Itt a WKTrackingDataManager kezeli az összes adatot és az eseménykövetés konfigurációját.

A WKTrackingDataViewPathHelper állítja elő az event_path értékeket.
Az AOP modul felel az összes esemény követéséért.
A részletes használatot a GitHubon találod.
Hogyan azonosítható egyértelműen egy esemény?
Két kérdés merül fel: hogyan ábrázoljunk egy eseményt, és hogyan biztosítsuk az egyediségét?
Esemény ábrázolása
Az eseményeket az event_path segítségével ábrázoljuk. Az eseményt kiváltó responder esetében az alapötlet a válaszadólánc követése és a lánc path útvonalának felépítése.
Az így kapott válaszadói path így néz ki:
"event_path" = "#buttonClick:#UIButton#UIButton[0]#UIView[0]#ViewController#...#UIApplication#AppDelegate
Esemény egyértelmű azonosítása
Egyes üzleti helyzetekben ugyanaz a button vagy más vezérlőelem különböző üzleti eseményeket jelöl, amikor a tulajdonságai megváltoznak.
Például a kezdőképernyő egyik button eleme kijelentkezve a Koppints a bejelentkezéshez feliratot mutathatja, bejelentkezés után pedig a Személyazonosság igazolása feliratot, ha az ellenőrzés még nem fejeződött be.
Ugyanannál a button elemnél a nézetfa nem változott, ezért a generált válaszadói path is ugyanaz marad.
Hasonló eset a UISwitch be- és kikapcsolt állapota, a UISegmentedControl tulajdonsága, az indexSelect, a UIStepper, valamint a UITableView és a UICollectionView interakciói egy cell elemmel.
Ennek kezelésére a WKTrackingData úgy építi fel az event_path értéket, hogy szelektíven hozzáfűzi a vezérlő saját tulajdonságait. Az így kapott event_path ekkor így néz ki:
"event_path" = "#buttonClick:#UIButton#UIButton[0]#UIView[0]#ViewController#...#UIApplication#AppDelegate#currentTitle=Button#state=1#enabled=1#selected=0";
Üzleti bővítések
Nézzünk egy másik helyzetet: egy kezdőképernyős banner körhintát.
Minden banner helyhez tartozik a szervertől kapott kép és cél-url, a pozíciók pedig konfigurálhatók.
Itt az egyes banner elemek célja minden index esetén változhat. A 0 pozíció eseménye nem állapítható meg pusztán az event_path alapján.
Az esemény egyértelmű azonosításához üzleti paramétereket, például url értéket kell hozzáfűznünk.
A WKTrackingData az üzleti paraméterek bővítését is támogatja, így a hívó saját paramétereket fűzhet hozzá:

A nem követendő vezérlők a wk_ignoreTracking segítségével kizárhatók:
self.slider.wk_ignoreTracking = YES;
További problémák
A különböző események követéséhez a WKTrackingData aspektusorientált megközelítést használ, és a runtime segítségével közvetlenül cseréli a metódusokat.
A UIAlertView, UIActionSheet, UITableView és UICollectionView követéséhez viszont a delegate metódusaikat kell kicserélnünk.
Ha a
delegate classmár megvalósítja a metódust, egyszerűen cseréljük ki.Ha a
delegate classnem valósítja meg, és mégis követni szeretnénk az eseményt, kézzel kell hozzáadnunk a megfelelődelegate methodmegvalósítását.
- (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_));
}
}
}
A gyakorlatban azonban a UITableView és a UICollectionView esetében, ha a delegate objektum nem valósította meg a metódust, a tableView:didSelectRowAtIndexPath: kézi hozzáadása egy implementation megadásával sem váltott ki hívást.
Először nézzük meg a szokásos tableView:didSelectRowAtIndexPath: hívási vermet:

Itt a UITableView egymás után ezt a négy metódust hívja meg egy cell elemre koppintás kezeléséhez:
- 1. [UITableView _userSelectRowAtPendingSelectionIndexPath:]
- 2. [UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:]
- 3. [UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect:]
- 4. [TableViewController tableView:didSelectRowAtIndexPath:]
A hívási sorrendből látszik, hogy a UITableView csak azután hívja a delegate class metódusát, a tableView:didSelectRowAtIndexPath: metódust, hogy meghívta a saját _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect: metódusát.
Tegyél töréspontot a _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect: metódusra, és vizsgáld meg az assembly kódot:

Ha a delegate class megvalósítja a tableView:didSelectRowAtIndexPath: metódust, minden működik, és a tableView:didSelectRowAtIndexPath: hívás végbemegy.
Ha viszont a delegate class nem valósítja meg a tableView:didSelectRowAtIndexPath: metódust, még a tableView:didSelectRowAtIndexPath: kézi hozzáadása egy implementation megadásával sem vezet ahhoz, hogy megpróbáljon válaszolni a tableView:didSelectRowAtIndexPath: hívásra.
Az assembly követése közvetlen jump utasítást mutat egy másik utasításra.
A WKTrackingData itt más megközelítést választ: közvetlenül kicseréli a [UITableView _userSelectRowAtPendingSelectionIndexPath:] metódust (hasonlóan a UICollectionView esetében). Így a UITableView és a UICollectionView akkor is követheti az interakciókat, ha a delegate objektum nem valósítja meg a megfelelő cell eseménymetódust.
4. Záró gondolatok
Több event_path érték ugyanahhoz az eseményhez
Tegyük fel, hogy több kiadott verzió létezik, apró képernyőeltérésekkel. Ugyanahhoz az eseményhez ekkor több event_path érték tartozhat.
A gyakorlatban ehhez a megfeleltetéshez együtt kell működni a szerveroldali kollégákkal. A háttérrendszerben konfigurálhatóvá tehető.
Az eseményelemzés optimalizálása
Az Üzleti bővítések rész bemutatta az üzleti paraméterek hozzáadását. A WKTrackingData ezt kategóriákkal valósítja meg.
A gyakorlatban a teljes eseménykövetés rengeteg sávszélességet pazarolt. Sok eseményre nem volt szükség [(ŏ_ŏ)].
További optimalizálásként a szerver olyan konfigurációs fájlt küldhet, amely felsorolja az összes jelenteni kívánt eseményt. Csak a konfigurációnak megfelelő event_path kerül feltöltésre.
Ezen a ponton az üzleti paraméterek a WKTrackingData nélkül is lekérhetők: közvetlenül a kvc használatával.
Például:
key_path = "viewController.banner.url"
Ha eddig eljutottál, nyisd meg a WKTrackingData projektet, és adj neki egy csillagot. Ha kérdésed van, nyiss egy issue-t a GitHubon, vagy szólj hozzá alább!