当前位置: 首页 > news >正文

AspectJ 在 Android 中的完整使用指南

一、环境配置(Gradle 7.0+ 适配)

1. 项目级 build.gradle
// 注意:沪江插件已停更,推荐官方兼容方案
buildscript {dependencies {classpath 'org.aspectj:aspectjtools:1.9.9.1' // AspectJ 工具}
}

2. 模块级 build.gradle

plugins {id 'com.android.application'id 'io.freefair.aspectj' // 官方推荐插件(支持 AGP 7.0+)
}dependencies {implementation 'org.aspectj:aspectjrt:1.9.9.1' // 运行时库
}

兼容性说明:若项目含 Kotlin,添加 id 'io.freefair.aspectj.post-compile-weaving' 插件

二、核心语法详解

1. 切点表达式(Pointcut)
表达式示例含义
execution(public * *(..))所有 public 方法
execution(* com.util.*.*(..))com.util 包下所有方法
@annotation(com.LogTrack)被 @LogTrack 注解的方法
within(com.ui..*)com.ui 包及其子包所有类的方法
call(* android.util.Log.d(..))拦截 Log.d() 的调用(非执行)
2. 通知类型(Advice)
@Before("pointcut()")          // 方法执行前
@After("pointcut()")           // 方法执行后(无论成败)
@AfterReturning(pointcut="", returning="result") // 方法返回后
@AfterThrowing(pointcut="", throwing="ex") // 抛出异常后
@Around("pointcut()")          // 完全控制方法执行(最常用)

三、实战案例

案例 1:自动日志追踪
@Aspect
public class DebugLogAspect {// 切点:标记 @DebugLog 的方法@Pointcut("execution(@com.example.DebugLog * *(..))")public void debugLogPointcut() {}@Around("debugLogPointcut()")public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable {MethodSignature signature = (MethodSignature) joinPoint.getSignature();String methodName = signature.getMethod().getName();long start = System.currentTimeMillis();Log.d("AspectJ", "▶️ " + methodName + " 开始 | 参数: " + Arrays.toString(joinPoint.getArgs()));Object result = joinPoint.proceed(); // 执行原方法long duration = System.currentTimeMillis() - start;Log.d("AspectJ", "◀️ " + methodName + " 结束 | 耗时: " + duration + "ms | 结果: " + result);return result;}
}
案例 2:权限申请自动化
// 定义权限注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequirePermission {String[] value(); // 需要申请的权限
}// 切面实现
@Aspect
public class PermissionAspect {@Around("execution(@RequirePermission * *(..)) && @annotation(permission)")public Object checkPermission(ProceedingJoinPoint pjp, RequirePermission permission) throws Throwable {Activity activity = (Activity) pjp.getTarget(); // 获取宿主ActivityString[] perms = permission.value();if (hasPermissions(activity, perms)) {return pjp.proceed(); // 已有权限} else {// 发起权限申请(需配合 ActivityResultLauncher)PermissionRequester.request(activity, perms, () -> {try { pjp.proceed(); } catch (Throwable ignored) {} });return null; // 阻断原方法执行}}private boolean hasPermissions(Context ctx, String... perms) {for (String perm : perms) {if (ContextCompat.checkSelfPermission(ctx, perm) != PERMISSION_GRANTED) return false;}return true;}
}

四、高频问题解决方案

问题 1:织入(Weaving)失效

排查步骤

  1. 检查是否应用了 AGP 7.0+ 的兼容插件

  2. 确认 aspectjrt 版本一致性

  3. 使用命令检查织入结果:

./gradlew clean assembleDebug --debug | grep "ajc"
问题 2:Lambda 表达式支持

在 build.gradle 中添加:

aspectj {excludeJar "com.android.support" // 排除冲突库weaveInfo = trueaddSerialVoid = true // 修复 Lambda 支持
}

五、性能优化建议

  1. 避免在切面中执行耗时操作
    (如:IO 读写、网络请求)

  2. 精确限定切点范围

// 劣质写法:扫描全包
@Pointcut("execution(* com.app..*.*(..))")// 优化写法:精确到类
@Pointcut("within(com.ui.HomeActivity) || within(com.service.*Impl)")

        编译时排除第三方库

aspectj {exclude "androidx.*", "com.google.*" 
}

六、AspectJ vs 其他方案对比

方案集成难度性能功能完整性适用场景
AspectJ★★★☆⚡⚡⚡✅ 100%需要完整 AOP 支持
ASM★★★★☆⚡⚡⚡⚡⚠️ 手动实现高性能字节码操作
动态代理★★☆❌ 仅限接口简单运行时拦截
注解处理器★★★☆⚡⚡⚠️ 无执行期生成代码替代运行时逻辑

💡 结论:AspectJ 仍是 Android 平台功能最完备的 AOP 方案,适合复杂横切逻辑。

七、高级技巧:编译时代码注入

在 @Around 中动态修改参数:

@Around("execution(* com.payment.process(..))")
public Object encryptPayment(ProceedingJoinPoint pjp) throws Throwable {Object[] args = pjp.getArgs();if (args.length > 0 && args[0] instanceof PaymentRequest) {PaymentRequest request = (PaymentRequest) args[0];request.setCardToken(AES.encrypt(request.getCardNumber())); // 自动加密args[0] = request; // 替换参数}return pjp.proceed(args); // 传入新参数
}

通过本指南,你可快速掌握 AspectJ 在 Android 中的工程化应用。建议从 日志监控权限管理 等场景入手,逐步深入字节码层优化。

相关文章:

  • WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
  • 能源即服务:智慧移动充电桩的供给模式创新
  • 2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
  • python3基础语法梳理
  • CppCon 2015 学习:The Importance of Being const
  • 盟接之桥EDI软件:为制造业打造高效、安全的数据桥梁
  • 【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
  • 自然语言处理——循环神经网络
  • Oracle常见进程杀进程测试
  • 《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析(四)DPHY ECC
  • 在阿里云上搭建n8n
  • Deepseek大模型私有化部署
  • 【论文阅读】:Weighted Graph Cuts without Eigenvectors:A Multilevel Approach
  • 精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑
  • LabVIEW超声频率跟踪
  • C++实现分布式网络通信框架RPC(2)——rpc发布端
  • JS红宝书笔记 10.11-10.16 函数
  • 基于 Three.js 的数字雨波纹效果技术解析
  • 数据库分批入库
  • android13 app的触摸问题定位分析流程
  • 公司网站建设重要性/推广有什么好方法
  • 网站设计制作的服务机构/看广告赚钱的平台
  • 手机选择网站/搜索引擎营销的主要方法包括
  • 百度提交网站收录/百度知道问答首页
  • 挂号网站建设/西安seo优化公司
  • java动态网站开发/石狮seo