AspectJ
AOP概念
AOP是Aspect Oriented Programming的缩写,即『面向切面编程』。它和我们平时接触到的OOP都是编程的不同思想,OOP,即『面向对象编程』,它提倡的是将功能模块化,对象化,而AOP的思想,则不太一样,它提倡的是针对同一类问题的统一处理,当然,我们在实际编程过程中,不可能单纯的安装AOP或者OOP的思想来编程,很多时候,可能会混合多种编程思想,大家也不必要纠结该使用哪种思想,取百家之长,才是正道
AspectJ
AspectJ实际上是对AOP编程思想的一个实践,当然,除了AspectJ以外,还有很多其它的AOP实现,例如ASMDex,但目前最好、最方便的,依然是AspectJ。
发现问题
当初做自己的项目,有部分代码我不想让别人通过反编译知道其逻辑,我做过很多防护措施:
- 代码混淆
- 核心方法Native
- 动态加载dex,加载dex之前dex文件加密
- 动态加载so
- 所有声明字符串加密
- 使用3方加固平台(治标不治本)
- 插入代码花指令,jui工具编译方法报错
前面5要措施,都不是今天要讲的核心,其实第5条措施和今天说的有一些关联,但是实现逻辑原理是不一样的(不是今天的重点),说下第6条,对抗反编译其实就是对抗反编译工具,jadx丶jui都可以看代码,我发现有部分代码jui是编译出错的,这段代码在实际功能找中没有任何作用,但是插入这段代码jui工具就会编译出错,这就和花指令是一个到了,无效的代码,给破解这带来难度,插入这代花指令代码,一开始我使用入侵的形式(其实就是手动复制粘贴),慢慢的核心方法越来越多,导致我阅读自己的代码都开始费劲了,学习了AspectJ,可以完美解决这个问题,废话不说开始
解决问题
- 当时我的方案是,通过ASM+Transformer库来完成这种逻辑,其实这种逻辑是可以实现的,我也能完成,但是在对ASM对class,由于我在方法内部插入的代码过多,ASM的class的字节码过于复杂,总是出错,开发成本非常高,上手难度很大,但是ASM库非常强大,更加灵活
- AsepcJ来解决(今天的主角),学习成本低,上手简单,完美解决问题
AspectJ的设计理念(概念)
Advice(通知)
注入到class文件中的代码。典型的 Advice 类型有 before、after 和 around,分别表示在目标方法执行之前、执行后和完全替代目标方法执行的代码。 除了在方法中注入代码,也可能会对代码做其他修改,比如在一个class中增加字段或者接口。
Joint point(连接点)
程序中可能作为代码注入目标的特定的点,例如一个方法调用或者方法入口。
Pointcut(切入点)
告诉代码注入工具,在何处注入一段特定代码的表达式。例如,在哪些 joint points 应用一个特定的 Advice。切入点可以选择唯一一个,比如执行某一个方法,也可以有多个选择,比如,标记了一个定义成@DebguTrace 的自定义注解的所有方法。
集成AspectJ
集成分为2种方法,建议插件集成
插件集成AspectJ
教程地址:https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx
- 创建主项目app
- 创建library,AsepctJ
- 根目录的build.gradle,插入 classpath ‘com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4’
- AsepctJ的build.gradle,依赖 api ‘org.aspectj:aspectjrt:1.8.9’
- App主项目,依赖 implementation project(’:aspectj’) ,应用plugin插件apply plugin: ‘com.hujiang.android-aspectjx’
开源插件地址讲的很清楚,看下就会拉
gradle集成
教程地址:https://github.com/JakeWharton/hugo
来个简单demo爽一下
app就是需要主项目,aspectj就是需要做插代码的library,看了上面的方式应该都会集成好了AspectJ
代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showMsg("我好牛B哦");
}
public void showMsg(String msg){
Log.d("wyz", msg);
}
}
AspectJ类
// 1:所需要插入代码的类,必须使用@Aspect注解
@Aspect
public class CoreAspetJ {
// 需要注入的方法
@After("call(* com.mmvoice.aspectjdemo.MainActivity.showMsg(java.lang.String))")
public void showTaost(JoinPoint joinPoint) {
Log.d("wyz", "AspectJ:牛B个锤子");
}
}
运行效果
运行输入了这2句,我的代码showMsg只打印一个Log的
总结
这一章节,主要讲解了下集成方式,以及概念性的东西,以及我遇到的问题和解决问题的方式。