本文主要描述了怎么样提高一个客户端开发排查和定位的效率,并且动手写了一个小工具的实践和思考,以及团队中其他合作者能够提高了定位问题效率,验证功能是否准确的效率。
作者/马杰 中国大学 MOCC 团队
编辑/刘振宇
一、前言
中国大学 MOOC 是由网易与高教社携手推出的在线教育平台,承接教育部国家精品开放课程任务,向大众提供中国知名高校的 MOOC 课程。目前,无论是课程数量、质量还是社会影响力,中国大学 MOOC 都已成为全球领先的中文慕课平台。
在日常的 Android 开发中,我们经常会遇到以下的一些问题:测试、运营、产品同学跑过来说这个页面出了问题,赶紧看下。这时候客户端开发同学就需要赶紧定位到具体的某个页面。
据观察,大部分的情况下对于一个突发页面的问题定位,或者业务方想让开发者确认这个页面的业务逻辑的时候,客户端开发者,往往需要花费比较长的时间去给业务方答复。如果近期业务可能还能记得,但是客户端的页面比较多,想要快速定位到具体业务页面,那么就需要花更多的时间去找相关的页面。
所以本文的想法是怎么快速找到对应的页面,帮助开发快速的进入业务代码,快速的回复业务方提出的问题。
二、方案实施
在探讨方案的时候,我们需要对比目前有哪些方案,对比之后再选择一种更加有效的方法。
2.1 解决问题的常用方式
在 Android 开发中解决上述提供的问题,常用的有以下 3 种方式:
· 打开 Android studio,靠着源码记忆,文案记忆去搜索;
· 使用 adb 命令来过滤当前的 activity;
// windows
adb shell dumpsys window windows | Select-String -Pattern 'mCurrentFocus|mFocusedApp|mLastOpeningApp|mObscuringWindow'
// Mac
adb shell dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp|mLastOpeningApp'
· 全局搜索关键文案。
上面 3 种方式是能够解决问题;但从时间效率上分析,可以估算一下每一种方式大概需要多长时间:
第一种,按照个人经验,熟悉项目代码的同学最快也要几十秒左右,慢的话 10 几分钟;
第二种,使用 adb 能够几秒就定位到页面,但是需要记住命令,或者提前设置命令快捷方式;
第三种,如果有很多相同文案,需要多搜索几遍,时间也可能是10几秒到1分钟不等。
所有上面几种方式得出的时间效率就是几秒到几分钟不等,而且基本都是需要代码或者 adb 的开发工具,依赖于开发环境。
既然需要花的时间也不少,那么是不是应该做一个工具来提升更快的定位速度,提升定位效率呢?
2.2 更加高效的方法
其实思路很简单,就是写一个开发的SDK,用来实时关注当前的页面信息,这个页面信息主要包含如下的信息:
- 当前 Activity 是哪个?
- 当前的 Fragment 是哪个?
- 当前页面的参数传递,如:intent 中的各种参数是什么?
效果图如下:
从上面信息就能够很快的定位到当前的页面;当一个页面的深度到非常深的时候,这样的小工具就特别好用;最快速度只要几秒就能快速定位到页面,效率提升快几十倍不止,而且能够当着测试和产品的面,能够把当前关键的参数给他看,如:xxxId、埋点信息等。
2.3 主要实现原理
上面的小工具,主要的工作是获得当前的Activity,获得当前Activity的方式主要有以下几种方式:
- 通过 RunningTaskInfo的 topActivity,该方法在后续的一些版本已经被禁用;
- 手写代码管理Activity,这个方法比较粗暴,维护比较麻烦;
- 通过反射 ActivityThread获得 currentActivityThread 从 mActivities 中查询获得;
- 使用AccessibilityService 这个辅助功能,这个方法获得的信息比较少;
- 通过 ActivityLifecycleCallback 监听来获得。
经过对比,选择使用AccessibilityService和ActivityLifecycleCallback 这2种方式去尝试。以下就简单的说下这2种方法的实现,并进行二者之间的对比以及最后做出的选择。
2.3.1 ActivityLifecycleCallback 方式
是不是很简单?为了避免内存泄漏,可以在 onDestroy 的时候把 topActivity 设置成 null,这种方式简单快速,不需要申请权限。
2.3.2 AccessibilityService 方式
· 继承 AccessibilityService
· manifest 配置
· 需要 res/xm/accessibilityservice.xml 文件
和 ActivityLifecycleCallback 相比,这种方式相对复杂点,但是也还是简单的。
2.3.3 2种方式的对比
从实现角度对比,使用 ActivityLifecycleCallback 比 AccessibilityService 更加简单。但是 AccessibilityService 有个优势就是可以不用集成到自己的 app 里面,可以独立运行,可以查看所有的当前页面是属于哪个 Activity,可以跨进程使用,使用 ActivityLifecycleCallback 必须要集成到自己的 app 中。
在实践过程中,其实我们不只是想获得当前的 Activity,我们还想知道当前的 Activity 中有哪些当前的fragment, 当前的Activity 从上一个 Activity 中获得了哪些参数,当前的fragment中有哪些参数等细节信息。那么只能集成到app中去的时候才会比较容易获得,所以最后选择了使用 ActivityLifecycleCallback的方式。
2.3.4 页面更详细的信息
一般页面上的信息开发,简单一点的就是一个 Activity 然后简单布局;复杂一点的基本都是 Activity + (ViewPager)Adatper + fragment,有时候fragment里面还会有 ViewPager 装载着fragment, 对于不熟悉代码的人找对应的业务逻辑页面和代码,还是需要花费不少时间的。所以页面信息fragment也很重要。
三、 提高效率举例
关于这个页面信息采集,在这里列举了几个使用场景,来证明效率得到了提高:
- 对于客户端开发者,能够快速的定位到当前出错的页面,特别是刚来的开发,或者不熟悉这块业务的,或者业务页面深度比较深的时候;
- 页面核心参数的确认,比如详情页面需要一些 id, 这些详细参数就不需要客户端同事打断点的方式去获取,运营和测试自己可以去查看;
- 在精品课和云课堂集成的时候,能够让测试同学快速的区分哪个是精品课里面的页面,哪个是云课堂里面的页面,方便测试知道当前页面是属于哪个业务端的;(这个场景是网易内部融合项目)
- 页面全链路参数传递验证场景。比如:首页点击需要传递转化率的参数一直传递到下页面,平时都是开发自己验证,有这个工具后,产品也能在提测后,从测试包上自己查看验证。
四、 页面信息其他想法
关于页面信息场景增强,以下几种页面信息方式,是认为可以进行扩充的:
- 可以获得 RecyclerView 中的 adapter;(有很多布局逻辑,放到了 adapter 里面的 ViewHolder)
- webview 当前信息的监控;(前端同事调试)
- 网络看板的监控;(当前页面的网络请求信息)
- 不连接电脑 Logcat 日志查看看板;(不用连接电脑,获得 adb 信息)
- 参考线,界面元素位置,对应元素的颜色。(UI 走查的验证)
以上的几点,主要是按照自身 app 的情况去判断是否需要实现,判断哪些实现性价比比较高。目前已经实现的,基本都是个人认为性价比是比较高的东西。
五、 总结
当我们遇见一个问题的时候,首先思考这个问题是不是自己比较难受的点,然后观察其他人是否有类似的情况。这个问题常用的解决方案什么?有没有工具方法去替代?如果没有,可以不可以用比较低的成本去制造一个工具?最后来提升自己的效率,这个工具如果能够帮助其他人,那么能效就更加好了。
-END-