AccessibilityService+WindowManager+SurfaceView开系统权限
一种通过自动获取用户权限增强产品体验的方法
本文是基于辅助功能+悬浮窗+SurfaceView来实现自动获取用户权限的具体方案设计与实现。辅助功能抢红包插件相信大家并不陌生,但是微信官方不允许,但是在工具软件领域还是可以大显身手,特别是开权限。辅助功能的作用就是实现节点查找和模拟点击,而悬浮窗实现需要的蒙层遮罩效果,SurfaceView则是实现流程的过渡动画。
1、 什么是辅助功能
辅助功能其实是一个Android系统提供给的一种服务,本身是继承Service类的。这个服务提供了增强的用户界面,旨在帮助残障人士或者可能暂时无法与设备充分交互的人们。
许多Android用户有不同的需求,要求它们以不同的方式与他们的Android设备进行交互。这包括用户视觉、物理或年龄限制,防止他们完全看到或使用触摸屏,和用户与听力损失可能无法感知声音和警报信息。 Android提供了辅助功能服务更容易帮助这些用户导航设备,包括语音、触觉反馈、手势导航,轨迹球和directional-pad导航。Android应用程序开发人员可以利用这些服务使应用程序更容易。 Android开发者也可以建立自己的辅助功能服务,可以提供增强的可用性特性,比如音频提示物理反馈和替代导航模式。辅助功能服务可以为所有应用程序提供这些增强功能,一组应用程序或只是一个单一的应用程序。
本文正是利用辅助功能服务提供的这些增强功能,实现在Android设备权限界面上查找到我们需要的节点信息,然后进行模拟点击。整个点击过程通过一个悬浮窗蒙层遮住,在悬浮窗上面通过SurfaceView实现一个不抢占和阻塞UI线程的一个过渡动画来与用户进行交互。
2、 整体方案流程
2.1. 整体功能流程图
图2-1 整体方案流程图
2.2. 权限数据管理流程
图2-2 数据管理流程图
3、 功能框架设计与实现
3.1. 框架模块设计
整个框架可分为辅助功能服务模块,权限数据控制模块,界面控制模块。辅助功能服务模块主要负责接收并筛选辅助功能回调事件,查找页面节点,并实现模拟点击。权限数据控制模块,主要负责控制云端库文件的下拉更新以及权限库文件的解析。界面控制模块主要控制整体权限开启流程,开启前的引导,开启过程中的蒙层上流畅的过渡动画,以及开启成功或失败后的状态提示。整体功能模块图3-1如下所示,整体框架图如图3-2所示。
3-1 整体功能模块图
图3-2 整体框架图
下面依次从辅助功能服务模块,权限数据控制模块,界面控制模块来描述具体的实现。
3.2. 辅助功能模块实现原理
自定义一个服务类AccessibilitySampleService(这个命名可以随意),继承系统的AccessibilityService并覆写onAccessibilityEvent和onInterrupt方法。编写好服务类之后,在系统配置文件(AndroidManifest.xml)中注册服务。完成前面两个步骤就完成了基本发辅助功能服务注册与配置,具体的功能实现需要在onAccessibilityEvent中完成,根据onAccessibilityEvent回调方法传递过来的AccessibilityEvent对象可以对事件进行过滤,结合AccessibilitySampleService本身提供的查找节点与模拟点击相关的接口即可实现权限节点的查找与点击。
辅助功能服务类实现
辅助功能服务注册与配置
在工程res目录下新建xml文件夹,新增accessibility_config.xml配置文件,内容如下:
在AndroidManifest中配置辅助功能服务
实现节点查找(这里是按文本进行查找,没有用View的ID)并点击
获取根节点
实现模拟点击
3.3. 权限数据控制模块实现原理
此模块逻辑比较独立,重点是权限库文件的设计与解析,库文件包括的内容就是每个机型的各个权限所以的页面的基本信息,比如权限的ID,权限名称,权限开启子步骤,权限所在页面路径等。库文件使用json文件格式描述,便于解析与维护。
权限库文件设计好之后,需要做云端更新,便于能做快速适配,及时修复问题。云端更新时需要设置好版本控制,设置好库文件的更新机制,比如是一天更新一次,还是每次使用功能时都检测是否需要更新,控制对本地库文件的覆盖机制,避免将错误的数据替换掉本地正确的数据。另外要规定好本地库文件的路径,方便程序对其进行解析。
单个权限节点配置信息如下:
delay_time属性代表点击前的等待加载时间,type_id是权限对应的id(这是自定义的),describe属性是对权限的一个描述(方便库文件的阅读而已),intent属性代表这个权限所在的包名跟具体的类名(这是最重要的,跳转就靠这个属性),step代码开启这个权限所需的步骤,find_node属性表示要在这个页面查找什么节点。至于库文件的设计格式这个依赖于程序的设计,可以不一样,只要知道原理即可。
3.4. 界面控制控制模块实现原理
界面控制模块主要是控制整体流程的交互,为了避免让用户看到开启权限的过程,需要使用Android的悬浮窗,在启动开启权限流程之后,实现一个悬浮窗覆盖在最顶层。并且在悬浮窗蒙层上面提供当前的进度与提示,告诉用户当前在做什么,做了多少。
在开启权限的过程中,所有的操作几乎都是在UI线程里面工作的,所以蒙层上如果用普通的动画方式实现的话,是会卡顿的,影响用户体验。所以在本发明中,使用了非阻塞UI线程的方式实现,那就是使用自定义SurfaceView实现自定义动画。因为SurfaceView的绘制在单独的绘制线程里面执行的,不会抢占UI线程的资源,不会对权限开启流程造成任何负面影响,反而减少了开启权限所需要的整体时间。另外在SurfaceView中实现流畅的过渡动画,减少用户等待时间,一直与用户有交互,增强用户体验。
悬浮窗蒙层上实现的动画效果如下所示:
4、 总结
本方法使用辅助功能自动开启权限,提供了可配置式的权限开启列表,具有很强的拓展性和可维护性,开启过程使用悬浮窗蒙层遮盖使得用户无需担忧,并且在蒙层上使用流畅的过渡动画和提示与用户进行友好交互,提升了产品体验,不再卡顿,不再有漫长的等待。这样能够减少因误触导致权限开启流程被中断的情况,同时能够提升用户的权限开启率和权限的开启成功率,从而提升软件的功能活跃,提升功能留存。
辅助功能Sample地址
本文中的所说的方案完整源码涉及公司信息安全,所以并没有提供。下面提供一个辅助功能基本使用的项目地址,后面也会抽离一部分代码加进去。
https://github.com/PopFisher/AccessibilitySample