ਕਲਾਇੰਟ ਪਾਸੇ ਇਵੈਂਟ ਟ੍ਰੈਕਿੰਗ ਮੋਟੇ ਤੌਰ ਉੱਤੇ ਤਿੰਨ ਸ਼੍ਰੇਣੀਆਂ ਵਿੱਚ ਆਉਂਦੀ ਹੈ:

  • ਕੋਡ-ਆਧਾਰਿਤ ਟ੍ਰੈਕਿੰਗ
  • ਦ੍ਰਿਸ਼ ਟ੍ਰੈਕਿੰਗ
  • ਸਵੈਚਾਲਿਤ ਟ੍ਰੈਕਿੰਗ

ਇਹ ਲੇਖ ਮੁੱਖ ਤੌਰ ਉੱਤੇ ਸਵੈਚਾਲਿਤ ਟ੍ਰੈਕਿੰਗ ਦੇ ਵਿਚਾਰ ਅਤੇ ਅਮਲ ਪ੍ਰਕਿਰਿਆ ਬਾਰੇ ਹੈ।

1. ਕੋਡ-ਆਧਾਰਿਤ ਟ੍ਰੈਕਿੰਗ

ਕੋਡ-ਆਧਾਰਿਤ ਟ੍ਰੈਕਿੰਗ ਦਾ ਮਤਲਬ ਹਰ ਟ੍ਰੈਕ ਕਰਨ ਯੋਗ ਥਾਂ ਉੱਤੇ interface ਕਾਲ ਕਰਕੇ ਇਵੈਂਟ ਡਾਟਾ ਸਿੱਧਾ ਅੱਪਲੋਡ ਕਰਨਾ ਹੈ। ਜ਼ਿਆਦਾਤਰ ਤੀਜੀ-ਧਿਰ ਵਿਸ਼ਲੇਸ਼ਣ ਸੇਵਾਵਾਂ ਸੁਵਿਧਾਜਨਕ ਕੋਡ-ਆਧਾਰਿਤ api ਦਿੰਦੀਆਂ ਹਨ।

ਪਰ ਸਮੱਸਿਆ ਇਹ ਹੈ ਕਿ ਟ੍ਰੈਕਿੰਗ ਕੋਡ ਕਾਰੋਬਾਰੀ ਤਰਕ ਵਿੱਚ ਹਰ ਥਾਂ ਖਿਲਰ ਜਾਂਦਾ ਹੈ ਅਤੇ ਉਸ ਨਾਲ ਸਖ਼ਤੀ ਨਾਲ ਜੁੜਦਾ ਹੈ। ਸਕ੍ਰੀਨ ਜਾਂ ਪ੍ਰਵਾਹ ਬਦਲਣ ਉੱਤੇ ਪੁਰਾਣੇ ਇਵੈਂਟਾਂ ਦਾ ਕੀ ਕਰੀਏ ਜਾਂ ਨਵੇਂ ਚਾਹੀਦੇ ਹਨ ਕਿ ਨਹੀਂ, ਸਪਸ਼ਟ ਨਹੀਂ ਰਹਿੰਦਾ। ਗਿਣਤੀ ਵਧਣ ਉੱਤੇ ਖਿਲਰੇ ਕੋਡ ਦੀ ਦੇਖਭਾਲ ਡਰਾਉਣੀ ਬਣਦੀ ਹੈ। macro ਅਤੇ factory class ਕੋਡ ਸੌਖਾ ਕਰ ਸਕਦੇ ਹਨ ਪਰ ਮੂਲ ਗੱਲ ਨਹੀਂ ਬਦਲਦੇ।

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

2. ਦ੍ਰਿਸ਼ ਟ੍ਰੈਕਿੰਗ

ਦ੍ਰਿਸ਼ ਟ੍ਰੈਕਿੰਗ ਇੱਕ ਦ੍ਰਿਸ਼ ਸਾਧਨ ਰਾਹੀਂ ਇਕੱਤਰ ਥਾਵਾਂ ਸੰਰਚਿਤ ਕਰਦੀ ਹੈ। ਕਲਾਇੰਟ ਆਪਣੇ-ਆਪ ਸੰਰਚਨਾ ਸਮਝ ਕੇ ਇਵੈਂਟ ਭੇਜਦਾ ਹੈ, ਜਿਸਨੂੰ “ਨਿਸ਼ਾਨ-ਰਹਿਤ ਟ੍ਰੈਕਿੰਗ” ਕਿਹਾ ਜਾਂਦਾ ਹੈ। ਇਸਦਾ ਇੱਕ ਪ੍ਰਤੀਨਿਧੀ open-source ਹੱਲ Mixpanel ਹੈ।

3. ਸਵੈਚਾਲਿਤ ਟ੍ਰੈਕਿੰਗ

ਸਵੈਚਾਲਿਤ ਜਾਂ full-event ਟ੍ਰੈਕਿੰਗ ਦਾ ਮਤਲਬ ਅਸਲ ਵਿੱਚ instrumentation ਨਾ ਹੋਣਾ ਨਹੀਂ। ਇਹ ਸਾਰੇ ਇਵੈਂਟ ਇਕੱਠੇ ਕਰਕੇ ਭੇਜਦੀ ਹੈ ਅਤੇ server ਲਾਭਦਾਇਕ ਡਾਟਾ ਛਾਂਟਦਾ ਹੈ।

ਹੋਰ ਸੁਧਾਰ ਵਜੋਂ server ਸੰਰਚਨਾ ਫ਼ਾਈਲ ਭੇਜ ਸਕਦਾ ਹੈ ਤਾਂ ਕਿ client ਆਪ ਇਵੈਂਟ ਛਾਂਟੇ।

KPI ਲਈ, ਮੈਂ ਇਸ ਵਿਚਾਰ ਦੇ ਆਲੇ-ਦੁਆਲੇ ਪਹੀਆ ਮੁੜ ਬਣਾਇਆ ਅਤੇ WKTrackingData ਤਿਆਰ ਕੀਤਾ।

ਇੱਥੇ WKTrackingData ਅਮਲ ਦੌਰਾਨ ਆਈਆਂ ਕੁਝ ਮੁਸ਼ਕਲਾਂ ਅਤੇ ਵਿਚਾਰ ਦਰਜ ਕਰਦਾ ਹਾਂ।

ਅਮਲ ਦਾ ਵਿਚਾਰ ਸਧਾਰਨ ਹੈ। ਕੋਡ ਇਸ ਤਰ੍ਹਾਂ ਸੰਗਠਿਤ ਹੈ:

WKTrackingData ਦੀ ਮੂਲ ਬਣਤਰ: manager, event path ਅਤੇ AOP module

ਇੱਥੇ WKTrackingDataManager ਸਾਰਾ ਡਾਟਾ ਪ੍ਰਬੰਧਨ ਅਤੇ ਇਵੈਂਟ ਟ੍ਰੈਕਿੰਗ ਸੰਰਚਨਾ ਸੰਭਾਲਦਾ ਹੈ।

ਇਵੈਂਟ ਟ੍ਰੈਕਿੰਗ ਸੰਰਚਨਾ ਦੀ ਮੂਲ ਵਰਤੋਂ ਮਿਸਾਲ

WKTrackingDataViewPathHelper, event_path ਮੁੱਲ ਬਣਾਉਂਦਾ ਹੈ।

AOP ਹਰ ਇਵੈਂਟ ਟ੍ਰੈਕ ਕਰਨ ਵਾਲਾ module ਹੈ।

ਵਿਸਤ੍ਰਿਤ ਵਰਤੋਂ ਲਈ GitHub ਵੇਖੋ।

ਇੱਕ ਇਵੈਂਟ ਨੂੰ ਵਿਲੱਖਣ ਤੌਰ ਉੱਤੇ ਕਿਵੇਂ ਪਛਾਣੀਏ?

ਦੋ ਸਵਾਲ ਹਨ: ਇਵੈਂਟ ਕਿਵੇਂ ਦਰਸਾਈਏ ਅਤੇ ਉਸਦੀ ਵਿਲੱਖਣਤਾ ਕਿਵੇਂ ਯਕੀਨੀ ਬਣਾਈਏ?

ਇਵੈਂਟ ਦਰਸਾਉਣਾ

ਇਵੈਂਟ event_path ਨਾਲ ਦਰਸਾਏ ਜਾਂਦੇ ਹਨ। ਇਵੈਂਟ ਚਲਾਉਣ ਵਾਲੇ responder ਲਈ ਮੁੱਖ ਵਿਚਾਰ ਉਸਦੀ responder chain ਦੇ ਪਿੱਛੇ ਜਾ ਕੇ ਉਸ chain ਦਾ path ਬਣਾਉਣਾ ਹੈ।

ਨਤੀਜੇ ਵਾਲਾ responder path ਇਸ ਤਰ੍ਹਾਂ ਹੈ:

"event_path" = "#buttonClick:#UIButton#UIButton[0]#UIView[0]#ViewController#...#UIApplication#AppDelegate
ਇਵੈਂਟ ਨੂੰ ਵਿਲੱਖਣ ਪਛਾਣ ਦੇਣਾ

ਕੁਝ ਕਾਰੋਬਾਰੀ ਹਾਲਤਾਂ ਵਿੱਚ ਇੱਕੋ button ਜਾਂ ਹੋਰ control ਆਪਣੀਆਂ property ਬਦਲਣ ਨਾਲ ਵੱਖਰੇ ਕਾਰੋਬਾਰੀ ਇਵੈਂਟ ਦਰਸਾਉਂਦਾ ਹੈ।

ਮਿਸਾਲ ਵਜੋਂ home screen ਦਾ button sign out ਹੋਣ ਉੱਤੇ ਸਾਈਨ ਇਨ ਲਈ ਟੈਪ ਕਰੋ ਅਤੇ sign in ਤੋਂ ਬਾਅਦ ਪਛਾਣ ਅਧੂਰੀ ਹੋਵੇ ਤਾਂ ਪਛਾਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ ਦਿਖਾ ਸਕਦਾ ਹੈ।

ਉਸੇ button ਦਾ view tree ਨਹੀਂ ਬਦਲਿਆ, ਇਸ ਲਈ ਬਣਿਆ responder path ਇੱਕੋ ਰਹਿੰਦਾ ਹੈ।

ਇਸੇ ਤਰ੍ਹਾਂ UISwitch ਦੀ on/off ਹਾਲਤ, UISegmentedControl ਦੀ indexSelect property, UIStepper ਅਤੇ UITableView ਜਾਂ UICollectionView ਦੀਆਂ cell ਕਾਰਵਾਈਆਂ ਹਨ।

ਇਸ ਲਈ WKTrackingData control ਦੀਆਂ ਚੁਣੀਆਂ property ਨੂੰ event_path ਨਾਲ ਜੋੜਦਾ ਹੈ। ਨਤੀਜੇ ਵਾਲਾ event_path ਇਸ ਤਰ੍ਹਾਂ ਬਣਦਾ ਹੈ:

"event_path" = "#buttonClick:#UIButton#UIButton[0]#UIView[0]#ViewController#...#UIApplication#AppDelegate#currentTitle=Button#state=1#enabled=1#selected=0";
ਕਾਰੋਬਾਰ-ਖ਼ਾਸ ਵਿਸਥਾਰ

ਇੱਕ ਹੋਰ ਹਾਲਤ ਸੋਚੋ: home screen ਉੱਤੇ banner carousel।

ਹਰ banner ਥਾਂ ਦੀ ਤਸਵੀਰ ਅਤੇ ਮੰਜ਼ਿਲ url server ਦਿੰਦਾ ਹੈ ਅਤੇ ਥਾਵਾਂ ਸੰਰਚਿਤ ਹੋ ਸਕਦੀਆਂ ਹਨ।

ਹਰ banner ਦੇ index ਦੀ ਮੰਜ਼ਿਲ ਸਥਿਰ ਨਹੀਂ। ਸਥਾਨ 0 ਦਾ ਇਵੈਂਟ ਕੇਵਲ event_path ਤੋਂ ਤੈਅ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।

ਵਿਲੱਖਣ ਪਛਾਣ ਲਈ url ਵਰਗੇ ਕਾਰੋਬਾਰੀ parameter ਜੋੜਨੇ ਪੈਂਦੇ ਹਨ।

WKTrackingData ਕਾਰੋਬਾਰੀ parameter ਵਿਸਥਾਰ ਵੀ ਦਿੰਦਾ ਹੈ, ਜਿਸ ਨਾਲ caller ਆਪਣੇ parameter ਜੋੜ ਸਕਦਾ ਹੈ:

ਕਾਰੋਬਾਰੀ parameter ਨਾਲ ਇਵੈਂਟ ਵਧਾਉਣ ਦੀ ਮੂਲ ਕੋਡ ਮਿਸਾਲ

ਜਿਨ੍ਹਾਂ controls ਨੂੰ ਟ੍ਰੈਕ ਨਹੀਂ ਕਰਨਾ, ਉਨ੍ਹਾਂ ਨੂੰ wk_ignoreTracking ਨਾਲ ਬਾਹਰ ਰੱਖ ਸਕਦੇ ਹੋ:

self.slider.wk_ignoreTracking = YES;

ਹੋਰ ਮੁੱਦੇ

ਵੱਖਰੇ ਇਵੈਂਟ ਟ੍ਰੈਕ ਕਰਨ ਲਈ WKTrackingData aspect-oriented ਤਰੀਕਾ ਅਪਣਾਉਂਦਾ ਅਤੇ runtime ਨਾਲ method ਸਿੱਧੇ swizzle ਕਰਦਾ ਹੈ।

ਪਰ UIAlertView, UIActionSheet, UITableView ਅਤੇ UICollectionView ਲਈ ਉਨ੍ਹਾਂ ਦੇ delegate methods swizzle ਕਰਨੇ ਪੈਂਦੇ ਹਨ।

  • ਜੇ delegate class method ਪਹਿਲਾਂ ਹੀ implement ਕਰਦੀ ਹੈ ਤਾਂ ਕੇਵਲ ਉਸਨੂੰ swizzle ਕਰੋ।

  • ਜੇ delegate class method implement ਨਹੀਂ ਕਰਦੀ ਅਤੇ ਫਿਰ ਵੀ ਇਵੈਂਟ ਟ੍ਰੈਕ ਕਰਨਾ ਹੈ ਤਾਂ ਸੰਬੰਧਤ delegate method ਦੀ implementation ਹੱਥੀਂ ਜੋੜਨੀ ਪਵੇਗੀ।

- (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 objects ਨੇ method implement ਨਹੀਂ ਕੀਤਾ, ਤਾਂ tableView:didSelectRowAtIndexPath: ਲਈ implementation ਹੱਥੀਂ ਜੋੜਨ ਨਾਲ ਵੀ ਇਹ ਚੱਲਿਆ ਨਹੀਂ।

ਪਹਿਲਾਂ ਆਮ tableView:didSelectRowAtIndexPath: call stack ਵੇਖੋ:

table-view row selection ਲਈ ਮੂਲ debugger call stack

ਇੱਥੇ UITableView, cell tap ਦਾ ਜਵਾਬ ਦੇਣ ਲਈ ਕ੍ਰਮ ਵਿੱਚ ਚਾਰ methods ਕਾਲ ਕਰਦਾ ਹੈ:

  • 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: method ਚਲਾਉਂਦਾ ਹੈ।

ਸਿੱਧਾ _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect: ਉੱਤੇ breakpoint ਲਾ ਕੇ assembly ਵੇਖੋ:

delegate method branch ਦਿਖਾਉਂਦਾ ਮੂਲ assembly ਦ੍ਰਿਸ਼

ਜੇ delegate class ਨੇ tableView:didSelectRowAtIndexPath: implement ਕੀਤਾ ਹੈ ਤਾਂ ਸਭ ਠੀਕ ਚੱਲਦਾ ਅਤੇ tableView:didSelectRowAtIndexPath: call ਪੂਰੀ ਹੁੰਦੀ ਹੈ।

ਪਰ ਜੇ delegate class ਨੇ tableView:didSelectRowAtIndexPath: implement ਨਹੀਂ ਕੀਤਾ, ਤਾਂ tableView:didSelectRowAtIndexPath: ਲਈ implementation ਹੱਥੀਂ ਜੋੜਨ ਉੱਤੇ ਵੀ tableView:didSelectRowAtIndexPath: ਦਾ ਜਵਾਬ ਦੇਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਨਹੀਂ ਹੁੰਦੀ।

assembly ਦੇ ਪਿੱਛੇ ਜਾਣ ਉੱਤੇ ਸਿੱਧਾ ਕਿਸੇ ਹੋਰ instruction ਵੱਲ jump ਦਿਸਦਾ ਹੈ।

WKTrackingData ਇੱਥੇ ਵੱਖਰਾ ਤਰੀਕਾ ਲੈਂਦਾ ਹੈ—ਸਿੱਧਾ [UITableView _userSelectRowAtPendingSelectionIndexPath:] swizzle ਕਰਦਾ ਹੈ (UICollectionView ਲਈ ਵੀ ਇਸੇ ਤਰ੍ਹਾਂ)। ਇਸ ਨਾਲ UITableView ਅਤੇ UICollectionView ਦੇ delegate object ਕੋਲ ਸੰਬੰਧਤ cell method ਨਾ ਹੋਣ ਉੱਤੇ ਵੀ ਮੇਲ-ਜੋਲ ਟ੍ਰੈਕ ਹੁੰਦਾ ਹੈ।

4. ਅਖ਼ੀਰਲੇ ਵਿਚਾਰ

ਇੱਕੋ ਇਵੈਂਟ ਲਈ ਕਈ event_path

ਕੁਝ ਸਕ੍ਰੀਨ ਫ਼ਰਕਾਂ ਵਾਲੇ ਕਈ ਰਿਲੀਜ਼ ਵਰਜਨ ਸੋਚੋ। ਇੱਕੋ ਇਵੈਂਟ ਦੇ ਫਿਰ ਕਈ event_path ਹੋ ਸਕਦੇ ਹਨ।

ਅਮਲ ਵਿੱਚ ਇਸ mapping ਲਈ server-side ਸਾਥੀਆਂ ਦਾ ਸਹਿਯੋਗ ਚਾਹੀਦਾ ਹੈ। ਇਸਨੂੰ backend ਵਿੱਚ ਸੰਰਚਿਤ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।

ਇਵੈਂਟ ਵਿਸ਼ਲੇਸ਼ਣ ਸੁਧਾਰ

ਪਿਛਲੇ ਕਾਰੋਬਾਰ-ਖ਼ਾਸ ਵਿਸਥਾਰ ਭਾਗ ਵਿੱਚ ਕਾਰੋਬਾਰੀ parameter ਜੋੜਨ ਦੀ ਗੱਲ ਸੀ। WKTrackingData ਇਹ categories ਰਾਹੀਂ ਕਰਦਾ ਹੈ।

ਅਮਲ ਵਿੱਚ full-event ਟ੍ਰੈਕਿੰਗ ਨੇ ਬਹੁਤ bandwidth ਵਿਅਰਥ ਕੀਤਾ। ਕਈ ਇਵੈਂਟ ਲੋੜੀਂਦੇ ਹੀ ਨਹੀਂ ਸਨ [(ŏ_ŏ)]।

ਅਗਲਾ ਸੁਧਾਰ ਹੈ ਕਿ server ਸੰਰਚਨਾ ਫ਼ਾਈਲ ਵਿੱਚ ਸਾਰੇ ਮੰਗੇ ਇਵੈਂਟ ਭੇਜੇ। ਕੇਵਲ ਸੰਰਚਨਾ ਨਾਲ ਮਿਲਦਾ event_path ਅੱਪਲੋਡ ਹੋਵੇ।

ਇੱਥੇ ਕਾਰੋਬਾਰੀ parameter ਲਈ WKTrackingData ਬਿਨਾਂ ਸਿੱਧਾ kvc ਵਰਤਿਆ ਜਾ ਸਕਦਾ ਹੈ।

ਮਿਸਾਲ:

key_path = "viewController.banner.url"

ਜੇ ਇੱਥੋਂ ਤੱਕ ਪੜ੍ਹ ਲਿਆ ਹੈ ਤਾਂ WKTrackingData ਖੋਲ੍ਹੋ ਅਤੇ ਇੱਕ star ਦਿਓ। ਸਵਾਲ ਹੋਵੇ ਤਾਂ GitHub ਉੱਤੇ issue ਖੋਲ੍ਹੋ ਜਾਂ ਹੇਠਾਂ ਟਿੱਪਣੀ ਕਰੋ!