在开发过程中,经常有需要拦截某个方法调用的需求。比如处理隐私政策中对隐私api的调用,处理对某些方法的频繁调用等。
- 全AGP版本适配
- 支持INVOKEVIRTUAL
- 支持INVOKESTATIC
-
第一步,加入classpath
repositories { mavenCentral() } buildscript { dependencies { classpath "io.github.wan-droid:method-intercept-plugin:0.0.1" //AGP4.0以下使用这一个 classpath "io.github.wan-droid:method-intercept-plugin-compat:0.0.1" } }
-
第二步,在app的build.gradle下应用插件
apply plugin:'method-intercept'
-
第三步,写拦截配置
在app目录下新建method_intercept.yaml文件
ownerClassName 是拦截方法的类名
methods.name 是拦截的方法名
methods.descriptor 是拦截方法的描述
methods.intercept 是指是否要拦截该方法
# 一个例子如下 intercept: - ownerClassName: android/accounts/AccountManager methods: - name: getAccounts descriptor: "()[Landroid/accounts/Account;" intercept: true - name: getAccountsByType descriptor: "(Ljava/lang/String;)[Landroid/accounts/Account;" intercept: true
-
第四步,编写拦截后调用的类
拦截后的调用类类名需要与被拦截的类的类名保持一致,包名需要增加前缀
intercept(可以配置)
。-
拦截公有方法
比如要拦截android.telephony.TelephonyManager的公有方法getDeviceId,你需要新建一个intercept.android.telephony.TelephonyManager的类,新建一个静态方法deviceId,它的第一个参数是被拦截类android.telephony.TelephonyManager的对象,后面的参数与原方法相同
package android.telephony; // 被拦截的类 public class TelephonyManager { public String getDeviceId() { //method body return "deviceId"; } public String getDeviceId(int id) { //method body return "deviceId"; } }
package interceptor.android.telephony;//注意包名前缀 // 用于拦截的类 public class TelephonyManager { public static String getDeviceId(android.telephony.TelephonyManager manager) { //method body return "intercept-deviceId"; } public static String getDeviceId(android.telephony.TelephonyManager manager, int id) { //method body return "intercept-deviceId"; } }
-
拦截类的静态方法
比如要拦截类android.provider.Settings的静态方法getString,你需要新建一个类intercept.android.provider.Settings,新建一个静态方法getString,所有的参数与原方法的参数一致
package android.provider; // 被拦截的类 public class Settings { public static String getString(android.content.ContentResolver resolver, String name) { //method body return "getString:" + name; } }
package interceptor.android.provider;//注意包名前缀 // 用于拦截的类 public class Settings { public static String getString(android.content.ContentResolver resolver, String name) { //method body return "intercept-getString:" + name; } }
-
methodIntercept {
packageSuffix = "intercept"//可以配置拦截的调用包名前缀。默认是intercept
blackList = ["androidx.*"]//可以配置不需要拦截的包名,可使用.*匹配子包名
}