• Aspect Android埋点统计activity页面使用时长 onResume onPause,并保存时长


    Aspect Android埋点统计activity页面使用时长 onResume onPause,并保存时长

    标记:

    1.项目下build.gradle

    1. dependencies {
    2. classpath 'com.android.tools.build:gradle:3.5.4'
    3. classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10'
    4. }

    2.app 文件夹下 build.gradle

    apply plugin: 'com.hujiang.android-aspectjx'
    1. // 配置 AspectJX
    2. aspectjx {
    3. exclude 'androidx.core','androidx.appcompat'
    4. }

    1. dependencies {
    2. .......
    3. // 引入 AspectJX 依赖
    4. implementation 'org.aspectj:aspectjrt: 1.9.8'
    5. ...
    6. }
    1. import org.aspectj.bridge.IMessage
    2. import org.aspectj.bridge.MessageHandler
    3. import org.aspectj.tools.ajc.Main
    4. android.applicationVariants.all { variant ->
    5. JavaCompile javaCompile = variant.javaCompile
    6. javaCompile.doLast {
    7. //下面的1.8是指我们兼容的jdk的版本
    8. String[] args = [
    9. "-showWeaveInfo",
    10. "-1.8",
    11. "-inpath", javaCompile.destinationDir.toString(),
    12. "-aspectpath", javaCompile.classpath.asPath,
    13. "-d", javaCompile.destinationDir.toString(),
    14. "-classpath", javaCompile.classpath.asPath,
    15. "-bootclasspath", android.bootClasspath.join(File.pathSeparator)
    16. ]
    17. MessageHandler handler = new MessageHandler(true);
    18. new Main().run(args, handler)
    19. def log = project.logger
    20. for (IMessage message : handler.getMessages(null, true)) {
    21. switch (message.getKind()) {
    22. case IMessage.ABORT:
    23. case IMessage.ERROR:
    24. case IMessage.FAIL:
    25. log.error message.message, message.thrown
    26. break;
    27. case IMessage.WARNING:
    28. case IMessage.INFO:
    29. log.info message.message, message.thrown
    30. break;
    31. case IMessage.DEBUG:
    32. log.debug message.message, message.thrown
    33. break;
    34. }
    35. }
    36. }
    37. }

    注意:

    aspectjx {。。。}   和
    android.applicationVariants.all {。。。。。}
    要与   android {...} 同级

    示例:

    1. @Aspect
    2. public class ClickAspect {
    3. private static final String TAG = ClickAspect.class.getSimpleName();
    4. private Map resumeTimeMap = new WeakHashMap<>();
    5. private Map durationMap = new WeakHashMap<>();
    6. private Map eventTrackerMap = new WeakHashMap<>();
    7. @Pointcut("execution(* android.view.View.OnClickListener.onClick(android.view.View))")
    8. public void onClickPointcut() {
    9. }
    10. @Pointcut("execution(* android.app.Activity.onCreate(..))")
    11. public void activityOnCreatePointcut() {
    12. }
    13. @Pointcut("execution(* bg.camera.com.MainActivity+.onDestroy(..))")
    14. public void activityDestroyPointcut() {
    15. }
    16. // 定义切入点,匹配Activity的onResume和onDestroy方法
    17. @Pointcut("execution(void android.app.Activity.onResume()) && target(activity)")
    18. public void onActivityResumed(Activity activity) {
    19. }
    20. @Pointcut("execution(void android.app.Activity.onPause()) && target(activity)")
    21. public void onActivityPaused(Activity activity) {
    22. }
    23. @Pointcut("execution(void android.app.Activity.onDestroy()) && target(activity)")
    24. public void onActivityDestroy(Activity activity) {
    25. }
    26. // 在Activity的onCreate方法前进行统计逻辑处理
    27. @Before("onActivityResumed(activity)")
    28. public void trackActivityResumed(JoinPoint joinPoint, Activity activity) {
    29. // 获取Activity的类名
    30. String className = activity.getClass().getSimpleName();
    31. // 获取当前时间戳
    32. long startTime = System.currentTimeMillis();
    33. // 存储Activity的开始时间戳
    34. // 可以使用SharedPreferences或其他方式进行持久化存储
    35. updateTrackPointInfoNameValue(activity, className, startTime);
    36. Log.i(TAG, activity.getClass().getSimpleName() + " onActivityResumed "+startTime);
    37. }
    38. // 在Activity的onDestroy方法后进行统计逻辑处理
    39. @After("onActivityPaused(activity)")
    40. public void trackActivityPaused(JoinPoint joinPoint, Activity activity) {
    41. // 获取Activity的类名
    42. String className = activity.getClass().getSimpleName();
    43. EventBean starTimeE = getTrackPointInfoNameValue(activity, className);
    44. long starTime = null != starTimeE ? starTimeE.getEventTime() : 0;
    45. // 获取停留当前时间戳
    46. long pausedTime = System.currentTimeMillis() - starTime;
    47. // 获取存储的开始时间戳
    48. // 根据开始时间戳和当前时间戳计算使用时长
    49. // 进行统计上报或其他处理逻辑
    50. updateTrackPointInfoNameValue(activity, className, pausedTime);
    51. Log.i(TAG, activity.getClass().getSimpleName() + " onActivityPaused "+pausedTime);
    52. }
    53. // 在Activity的onDestroy方法后进行统计逻辑处理
    54. @After("onActivityDestroy(activity)")
    55. public void trackActivityDestroy(JoinPoint joinPoint, Activity activity) {
    56. // 获取Activity的类名
    57. String className = activity.getClass().getSimpleName();
    58. removeTrackPointInfoNameValue(activity, System.currentTimeMillis());
    59. Log.i(TAG, activity.getClass().getSimpleName() + " onActivityPaused");
    60. // 注销之后Fragment onStop之后的生命周期将不再执行
    61. // 进行统计上报或其他处理逻辑
    62. }
    63. @After("onClickPointcut()")
    64. public void afterOnClick(JoinPoint joinPoint) throws Throwable {
    65. Object target = joinPoint.getTarget();
    66. String className = "";
    67. if (target != null) {
    68. className = target.getClass().getSimpleName();
    69. }
    70. Object[] args = joinPoint.getArgs();
    71. if (args.length > 0 && args[0] instanceof View) {
    72. View view = (View) args[0];
    73. String entryName = view.getResources().getResourceEntryName(view.getId());
    74. // TrackPoint.onClick(className, entryName);
    75. }
    76. // joinPoint.proceed();
    77. // 点击事件执行后执行的代码
    78. Log.d(TAG, "Button clicked");
    79. }
    80. @Around("activityOnCreatePointcut()")
    81. public void pageOpen(ProceedingJoinPoint joinPoint) throws Throwable {
    82. String name = joinPoint.getSignature().toShortString();
    83. long time = System.currentTimeMillis();
    84. Object target = joinPoint.getTarget();
    85. String className = target.getClass().getSimpleName();
    86. // updateTrackPointInfoNameValue(activity, className, 0L);
    87. // TrackPoint.onPageOpen(className);
    88. joinPoint.proceed();
    89. Log.e(TAG, name + " activityOnCreatePointcut: " + (System.currentTimeMillis() - time));
    90. }
    91. @Around("activityDestroyPointcut()")
    92. public void pageClose(ProceedingJoinPoint joinPoint) throws Throwable {
    93. long time = System.currentTimeMillis();
    94. Object target = joinPoint.getTarget();
    95. String className = target.getClass().getSimpleName();
    96. // TrackPoint.onPageClose(className);
    97. joinPoint.proceed();
    98. Log.e(TAG, className + " activityOnCreatePointcut: " + (System.currentTimeMillis() - time));
    99. }
    100. public static boolean hasId(int[] arr, int value) {
    101. for (int i : arr) {
    102. if (i == value)
    103. return true;
    104. }
    105. return false;
    106. }
    107. /**
    108. * 性能监控
    109. *
    110. * AspectJ其实在Android中的应用主要还是性能监控、日志埋点等,下面以一个简单的例子表示:
    111. * 我们监控布局加载耗时,判断布局是否嵌套过多或者过于复制导致Activity启动卡顿,首先我们知道Activity是通过setContentView方法加载布局的:
    112. * 1、布局解析过程,IO过程
    113. * 2、创建View为反射过程
    114. * 这两步均为耗时操作,所以我们需要监控setContentView
    115. *
    116. * 日常开发中,我们可以将耗时上传到服务器,收集用户信息,找到卡顿Activity做出对应优化
    117. * @param point
    118. * @throws Throwable
    119. */
    120. @Around("execution(* android.app.Activity.setContentView(..))")
    121. public void getContentViewTime(ProceedingJoinPoint point) throws Throwable {
    122. String name = point.getSignature().toShortString();
    123. long time = System.currentTimeMillis();
    124. point.proceed();
    125. Log.e(TAG, name + " cost: " + (System.currentTimeMillis() - time));
    126. }
    127. @Around("call (* bg.eyccamera.com.MyApp.**(..))")
    128. public void getTime(ProceedingJoinPoint joinPoint) {
    129. Signature signature = joinPoint.getSignature();
    130. String name = signature.toShortString();
    131. long time = System.currentTimeMillis();
    132. try {
    133. joinPoint.proceed();
    134. } catch (Throwable throwable) {
    135. throwable.printStackTrace();
    136. }
    137. Log.i(TAG, name + " cost" + (System.currentTimeMillis() - time));
    138. }
    139. private void updateTrackPointInfoNameValue(Context context, String name, long time) {
    140. DatabaseManager.getInstance(context).insertData(new EventBean(name, time));
    141. }
    142. private EventBean getTrackPointInfoNameValue(Context context, String name) {
    143. return getTrackPointInfoNameValue(context, name, 0);
    144. }
    145. private EventBean getTrackPointInfoNameValue(Context context, String name, long time) {
    146. List eventList = null;
    147. EventBean eventBean = null;
    148. eventList = DatabaseManager.getInstance(context).getAllData();
    149. if (null != eventList && eventList.size() > 0) {
    150. for (int i = 0; i < eventList.size(); i++) {
    151. if (name.equals(eventList.get(i).getPath())) {
    152. eventBean = eventList.get(i);
    153. break;
    154. }
    155. }
    156. }
    157. return eventBean;
    158. }
    159. private void removeTrackPointInfoNameValue(Context context, long evenTime) {
    160. DatabaseManager.getInstance(context).removeData(evenTime/ 1000);
    161. }
    162. }

  • 相关阅读:
    c++学习第十三
    单例模式--Java
    concrt140.dll怎么下载,concrt140.dll修复工具(修复精灵下载)一键修复问题
    mmrotate自定义数据集安装部署训练测试
    菇多糖-聚乙二醇-大环配体NOTA,大环配体NOTA-PEG-香菇多糖
    STM32Cube高效开发教程<基础篇>(七)----基础定时器
    java常量命名规则简介说明
    MyBatisPlus详解
    【数据结构-进阶】二叉搜索树
    城市内涝解决方案:实时监测,提前预警,让城市更安全
  • 原文地址:https://blog.csdn.net/ck3345143/article/details/133950510