1.現有的幾種埋點技術的實現原理和優劣分析 (1)代碼埋點:將收集數據的代碼直接寫在需要的地方,當用戶點擊某個控制項或者打開某個頁面時調用到該部分代碼完成數據的收集。 優勢:準確性高,收集數據和發送數據都能精確控制,同時能方便的設置自定義屬性,自定義控制項,自定義View等。 劣勢:埋點工作量大,更新代 ...
1.現有的幾種埋點技術的實現原理和優劣分析
(1)代碼埋點:將收集數據的代碼直接寫在需要的地方,當用戶點擊某個控制項或者打開某個頁面時調用到該部分代碼完成數據的收集。
優勢:準確性高,收集數據和發送數據都能精確控制,同時能方便的設置自定義屬性,自定義控制項,自定義View等。
劣勢:埋點工作量大,更新代價大。
(2)可視化埋點:根據配置文件收集用戶行為,從而獲取數據進行分析。
優勢:無須手動埋點,配置文件可動態更新。
劣勢:配置文件的配置比較耗時,彈出框,隱藏控制項等行為不能收集。收集的數據比較簡單,只能收集用戶行為,不能收集到與行為相關的具體數據。
(3)無埋點:與可視化埋點基本一致。不同點在於可視化埋點是根據配置文件收集數據,無埋點是預先收集所有的用戶行為,然後根據配置文件來提取數據。無埋點可以通過修改配置文件追溯之前的用戶行為數據。
(4)後端埋點:Sensors Analytics 這個平臺有解決方案,優點是能收集到詳細的與行為相關的數據,適用於電商等大平臺。比如用戶選擇了一件商品,點擊了加入購物車,那麼可以收集到用戶信息,商品信息,商品價格,商品庫存,賣家等諸多信息。
埋點技術的選擇
(1)代碼埋點:既可以自己與後臺定義介面,也可以使用第三方,常用的有友盟,百度統計等。
(2)可視化埋點和無埋點:移動端可以自己實現數據採集(下麵有Android端的實現原理和demo)。第三方有諸葛IO,GrowingIO 。在知乎上查了關於這兩個平臺的信息,GrowingIO隱藏收費,官網並沒有說到收費,但是使用15天後發郵件通知收費並停止數據採集和分析。諸葛IO免費模式的數據量是每月200萬條,還有其他收費模式。
(3)後端埋點:Sensors Analytics
總結:根據當前公司產品特點和對埋點的要求,建議用可視化埋點;雖然諸葛IO的免費數據量對目前公司App使用規模來說夠用,但是一方面以後數據量會越來越大,另一方面用戶數據會被第三方掌握;同時在實現上面沒有技術難點,所以,建議自己實現。
附錄:Android實現可視化埋點技術
原理解析:
(1)頁面跳轉:Activity的生命周期,創建BaseActivity基類,實現對Activity生命周期的監聽。
(2)控制項的點擊:根據UI佈局的特性和Android點擊事件傳遞機制實現。讓創建的BaseActivity基類重寫Activity的dispatchTouchEvent方法,當touch button時,可以獲取到按下(DOWN)和抬起(UP)時產生的MotionEvent對象。這個MotionEvent對象有兩個方 法,getRawX()和getRawY(),通過這兩個方法我們可以獲取到“點擊位置”在界面中的坐標。然後搜索所有的子View或者控制項的佈局區域是否包含“點擊位置”,從而來判斷哪個View或控制項被點擊。
難點:如何標識點擊的控制項,這裡我們用該控制項實例化所在的類名和該控制項的UI路徑來做唯一標識。
下麵實現一個具體Demo:
(1)先寫一個簡單的登陸界面:有兩個EditText分別輸入用戶名和密碼,一個登陸Button,一個去註冊的TextView。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/top" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:orientation="vertical" tools:context="com.wangliang160818.traking.MainActivity"> <EditText android:id="@+id/activity_main_user" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="輸入用戶名 "/> <EditText android:id="@+id/activity_main_pwd" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="輸入密碼 "/> <TextView android:id="@+id/login" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="登陸" android:layout_marginTop="12dp" android:background="@color/colorPrimary" android:padding="10dp" android:textColor="@android:color/white" android:textSize="22sp"/> <TextView android:id="@+id/register" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="去註冊" android:layout_marginTop="12dp" android:background="@color/colorAccent" android:padding="10dp" android:textColor="@android:color/white" android:textSize="16sp"/> </LinearLayout>
(2)然後模擬埋點數據,實際中就是我們放在伺服器的埋點文件,通過動態修改這個文件實現動態埋點的效果。
@Override public void onWindowFocusChanged (boolean hasFocus){ super.onWindowFocusChanged(hasFocus); if(allView != null) allView.clear(); allView = getView((ViewGroup) rootView); for(int i=0;i<allView.size();i++) { Log.v("out", allView.get(i).toString()); viewPath.add(mClassName+"."+allView.get(i).toString().split("\\{")[0]); } Log.v("out" , allView.size()+""); Rect outRect = new Rect(); this.getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect); statusBarHeight = outRect.top; }
遍歷佈局文件
/*獲取所有View和沒有子View的ViewGroup*/ public ArrayList<View> getView(ViewGroup viewGroup){ if(views == null) views = new ArrayList<View>(); if(viewGroup == null) return null; //views.add(viewGroup); int count = viewGroup.getChildCount(); for(int i=0;i<count;i++){ if(!(viewGroup.getChildAt(i) instanceof ViewGroup)){ views.add(viewGroup.getChildAt(i)); }else this.getView(viewGroup); } return views; }
點擊時的處理
/*重寫dispatchTouchEvent*/ public boolean dispatchTouchEvent(MotionEvent ev) { if(ev.getAction() == MotionEvent.ACTION_UP){ /*獲取當前點擊位置,遍歷佈局,獲取當前點擊位置對應的view,根據view映射路徑,與json文件中的對比*/ double x = ev.getRawX(); double y = ev.getRawY() - statusBarHeight; if(allView2 != null) allView2.clear(); allView2 = getView((ViewGroup) rootView); for(int i=0;i<allView2.size();i++) { /*獲取點擊位置的view*/ int left = allView2.get(i).getLeft(); int right = allView2.get(i).getRight(); int top = allView2.get(i).getTop(); int bottom = allView2.get(i).getBottom(); if(x > left && x < right && y > top && y < bottom){ /*判斷這個view是否是我們要埋點的*/ String s = mClassName+"."+allView2.get(i).toString().split("\\{")[0]; if(viewPath.contains(s)){ Log.v("out" , "這是我們的埋點:"+s); } } } } return super.dispatchTouchEvent(ev); }
總結:根據無埋點原理初步實現了,目前還有幾個問題:
(1)每個View都必須有唯一標識,當前採用的是用view的路徑,但是這樣當佈局文件層級比較複雜的時候,獲取路徑還有問題。
(2)其二,當佈局有margin,標題欄等情況時需要額外考慮。
將以上兩個問題完善後可以在實際應用中使用,後續做這部分工作。