Android AspectJ common Buried, intercept, monitor the use of annotations

Make a record of learning:

Android AOP programming in
Android's AOP
Android Studio custom Gradle plugin
to see in Android AspectJ strong insertion
jarryleo / MagicBuriedPoint

The two uses AspectJ

(1) modified with a custom annotation entry points, entry points precisely controlled, it is invasive type;

(2) does not require any modifications to the code in the entry point, it is non-invasive.

Intrusive

Invasive usage, typically using a custom annotations, as an entry point selection rule.

Non-invasive

Non-invasive, that does not require the use of additional notes to modify the entry point, entry point without modifying the code.

Access projects use:

In general we will create a separate module provides access to other projects to use the module below TrackPoint

build.gradle module configuration

Two ways: 1.apply plugin: 'android-aspectjx'

                  2.implementation 'org.aspectj:aspectjrt:1.8.+'

Notes ways:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AspectAnalyze {
    String name();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AspectDebugLog {
}
public class MainActivity extends Activity {
    private Button myButton;
    private final String TAG= this.getClass().getSimpleName();

    @AspectAnalyze(name = "MainActivity.onCreate")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myButton=findViewById(R.id.myButton);
        myButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"text",Toast.LENGTH_LONG).show();
                onNameClick();
            }
        });
    }

    @AspectDebugLog
    @AspectAnalyze(name = "onNameClick")
    public void onNameClick() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @AspectAnalyze(name = "MainActivity.onDestroy")
    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }
}
package com.trackpoint;

import android.util.Log;

import com.trackpoint.annotation.AspectAnalyze;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.aspectj.lang.reflect.SourceLocation;

@Aspect
public class AnnotationAspectTrace {
    private final String TAG = this.getClass().getSimpleName();
    private static AspectTraceListener aspectTraceListener;

    /**
     * 针对所有继承 Activity 类的 onCreate 方法
     */
    @Pointcut("execution(* android.app.Activity+.onCreate(..))")
    public void activityOnCreatePointcut() {

    }

    /**
     * 针对带有AspectAnalyze注解的方法
     */
    @Pointcut("execution(@com.trackpoint.annotation.AspectAnalyze * *(..))")
    public void aspectAnalyzeAnnotation() {
    }
    /**
     * 针对带有AspectAnalyze注解的方法
     */
    @Pointcut("execution(@com.trackpoint.annotation.AspectDebugLog * *(..))")
    public void aspectDebugLogAnnotation() {
    }
    /**
     * 针对前面 aspectAnalyzeAnnotation() 的配置
     */
    @Around("aspectAnalyzeAnnotation()")
    public void aroundJoinAspectAnalyze(final ProceedingJoinPoint joinPoint) throws Throwable {
        Object target = joinPoint.getTarget();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        AspectAnalyze aspectAnalyze = methodSignature.getMethod().getAnnotation(AspectAnalyze.class);
        long startTimeMillis = System.currentTimeMillis();
        joinPoint.proceed();
        if (aspectTraceListener != null) {
            aspectTraceListener.onAspectAnalyze(joinPoint, aspectAnalyze, methodSignature, System.currentTimeMillis() - startTimeMillis);
        }
    }
    /**
     * 针对前面 aspectDebugLogAnnotation() 或 activityOnCreatePointcut() 的配置
     */
    @Around("aspectDebugLogAnnotation() || activityOnCreatePointcut()")
    public void aroundJoinAspectDebugLog(final ProceedingJoinPoint joinPoint) throws Throwable {
        long startTimeMillis = System.currentTimeMillis();
        joinPoint.proceed();
        long duration = System.currentTimeMillis() - startTimeMillis;
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        SourceLocation location = joinPoint.getSourceLocation();
        String message = String.format("%s(%s:%s) [%sms]", methodSignature.getMethod().getName(), location.getFileName(), location.getLine(), duration);
        if (aspectTraceListener != null) {
            aspectTraceListener.logger("AspectTrace", message);
        } else {
            Log.e("AspectTrace", message);
        }
    }

    public static void setAspectTraceListener(AspectTraceListener aspectTraceListener) {
        AnnotationAspectTrace.aspectTraceListener = aspectTraceListener;
    }

    public interface AspectTraceListener {
        void logger(String tag, String message);

        void onAspectAnalyze(ProceedingJoinPoint joinPoint, AspectAnalyze aspectAnalyze, MethodSignature methodSignature, long duration);
    }
}

Non-invasive:

The following are several common scenarios

package com.trackpoint;

import android.util.Log;
import android.widget.Toast;

import com.trackpoint.annotation.AspectAnalyze;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.aspectj.lang.reflect.SourceLocation;

@SuppressWarnings("unused")
@Aspect
public class AspectTrace {
    private final String TAG = "AspectTrace";

    @Around("call(* android.widget.Toast.setText(java.lang.CharSequence))")
    public void handleToastText(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Log.d(TAG," start handleToastText");
        proceedingJoinPoint.proceed(new Object[]{"处理过的toast"}); //这里把它的参数换了
        Log.d(TAG," end handleToastText");
    }

    @Before("call(* android.widget.Toast.show())")
    public void changeToast(JoinPoint joinPoint) throws Throwable {
        Toast toast = (Toast) joinPoint.getTarget();
        toast.setText("修改后的toast");
        Log.d(TAG, " --> changeToast");
    }

    /**
     * 在MainActivity的所有生命周期的方法中打印log
     * @param joinPoint
     * @throws Throwable
     */
    @Before("execution(* android.app.Activity.**(..))")
    public void method(JoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String className = joinPoint.getThis().getClass().getSimpleName();
        Log.e(TAG, "class:" + className+" method:" + methodSignature.getName());
    }

}

@Aspect
public class ViewAspect {
    private final String TAG = "ViewAspect";

    @Pointcut("execution(void android.view.View.OnClickListener.onClick(..))")
    public void onClickPointcut() {
    }

    @Pointcut("execution(* *.*onTouch(..))")
    public void onTouchPointcut() {
        Log.d(TAG,"onTouchPointcut");
    }


    @Around("onClickPointcut()")
    public void aroundJoinClickPoint(final ProceedingJoinPoint joinPoint) throws Throwable {
        Object target = joinPoint.getTarget();
        String className = "";
        if (target != null) {
            className = target.getClass().getName();
        }
        //获取点击事件view对象及名称,可以对不同按钮的点击事件进行统计
        Object[] args = joinPoint.getArgs();
        if (args.length >= 1 && args[0] instanceof View) {
            View view = (View) args[0];
            int id = view.getId();
            String entryName = view.getResources().getResourceEntryName(id);
            TrackPoint.onClick(className, entryName);
        }
        joinPoint.proceed();//执行原来的代码
    }
}

Encounter problems:

1. The use of the process often does not interface OnTouch (..)

2. Each change aspect code needs to clean items

github demo Code: https://github.com/xingchongzhu/AspectJDemo

Published 92 original articles · won praise 27 · views 90000 +

Guess you like

Origin blog.csdn.net/zhuxingchong/article/details/104756795