Tracker

Project Url: ttpai/Tracker
Introduction: Tracker 是 Android 上的一个用户行为跟踪框架,根据预先订阅的事件链,以观察者模式监听用户的行为,当用户的行为与订阅的一样时,通知给订阅者。
More: Author   ReportBugs   
Tags:

Tracker 是 Android 上的一个用户行为跟踪框架,根据预先订阅的事件链,以观察者模式监听用户的行为,当用户的行为与订阅的一样时,通知给订阅者。

没有看明白?

没关系,直接说明 traker 的应用场景。“埋点”,当我们的 app 到一定阶段时,一定会有埋点需求,例如在某按钮点击后统计埋点,进行上报,给到产品,可以统计功能的使用度。还有页面跳转 等等……当然还有复杂的埋点,如页面的多级跳传,A->B->C 。或者多个入口进同一页面的分别埋点 A->C, B->C。在埋点服务上,我们一般会选择第三方的服务,如友盟等……,但是埋点代码还是需要我们来写到指定的地方的。这种埋点称为代码埋点。开发人员需要把埋点代码写到业务代码中。在埋点多了后,在重构时,会容易不小心删除埋点,而且也不好管理。当然还有全埋点,也就是在所有的点击事件或页面跳转的地方插入埋点代码,然后一起上报,由专门分析人员从中分析数据。但是这样会造成上传数据量过大,有时候无法精准的统计到某个功能。基于此背景,我们希望能做到按需埋点,但是又能最大程度的不侵入业务代码。使埋点代码集中放到一起管理,而且还要能实现复杂的埋点。所以 Tracker(追踪者) 就是这样产生的。

支持 全量埋点 的监听,示例参考 com.ttpai.sample.FullPointer.java

  1. 监听 所有 view 的点击
  2. 监听 所有页面(activity+Fragment) 的 进入、退出、可见与不可见
  3. 监听 所有 dialog/popupWindow 的 show、dismiss

注? Tracker 框架 只是一个监听的框架,如监听到 view 的点击,回调触发,具体的埋点逻辑需要自己实现,因为各家埋点逻辑不同,不可能统一实现

如何接入?

在 project 中的 build.gradle 中

buildscript {
    dependencies {
        ...
        //gradle 4.0+
        classpath 'com.android.tools.build:gradle:4.0.1'

        classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10'
    }
    allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
    }
 }

在 app 的 build.gradle 中

 apply plugin: 'com.hujiang.android-aspectjx'

 dependencies {
     implementation 'com.github.ttpai:Tracker:1.0.4'
 }

在 application 中注册

@Override
public void onCreate() {
    super.onCreate();
    Track.initTrack(getApplication());
}

如何使用?

监听 AActivity 跳转到 某页面事件:

Track.from(AActivity.class).to(BActivity.class).subscribe(new OnSubscribe<Intent>() {
    @Override
    public void call(Intent intent) {
        Log.d(TAG, "A->B");
    }
});

监听 AActivity 中的某 view 被点击:

  Track.from(AActivity.class).viewClick(R.id.button).subscribe(new OnSubscribe<View>() {
      @Override
      public void call(View view) {
          Log.d(TAG, "A.click(R.id.button)");
      }
 });

除此之外,还可方便实现全局事件监听。在此这上,完成全量埋点的方案

//全 view click 事件
        Track.fromAnyActivity().anyViewClick().subscribe(view -> {
            String actionId = TrackTools.getViewActionId(view);
            String pageId = TrackTools.getPageId(view);
            Object params = TrackTools.getViewParams(view);
            String content = TrackTools.getViewContent(view);
            Map map = extManager.getExtParamsMap(actionId, params, Block.VIEWTAG);

            //插入事件
            LogUtil.i(TAG, "anyViewClick actionId: %s pageId=%s content=%s map=%s", actionId, pageId, content, map);

            insertPoint(actionId, pageId, FullPointer.ACTION_EVENT, CLICK_ACTION, map, content);
        });

//全页面 activity show/hide:

        Track.fromAnyActivity().activityOnCreated().subscribe(activity -> {
            onPageLifeCycle(activity, LIFECYCLE_ENTER);

        }).activityOnResumed().subscribe(activity -> {
            onActivityShowHide(activity, true);
        }).activityOnPaused().subscribe(activity -> {
            onActivityShowHide(activity, false);
        }).activityOnDestroyed().subscribe(activity -> {
            onPageLifeCycle(activity, LIFECYCLE_EXIT);
            TrackTools.cleanPageParams(activity);
        });

//全 fragment 的 show/hide:

//fragment show/hide:
        Track<?> fragmentTrack = Track.from(FragmentActivity.class);
        fragmentTrack.fragmentOnCreateView(Fragment.class).subscribe(fragment -> {
            if (fragment.getView() != null) {
                TrackTools.setViewFragmentTag(fragment.getView(), fragment);
            }
            onPageLifeCycle(fragment, LIFECYCLE_ENTER);
        }).fragmentOnDestroyed(Fragment.class).subscribe(fragment -> {
            onPageLifeCycle(fragment, LIFECYCLE_EXIT);
            TrackTools.cleanPageParams(fragment);
        });

        fragmentTrack.fragmentOnHiddenChanged(Fragment.class).subscribe(fragment ->
                onFragmentShowHide(fragment, !fragment.isHidden()));
        fragmentTrack.fragmentSetUserVisibleHint(Fragment.class).subscribe(fragment -> {
            if (fragment.isResumed()) {
                onFragmentShowHide(fragment, fragment.getUserVisibleHint());
            }
        });
        fragmentTrack.fragmentOnResumed(Fragment.class).subscribe(fragment -> {
            if (!fragment.isHidden() && fragment.getUserVisibleHint()) {
                onFragmentShowHide(fragment, true);
            }
        });
        fragmentTrack.fragmentOnPaused(Fragment.class).subscribe(fragment -> {
            if (!fragment.isHidden() && fragment.getUserVisibleHint()) {
                onFragmentShowHide(fragment, false);
            }
        });
Apps
About Me
GitHub: Trinea
Facebook: Dev Tools