Skip to content

Latest commit

 

History

History
516 lines (380 loc) · 24.6 KB

README_EN.md

File metadata and controls

516 lines (380 loc) · 24.6 KB

English | 简体中文

🔥🔥🔥Help you transform into an Android platform framework with AOP architecture AndroidAOP

Build Downloads Python Package Index Docker Pulls Sponsors

README.md

It is recommended to click Docs below to directly view the documentation with better experience

Brief Description

        This is a framework that helps Android App transform into AOP architecture. With just one annotation, you can request permissions, switch threads, prohibit multiple clicks, monitor all click events at once, monitor the life cycle, etc. You can also customize your own Aop code without using AspectJ.

Special feature

1 . This library has built-in some aspect annotations commonly used in development for you to use.

2 . This library supports you to make aspects by yourself, and the syntax is simple and easy to use.

3 . This library supports Java and Kotlin code simultaneously

4 . This library supports switching into third-party libraries

5 . This library supports the case where the pointcut method is a Lambda expression.

6 . This library supports coroutine functions whose pointcut methods are suspend.

7 . This library supports generating Json files of all pointcut information to facilitate an overview of all pointcut locations Configure here

8 . This library supports debug rapid development mode, allowing you to package at almost the same speed

9 . This library supports component-based development mode

10. This library is pure static weaving into AOP code

11. This library is not implemented based on AspectJ. The amount of woven code is very small and the intrusion is extremely low

12. Rich and complete usage documentation helps you fully understand the usage rules of this library click here to go to the wiki document

13. There are also plug-in assistants that help you generate section codes for your use click here to download

show

Version restrictions

Minimum Gradle version: 7.6👇

show

Minimum SDK version: minSdkVersion >= 21

Star trend chart

Stargazers over time


Steps for usage

Can I give the project a Star before starting? Thank you very much, your support is my only motivation. Welcome Stars and Issues!

1. Introduce the plug-in, choose one of the two methods below (required)

Method 1: apply method

Depend on the plug-in in build.gradle in the project root directory

  • Using the plugins DSL:

    plugins {
        //Required item 👇 apply is set to true to automatically apply debugMode to all modules, if false, follow step 5 below.
        id "io.github.FlyJingFish.AndroidAop.android-aop" version "2.2.5" apply true
    }
    Using legacy plugin application:
    buildscript {
         dependencies {
             //Required items 👇
             classpath 'io.github.FlyJingFish.AndroidAop:android-aop-plugin:2.2.5'
         }
    }
    //👇Add this sentence to automatically apply debugMode to all modules. If not, follow step 5 below.
    apply plugin: "android.aop"

Add in build.gradle of app

  • Using the plugins DSL:

    //Required items 👇
    plugins {
         ...
         id 'android.aop'//It is best to put it on the last line
    }
    Using legacy plugin application:
    //Required items 👇
    apply plugin: 'android.aop' //It's best to put it on the last line

Method 2: plugins method

  • Add directly to build.gradle of app

    //Required items 👇
    plugins {
         ...
         id "io.github.FlyJingFish.AndroidAop.android-aop" version "2.2.5"
    }

2. If you need to customize aspects, and the code is Kotlin (optional)

  • Depend on the plug-in in build.gradle in the project root directory
plugins {
     //Optional 👇, if you need to customize aspects and use the android-aop-ksp library, you need to configure it. The version number below is determined according to the Kotlin version of your project
     id 'com.google.devtools.ksp' version '1.8.0-1.0.9' apply false
}

List of matching version numbers for Kotlin and KSP Github

3. Introduce dependent libraries (required)

plugins {
     //Optional 👇, if you need to customize aspects and use the android-aop-ksp library, you need to configure it
     id 'com.google.devtools.ksp'
}

dependencies {
     //Required items 👇
     implementation 'io.github.FlyJingFish.AndroidAop:android-aop-core:2.2.5'
     //Optional 👇This package provides some common annotation aspects
     implementation 'io.github.FlyJingFish.AndroidAop:android-aop-extra:2.2.5'
    
     //Required item 👇If you already have this item in your project, you don’t need to add it.
     implementation 'androidx.appcompat:appcompat:1.3.0' // At least in 1.3.0 and above
     
     //Optional 👇, if you want to customize aspects, you need to use them, ⚠️supports aspects written in Java and Kotlin code
     ksp 'io.github.FlyJingFish.AndroidAop:android-aop-ksp:2.2.5'
     //Optional 👇, if you want to customize aspects, you need to use them, ⚠️only applies to aspects written in Java code
     annotationProcessor 'io.github.FlyJingFish.AndroidAop:android-aop-processor:2.2.5'
     //⚠️Choose one of the above android-aop-ksp and android-aop-processor
}

Tip

1、ksp or annotationProcessor can only scan the current module. Custom aspect codes are added to the module where they are located. But custom aspect codes are globally effective; required dependencies can be added only to public modules through the API.
"android-aop-extra" usage tutorial

4. Add the androidAopConfig configuration item in app’s build.gradle (this step is an optional configuration item)

Click here to see how to configure

5. The code weaving method can be set during development (this step is an optional configuration item)

Click here to see how to configure

This library has some built-in functional annotations for you to use directly.

Annotation name Parameter description Function description
@SingleClick value = interval of quick clicks, default 1000ms Click the annotation and add this annotation to make your method accessible only when clicked
@DoubleClick value = maximum time between two clicks, default 300ms Double-click annotation, add this annotation to make your method enterable only when double-clicked
@IOThread ThreadType = thread type Switch to the sub-thread operation. Adding this annotation can switch the code in your method to the sub-thread for execution
@MainThread No parameters The operation of switching to the main thread. Adding this annotation can switch the code in your method to the main thread for execution
@OnLifecycle* value = Lifecycle.Event Monitor life cycle operations. Adding this annotation allows the code in your method to be executed only during the corresponding life cycle
@TryCatch value = a flag you customized Adding this annotation can wrap a layer of try catch code for your method
@Permission* value = String array of permissions The operation of applying for permissions. Adding this annotation will enable your code to be executed only after obtaining permissions
@Scheduled initialDelay = delayed start time
interval = interval
repeatCount = number of repetitions
isOnMainThread = whether to be the main thread
id = unique identifier
Scheduled tasks, add this annotation to make your method Executed every once in a while, call AndroidAop.shutdownNow(id) or AndroidAop.shutdown(id) to stop
@Delay delay = delay time
isOnMainThread = whether the main thread
id = unique identifier
Delay task, add this annotation to delay the execution of your method for a period of time, call AndroidAop.shutdownNow(id) or AndroidAop .shutdown(id) can be canceled
@CheckNetwork tag = custom tag
toastText = toast prompt when there is no network
invokeListener = whether to take over the check network logic
Check whether the network is available, adding this annotation will allow your method to enter only when there is a network
@CustomIntercept value = a flag of a string array that you customized Custom interception, used with AndroidAop.setOnCustomInterceptListener, is a panacea

Tip

The above functions are located in the android-aop-extra library. For detailed instructions, please see the documentation

Custom Aspects

This library uses the following five annotations to implement custom aspects

  • @AndroidAopPointCut is an aspect that annotates methods
  • @AndroidAopMatchClassMethod is the aspect of matching class methods
  • @AndroidAopReplaceClass is called by the replacement method
  • @AndroidAopModifyExtendsClass is a modified inherited class
  • @AndroidAopCollectMethod Is a collection inheritance class

1. @AndroidAopPointCut is used to make aspects in the form of annotations on the method. The above annotations are all made through this. Wiki documentation

  • Create annotations(You need to implement the BasePointCut interface, and fill in the annotations above for its generic type)
@AndroidAopPointCut(CustomInterceptCut::class)
@Target(
    AnnotationTarget.FUNCTION,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER
)
@Retention(
    AnnotationRetention.RUNTIME
)
annotation class CustomIntercept(vararg val value: String = [])
Java writing method:
@AndroidAopPointCut(CustomInterceptCut.class)
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomIntercept {
    String[] value() default {};
}
  • Create a class that annotates the aspect (needs to implement the BasePointCut interface, and fill in the above annotation with its generic type)
class CustomInterceptCut : BasePointCut<CustomIntercept> {
     override fun invoke(
         joinPoint: ProceedJoinPoint,
         annotation: CustomIntercept //annotation is the annotation you add to the method
     ): Any? {
         //Write your logic here
         // joinPoint.proceed() means to continue executing the logic of the point-cut method. If this method is not called, the code in the point-cut method will not be executed.
         // About ProceedJoinPoint, you can see the wiki document, click the link below for details
         return joinPoint.proceed()
     }
}
  • use

Directly add the annotation you wrote to any method, for example, to onCustomIntercept(). When onCustomIntercept() is called, it will first enter the invoke method of CustomInterceptCut mentioned above.

@CustomIntercept("I am custom data")
fun onCustomIntercept(){
    
}

This library has some built-in functional annotations for you to use directly

2. @AndroidAopMatchClassMethod is used to match aspects of a certain class and its corresponding method, Wiki documentation

If you want to Hook all onClicks of android.view.View.OnClickListener, to put it bluntly, you want to globally monitor all click events of OnClickListener. The code is as follows:

@AndroidAopMatchClassMethod(
     targetClassName = "android.view.View.OnClickListener",
     methodName = ["onClick"],
     type = MatchType.EXTENDS //type must be EXTENDS because you want to hook all classes that inherit OnClickListener
)
class MatchOnClick : MatchClassMethod {
// @SingleClick(5000) //Combined with @SingleClick, add multi-point prevention to all clicks, 6 is not 6
     override fun invoke(joinPoint: ProceedJoinPoint, methodName: String): Any? {
         Log.e("MatchOnClick", "======invoke=====$methodName")
         return joinPoint.proceed()
     }
}

3. @AndroidAopReplaceClass is used for replacement method calls, Wiki documentation

This method is a supplement to @AndroidAopMatchClassMethod

  • Kotlin
@AndroidAopReplaceClass("android.util.Log")
object ReplaceLog {
    @AndroidAopReplaceMethod("int e(java.lang.String,java.lang.String)")
    @JvmStatic
    fun e( tag:String, msg:String) :Int{
        return Log.e(tag, "ReplaceLog-$msg")
    }
}
Java
@AndroidAopReplaceClass(
         "android.widget.Toast"
)
public class ReplaceToast {
    @AndroidAopReplaceMethod(
            "android.widget.Toast makeText(android.content.Context, java.lang.CharSequence, int)"
    )
    //  Because the replaced method is static, the parameter type and order correspond to the replaced method one-to-one.
    public static Toast makeText(Context context, CharSequence text, int duration) {
        return Toast.makeText(context, "ReplaceToast-"+text, duration);
    }
    @AndroidAopReplaceMethod(
            "void setGravity(int , int , int )"
    )
    //  Because the replaced method is not a static method, the first parameter is the replaced class, and the subsequent parameters correspond to the replaced method one-to-one.
    public static void setGravity(Toast toast,int gravity, int xOffset, int yOffset) {
        toast.setGravity(Gravity.CENTER, xOffset, yOffset);
    }
    @AndroidAopReplaceMethod(
            "void show()"
    )
    //  Although the replaced method has no parameters, because it is not a static method, the first parameter is still the replaced class.
    public static void show(Toast toast) {
        toast.show();
    }
}

4. @AndroidAopModifyExtendsClass is an inherited class that modifies the target classWiki documentation

Usually, you replace one layer in the inheritance relationship of a class, then rewrite some functions, and add some logic code you want to add to the rewritten functions to monitor and rewrite the original logic.

@AndroidAopModifyExtendsClass("androidx.appcompat.widget.AppCompatImageView")
public class ReplaceImageView extends ImageView {
    public ReplaceImageView(@NonNull Context context) {
        super(context);
    }
    public ReplaceImageView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ReplaceImageView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void setImageDrawable(@Nullable Drawable drawable) {
        super.setImageDrawable(drawable);
        //做一些监测或者再次修改
    }
}

5. @AndroidAopCollectMethod is a aspects that collects inherited classes of a class Wiki documentation

It is extremely simple to use, the sample code has already explained

  • Kotlin
object InitCollect {
     private val collects = mutableListOf<SubApplication>()

     @AndroidAopCollectMethod
     @JvmStatic
     fun collect(sub: SubApplication){
       collects.add(sub)
     }
  
     // Call this method directly. The collects collection contains data.
     fun init(application: Application){
         for (collect in collects) {
             collect.onCreate(application)
         }
     }
}
Java
public class InitCollect2 {
  private static List<SubApplication2> collects = new ArrayList<>();
  @AndroidAopCollectMethod
  public static void collect(SubApplication2 sub){
    collects.add(sub);
  }

  // Call this method directly. The collects collection contains data.
  public static void init(Application application){
    Log.e("InitCollect2","----init----");
    for (SubApplication2 collect : collects) {
      collect.onCreate(application);
    }
  }
}

The library comes with proguard-rules.pro rules and is automatically imported. Normally no manual import is required. You can also go here to view proguard-rules

Appreciation

You’ve all seen it here. If you like AndroidAOP, or feel that AndroidAOP has helped you, you can click “Star” in the upper right corner to support it. Your support is my motivation, thank you~ 😃

If you feel that AndroidAOP has saved you a lot of development time and added luster to your project, you can also scan the QR code below and invite the author for a cup of coffee ☕

If you comment on the name in the donation message, it will be recorded in the list~ If you are also a GitHub open source author, you can leave the GitHub project address or personal homepage address when donating, and the link will be added to the list.

Contact information

  • If you have any questions, you can join the group to communicate QQ: 641697838

Finally, I recommend some other libraries I wrote