ReInjectPlugin
类似于AOP编程或Xposed,我们经常发现下面的这些场景,需要添加一些代码,但又不想在原来的项目业务逻辑:
- 性能打点:对http, 文件访问,数据库访问,rpc调用
- 业务打点:如界面打点工具,记录进出每一个activity的时间
- 实例监控:记录某一个特定对象的分配和释放情况,用于调测定位内存泄漏的场景
这些要修改的文件,一方面有可能是三方库的代码,如sqlite,okhttp等,必须要编译自己的版本或在本项目内做一个封装类,才能拦截到;
也有可能,这些类的修改涉及非常多,修改非常发散。
ReInjectPlugin正是为了解决此类问题而来,只需要写好配置文件,并编写拦截后的代码,就可以实现对apk内任何一个类的注入和修改。
使用说明
添加插件配置
插件已发布到mavenCenter,需要添加mavenCenter作为开源引用仓。
修改根项目build.gradle文件,添加脚本引用说明
buildscript {
dependencies {
classpath 'io.github.nylon009:reinject-plugin:0.0.1'
}
}
在app/build.gradle使用此插件
plugins {
id 'io.github.nylon009.reinject-plugin'
}
配置文件
在app工程下增加ReInject.json配置文件
注意在实现类InjectUtils中,静态方法和动态方法的拦截实现类是不一样的。
动态方法拦截时,第一个参数永远是原来调用的类实例,这样可以方便获取实例内部的信息,甚至修改成员值。
{
"injects": [
{
"className": "com.nylon.app.Utils",
"methodName": "foobar",
"methodSignature": "(Ljava/lang/String;)V",
"injectClassName": "com.nylon.app.InjectUtils",
"injectEnterMethodName": "foobarEnter",
"injectExitMethodName": "foobarExit"
},
{
"className": "com.nylon.app.Utils",
"methodName": "hello",
"methodSignature": "(Ljava/lang/String;)V",
"injectClassName": "com.nylon.app.InjectUtils",
"injectEnterMethodName": "helloEnter",
"injectExitMethodName": "helloExit"
}
]
}
拦截静态方法
原始代码com.nylon.app.Utils
public static void foobar(String test){
Log.d(TAG, "foobar");
}
编译完成后,通过jadx可以查看修改后的代码如下:
public static void foobar(String test) {
InjectUtils.foobarEnter(test); // 这一行是注入的代码
Log.d(TAG, "foobar");
InjectUtils.foobarExit(test); // 这一行是注入的代码
}
注入非静态函数
原始类com.nylon.app.Utils
public void hello(String msg) {
Log.d(TAG, "hello " + msg);
}
注入后的代码
public void hello(String msg) {
InjectUtils.helloEnter(this, msg); // 这一行是注入的代码,第一个参数是新增参数
Log.d(TAG, "hello " + msg);
InjectUtils.helloExit(this, msg); // 这一行是注入的代码,第一个参数是新增参数
}
怎么样修改插件并调试
修改Plugin模块中,发布插件的版本号,并通过以下命令发布到本地repo目录
./gradlew :Plugin:assemble :Plugin:publishAllPublicationsToMyRepoRepository
在项目里已添加了repo目录为maven仓,因此无须再手动添加。
更新app/build.gradle里插件使用的版本号,就可以用上新版本了。
其它
项目地址: github ReInjectPlugin
项目在实现时,参考了AndroidPluginStudy的部分实现代码,在此表示感谢。