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