Penjejakan peristiwa di pihak klien secara umum terbahagi kepada tiga kategori:

  • Penjejakan berasaskan kod
  • Penjejakan visual
  • Penjejakan automatik

Artikel ini terutamanya memperkenalkan idea dan proses pelaksanaan di sebalik penjejakan automatik.

1. Penjejakan berasaskan kod

Penjejakan berasaskan kod bermaksud memanggil antara muka pada setiap titik yang mahu dijejaki dan memuat naik data peristiwa secara terus. Kebanyakan perkhidmatan analitik pihak ketiga menyediakan api penjejakan kod yang mudah digunakan.

Namun, ini menimbulkan masalah: kod penjejakan bertaburan di seluruh logik perniagaan dan terikat rapat dengannya. Apabila skrin atau aliran perniagaan berubah, tidak jelas apa yang perlu dilakukan dengan peristiwa lama atau sama ada peristiwa baharu diperlukan. Apabila bilangan peristiwa meningkat, penyelenggaraan kod yang bertaburan menjadi mimpi ngeri. Makro dan kelas kilang boleh memudahkan kod, tetapi tidak mengubah masalah asas.

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

2. Penjejakan visual

Penjejakan visual mengkonfigurasi titik pengumpulan melalui alat visual. Klien mentafsir konfigurasi secara automatik dan melaporkan peristiwa, lalu menghasilkan apa yang dipanggil “penjejakan tanpa kesan”. Salah satu penyelesaian sumber terbuka yang mewakilinya ialah Mixpanel.

3. Penjejakan automatik

Penjejakan automatik, yang juga dipanggil penjejakan semua peristiwa, sebenarnya bukan bermakna tiada instrumentasi. Ia mengumpul dan melaporkan semua peristiwa, kemudian pelayan menapis data yang berguna.

Sebagai pengoptimuman lanjut, pelayan boleh menghantar fail konfigurasi supaya klien sendiri menapis peristiwa.

Demi KPI, saya mencipta semula penyelesaian berdasarkan idea ini dan membina WKTrackingData.

Di sini saya merekodkan beberapa masalah dan idea daripada pelaksanaan WKTrackingData.

Idea pelaksanaannya mudah. Kod disusun seperti berikut:

Seni bina WKTrackingData asal: pengurus, laluan peristiwa dan modul AOP

Di sini, WKTrackingDataManager mengendalikan semua pengurusan data dan konfigurasi penjejakan peristiwa.

Contoh penggunaan asal bagi konfigurasi penjejakan peristiwa

WKTrackingDataViewPathHelper menjana nilai event_path.

AOP ialah modul yang bertanggungjawab menjejaki setiap peristiwa.

Untuk penggunaan terperinci, lawati GitHub.

Bagaimanakah peristiwa boleh dikenal pasti secara unik?

Terdapat dua persoalan: bagaimana kita mewakili peristiwa, dan bagaimana kita memastikan keunikannya?

Mewakili peristiwa

Peristiwa diwakili menggunakan event_path. Bagi responder yang mencetuskan peristiwa, idea utamanya ialah mengikuti rantaian responder dan membina path rantaian tersebut.

Nilai path responder yang terhasil kelihatan seperti ini:

"event_path" = "#buttonClick:#UIButton#UIButton[0]#UIView[0]#ViewController#...#UIApplication#AppDelegate
Mengenal pasti peristiwa secara unik

Dalam sesetengah senario perniagaan, button atau kawalan yang sama mewakili peristiwa perniagaan berbeza apabila sifatnya berubah.

Contohnya, button pada skrin utama mungkin memaparkan Ketik untuk log masuk ketika pengguna belum log masuk, kemudian Sahkan identiti selepas log masuk jika pengesahan identiti masih belum lengkap.

Bagi button yang sama, pepohon paparan tidak berubah, maka path responder yang dijana kekal sama.

Kes serupa termasuk keadaan hidup/mati UISwitch, sifat indexSelect pada UISegmentedControl, UIStepper, serta interaksi UITableView atau UICollectionView dengan cell.

Untuk menanganinya, WKTrackingData membina event_path dengan menambahkan sifat kawalan itu sendiri secara terpilih. event_path yang terhasil kemudian kelihatan seperti ini:

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

Pertimbangkan satu lagi senario: karusel banner pada skrin utama.

Setiap penempatan banner mempunyai imej dan url destinasi yang diberikan pelayan, dan kedudukannya boleh dikonfigurasi.

Di sini, banner pada setiap index tidak mempunyai destinasi tetap. Peristiwa pada kedudukan 0 tidak dapat ditentukan melalui event_path sahaja.

Untuk mengenal pasti peristiwa secara unik, kita perlu menambahkan parameter khusus perniagaan seperti url.

WKTrackingData turut menyokong sambungan parameter perniagaan dan membenarkan pemanggil menambahkan parameter tersuai:

Contoh kod asal yang melanjutkan peristiwa dengan parameter perniagaan

Kawalan yang tidak patut dijejaki boleh dikecualikan menggunakan wk_ignoreTracking:

self.slider.wk_ignoreTracking = YES;

Masalah lain

Untuk menjejaki peristiwa berbeza, WKTrackingData menggunakan pendekatan berorientasikan aspek dan menggunakan runtime untuk melakukan pertukaran pelaksanaan kaedah (method swizzling) secara terus.

Namun, untuk menjejaki UIAlertView, UIActionSheet, UITableView dan UICollectionView, kita perlu menukar ganti kaedah delegate mereka.

  • Jika delegate class sudah melaksanakan kaedah itu, tukarkannya sahaja.

  • Jika delegate class tidak melaksanakannya tetapi kita masih mahu menjejaki peristiwa, kita perlu menambahkan pelaksanaan bagi delegate method yang sepadan secara manual.

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

Pelaksanaannya ada di sini

Namun, dalam amalan dengan UITableView dan UICollectionView, apabila objek delegate tidak melaksanakan kaedah itu, penambahan tableView:didSelectRowAtIndexPath: secara manual dengan sebuah implementation masih tidak menyebabkannya dipanggil.

Pertama, lihat tindanan panggilan biasa bagi tableView:didSelectRowAtIndexPath::

Tindanan panggilan penyahpepijat asal bagi pemilihan baris paparan jadual

Di sini, UITableView memanggil empat kaedah berikut secara berturutan untuk bertindak balas terhadap ketikan cell:

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

Urutan panggilan menunjukkan bahawa UITableView meminta delegate class menjalankan kaedah tableView:didSelectRowAtIndexPath: hanya selepas memanggil kaedahnya sendiri _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect:.

Tetapkan titik henti pada _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect: dan periksa kod himpunan:

Paparan himpunan asal yang menunjukkan cabang kaedah delegate

Jika delegate class melaksanakan tableView:didSelectRowAtIndexPath:, semuanya berfungsi dan panggilan tableView:didSelectRowAtIndexPath: selesai.

Namun, jika delegate class tidak melaksanakan tableView:didSelectRowAtIndexPath:, walaupun tableView:didSelectRowAtIndexPath: ditambahkan secara manual dengan implementation, sistem masih tidak cuba memberi respons kepada tableView:didSelectRowAtIndexPath:.

Menelusuri kod himpunan menunjukkan bahawa pelaksanaan membuat jump terus ke arahan lain.

WKTrackingData menggunakan pendekatan lain di sini, dengan menukar terus [UITableView _userSelectRowAtPendingSelectionIndexPath:] (dan pendekatan serupa untuk UICollectionView). Ini membolehkan UITableView dan UICollectionView menjejaki interaksi walaupun objek delegate tidak melaksanakan kaedah peristiwa cell yang sepadan.

4. Penutup

Pelbagai nilai event_path bagi peristiwa yang sama

Pertimbangkan beberapa versi yang telah dikeluarkan dengan sedikit perbezaan pada skrin. Peristiwa yang sama mungkin mempunyai beberapa nilai event_path.

Dalam amalan, pemetaan ini memerlukan kerjasama rakan bahagian pelayan. Ia boleh dijadikan boleh dikonfigurasi di bahagian belakang.

Mengoptimumkan analitik peristiwa

Bahagian sambungan khusus perniagaan menerangkan penambahan parameter perniagaan. WKTrackingData melaksanakannya melalui kategori.

Dalam amalan, penjejakan semua peristiwa membazirkan banyak lebar jalur. Banyak peristiwa itu sebenarnya tidak diperlukan [(ŏ_ŏ)].

Pengoptimuman lanjut ialah pelayan menghantar fail konfigurasi yang menyenaraikan setiap peristiwa yang mahu dilaporkan. Hanya event_path yang sepadan dengan konfigurasi akan dimuat naik.

Pada tahap ini, parameter perniagaan juga boleh diambil tanpa WKTrackingData: gunakan sahaja kvc secara terus.

Contohnya:

key_path = "viewController.banner.url"

Jika anda membaca sehingga sini, buka WKTrackingData dan berikan bintang. Jika ada pertanyaan, buka isu di GitHub atau tinggalkan komen di bawah!