Android無痕埋點(diǎn)(1)— 點(diǎn)擊監(jiān)聽

背景

很多時候,因?yàn)楫a(chǎn)品都會要獲取用戶的行為,需要客戶端進(jìn)行相關(guān)的埋點(diǎn)凭需。埋點(diǎn)主要分為兩種:

  1. 侵入式埋點(diǎn)
    在每個需要埋點(diǎn)的地方手動添加代碼
  • 優(yōu)點(diǎn):埋點(diǎn)準(zhǔn)確,可以精確描述不同組件之間的關(guān)聯(lián)
  • 缺點(diǎn):代碼耦合度高肝匆,后期難以維護(hù)粒蜈,不需要的埋點(diǎn)需要手動刪除
  1. 無痕埋點(diǎn)
    通過全局監(jiān)聽或AOP技術(shù)給所有的View添加埋點(diǎn)
  • 優(yōu)點(diǎn):代碼耦合度低,靈活度高术唬,不同項(xiàng)目可復(fù)用
  • 缺點(diǎn):沒有侵入式埋點(diǎn)精準(zhǔn)薪伏,無法描述兩個組件之間的關(guān)聯(lián)

面試一句話

無痕埋點(diǎn)就是一種通過全局監(jiān)聽或者AOP技術(shù)省去手動埋點(diǎn)的技術(shù),它和代碼耦合度低粗仓,靈活度高嫁怀,適用于組件間關(guān)聯(lián)性不強(qiáng)的業(yè)務(wù)埋點(diǎn)


Code

完整代碼可見 -- 代碼路徑


技術(shù)點(diǎn)

無痕埋點(diǎn)的技術(shù)路徑包括View操作的攔截,上報(bào)信息的設(shè)置與埋入借浊,上報(bào)

  1. 點(diǎn)擊監(jiān)聽
  2. 滑動監(jiān)聽
  3. 埋點(diǎn)信息
  4. ASpect監(jiān)聽

點(diǎn)擊監(jiān)聽

實(shí)現(xiàn)方法

通過給View設(shè)置setAccessibilityDelegate來獲取sendAccessibilityEvent回調(diào)監(jiān)聽View的點(diǎn)擊事件

原理

  1. 當(dāng)View被點(diǎn)擊時候塘淑,最后都會走到performClick()方法
    public boolean performClick() {
          // We still need to call this method to handle the cases where performClick() was called
          // externally, instead of through performClickInternal()
          notifyAutofillManagerOnClick();
    
          final boolean result;
          final ListenerInfo li = mListenerInfo;
          if (li != null && li.mOnClickListener != null) {
              playSoundEffect(SoundEffectConstants.CLICK);
              li.mOnClickListener.onClick(this);
              result = true;
          } else {
              result = false;
          }
          // 關(guān)鍵方法
          sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    
          notifyEnterOrExitForAutoFillIfNeeded(true);
    
          return result;
      }
    
  2. 再看sendAccessibilityEvent()方法,可以看到只要view的mAccessibilityDelegate為非空的,就會觸發(fā)sendAccessibilityEvent()回調(diào)
    public void sendAccessibilityEvent(int eventType) {
        if (mAccessibilityDelegate != null) {
            mAccessibilityDelegate.sendAccessibilityEvent(this, eventType);
        } else {
            sendAccessibilityEventInternal(eventType);
        }
    }
    
  3. 所以我們只需要給View設(shè)置AccessibilityDelegate蚂斤,就能對點(diǎn)擊事件進(jìn)行監(jiān)聽,host代表被監(jiān)聽的View存捺,eventType代表事件類型,比如點(diǎn)擊、輸入
    view.setAccessibilityDelegate(new View.AccessibilityDelegate(){
        @Override
        public void sendAccessibilityEvent(View host, int eventType) {
            super.sendAccessibilityEvent(host, eventType);
            Log.d(TAG, "sendAccessibilityEvent: ");
        }
    });
    
  4. 對于層級很深的ViewGroup捌治,我們可以通過遍歷的方式岗钩,對他層級內(nèi)的View和ViewGroup添加監(jiān)聽,為了避免動態(tài)添加的View沒有添加監(jiān)聽肖油,我們需要給ViewGroup添加childView的監(jiān)聽
    /**
     * 設(shè)置Activity頁面中View的事件監(jiān)聽
     *
     * @param activity
     */
    public void setTracker(Activity activity) {
        // 找到根路徑的View
        View contentView = activity.findViewById(android.R.id.content);
        if (contentView != null) {
            setViewTracker(contentView, null);
        }
    }
    
    /**
     * 設(shè)置Fragment頁面中View的事件監(jiān)聽
     *
     * @param fragment
     */
    public void setTracker(Fragment fragment) {
        View contentView = fragment.getView();
        if (contentView != null) {
            setViewTracker(contentView, fragment);
        }
    }
    
    
    /**
     * 設(shè)置View上的事件監(jiān)聽
     *
     * @param view
     */
    public void setTracker(View view) {
        if (view != null) {
            setViewTracker(view, null);
        }
    }
    
    /**
     * 判斷view是否需要埋點(diǎn)兼吓,目前默認(rèn)只要可以點(diǎn)擊的都是true
     *
     * @param view
     * @return
     */
    private boolean needTracker(View view) {
        return true;
    }
    
    
    /**
     * 對每個View添加埋點(diǎn)的監(jiān)聽
     *
     * @param view
     * @param fragment
     */
    private void setViewTracker(View view, Fragment fragment) {
        if (needTracker(view)) {
            if (fragment != null) {
                view.setTag(FRAGMENT_TAG_KEY, fragment);
            }
            view.setAccessibilityDelegate(this);
        }
        if (view instanceof ViewGroup) {
            int childCount = ((ViewGroup) view).getChildCount();
            for (int i = 0; i < childCount; i++) {
                setViewTracker(((ViewGroup) view).getChildAt(i), fragment);
            }
            ((ViewGroup) view).setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
                @Override
                public void onChildViewAdded(View parent, View child) {
                    setTracker(parent);
                }
    
                @Override
                public void onChildViewRemoved(View parent, View child) {
                    setTracker(parent);
                }
            });
            if (needTracker(view)) {
                view.setAccessibilityDelegate(this);
                viewScrollListener.setScrollListener(view);
            }
        }
    }
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市森枪,隨后出現(xiàn)的幾起案子视搏,更是在濱河造成了極大的恐慌,老刑警劉巖县袱,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浑娜,死亡現(xiàn)場離奇詭異,居然都是意外死亡式散,警方通過查閱死者的電腦和手機(jī)筋遭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來杂数,“玉大人宛畦,你說我怎么就攤上這事∽嵋疲” “怎么了次和?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長那伐。 經(jīng)常有香客問我踏施,道長,這世上最難降的妖魔是什么罕邀? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任畅形,我火速辦了婚禮,結(jié)果婚禮上诉探,老公的妹妹穿的比我還像新娘日熬。我一直安慰自己,他們只是感情好肾胯,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布竖席。 她就那樣靜靜地躺著,像睡著了一般敬肚。 火紅的嫁衣襯著肌膚如雪毕荐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天艳馒,我揣著相機(jī)與錄音憎亚,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛第美,可吹牛的內(nèi)容都是我干的蝶锋。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼斋日,長吁一口氣:“原來是場噩夢啊……” “哼牲览!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起恶守,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贡必,沒想到半個月后兔港,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡仔拟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年衫樊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片利花。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡科侈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出炒事,到底是詐尸還是另有隱情臀栈,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布挠乳,位于F島的核電站权薯,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏睡扬。R本人自食惡果不足惜盟蚣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望卖怜。 院中可真熱鬧屎开,春花似錦、人聲如沸马靠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽如孝。三九已至,卻和暖如春娩贷,著一層夾襖步出監(jiān)牢的瞬間第晰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茁瘦,地道東北人品抽。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像甜熔,于是被迫代替她去往敵國和親圆恤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351