目录
1.1先看下为什么采用View.AccessibilityDelegate方式,通过View源码如何执行点击事件:
1.2完成替换View中AccessibilityDelegate类,实现sendAccessibilityEvent(this, eventType)方法
2.3.1Activity及Fragment相关hook接受,点击事件接受
手动无埋点的方式,效率低,成本高,见效慢,故开发一套sdk自动采集pv,click等事件;
实现无埋点主流方案有几下几种:
1.View.AccessibilityDelegate
1.1先看下为什么采用View.AccessibilityDelegate方式,通过View源码如何执行点击事件:
public boolean performClick() {
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;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
第一步:调用View设置的点击事件实例onClick()回调方法,View接受到点击事件回调执行登录,注册,播放视频等操作;
ListenerInfo.mOnClickListener.onClick(this);
第二步:发送给定类型的可访问性事件,AccessibilityEvent定义了可访问的事件类型例如:点击事件-TYPE_VIEW_CLICKED,长按事件-TYPE_VIEW_LONG_CLICKED等;
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
public void sendAccessibilityEvent(int eventType) {
if (mAccessibilityDelegate != null) {
mAccessibilityDelegate.sendAccessibilityEvent(this, eventType);
} else {
sendAccessibilityEventInternal(eventType);
}
}
通过如上代码我们发现最后调用AccessibilityDelegate实例对象方法sendAccessibilityEvent(this, eventType),那么是否可以重写AccessibilityDelegate类和sendAccessibilityEvent(this, eventType)来完成埋点操作呢?
public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) {
mAccessibilityDelegate = delegate;
}
我们发现可以自己手动设置AccessibilityDelegate实例替换View中现有AccessibilityDelegate实例对象,在自定义AccessibilityDelegate类sendAccessibilityEvent(this, eventType)完成埋点操作;
1.2完成替换View中AccessibilityDelegate类,实现sendAccessibilityEvent(this, eventType)方法
在Application提供了监听Activity生命周期的方法registerActivityLifecycleCallbacks(),在生命周期回调onActivityResumed()方法中为RootView下的所有视图设置自己实现AccessibilityDelegate类进行埋点;
public void initActivityLifeCycle(){
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityResumed(Activity activity) {
sendLog(activity, "onActivityResumed");
ViewGroup viewGroup = (ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content);
mOnGlobalLayoutListener = new MOnGlobalLayoutListener(viewGroup);
viewGroup.getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
}
@Override
public void onActivityPaused(Activity activity) {
sendLog(activity, "onActivityPaused");
ViewGroup viewGroup = (ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content);
viewGroup.getViewTreeObserver().removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
mOnGlobalLayoutListener = null;
}
});
}
//遍历设置AccessibilityDelegate实现类
public void setAccessibilityDelegate(ViewGroup viewGroup){
int childCount = viewGroup.getChildCount();
for(int i=0; i<childCount; i++){
if(viewGroup.getChildAt(i) instanceof ViewGroup){
setAccessibilityDelegate((ViewGroup) viewGroup.getChildAt(i));
}else{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
if(viewGroup.getChildAt(i).hasOnClickListeners()){
BuryingPointAccessibilityDelegate accessibilityDelegate = new BuryingPointAccessibilityDelegate();
viewGroup.getChildAt(i).setAccessibilityDelegate(accessibilityDelegate);
}
}
}
}
}
private class MOnGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener{
private ViewGroup viewGroup;
public MOnGlobalLayoutListener(ViewGroup viewGroup){
this.viewGroup = viewGroup;
}
@Override
public void onGlobalLayout() {
setAccessibilityDelegate(viewGroup);
}
}
private MOnGlobalLayoutListener mOnGlobalLayoutListener;
埋点实现:
/**
* AccessibilityDelegate实现类,完成埋点操作
*/
public class BuryingPointAccessibilityDelegate extends View.AccessibilityDelegate {
@Override
public void sendAccessibilityEvent(View host, int eventType) {
super.sendAccessibilityEvent(host, eventType);
//埋点
sendLog(host, eventType);
}
private void sendLog(View host, int eventType) {
if(eventType == AccessibilityEvent.TYPE_VIEW_CLICKED){
Log.d(ViewPathUtil.getViewPath(host), "AccessibilityEvent.TYPE_VIEW_CLICKED");
}
//...
}
}
MainActivity[OneFragment]:LinearLayout/FrameLayout[0]/LinearLayout[0]/AppCompatTextView[0]
AccessibilityEvent.TYPE_VIEW_CLICKED
注意事项:
a.跟视图是指的android.R.id.content,activity.getWindow().getDecorView().findViewById(android.R.id.content)