Asiakaspuolen tapahtumaseuranta jakautuu yleisesti kolmeen ryhmään:

  • Koodipohjainen seuranta
  • Visuaalinen seuranta
  • Automaattinen seuranta

Tämä artikkeli esittelee pääasiassa automaattisen seurannan ajatuksia ja toteutusprosessia.

1. Koodipohjainen seuranta

Koodipohjainen seuranta tarkoittaa rajapinnan kutsumista jokaisessa seurattavassa kohdassa ja tapahtumatietojen lähettämistä suoraan. Useimmat kolmannen osapuolen analytiikkapalvelut tarjoavat tähän kätevän api-rajapinnan.

Tästä syntyy kuitenkin ongelma: seurantakoodi hajaantuu liiketoimintalogiikkaan ja kytkeytyy siihen tiukasti. Kun näkymät tai prosessit muuttuvat, vanhojen tapahtumien kohtalo ja uusien tarve jäävät epäselviksi. Tapahtumamäärän kasvaessa hajanaisen seurantakoodin ylläpito muuttuu painajaiseksi. Makrot ja tehdasluokat voivat yksinkertaistaa koodia, mutta eivät muuta perusongelmaa.

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

2. Visuaalinen seuranta

Visuaalisessa seurannassa keräyspisteet määritetään visuaalisella työkalulla. Asiakasohjelma jäsentää määrityksen automaattisesti ja raportoi tapahtumat, jolloin syntyy niin sanottu ”jäljetön seuranta”. Yksi tunnettu avoimen lähdekoodin ratkaisu on Mixpanel.

3. Automaattinen seuranta

Automaattinen eli kaikkien tapahtumien seuranta ei oikeasti tarkoita, ettei instrumentointia olisi. Se kerää ja raportoi kaikki tapahtumat, joista palvelin suodattaa hyödylliset tiedot.

Lisäoptimointina palvelin voi lähettää määritystiedoston, jonka avulla asiakasohjelma suodattaa tapahtumat itse.

KPI-mittareiden vuoksi keksin tämän ajatuksen pohjalta pyörän uudelleen ja rakensin WKTrackingDatan.

Kirjaan tässä joitakin WKTrackingDatan toteutuksessa kohtaamiani ongelmia ja ajatuksia.

Toteutusajatus on yksinkertainen. Koodi on järjestetty näin:

Alkuperäinen WKTrackingData-arkkitehtuuri: hallinta, tapahtumapolut ja AOP-moduulit

Tässä WKTrackingDataManager hoitaa kaiken tiedonhallinnan ja tapahtumaseurannan määritykset.

Alkuperäinen käyttöesimerkki tapahtumaseurannan määrityksestä

WKTrackingDataViewPathHelper luo event_path-arvot.

AOP on kaikkien tapahtumien seurannasta vastaava moduuli.

Tarkat käyttöohjeet ovat GitHubissa.

Miten tapahtuma voidaan yksilöidä?

Kysymyksiä on kaksi: miten tapahtuma esitetään ja miten sen yksilöllisyys varmistetaan?

Tapahtuman esittäminen

Tapahtumat esitetään event_path-arvolla. Tapahtuman laukaisevan responder-olion kohdalla perusajatus on seurata sen responder-ketjua ja muodostaa ketjun path.

Tuloksena oleva responder-path näyttää tältä:

"event_path" = "#buttonClick:#UIButton#UIButton[0]#UIView[0]#ViewController#...#UIApplication#AppDelegate
Tapahtuman yksilöinti

Joissakin liiketoimintatilanteissa sama button tai muu ohjain tarkoittaa ominaisuuksiensa muuttuessa eri liiketoimintatapahtumia.

Esimerkiksi etusivun button voi uloskirjautuneena näyttää tekstin Napauta kirjautuaksesi ja sisäänkirjautumisen jälkeen Vahvista henkilöllisyys, jos vahvistus on vielä kesken.

Saman button-ohjaimen näkymäpuu ei ole muuttunut, joten sen luoma responder-path pysyy samana.

Vastaavia tapauksia ovat UISwitch-kytkimen tila, UISegmentedControl-ominaisuus indexSelect, UIStepper sekä UITableView- tai UICollectionView-näkymän cell-vuorovaikutukset.

Tätä varten WKTrackingData lisää event_path-arvoon valikoidusti ohjaimen omia ominaisuuksia. Tuloksena oleva event_path näyttää tältä:

"event_path" = "#buttonClick:#UIButton#UIButton[0]#UIView[0]#ViewController#...#UIApplication#AppDelegate#currentTitle=Button#state=1#enabled=1#selected=0";
Liiketoimintakohtaiset laajennukset

Tarkastellaan toista tilannetta: etusivun banner-karusellia.

Palvelin toimittaa jokaisen banner-paikan kuvan ja kohde-url-osoitteen, ja paikat ovat määritettävissä.

Kunkin banner-kohdan index ei siis johda kiinteään kohteeseen. Paikan 0 tapahtumaa ei voi päätellä pelkästä event_path-arvosta.

Tapahtuman yksilöimiseksi on lisättävä liiketoimintakohtaisia parametreja, kuten url.

WKTrackingData tukee myös liiketoimintaparametrien laajennuksia, joten kutsuja voi lisätä omia parametrejaan:

Alkuperäinen koodiesimerkki tapahtumien laajentamisesta liiketoimintaparametreilla

Ohjaimet, joita ei pidä seurata, voidaan ohittaa wk_ignoreTracking-arvolla:

self.slider.wk_ignoreTracking = YES;

Muita ongelmia

Eri tapahtumien seurantaa varten WKTrackingData käyttää aspektisuuntautunutta lähestymistapaa ja vaihtaa menetelmiä suoraan runtime-ajon aikana.

Seurattaessa UIAlertView-, UIActionSheet-, UITableView- ja UICollectionView-tapahtumia on kuitenkin vaihdettava niiden delegate-menetelmiä.

  • Jos delegate class toteuttaa jo menetelmän, se vain vaihdetaan.

  • Jos delegate class ei toteuta sitä mutta haluamme silti seurata tapahtumaa, vastaavan delegate method -menetelmän toteutus on lisättävä käsin.

- (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_));
        }
    }
}

Toteutus on täällä

Käytännössä huomasin kuitenkin, että kun UITableView- ja UICollectionView-näkymien delegate-oliot eivät toteuttaneet menetelmää, tableView:didSelectRowAtIndexPath:-menetelmän lisääminen käsin implementation-toteutuksella ei vieläkään saanut sitä käynnistymään.

Katsotaan ensin tavallista tableView:didSelectRowAtIndexPath:-kutsupinoa:

Alkuperäinen virheenkorjaimen kutsupino taulukkonäkymän rivin valinnasta

Tässä UITableView kutsuu nämä neljä menetelmää järjestyksessä vastatakseen cell-napautukseen:

  • 1. [UITableView _userSelectRowAtPendingSelectionIndexPath:]
  • 2. [UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:]
  • 3. [UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect:]
  • 4. [TableViewController tableView:didSelectRowAtIndexPath:]

Kutsujärjestys osoittaa, että UITableView kutsuu delegate class -luokan tableView:didSelectRowAtIndexPath:-menetelmää vasta oman _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect:-menetelmänsä jälkeen.

Aseta keskeytyskohta menetelmään _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect: ja tarkastele assembly-koodia:

Alkuperäinen assembly-näkymä, jossa näkyy delegate-menetelmän haara

Jos delegate class toteuttaa tableView:didSelectRowAtIndexPath:-menetelmän, kaikki toimii ja tableView:didSelectRowAtIndexPath:-kutsu valmistuu.

Jos delegate class ei toteuta tableView:didSelectRowAtIndexPath:-menetelmää, edes tableView:didSelectRowAtIndexPath:-menetelmän lisääminen käsin implementation-toteutuksella ei johda yritykseen vastata tableView:didSelectRowAtIndexPath:-menetelmään.

Assembly-koodia seuraamalla näkyy suora jump toiseen käskyyn.

WKTrackingData käyttää tässä eri tapaa ja vaihtaa suoraan menetelmän [UITableView _userSelectRowAtPendingSelectionIndexPath:] (ja vastaavasti UICollectionView-näkymässä). Näin UITableView- ja UICollectionView-vuorovaikutukset voidaan jäljittää, vaikka delegate-olio ei toteuta vastaavaa cell-tapahtumamenetelmää.

4. Lopuksi

Samalla tapahtumalla useita event_path-arvoja

Ajattele useita julkaistuja versioita, joiden näkymissä on pieniä eroja. Samalla tapahtumalla voi silloin olla useita event_path-arvoja.

Käytännössä tämä vastaavuus vaatii yhteistyötä palvelinpuolen kollegojen kanssa. Se voidaan tehdä taustajärjestelmässä määritettäväksi.

Tapahtuma-analytiikan optimointi

Edellä Liiketoimintakohtaiset laajennukset -osio kuvasi liiketoimintaparametrien lisäämistä. WKTrackingData toteuttaa sen kategorioilla.

Käytännössä kaikkien tapahtumien seuranta tuhlasi paljon kaistanleveyttä. Monet tapahtumat olivat tarpeettomia [(ŏ_ŏ)].

Lisäoptimointina palvelin voi lähettää määritystiedoston, jossa luetellaan kaikki raportoitavaksi halutut tapahtumat. Vain määritystä vastaava event_path lähetetään.

Tässä vaiheessa liiketoimintaparametrit voi hakea myös ilman WKTrackingDataa: käytä suoraan kvc:tä.

Esimerkiksi:

key_path = "viewController.banner.url"

Jos luit tänne asti, avaa WKTrackingData ja anna sille tähti. Jos sinulla on kysymyksiä, avaa issue GitHubissa tai jätä kommentti alle!