您的位置 首页 > 加盟资讯

android数据埋点,ios aop埋点

背景最近收到一些运营需求,需要嵌入数据,但是刚收到需求的时候,只有一个解决方案:给每个页面添加监控,而我想要添加的业务数据就是添加。巨大的工作量和超强的人脉关系,想想都让人难以承受。我忍不住为我的头发感到难过。然后我了解到面向方面的编程是可能的。接下来是一个关于实际使用Aspectj 的故事。

实际操作时,请参考第一步的项目配置,将其添加到项目的build.gradle中的依赖中。

步骤2:在APP的build.gradle依赖中引入以下代码。

实现“org.aspectj:aspectjrt:1.8.9”

* 第三步是将其添加到应用程序的build.gradle中的android目录中。

import org.aspectj.bridge.IMessageimport org.aspectj.bridge.MessageHandlerimport org.aspectj.tools.ajc.Mainfinal def log=project.loggerandroid.applicationVariants.all {variant -//if (!variant.buildType.isDebuggable()) {//log.debug('Skipping non-debuggable build type '${variant.buildType.name}'.')//return//}//此代码导致release javaCompile=ariant.javaCompilerjavaCompile JavaCompile 失败。 doLast {String[] args=['-showWeaveInfo','-1.8','-inpath', javaCompile.destinationDir.toString(),'-aspectpath', javaCompile.classpath.asPath,'-d', javaCompile.destinationDir .toString(),'-classpath', javaCompile.classpath.asPath,'-bootclasspath', project.android.bootClasspath.join(File.pathSeparator)]log.debug 'ajc args: ' + Arrays.toString(args)MessageHandler 处理程序=new MessageHandler(true)new Main().run(args, handler)for (IMessage message : handler.getMessages(null, true)) {switch (message.getKind()) {case IMessage.ABORT:case IMessage.ERROR:case IMessage 。 FAIL:log.error message.message, message. thrownbreakcase IMessage.WARNING:log.warn message.message, message. thrownbreakcase IMessage.INFO:log.info message.message, message. thrownbreakcase IMessage.DEBUG:log.debug message.message, message. thrownbreak}}}

上面这段是从网上抄来的别人的文章,但是当时有一个bug,导致官方包部分代码无法成功插入,不过这个代码是后来才发现的。我成功注释掉了下面的代码。

if (!variant.buildType.isDebuggable()) {log.debug('跳过不可调试的构建类型'${variant.buildType.name}'.')return}

至此,AOP配置完成。然后根据你的需求贴出你已经完成的相关业务代码。

1. 统计页面停留时间。

这里的统计数据来自极光推送。官方文档要求在每个页面生命周期的开头和结尾添加两句话。无论如何,我们的项目有100 多页。如果每一页都加上的话,工作量……一言难尽。我们来看看切面是如何实现页面监控的。

执行代码

@Aspectpublic class TraceAspect {private static Final String TAG='aop_page_trace';@After('execution(* android.app.Activity.onResume(.)) )')public void onActivityMethodBefore(JoinPoint joinPoint) throws Throwable {Signature Signature=joinPoint.getSignature();System.out.println(TAG + '方面点执行开始上下文==' + (Context) joinPoint.getThis());System.out.println(TAG + '方面点执行开始类名' +signature.getDeclaringType().getCanonicalName());JAnalyticsInterface.onPageStart((Context) joinPoint.getThis(),signature.getDeclaringType().getCanonicalName());}@After('execution(* android.app.Activity. onPause(.)) ')public void onActivityMethodDestory(JoinPoint joinPoint) throws Throwable {Signature Signature=joinPoint.getSignature();JAnalyticsInterface.onPageEnd((Context) joinPoint.getThis(), signal.getDeclaringType().getCanonicalName( )) ;System.out.println(TAG +'执行并销毁切面点context==' + (Context) joinPoint.getThis());System.out.println(TAG +'执行并销毁切面点类名' + 签名。 getDeclaringType().getCanonicalName());}

Execution 一般指定一个方法的执行,但由于没有未来的注解或权限限制,所以这里什么都不写;返回值用* 代替,表示可以使用任何返回值。 on*代表函数名,完整路径,下面的模型表示on后面可以连接任何内容,后面的(.)表示参数可以是任意值。

@After指的是在jPoint()之后执行。该通配符通常用于避免影响先前代码的执行。

2.与按钮点击和页面跳转相关的隐藏点

我们先来说说想法。我这里使用了注释。第一步是自定义注释,第二步是在必要时引用当前注释。第三步是找到方面检查引用注释的切入点。第四步是在切点处添加必要的逻辑代码。

自定义注解的代码如下

/***点击时间嵌入点标注2019-10-30*/@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.FIELD})public @interface ClickAnnotate {int type()default0; //我们定义了类型参数,根据我们的需求进行标记,以便我们找到切入点后进行业务决策。监控点击或跳转的切面代码如下@Aspectpublic class ClickAspect {private static Final String TAG='aop_click '; private String Intention=IntentionAty .class.getCanonicalName();@Pointcut('execution(@com .aoptest.annotation) .ClickAnnotate * *(.))')public void clickP() {}@After('clickP( )')public void insertCodeBlock( JoinPoint joinPoint) throws Throwable {MethodSignature methodSignature=((MethodSignature) joinPoint.getSignature()) ;Method method=methodSignature.getMethod();if (method.isAnnotationPresent(ClickAnnotate.class)) {ClickAnnotate clickAnnotate=method.getAnnotation(ClickAnnotate.class);int type=clickAnnotate.type();switch (type ) {case 常量.AOP_HOME_MENNU://这个常量是自定义的String menCode='';if (joinPoint.getArgs() !=null joinPoint.getArgs() .length 0) {if (joinPoint.getArgs()[0]instanceof String) {menCode=(String) joinPoint.getArgs()[0];}} //joinPoint.getArgs()是进入方法的参数,一定要注意数组越界问题if (TextUtils.isEmpty( menCode)) return;switch (menCode) {case 'MENU_HOME_HYGL':Log.i(TAG, 'insertCodeBlock:点击了会员管理');break;case 'MENU_HOME_YXDD':Log.i(TAG, 'insertCodeBlock:按预定顺序点击了'); break;}break;}}}} 此时,我们需要对方面做的所有事情都已完成。下一步就是简单地调用注释来指示代码需要剪切的位置。

/**** @param menuCode 菜单对应的代码*/@ClickAnnotate(type=Constants.AOP_HOME_MENNU) //这里的常量对应上面的方面private void setMenuJump(String menuCode) {Class className=null ;if ( menuCode.equals('MENU_HOME_YXDD')) {className=IntentionAty.class;}if (className !=null) {startActivity(new Intent(mContext, className));}}调用上述步骤后,切面检查@ClickAnnotate注解,调用All方法,找到切入点,插入相关代码。由于我们在这里考虑了重用,因此我们在注释中定义了类型来区分它们。

总结

项目内。使用混淆时,请注意不要混淆注释。如果不进行混淆,该方面将不会执行。在考虑了这个需求之后,我们发现AOP是一个不错的选择。 AOP显着降低了代码耦合性,大大提高了代码的可维护性。有关如何编写AOP 相关注解和表达式的信息,请参阅AOP 常用注解和概念(https://www.codercto.com/a/23534.html)。相关概念已经解释到这里了,我就不照搬了。这里。

本站涵盖的内容、图片、视频等数据,部分未能与原作者取得联系。若涉及版权问题,请及时通知我们并提供相关证明材料,我们将及时予以删除!谢谢大家的理解与支持!

Copyright © 2023