### AspectJ MainActivity Example Source: https://github.com/flyjingfish/androidaop/blob/master/docs/AspectJ_Migration_Guide.md A simple MainActivity class used as an example for AspectJ method execution matching. ```kotlin package com.flyjingfish.test class MainActivity : BaseActivity() { fun threadTest() { Log.e("threadTest", "------") } } ``` -------------------------------- ### Example Ordinary Method with Return Value Source: https://github.com/flyjingfish/androidaop/blob/master/docs/Pointcut_return.md An example of an ordinary Java method that returns an integer. ```java @MyAnno public int numberAdd(int value1,int value2){ int result=value1+value2; return result; } ``` -------------------------------- ### Fuzzy Matching: Wildcard for All Methods Source: https://github.com/flyjingfish/androidaop/wiki/@AndroidAopMatchClassMethod Example demonstrating fuzzy matching where '*' in methodName matches all methods of the target class. ```kotlin methodName has only one method name "*" to match all methods in the class ``` -------------------------------- ### Example Java OnClickListener Source: https://github.com/flyjingfish/androidaop/blob/master/docs/AndroidAopMatchClassMethod.md An example of an abstract Java class implementing View.OnClickListener. ```java public abstract class MyOnClickListener implements View.OnClickListener { @Override public void onClick(View v) { ... //This is the necessary logic code } } ``` -------------------------------- ### Example Kotlin SetOnClickListener Source: https://github.com/flyjingfish/androidaop/blob/master/docs/AndroidAopMatchClassMethod.md Example of setting an OnClickListener using an anonymous inner class in Kotlin, calling the superclass method. ```kotlin binding.btnSingleClick.setOnClickListener(object : MyOnClickListener() { override fun onClick(v: View?) { super.onClick(v)//Especially this sentence calls the parent class onClick and wants to retain the logic of executing the parent class method onSingleClick() } }) ``` -------------------------------- ### Permission Request Handling with @Permission Source: https://github.com/flyjingfish/androidaop/blob/master/docs/android_aop_extra.md Implement a listener for @Permission annotations to manage runtime permission requests. This example uses RxPermissions to handle requests for FragmentActivity and Fragment targets. Ensure the target is a FragmentActivity or Fragment, or handle other cases manually. ```java AndroidAop.INSTANCE.setOnPermissionsInterceptListener(new OnPermissionsInterceptListener() { @SuppressLint("CheckResult") @Override public void requestPermission(@NonNull ProceedJoinPoint joinPoint, @NonNull Permission permission, @NonNull OnRequestPermissionListener call) { Object target = joinPoint.getTarget(); if (target instanceof FragmentActivity){ RxPermissions rxPermissions = new RxPermissions((FragmentActivity) target); rxPermissions.request(permission.value()).subscribe(call::onCall); }else if (target instanceof Fragment){ RxPermissions rxPermissions = new RxPermissions((Fragment) target); rxPermissions.request(permission.value()).subscribe(call::onCall); }else{ // TODO: target is not FragmentActivity or Fragment, which means the method where the annotation is located is not among them. Please handle this situation yourself. // Suggestion: The first parameter of the pointcut method can be set to FragmentActivity or Fragment, and then joinPoint.args[0] can be obtained } } }); ``` -------------------------------- ### Precise Matching: Method Signature Source: https://github.com/flyjingfish/androidaop/wiki/@AndroidAopMatchClassMethod Example of precise matching for a method, specifying return type and parameter types. ```kotlin Return type Method name(Parameter type, Parameter type...) ``` -------------------------------- ### Fuzzy Matching: Package Name Wildcard Source: https://github.com/flyjingfish/androidaop/wiki/@AndroidAopMatchClassMethod Example demonstrating fuzzy matching where '.*' at the end of targetClassName with type = MatchType.SELF matches all classes within that package and its sub-packages. ```kotlin targetClassName ends with `.*` and has other characters, and `type = MatchType.SELF`, then it matches all classes in the package, including sub-packages ``` -------------------------------- ### Handle @AfterReturning and @AfterThrowing with Matcher Aspects Source: https://github.com/flyjingfish/androidaop/blob/master/docs/zh/FAQ.md This example demonstrates how to simulate AspectJ's `@AfterReturning` and `@AfterThrowing` using matcher aspects. The `try-catch` block within the `invoke` method allows you to execute code after a successful return or after an exception is thrown. ```kotlin @AndroidAopMatchClassMethod( targetClassName = "com.flyjingfish.test_lib.TestMatch", methodName = ["test2"], type = MatchType.SELF ) class MatchTestMatchMethod : MatchClassMethod { override fun invoke(joinPoint: ProceedJoinPoint, anno: TryCatch): Any? { return try { val value = joinPoint.proceed() // 这里就是 @AfterReturning value } catch (e: Throwable) { // 这里就是 @AfterThrowing throw RuntimeException(e) } } } ``` -------------------------------- ### Application Class Integration Source: https://github.com/flyjingfish/androidaop/wiki/@AndroidAopCollectMethod Example of how to integrate the InitCollect class into an Android Application class by calling its init method. ```java public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); InitCollect.init(this); } } ``` -------------------------------- ### Java Example: Replacing Toast makeText Source: https://github.com/flyjingfish/androidaop/blob/master/docs/AndroidAopReplaceClass.md This snippet demonstrates replacing the `makeText` method of `android.widget.Toast` with a custom implementation. The replaced method is static, so the parameter types and order must match exactly. The custom implementation prepends 'ReplaceToast-' to the text. ```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 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 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(); } } ``` -------------------------------- ### Replace all classes inheriting from AppCompatImageView with ReplaceImageView2 (isParent = true) Source: https://github.com/flyjingfish/androidaop/blob/master/docs/AndroidAopModifyExtendsClass.md This example shows how to replace the inherited class for all classes that inherit from AppCompatImageView with ReplaceImageView2. Use this when you need to apply modifications to a hierarchy of classes. ```java @AndroidAopModifyExtendsClass( value = "androidx.appcompat.widget.AppCompatImageView", isParent = true ) public class ReplaceImageView2 extends ImageView { public ReplaceImageView2(@NonNull Context context) { super(context); } public ReplaceImageView2(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public ReplaceImageView2(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public void setImageDrawable(@Nullable Drawable drawable) { super.setImageDrawable(drawable); //Do some monitoring or modify again } } ``` -------------------------------- ### Replace AppCompatImageView with ReplaceImageView1 (isParent = false) Source: https://github.com/flyjingfish/androidaop/blob/master/docs/AndroidAopModifyExtendsClass.md This example demonstrates replacing the direct inherited class of AppCompatImageView with ReplaceImageView1. It's used when you want to modify only the immediate inherited class and not its descendants. ```java @AndroidAopModifyExtendsClass( value = "androidx.appcompat.widget.AppCompatImageView", isParent = false ) public class ReplaceImageView1 extends ImageView { public ReplaceImageView1(@NonNull Context context) { super(context); } public ReplaceImageView1(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public ReplaceImageView1(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public void setImageDrawable(@Nullable Drawable drawable) { super.setImageDrawable(drawable); //Do some monitoring or modify again } } ``` -------------------------------- ### Network Availability Check with @CheckNetwork Source: https://github.com/flyjingfish/androidaop/blob/master/docs/android_aop_extra.md Implement a listener for @CheckNetwork annotations to perform network availability checks before method execution. This example shows how to enable the listener and provides a placeholder for custom toast messages. ```java AndroidAop.INSTANCE.setOnCheckNetworkListener(new OnCheckNetworkListener() { @Nullable @Override public Object invoke(@NonNull ProceedJoinPoint joinPoint, @NonNull CheckNetwork checkNetwork, boolean availableNetwork) { return null; } }); ``` ```kotlin @CheckNetwork(invokeListener = true) fun toSecondActivity(){ startActivity(Intent(this,SecondActivity::class.java)) } ``` ```java AndroidAop.INSTANCE.setOnToastListener(new OnToastListener() { @Override public void onToast(@NonNull Context context, @NonNull CharSequence text, int duration) { } }); ``` -------------------------------- ### 配置 Gradle 运行外部工具以停止进程 Source: https://github.com/flyjingfish/androidaop/wiki/常见问题 在 Windows 环境下,当遇到文件占用导致编译失败时,可以配置 Gradle 运行一个外部工具来停止所有 Gradle 进程,以解决文件占用问题。请确保项目路径配置正确。 ```gradle Program: 项目所在的绝对路径\gradlew.bat Arguments: ./gradlew --stop Working directory: 项目所在的绝对路径\ ``` -------------------------------- ### Windows 电脑编译报错或文件占用解决方案 Source: https://github.com/flyjingfish/androidaop/blob/master/docs/zh/FAQ.md 当在 Windows 电脑上遇到编译报错或文件占用问题时,可以尝试升级 Gradle 版本、更新库到最新版,并将 `id 'android.aop'` 放在 `build.gradle` 的最后一行。如果问题仍然存在,可以配置运行外部工具来执行 `./gradlew --stop` 命令。 ```properties id 'android.aop' ``` ```properties Program: ```项目所在的绝对路径\gradlew.bat``` Arguments: ```./gradlew --stop``` Working directory: ```项目所在的绝对路径\``` ``` -------------------------------- ### Introduce Dependent Libraries (Kotlin) Source: https://github.com/flyjingfish/androidaop/blob/master/docs/getting_started.md Configure your module's build.gradle.kts file with the necessary AndroidAOP dependencies. This includes the core library, optional extra aspects, and either ksp or annotationProcessor for custom aspects. ```kotlin 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-core:2.7.5") //👇Optional (1)👈 This package provides some common annotation aspects implementation("io.github.flyjingfish:androidaop-extra:2.7.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 //👇Choose one (2)👈Click + to view detailed description, ⚠️supports aspects written in Java and Kotlin code ksp("io.github.flyjingfish:androidaop-apt:2.7.5") //👇Choose one (3)👈Click + to view detailed description, ⚠️only applies to aspects written in Java code annotationProcessor("io.github.flyjingfish:androidaop-apt:2.7.5") //⚠️Choose one of the above ksp and annotationProcessor //If you only use the functions in android-aop-extra, you don't need to select these two options } ``` -------------------------------- ### BasePointCut with No Proceed Call Source: https://github.com/flyjingfish/androidaop/blob/master/docs/Suspend_cut.md An example of an ordinary aspect processing class where `proceed()` is not called, and the method returns directly. ```kotlin class MyAnnoCut3 : BasePointCut { override fun invoke(joinPoint: ProceedJoinPoint, anno: MyAnno3): Any? { Log.e("MyAnnoCut3", "====invoke=====") return null } } ``` -------------------------------- ### Match AppCompatActivity startActivity Source: https://github.com/flyjingfish/androidaop/wiki/@AndroidAopMatchClassMethod Matches all startActivity methods called on classes extending AppCompatActivity. Use this to monitor activity transitions. ```java import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.flyjingfish.androidaop.ProceedJoinPoint; import com.flyjingfish.androidaop.annotation.AndroidAopMatchClassMethod; import com.flyjingfish.androidaop.annotation.AnnType; import com.flyjingfish.androidaop.annotation.AnnType.MatchType; import com.flyjingfish.androidaop.base.MatchClassMethod; @AndroidAopMatchClassMethod( targetClassName = "androidx.appcompat.app.AppCompatActivity", methodName = {"startActivity"}, type = MatchType.EXTENDS ) public class MatchActivityMethod implements MatchClassMethod { @Nullable @Override public Object invoke(@NonNull ProceedJoinPoint joinPoint, @NonNull String methodName) { // 在此写你的逻辑 return joinPoint.proceed(); } } ``` -------------------------------- ### Introduce Dependent Libraries (Groovy) Source: https://github.com/flyjingfish/androidaop/blob/master/docs/getting_started.md Configure your module's build.gradle file with the necessary AndroidAOP dependencies. This includes the core library, optional extra aspects, and either ksp or annotationProcessor for custom aspects. ```groovy 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-core:2.7.5" //👇Optional (1)👈 This package provides some common annotation aspects implementation "io.github.flyjingfish:androidaop-extra:2.7.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 //👇Choose one (2)👈Click + to view detailed description, ⚠️supports aspects written in Java and Kotlin code ksp "io.github.flyjingfish:androidaop-apt:2.7.5" //👇Choose one (3)👈Click + to view detailed description, ⚠️only applies to aspects written in Java code annotationProcessor "io.github.flyjingfish:androidaop-apt:2.7.5" //⚠️Choose one of the above ksp and annotationProcessor //If you only use the functions in android-aop-extra, you don't need to select these two options } ``` -------------------------------- ### Replace Toast Class in Java Source: https://github.com/flyjingfish/androidaop/blob/master/README.md Replaces android.widget.Toast methods to modify toast behavior. This example shows how to replace 'makeText', 'setGravity', and 'show' methods. ```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(); } } ``` -------------------------------- ### Insert Code Before and After Method (Matching Aspect) Source: https://github.com/flyjingfish/androidaop/blob/master/docs/FAQ.md Use a matching aspect to insert code before and after a method's execution. The `joinPoint.proceed()` call is essential for continuing the method execution. ```kotlin @AndroidAopMatchClassMethod( targetClassName = "com.flyjingfish.test_lib.TestMatch", methodName = ["test2"], type = MatchType.SELF ) class MatchTestMatchMethod : MatchClassMethod { override fun invoke(joinPoint: ProceedJoinPoint, methodName: String): Any? { //Insert code before the method val value = joinPoint.proceed() //Insert code after the method return value } } ``` -------------------------------- ### Collect Inherited Classes in Java Source: https://github.com/flyjingfish/androidaop/blob/master/README.md Collects instances or classes that inherit from SubApplication2. This Java version achieves the same goal as the Kotlin example, gathering specific application components. ```java public class InitCollect2 { private static List collects = new ArrayList<>(); private static final List> collectClazz = new ArrayList<>(); @AndroidAopCollectMethod public static void collect(SubApplication2 sub){ collects.add(sub); } @AndroidAopCollectMethod public static void collect3(Class sub) { collectClazz.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); } } } ``` -------------------------------- ### 解压 JAR 包并移除 META-INF 文件 Source: https://github.com/flyjingfish/androidaop/wiki/常见问题 当遇到 'Caused by: java.lang.SecurityException: digest error' 报错时,需要检查引入的 JAR 包。如果 JAR 包中包含 META-INF 目录下的特定文件,需要将其移除。此操作适用于 Linux/macOS 环境。 ```bash cd /Users/a111/Downloads/ida-android-new/app/libs ``` ```bash jar -xvf bcprov-jdk15on-1.69.jar ``` ```bash jar -cfm0 bcprov-jdk15on-1.69.jar META-INF/MANIFEST.MF org ``` -------------------------------- ### Match and Hook Class Methods (Kotlin) Source: https://github.com/flyjingfish/androidaop/blob/master/README.md Use @AndroidAopMatchClassMethod to hook methods of a specific class. This example demonstrates hooking all onClick methods of Android's View.OnClickListener. ```kotlin @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() } } ``` -------------------------------- ### Modify Class Inheritance with @AndroidAopModifyExtendsClass Source: https://github.com/flyjingfish/androidaop/blob/master/docs/getting_started.md Use @AndroidAopModifyExtendsClass to replace the inherited class of a target class, allowing for monitoring or modification of original logic. This example replaces AppCompatImageView with a custom ImageView. ```java @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); //做一些监测或者再次修改 } } ``` -------------------------------- ### 组件化项目 AAR 包打包速度优化配置 Source: https://github.com/flyjingfish/androidaop/blob/master/docs/zh/FAQ.md 在组件化项目中,为了加快打包速度,可以启用 `debugMode` 并根据发布类型调整配置。发布 AAR 包时,应关闭 `debugMode.variantOnlyDebug`。如果 AAR 包已进行 AOP 处理,可以在 `app` 模块的 `androidAopConfig` 中排除这些 AAR 包。 ```properties androidAop.debugMode = true androidAop.debugMode.variantOnlyDebug = false ``` ```properties androidAop.reflectInvokeMethod = true androidAop.reflectInvokeMethod.variantOnlyDebug = false ``` ```groovy androidAopConfig { //👇 排除掉已经进行过 AOP 处理的 aar 包,依旧可以读取这些包的切面配置 exclude 'aar包名1', 'aar包名2' //❗️❗️❗️值得一提的是在你发布 aar 的时候,不要把你要发布的 aar 的包名配置到这,否则 aar 是不会经过 AOP 处理的 } ``` -------------------------------- ### Java: Collect SubApplication Instances and Classes Source: https://github.com/flyjingfish/androidaop/blob/master/docs/AndroidAopCollectMethod.md Collects instances and class objects of classes inherited from SubApplication. Supports regex filtering for specific class names. ```java public class InitCollect { private static final List collects = new ArrayList<>(); private static final List> collectClazz = new ArrayList<>(); @AndroidAopCollectMethod //Collect classes inherited from SubApplication and call back its instance object public static void collect(SubApplication sub) { collects.add(sub); } @AndroidAopCollectMethod //Collect classes inherited from SubApplication and call back its class object public static void collect2(Class sub) { collectClazz.add(sub); } @AndroidAopCollectMethod(regex = ".*?\\$\$Router") //Collect classes that match the regex regular expression and call back their instance objects. Can also be used in combination with inheritance public static void collectRouterClassRegex(Class sub) { Log.e("InitCollect2", "----collectRouterClassRegexClazz----" + sub); } @AndroidAopCollectMethod(regex = ".*?\\$\$Router") //Collect classes that match the regex regular expression and call back their class objects. Can also be used in conjunction with inheritance public static void collectRouterClassRegex(Object sub) { Log.e("InitCollect2", "----collectRouterClassRegexObject----" + sub); } //Directly call this method (method name is not limited) The above functions will be called back in full public static void init(Application application) { Log.e("InitCollect2", "----init---- "); for (SubApplication2 collect : collects) { collect.onCreate(application); } } } ``` -------------------------------- ### Hook All OnClicks in OnClickListener Subclasses Source: https://github.com/flyjingfish/androidaop/blob/master/docs/getting_started.md This example demonstrates how to hook all `onClick` methods across all subclasses of `android.view.View.OnClickListener`. Use `MatchType.EXTENDS` to match methods in subclasses. Note that if a subclass does not have the specified method, the aspect will be invalid. ```kotlin @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() } } ``` -------------------------------- ### Execute CleanKeepAopCache Gradle Task Source: https://github.com/flyjingfish/androidaop/blob/master/docs/zh/getting_started.md Run the aaaCleanKeepAopCache command to clean the project and potentially reduce subsequent build times. ```bash ./gradlew aaaCleanKeepAopCache ``` -------------------------------- ### Add AndroidAOP Dependencies Source: https://github.com/flyjingfish/androidaop/blob/master/README.md Configure your app's build.gradle file to include the AndroidAOP core library and optional extra functionalities. Ensure you have the correct version of androidx.appcompat. If customizing aspects, choose either ksp or annotationProcessor. ```gradle 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-core:2.7.5' //Optional 👇This package provides some common annotation aspects implementation 'io.github.flyjingfish:androidaop-extra:2.7.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 //Choose one 👇, if you want to customize aspects, you need to use them, ⚠️supports aspects written in Java and Kotlin code ksp 'io.github.flyjingfish:androidaop-apt:2.7.5' //Choose one 👇, if you want to customize aspects, you need to use them, ⚠️only applies to aspects written in Java code annotationProcessor 'io.github.flyjingfish:androidaop-apt:2.7.5' //⚠️Choose one of the above ksp and annotationProcessor //If you only use the functions in android-aop-extra, you don't need to select these two options } ``` -------------------------------- ### Configure Android AOP in build.gradle (Groovy) Source: https://github.com/flyjingfish/androidaop/blob/master/docs/getting_started.md Set up Android AOP plugin and configure its behavior like enabling/disabling, including/excluding packages, and verifying inheritance. This is an optional configuration. ```groovy plugins { ... id 'android.aop'//It is best to put it on the last line } androidAopConfig { // enabled is false, the aspect no longer works, the default is not written as true enabled true // `includeKotlin` set to `true` will scan Kotlin and Kotlinx code; the default is `false` if not specified. includeKotlin false // include does not set all scans by default. After setting, only the code of the set package name will be scanned. include 'Package name of your project', 'Package name of custom module', 'Package name of custom module' // exclude is the package excluded during scanning // Can exclude kotlin related and improve speed exclude 'kotlin.jvm', 'kotlin.internal','kotlinx.coroutines.internal', 'kotlinx.coroutines.android' // Exclude packaged entity names excludePackaging 'license/NOTICE' , 'license/LICENSE.dom-software.txt' , 'license/LICENSE' // verifyLeafExtends Whether to turn on verification leaf inheritance, it is turned on by default. If type = MatchType.LEAF_EXTENDS of @AndroidAopMatchClassMethod is not set, it can be turned off. verifyLeafExtends true //Disabled by default. Enabled after Build or Packaging, a cut information file will be generated in app/build/tmp/ (cutInfo.json, cutInfo.html) cutInfoJson false } android { ... } ``` -------------------------------- ### Match All Methods in a Package Source: https://github.com/flyjingfish/androidaop/blob/master/docs/AndroidAopMatchClassMethod.md To match all methods in all classes within a package and its subpackages, use a wildcard in `targetClassName` like `com.flyjingfish.androidaop.*`. The `methodName` can also use wildcards for fuzzy or exact matching. ```kotlin @AndroidAopMatchClassMethod( targetClassName = "com.flyjingfish.androidaop.*", methodName = ["*"], type = MatchType.SELF ) class MatchAll : MatchClassMethod { override fun invoke(joinPoint: ProceedJoinPoint, methodName: String): Any? { Log.e( "MatchAll", "---->${joinPoint.targetClass}--${joinPoint.targetMethod.name}--${joinPoint.targetMethod.parameterTypes.toList()}" ); return joinPoint.proceed() } } ``` -------------------------------- ### Configure ProGuard for Mapping Source: https://github.com/flyjingfish/androidaop/blob/master/docs/About_obfuscation.md Add these configurations to your obfuscation configuration file to ensure mapping files are generated and line number information is preserved. ```proguard # Mapping file -printmapping proguard-map.txt # Keep the code line number when throwing an exception -keepattributes SourceFile,LineNumberTable ``` -------------------------------- ### Configure debugMode in gradle.properties Source: https://github.com/flyjingfish/androidaop/blob/master/docs/zh/getting_started.md Enable debugMode for faster compilation by using the current packaging method. Setting this to false enforces a full packaging method. ```properties androidAop.debugMode=true //设置为 true 走您项目当前的打包方式 ,false 则为全量打包方式,不写默认false ``` -------------------------------- ### Configure Android AOP in build.gradle (Kotlin) Source: https://github.com/flyjingfish/androidaop/blob/master/docs/getting_started.md Set up Android AOP plugin and configure its behavior like enabling/disabling, including/excluding packages, and verifying inheritance using Kotlin DSL. This is an optional configuration. ```kotlin plugins { ... id("android.aop")//It is best to put it on the last line } androidAopConfig { // enabled is false, the aspect no longer works, the default is not written as true enabled = true // include does not set all scans by default. After setting, only the code of the set package name will be scanned. include("Package name of your project", "Package name of custom module", "Package name of custom module") // exclude is the package excluded during scanning // Can exclude kotlin related and improve speed exclude("kotlin.jvm", "kotlin.internal","kotlinx.coroutines.internal", "kotlinx.coroutines.android") // Exclude the entity name of the package excludePackaging("license/NOTICE" , "license/LICENSE.dom-software.txt" , "license/LICENSE") // verifyLeafExtends Whether to turn on verification leaf inheritance, it is turned on by default. If type = MatchType.LEAF_EXTENDS of @AndroidAopMatchClassMethod is not set, it can be turned off. verifyLeafExtends = true //Disabled by default. Enabled after Build or Packaging, a cut information file will be generated in app/build/tmp/ (cutInfo.json, cutInfo.html) cutInfoJson = false } android { ... } ``` -------------------------------- ### ARouter 路由中心类方法匹配与注册 (Kotlin) Source: https://github.com/flyjingfish/androidaop/wiki/切面启示 定义了一个匹配 ARouter 的 `LogisticsCenter` 类中的 `loadRouterMap` 方法,并在方法执行后,调用 `AlibabaCollect` 收集到的类名进行注册。适用于在 ARouter 初始化流程中自动注册路由表的场景。 ```kotlin @AndroidAopMatchClassMethod( targetClassName = "com.alibaba.android.arouter.core.LogisticsCenter", methodName = ["loadRouterMap"], type = MatchType.SELF ) class ARouterMatch :MatchClassMethod { override fun invoke(joinPoint: ProceedJoinPoint, methodName: String): Any? { val any = joinPoint.proceed() val registerMethod = LogisticsCenter::class.java.getDeclaredMethod("register",java.lang.String::class.java) registerMethod.isAccessible = true val classNameSet = AlibabaCollect.getClassNameSet() classNameSet.forEach { registerMethod.invoke(null,it) Log.e("ARouterMatch","registerMethod=$it") } return any } } ``` -------------------------------- ### Java: Singleton Pattern with @AndroidAopCollectMethod Source: https://github.com/flyjingfish/androidaop/blob/master/docs/AndroidAopCollectMethod.md Demonstrates a thread-safe, lazy-loaded singleton pattern using @AndroidAopCollectMethod to collect the instance. ```java public class TestInstance { private static TestInstance instance; @AndroidAopCollectMethod(regex = "^com.flyjingfish.lightrouter.TestInstance$") public static void collectInstance(Object any) { instance = (TestInstance) any; } public static TestInstance getInstance() { return instance; } public void test() { Log.e("TestInstance", "=====test="); } } ``` -------------------------------- ### Apply AndroidAOP Plugin using Plugins DSL (Groovy) Source: https://github.com/flyjingfish/androidaop/blob/master/docs/getting_started.md Use this method to apply the AndroidAOP plugin in your project's root build.gradle file using the plugins DSL. Ensure 'apply true' is set to automatically apply debugMode. ```groovy plugins { //👇Required item (1)👈 apply is set to true to automatically apply debugMode to all modules, If false, follow step 5 below to configure debugMode in manual mode. id "io.github.flyjingfish.androidaop" version "2.7.5" apply true } ``` -------------------------------- ### Apply AndroidAOP Plugin using Plugins DSL (Method 2 - Groovy) Source: https://github.com/flyjingfish/androidaop/blob/master/docs/getting_started.md Alternative method to apply the AndroidAOP plugin directly in the build.gradle of an application or dynamic feature module using the plugins DSL. ```groovy //Required items 👇 plugins { ... id "io.github.flyjingfish.androidaop" version "2.7.5" } ``` -------------------------------- ### Kotlin: Collect SubApplication Instances and Classes Source: https://github.com/flyjingfish/androidaop/blob/master/docs/AndroidAopCollectMethod.md Collects instances and class objects of classes inherited from SubApplication. Supports regex filtering for specific class names. ```kotlin object InitCollect { private val collects = mutableListOf() private val collectClazz: MutableList> = mutableListOf() @AndroidAopCollectMethod @JvmStatic //Collect classes inherited from SubApplication and call back its instance object fun collect(sub: SubApplication) { collects.add(sub) } @AndroidAopCollectMethod @JvmStatic //Collect classes inherited from SubApplication and call back its class object fun collect2(sub: Class) { collectClazz.add(sub) } @AndroidAopCollectMethod(regex = ".*?\\$\\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$\\$ o "com.flyjingfish.lightrouter.TestInstance$"}) @JvmStatic //Collect classes that match the regex regular expression and call back their instance objects. Can also be used in combination with inheritance fun collectRouterClassRegex(sub: Any) { Log.e("InitCollect", "----collectRouterClassRegexObject----$sub") } //Directly call this method (method name is not limited) The above functions will be called back fun init(application: Application) { for (collect in collects) { collect.onCreate(application) } } } ``` -------------------------------- ### AspectJ Call Matching for System Methods Source: https://github.com/flyjingfish/androidaop/blob/master/docs/AspectJ_Migration_Guide.md Demonstrates AspectJ's 'call' pointcut for matching system methods, such as logging errors in Android's Log class. ```java @Aspect public final class TestAspectJ { @Pointcut("call(* android.util.Log.e(..))") public void pointcutThreadTest() { } @Around("pointcutThreadTest()") public final Object cutExecute(final JoinPoint joinPoint) throws Throwable { Log.e("TestAspectJ", "====cutExecute"); return null; } } ``` -------------------------------- ### Apply AndroidAOP Plugin using Plugins DSL (Kotlin) Source: https://github.com/flyjingfish/androidaop/blob/master/docs/getting_started.md Use this method to apply the AndroidAOP plugin in your project's root build.gradle file using the plugins DSL in Kotlin. Ensure 'apply true' is set to automatically apply debugMode. ```kotlin plugins { //👇Required item (1)👈 apply is set to true to automatically apply debugMode to all modules, If false, follow step 5 below to configure debugMode in manual mode. id("io.github.flyjingfish.androidaop") version "2.7.5" apply true } ``` -------------------------------- ### BasePointCutSuspend with proceedIgnoreOther Source: https://github.com/flyjingfish/androidaop/blob/master/docs/Suspend_cut.md Demonstrates the processing method for suspend functions using `BasePointCutSuspend` and `proceedIgnoreOther` within a `withContext` block. ```kotlin class MyAnnoCut3 : BasePointCutSuspend { override suspend fun invokeSuspend(joinPoint: ProceedJoinPointSuspend, anno: MyAnno3) { withContext(Dispatchers.Main) { ... joinPoint.proceedIgnoreOther(object : OnSuspendReturnListener2 { override fun onReturn(proceedReturn: ProceedReturn2): Any? { Log.e("MyAnnoCut3", "====invokeSuspend=====") return null } }) } } } ``` -------------------------------- ### Insert Code Before and After Methods using Annotation Aspects Source: https://github.com/flyjingfish/androidaop/blob/master/docs/zh/FAQ.md Implement `BasePointCut` for annotation aspects. The `invoke` method receives the annotation and `ProceedJoinPoint`. Code before `joinPoint.proceed()` executes before the annotated method, and code after executes after. ```kotlin class CustomInterceptCut : BasePointCut { override fun invoke( joinPoint: ProceedJoinPoint, annotation: CustomIntercept //annotation就是你加到方法上的注解 ): Any? { //在方法前插入代码 val value = joinPoint.proceed() //在方法后插入代码 return value } } ```