作者:Tamic
連結:https://juejin.im/post/5b88bc04e51d4538c210bfbf
背景
目前統計打點已經是一個產品常見的需求,尤其在業務樣式探索的前期,埋點功能更是必不可少的功能,下麵將介紹最簡單的app全埋點方案!
什麼是資料埋點
資料埋點是一般專案採用統計UV,PV,Action,Time等一系列的資料資訊,對特定使用者行為或事件進行捕獲、處理和傳送的相關技術及其實施過程。
為什麼要資料埋點
產品或運營分析人員,基於埋點資料分析需要,對使用者行為的每一個事件進行埋點佈置,並透過SDK上報埋點的資料結果,進行分析,併進一步最佳化產品或指導運營。
資料埋點包括哪些
資料埋點採集樣式
自動埋點
App透過代理,呼叫Sdk相關API,進行的將資料埋點上報的樣式.
無痕埋點
無需透過專門提供代理類,直接由sdk提供相關介面,或者透過編譯工具,預編譯替換程式碼等,直接由sdk全部負責採集上報
視覺化埋點
視覺化埋點指 前端或者app端基於dom 元素和控制元件所精準自動埋點的上報的方案。
對比分析:
自動埋點:
缺點:
1、開發人員工作量大,需對業務提供唯一的ID,來區分每一個業務,無論是否提供sdk代理,業務開發人員至少需要多次呼叫sdk相關API.
2、業務人員和產品溝通成本提高,需要對具體業務制定相關的業務標識,以便於產品分析和統計
優點:
產品運營工作量少,對照業務對映表,就能分析出還原相關業務場景, 資料比較精細,無需大量的加工和處理。無痕埋點
缺點:
1、sdk開發人員需提供一套無痕埋點技術成品,包括能正確獲取PV,UV,ACtion,TIme等多項統計指標。前期技術投入大。
2、資料量大,需後端落地進行大量處理,並由產品進行自我還原業務員場景。 無論採用智慧系統平臺,還是透過原生的資料庫查詢資料,都是一種大量的分析精力。
優點:
1、開發人員工作量小,無需對業務標識進行唯一區分,由sdk自動進行生成,ID規則由sdk和產品進行約定。減少業務人員的溝通成本和使用步驟。
2、資料量全面,改寫面廣,產品可按需進行分析。做到毫無遺漏。
3、支援動態頁面和區域性動效的統計。視覺化埋點
優點:
1、相對資料量而言
相比較於無埋點相而言對較低,但是這個視覺化元素的識別技術是客戶端或者前端所要實現的,唯一id生成也無需客戶端去自定義規則,這套生成規則由相關產品在自動化工具的情況下生成配置表,下發到客戶端,再由客戶端按坑就班到相關介面去實現。
2、資料量相對精確
缺點:
1、視覺化工具的平臺的搭建,靜態頁面的元素識別都需要額外開發。
2、動態效果可能會遺漏。
實現方案:
埋點需求可參考我之前的文章:
App優質精準的使用者行為統計和日誌打撈方案:https://blog.csdn.net/sk719887916/article/details/50931485
App打造自定義的統計SDK:
https://www.jianshu.com/p/cd83e81b78aa
自動埋點實際上也是,提供一個base類,由業務類繼承base類,在base裡面做相關統計api呼叫,
可參考我的github:github.com/Tamicer/Sky…
打點要素
android端打點的四個要素
1、view展現,點選,消失
AccessibilityDelegate.
AccessibilityDelegate的使用(API level 14)
AccessibilityDelegate主要用來對view做一個檢測,包括view的點選,選中,滑動,touch,文字變化及描述等等,可以用來做一些資料統計或者分析
建立一個自定義的AccessibilityDelegate,實現sendAccessibilityEvent(View host, int eventType)方法,然後透過view.setAccessibilityDelegate(),當該view的相關屬性出現變化時,就會回呼到實現的sendAccessibilityEvent方法中,我們可以透過AccessibilityEvent.type_xxx來區分eventType是什麼型別,然後做不同的處理
給View設定AccessibilityDelegate,而當View 產生了click,long_click 等事件的時候.會在響應原有的Listener方法後.傳送訊息給
AccessibilityDelegate.然後在sendAccessibilityEvent方法下做打點操作.2、頁面監聽
ActivityLifecycleCallbacks
application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {}
在onResume中對activity.getWindow().getDecorView().getRootView()進行向下遍歷3、定位View
View 的唯一性.
根據context的className+View自身的 Id的String 值.(String 值可以反射R檔案得到)+View 的className值確定.
當前沒有id.向上需要父類的id,如果父類id 沒有則記錄父類className+getChildAt()值並且繼續往上找,直到找到有id的view或者沒有父類為止4、上報時機
啟動上報 輪詢上報,網路變化,前後臺切換,主動上報,推送回撈
核心實現:
以Android作為列子:
提供自動遍歷元素 並能撲捉點選的控制元件的activity, 並能在生命週期統計pv的開啟和關閉,呼叫我開源的SkyMonitoring的對應的api.
複寫dispatchTouchEvent(MotionEvent ev) 事件函式,確定被點選的view的相關位置,並生成唯一的ID,企業級app都是從伺服器下發對應的ID,對應頁面去呼叫埋點sdk Api,實現事件行為TcStatInterface.initEvent(path.viewTree);。
這個path就是view的路徑,頁面的深度路徑,包括開啟和關閉sdk在SkyMonitoring中已能自動獲取。
本次demo是id生成規則是按照 :包名+ Activity+ Viewgroup+ Layout+ view + View index + viewID實現的。
業務直接去繼承TamicActivity即可,就能去實現所有視覺化view的埋點功能。
程式碼如下:
public abstract class TamicActivity extends AppCompatActivity {
private int statusBarHeight;
View rootView;
String rootViewTree;
String bigDataPrefix;
String bigDataIngorePrefix;
String bigDataEventPrefix;
private String TAG = "LYK";
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
//獲取到根節點的view
rootView = getWindow().getDecorView();
//控制元件在檢視樹上的根路徑
rootViewTree = getPackageName() + "." + getClass().getSimpleName();
//字首名 bigData
bigDataPrefix = "Tamic_test";
//字首名 bigData_
bigDataIngorePrefix = bigDataPrefix + "";
//字首名 bigdata_ignore
bigDataEventPrefix = bigDataIngorePrefix +"Igmore";
}
@Override
protected void onResume() {
super.onResume();
TcStatInterface.recordPageStart(TamicActivity.this);
}
@Override
protected void onPause() {
super.onPause();
TcStatInterface.recordPageEnd();
}
@Override
protected void onDestroy() {
super.onDestroy();
// APP退出
TcStatInterface.recordAppEnd();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_DOWN){
ViewPath path = findClickView(ev);
if(path != null) {
Log.e(TAG, "path -->" + path.viewTree);
TcStatInterface.initEvent(path.viewTree);
}
}
return super.dispatchTouchEvent(ev);
}
private ViewPath findClickView(MotionEvent ev) {
Log.e(TAG, "bigdata-->findClickView");
ViewPath clickView = new ViewPath(rootView, rootViewTree);
return searchClickView(clickView, ev, 0);
}
private ViewPath searchClickView(ViewPath myView, MotionEvent event, int index) {
ViewPath clickView = null;
View view = myView.view;
if (isInView(view, event)) {
myView.level++;
if (myView.level == 2 && !"LinearLayout".equals(view.getClass().getSimpleName())) {
myView.filterLevelCount++;
}
if (myView.level > myView.filterLevelCount) {
myView.viewTree = myView.viewTree + "." + view.getClass().getSimpleName() + "[" + index + "]";
}
Log.i(TAG, "bigdata-->tag = " + view.getTag());
if (view.getTag() != null) {
// 主動標記不需要統計時,不進行自動統計
String tag = view.getTag().toString();
if (tag.startsWith(bigDataIngorePrefix)) {
return null;
} else if (tag.startsWith(bigDataPrefix)) {
if (tag.startsWith(bigDataEventPrefix)) {
myView.specifyTag = tag.replace(bigDataEventPrefix, "");
}
return myView;
}
}
if (view instanceof ViewGroup) {
if (view instanceof AbsListView) {
Log.i(TAG, "bigdata-->AbsListView ");
return null;
}
ViewGroup group = (ViewGroup) view;
int childCount = group.getChildCount();
if (childCount == 0) {
return myView;
}
for (int i = childCount - 1; i >= 0; i--) {
myView.view = group.getChildAt(i);
clickView = searchClickView(myView, event, i);
if (clickView != null) {
return clickView;
}
}
} else {
clickView = myView;
}
}
return clickView;
}
private boolean isInView(View view, MotionEvent event) {
if (view == null || view.getVisibility() != View.VISIBLE) {
return false;
}
int clickX = (int) event.getRawX();
int clickY = (int) event.getRawY();
int[] location = new int[2];
view.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
int width = view.getWidth();
int height = view.getHeight();
return clickX > x && clickX y && clickY }
}
App專案整合使用,初始化url和相關統計配置字典,這個字典可以從伺服器下發下來,我本次只是透過簡單的本地檔案做實踐。
public class StatAppliation extends Application {
@Override
public void onCreate() {
super.onCreate();
// you app id
int appId = 21212;
// assets
String fileName = "my_statconfig.json";
String url = "https://github.com/Tamicer/TamicAppMonitoring";
// init statSdk
TcStatInterface.initialize(this, appId, "you app chanel", fileName);
TcStatInterface.setUrl(url);
TcStatInterface.setUploadPolicy(TcStatInterface.UploadPolicy.UPLOAD_POLICY_DEVELOPMENT, TcStatInterface.UPLOAD_TIME_ONE);
}
}
作者:Tamic
連結:https://juejin.im/post/5b88bc04e51d4538c210bfbf
來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
視覺化也可以透過aop插樁實現,但是實現起來對程式碼的入侵性太高,這裡不做介紹。
aop插樁對碎片化fragment支援比較好。對這塊的介紹可看我以前在公眾號推送的一篇文章:https://mp.weixin.qq.com/s/neH9JXL5AYzjaAaxF-ZF-g
可參考:
https://www.baidu.com/link?url=FniQOFyj1pd6O5Fz6viRMN3ZgexIKAk7SQ08EgpBU9cHHMszPlm2jRXJ21mkomtY&wd;=&eqid;=ffc87acf0005fd18000000045a5d98dd
專案地址
https://github.com/Tamicer/TamicAppMonitoring
●編號374,輸入編號直達本文
●輸入m獲取到文章目錄
Java程式設計
更多推薦《18個技術類公眾微信》
涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。