Skip to content

LukeLuAndroid/AndroidTracker

Repository files navigation

项目介绍:

通过插装方法,实现自动埋点,在需要获取方法信息的时候,可通过服务端下发指令,
来根据方法的参数和返回值来判断方法中可能存在的问题。

一.添加依赖

implementation project(':TrackerLibrary-Android')
annotationProcessor project(':TrackerProcessor')

android平台可选择android和java两个版本,java平台则只能用java版本(有且只需使用一个版本)

二.初始化,在application中添加如下初始化,addTracker用来表示需要添加的埋点,uploadLogInfo用来自定义上传接口。

如果addTracker返回true则不会执行uploadLogInfo方法,当返回false的时候,下次进入app会统一请求uploadLogInfo,并根据listener判断上传失败或成功

当前抽出数据的存储方式,app可以自定义数据存储和指令存储的方式,通过setTrackerStoreListener()来自定义

Trackers.instance().setTrackerAddListener(new TrackerAddListener() {
    @Override
    public boolean addTracker(String className, String methodName,String tag,Object... args) {
        return false;
    }
}).setTrackerUploadListener(new TrackerUploadListener() {
    @Override
    public void uploadLogInfo(List<TraceLog> list, TrackerResultListener listener) {

    }
}).setDebug(BuildConfig.DEBUG).init();

如果需要自定义数据存储则可设置

Trackers.instance().setTrackerStoreListener(new TrackerStoreListener() {
     @Override
     public Map<String, List<String>> getAllCommand() {
         return null;
     }

     @Override
     public void restoreGroup(List<String> list) {

     }

     @Override
     public List<String> getAllPermitGroup() {
         return null;
     }

     @Override
     public void restoreCommand(Map<String, List<String>> map) {

     }

     @Override
     public void addTraceLog(TraceLog traceLog) {

     }

     @Override
     public List<TraceLog> queryLogs() {
         return null;
     }

     @Override
     public int queryCountByLog(TraceLog traceLog) {
         return 0;
     }

     @Override
     public void removeLogs(List<TraceLog> list) {

     }
   });

三.在需要的类或方法上用Tracker去注解,同时Tracker有几个参数可选

1.enable 是否开启 2.group 当前所属分组 3.tag 标签信息 4.injectorType 所用的注解方法(暂时不需要修改,只支持InjectType.DEFAULT) 5.injectRule 使用方法 injectRule = @InjectRule(regex = "method+\d*")

四.举一个例子

@Tracker
public class Server extends BaseServer {
    public Server() {

    }

    public String[] getSomeThings() {
        System.out.println("不只是这么简单");
        String[] tt = {"ddd", "sss"};
        return tt;
    }

    @Tracker(enable = false)
    public char getSomeThingsUnTracker() {
        return '1';
    }
}

这个例子中 getSomeThings()方法会得到注入,getSomeThingsUnTracker()方法则不会,(后续会添加配置规则功能) 得到的效果是:

public String[] getSomeThings() {
    if (TrackerDefaultInjector.isEnable("com.guuidea.tracker.Server", "getSomeThings", new String[0], new String[0], new Object[0])) {
        TrackerDefaultInjector.insertFront(this, "com.guuidea.tracker.Server", "getSomeThings", new String[0], new String[0], "", new Object[0]);
    }

    String[] tt = new String[]{"ddd", "sss"};
    if (TrackerDefaultInjector.isEnable("com.guuidea.tracker.Server", "getSomeThings", new String[0], new String[0], new Object[0])) {
        TrackerDefaultInjector.insertBack(this, "com.guuidea.tracker.Server", "getSomeThings", new String[0], new String[0], "", tt, new Object[0]);
    }
    return (String[])((String[])tt);
}

isEnable方法的参数说明: 1.类名 2.方法名 3.参数名 4.group 5.参数值

insertFront参数说明: 1.当前对象 2.类名 3.方法名 4.参数名 5.group 6.tag值 7.参数值

insertBack方法和insertFront参数说明方法的区别是 insertBack在倒数第二参数多了一个返回值,该例子上就多了一个tt,如果该方法有返回值则返回结果,没有则返回null

五.关于获取属性对象

 Command.instance().openGroup(group); //打开权限  只是打开权限 可以获取log
 Command.instance().addCommand("com.guuidea.tracker.Server.getSomeThings()", "before#getLog#");
  //在方法执行之前获取log
 Command.instance().addCommand("com.guuidea.tracker.Server.getSomeThings()", "after#getResult#[{\"name\":\"\",\"key\":1},{\"name\":\"aa\",\"key\":2}]");
 //在方法之后获取返回值的第一个元素,返回值本身是一个数组则name即空就可,该结果取的事返回值的第一个元素的aa属性的第二个元素
 Command.instance().addCommand("com.guuidea.tracker.Server.getSomeThings(a,b)", "before#getArgs#0#[{\"name\":\"\",\"key\":1}]");
 //方法执行前的第0个参数的第一个元素
 Command.instance().restoreCommand();

 目前获取对象数据的方式有一下四种
 public static final String GET_LOG = "getLog";  ////只支持在方法之前 即before#getLog
 //获取结果
 public static final String GET_RESULT = "getResult";  //只支持方法之后 即after#getResult
 //方法的参数
 public static final String GET_ARGS = "getArgs";  //方法前后都可以
 //类的属性
 public static final String GET_PROP = "getProp";  //方法前后都可以

六.关于配置规则

新增@InjectRule,它有一个isMainRule的属性,表示是否主rule,默认false就好

在app中新建一个类或者用在application上加一个注解如下:

@InjectRule(regex = "^test+\\w*", attrs = {Modifier.PUBLIC},isMainRule = true)
public class MainApplication extends Application {
}

这样表示匹配名字为test开头的方法名,且方法为PUBLIC属性,同时有效

除了主规则外,其他情况@InjectRule不可以单独使用,需配合@Tracker使用如下:

@Tracker(injectRule = @InjectRule(regex = "onCreate"))
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    }
}

regex:表示正则匹配 Modifier:目前支持的修饰符有 PUBLIC,PROTECTED,PRIVATE,ABSTRACT,STATIC,FINAL

如果同时存在主rule和当前rule,则以当前rule为准。

七.支持第匿名类(在正常类下的第一层匿名类),比如:

* 1.
```
mTvAdd.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
        }
    });
```

则插装路径信息为:com.guuidea.tracker.MainActivity.onCreate.mTvAdd.onClick1 按照第五条获取参数信息的时候可以用 Command.instance().addCommand("com.guuidea.tracker.MainActivity.onCreate.mTvAdd.onClick(v)", "before#getLog#");

* 2.
```
new Handler().postDelay(new Runnable(){
   public void run(){
   }
});
```

则插装路径信息为:com.guuidea.tracker.MainActivity.onCreate.new Handler().run0 注意:匿名类的方法插装需要在父类的基础上添加注解,本身不支持注解

八. 关于插装与否的判定,当前方法或类的颗粒度越小,权限越大,即

 @Tracker(injectRule = @InjectRule(regex = "test"))
 private class SearchClass {
    @Tracker()
    public class KeyListener implements View.OnKeyListener {
        @Override
        public boolean onKey(View arg0, int arg1, KeyEvent arg2) {
            return false;
        }
    }
 }

这个例子中KeyListener的注解@Tracker优先级高于SearchClass的注解,所以onKey方法还是会被插装

九.高级自定义,现在可以自定义设置定义TrackerNode

Trackers.instance().setTrackerNodeProvider(new TrackerNodeProvider() {
    @Override
    public TrackerNode newInstance(Object o, String s, String s1, String[] strings, String[] strings1, String s2, String s3, Object... objects) {
        return null;
    }

    @Override
    public TrackerNode newInstance(Tracker tracker, Object o, String s, String s1, String[] strings, String[] strings1, String s2, Method method, Object... objects) {
        return null;
    }
})

TrackerNode主要包括三个方法:

  public abstract Object getParameter(String name, String def);

  public abstract TrackerInvoker invoker(Object input);

  public abstract void execute(String script, String type, Object result, Object... args);

其中execute方法会执行指令的时候会执行,invoker方法在针对反射注入法的时候会执行

十.添加了一些工具类在TrackerUtils中,以及一些callback类中添加两个默认定义的addListener和UploadListener的方法处理分别为

RocketChatCallBack、RocketChatCallBackWithOutToken和DefaultUploadListenerImpl、RockerChatUploaderImpl

十一. 添加混淆规则

-keep public class com.sdk.tracker.Trackers -keep public class com.sdk.tracker.log.TraceLog -keep public class com.sdk.annotation.{;} -keep public class com.sdk.tracker.db.listener.{;}

About

android自动埋点实现

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published