藏在微信里的温度,无障碍开发框架分享

藏在微信里的温度,无障碍开发框架分享

腾小云导读

现我国现有4471w视障/听障人士,60岁及以上人群达2.6亿规划。微信作为国民级运用,完成无障碍迫在眉睫。为了协助他们更好地运用微信 App,Android微信完成了适老化及无障碍改造。本文首要介绍Android 微信开发团队依据适老化及无障碍需求,完成的一个协助业务侧进行无障碍功用开发的结构。希望能给广阔开发爱好者带来协助和启示!


看目录,点收藏

1 无障碍需求结构布景

1.1 无障碍需求

1.2 结构简介

2 无障碍开发基础知识

2.1 读屏软件辨认View原理

2.2读屏软件后的事情分发原理

3 结构完成的全体流程和履行原理

3.1 全体流程

3.2 履行原理

4 中心阐明:大局热区补足机制

4.1布景阐明

4.2详细完成

4.3 额定阐明

5走查东西

6 总结

01、无障碍需求结构

现在,业界已经有一致性的无障碍开发守则。例如 Web Content Accessibility Guidelines (WCAG) 2.0,它是由互联网的首要国际标准组织万维网联盟 (W3C) 的Web可访问性建议 (WAI) 发布的一系列 Web 可访问性指南的一部分。

此外,WAI-ARIA(可访问的富Internet运用程序套件)是由万维网联盟(W3C)发布的一项关于 A11 Y技能运用标准。该标准界说了一种使残障人士更易于访问 Web 内容和 Web 运用程序的办法,增加 HTML、JavaScript 和相关技能开发的网站动态内容以及用户界面组件的可访问性。

现在,Android没有官方一致、便利的结构,官方供给的原生api并不是特别好用,所以微信团队对其进行参考,开发了一个无障碍结构,依据原生的api进行了再封装,将繁琐的无障碍适配逻辑封装在底层,以声明式接口的形式,让上层业务能以更简便更解耦的代码,完成无障碍的适配。接下来咱们进行共享:

1.1无障碍需求

本结构首要具有以下特性:

  • 可感知性 :包含大字体适配,颜色对比度等 。
  • 可操作性 :首要是过小热区的扩展,提高老年人/残疾人的交互体会 。
  • 可了解性 :微信应供给读屏案牍等信息,协助盲人在敞开 Talkback 等读屏软件的状况下,正常运用微信。

下面给出一些较为典型的需求:

  • 需求1:过小热区的扩展

需求是要求微信内的一切可交互控件,可点击规划不得低于 44dp * 44dp。

巨细不合规的控件,假如一个个进行排查、布局修正。工程量巨大。

  • 需求2:呼应区域会随无障碍开关产生改变

藏在微信里的温度,无障碍开发框架分享

该 Item 由一个 SwitchButton + TextView 组成。

敞开 Talkback 时,整个 Item 辨认为一个焦点,选中双击是触发点击 switch的逻辑。在无障碍形式下,选中双击是直接触发相应控件的 Click 事情。可是在不开 Talkback 的状况下点击 Item 又无需呼应,只呼应 SwitchButton 。也便是点击区域会随 Talkback 开关产生改变。

完成或许是:在 ItemClick 中进行 if 判别。但这样写侵入性高,难维护。

  • 需求3:读屏案牍由其他的控件的值组合

藏在微信里的温度,无障碍开发框架分享

选中头像,读屏案牍:腾讯行政的头像,有 2 条未读消息。需求读出列表中其他关联内容,这种只能把适配代码侵入到 Adapter中。

1.2 结构简介

结构将不同的无障碍需求的完成进行封装,抽象成不同的规矩。

业务侧可以将一个页面/业务的无障碍需求,在一个装备类里运用规矩表达出来,再由结构进行处理。完成相应的作用。

classChatAccessibility(activity: AppCompatActivity) :
BaseAccessibilityConfig(activity) {  
overridefuninitConfig() {  
// 设置 contentDesc  
view(rootId,viewId).desc(R.string.send_smiley)  
// ...  
}  
}

结构基类 BaseAccessibilityConfig 供给了一系列用于表达规矩的 api,包含但不限于如下功用:

  • 经过装备一致设置 contentDescription

  • 支撑把多个 View 组合成一体进行读屏

  • 经过装备禁用某个View被 Talkback 集合的能力

  • 支撑按指定次序进行读屏,支撑部分操控 Talkback 集合次序

  • 支撑设定在 Activity 启动后的第一个读屏控件

  • 支撑对某个父 View 的 disableChildren 功用

  • 在某个 View 满意条件时,对其进行读屏,但不集合

  • 在某个 View 满意条件时,读出提早设定的 string,但不集合

  • 大局热区宽高补齐至 44dp,并供给自界说热区扩展/禁用热区扩展的功用 …

02、无障碍开发基础知识

在深化了解结构的规划前,先来介绍一些无障碍功用开发的基础知识。

2.1 基础知识1:读屏软件辨认 View 原理

藏在微信里的温度,无障碍开发框架分享

读屏软件无法直接辨认到View,只能辨认到View供给的虚拟节点「Node」,View 和虚拟节点一般是一一对应的。当页面内容产生改变,比方 View 被设值,或者产生翻滚等状况,View 会向无障碍体系发送一个事情,告诉体系。

然后体系就回头向 View 索取节点,组成页面更新后新的节点树,而 「节点树 和 ViewTree 是一一对应的」。此时读屏软件拿到的便是新的内容了。

2.2 基础知识2:读屏软件后的事情分发流程

分为上下两部分:读屏软件阻拦处理行为、读屏软件接受事情。

藏在微信里的温度,无障碍开发框架分享

流程如下:

  • 读屏软件阻拦用户 Touch 事情,依据事情的坐标去定位到目标节点。

  • 将 Touch 事情解释为节点行为,这里以接触选中为例,那么便是集合行为。

  • 读屏软件经过该节点向无障碍体系发送,无障碍体系又转发给View(集合产生的绿框便是在View的内部处理里去制作的)。

  • 生成新的虚拟节点并供给给读屏软件后,读屏软件组合信息,经过 TTS 语音引擎的 api 读出。

读屏软件展现给用户的一切信息,悉数来自虚拟节点。可以在节点生成的过程中,修正节点的信息,所以这里是一个绝佳的**「信息自界说」**的当地。

选用将一切的 View 都「Wrap 一层 AccessibilityDelegate」的方式,「在 onInitializeAccessibilityNodeInfo 办法中修正节点信息」。

03、结构完成全体流程与履行原理

3.1 全体流程

藏在微信里的温度,无障碍开发框架分享

  1. 业务侧完成规矩装备类,编写的规矩会进入装备池。

  2. 结构在View生成节点给体系的时分进行阻拦 「(onInitializeAccessibilityNodeInfo)」

  3. 在装备池中寻找匹配的规矩。

  4. 依据匹配的规矩对节点进行修正。

  5. 终究生成的节点就会由体系交由给读屏软件进行读屏。

3.2 履行原理

藏在微信里的温度,无障碍开发框架分享

中心原理:选用依据职责链的流水线来处理。全体流程首要分为两部分:

  • View 预处理职责链(图示左边):履行预出来操作,如异步生成缓存、View符号等;

  • 节点处理职责链(图示右边):节点处理的一起会同步查找规矩进行设置。

接下来首要简略介绍下结构的一个中心功用的完成:「大局热区补足机制」 (坐落结构流程中的预处理职责链中的一环)。

04、中心阐明:大局热区补足机制

4.1 布景阐明

  • 需求阐明

过小热区扩展,即微信内的一切可交互控件可点击规划不得低于 44dp * 44dp,像一些巨细不合规的控件,假如一个个进行排查、布局修正,工程量太巨大。还有热区其他一些需求 etc。

  • 问题难点

一般会挑选直接修正 padding,有些乃至需求改动相应布局,但这样的改动工作量太大且容易影响本来视图布局。

  • 处理计划

需求一个大局的热区补足机制,将过小热区补足至标准。

4.2 详细完成

「创立 View 的一致入口」 去设置 TouchDelegate 代理,由父 View 作为TouchDelegate 的承载 View 去代理 Touch 事情,这里有几个问题需求处理:

  • 怎么找到合适的承载View

  • 热区及时更新

  • 性能优化

  • 读屏形式下的热区扩展

下面咱们别离展开讲。

  • 要点问题1:怎么找到合适的承载 View

从目标 View 向上冒泡,找到一个合适的父 View。那么需求 「冒泡终止条件」。 首要条件一肯定是 「足够大」。当时 View 够大了就没必要再往上冒了。

藏在微信里的温度,无障碍开发框架分享

可是这样会存在问题:子 View 的 Click优先级高于父View的TouchDelegate。事情派发机制:

从父 View 往子 View 派发,从子 View 向上处理。View 的事情处理次序是先 OnTouchListener,然后是 TouchDelegate,再是Click、LongClick。

所以会导致下图的状况:

藏在微信里的温度,无障碍开发框架分享

现在进行了折中处理,相比上图,显然是下图的扩展后的体会更佳:

藏在微信里的温度,无障碍开发框架分享

一起加入了条件二:「该承载 View 是 Clickable、LongClickable」。终究计划流程确定如下:

藏在微信里的温度,无障碍开发框架分享

  • 要点问题2:热区及时更新

布景: 承载 View 的 TouchDelegate 需求的参数包含一个 Rect,也便是对扩展的热区进行呼应。

问题: 这个矩阵是提早传入,且和 小 View 没有直接的关系。假如小 View 的布局产生变动,会导致扩展后热区没有及时跟上改变。导致热区错位。

处理计划: 在 小 View 的 onLayoutChange 中重新进行一遍 View 扩展计划 的处理。一起为了避免 onLayoutChange 履行过于频频,将 onLayoutChange 包装成 View 的一个事情。假如短时间内屡次 onLayoutChange ,则只在终究一次 onLayoutChange 的时分进行 「View扩展计划」处理。

  • 要点问题3:性能优化

布景 :开始的 View 扩展计划履行机遇是在创立 View 的一致入口,也便是在 LayoutInflate 的 onCreateView 中同步履行,每个 View 都得履行。

问题:由于 View 数量较为巨大,所以存在较大的性能危险。

处理计划:选用了异步计划并一起对 View 处理任务进行收拢。将履行机遇提早到 LayoutInflate.inflate 并异步处理,在异步任务中去遍历该 inflate 的根 View的一切子 View。尽量不去阻塞主线程的运行。

  • 要点问题4:读屏形式下的热区扩展

经过上面的完成,点击热区确实是扩展了。可是在读屏形式下选中的时分,选中的框并没有扩展。那么首要需求知道,选中时的框是以什么作为 Bound。

绿框的制作中心逻辑坐落 ViewRootImpl 中的一个 drawAccessibilityFocusedDrawableIfNeeded(),该办法的调用机遇是用户接触选中某个View后,传递到 ViewRootImpl 时进行调用,也便是读屏选中的绿框是由体系制作的,而不是由读屏软件制作的。从源码中能够得知的是,绿框的Bound 依据是否有虚拟节点,分为两种状况:

privatevoiddrawAccessibilityFocusedDrawableIfNeeded(Canvas canvas){
finalRect bounds = mAttachInfo.mTmpInvalRect;  
if(getAccessibilityFocusedRect(bounds)) {  
finalDrawable drawable = getAccessibilityFocusedDrawable();  
if(drawable !=null) {  
drawable.setBounds(bounds);  
drawable.draw(canvas);  
}  
}elseif(mAttachInfo.mAccessibilityFocusDrawable !=null) {  
mAttachInfo.mAccessibilityFocusDrawable.setBounds(0,0,0,0);  
}  
}  
privatebooleangetAccessibilityFocusedRect(Rect bounds){  
...  
finalAccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();  
if(provider ==null) {  
host.getBoundsOnScreen(bounds,true);  
}elseif(mAccessibilityFocusedVirtualView !=null) {  
mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);  
}else{  
returnfalse;  
}  
...  
return!bounds.isEmpty();  
}

经过盯梢源码发现,这是由于 「绿框的制作」 是依据 View.getBoundInScreen 获取的矩阵来做到的。而 TouchDelegate 的设置无法改变 View.getBoundInScreen 获取到的矩阵。在运用虚拟节点的状况下,才会运用虚拟节点的Bound进行制作。

对于这个问题,咱们的处理思路是:

  • 对每个 View 设置自界说的 AccessibilityDelegate, 并完成其间的 getAccessibilityNodeProvider 办法。

  • 假如判别 View 需求扩展,在 getAccessibilityNodeProvider 中回来自界说的 Provider。

  • 在自界说的 Provider 中,计算 View 的扩展后的矩阵在屏幕上的位置。

  • 将矩阵设置给虚拟节点,并回来给体系。

4.3 额定阐明

  • 怎么匹配规矩与View?

结构将装备池按 Activity 划分,极大削减抵触概率,一起削减装备池巨细,加速查找规矩的速度,供给 layoutId + viewId,rootId + viewId 两种形式的 View 定位机制。由两个 Id 确定一个 View,削减抵触。

  • 查找规矩时间长或许导致的主线程卡顿?

由于查找规矩的机遇是在生成节点,是由体系触发且无法异步。在查找规矩的过程中,运用预处理的时分提早生成的缓存进行查找,尽或许削减耗时。

05、走查东西

5.1 布景

当完成无障碍需求的开发后,需进行验证。在验证过程中发现敞开验证功率低下,需敞开读屏软件后,逐一元素验证。

5.1.1 处理计划与原理

依据无障碍服务(AccessibilityService)开发、集成了在不敞开 Talkback 的状况下能展现读屏区域一个无障碍功用走查东西,无需敞开 Talkback 逐一手动接触,就能高效检查无障碍适配状况。

藏在微信里的温度,无障碍开发框架分享

完成原理如下:

  • 自界说完成一个 AccessibilityService 用于获取到当时活跃窗口的根节点。

  • 每隔 0.5s 进行一次节点的获取:从当时活跃窗口的根节点遍历一切的节点,逐一进行判别是否会被集合。

  • 对经过答应集合的节点进行信息搜集,在一次遍历完成后告诉到 DrawService。

  • 提早在window中增加一个 View 用于制作信息,由 DrawService 进行制作。

5.2 详细完成

要害完成:怎么判别一个节点能否被集合,即需了解 Talkback 是怎么集合,流程如下:

1、假如是支撑 WebView 中 Html 无障碍,特殊判别。

2、假如不行见,则不集合。

3、判别是否是画中画,像下图的红框这种便是画中画,假如是画中画,这个便是焦点。

藏在微信里的温度,无障碍开发框架分享

4、该节点是否和 window 鸿沟重合等大。对于这种和 window 等大的节点,Talkback 挑选不做集合。

5、检查该节点是否 clickable/longClickable/focusable 或者是列表的“会说话的” 顶层视图(满意->6 不满意->7)列表(ListView/RecycleView)的顶层视图例子如下:

藏在微信里的温度,无障碍开发框架分享

可是集合的前提是“会说话的”。“会说话的”包含以下几个条件:

  • HasText:包含 contentDescription、text、hintText(包含 Button 的 Text)。

  • hasStateDescription:包含 CheckBox 的已选未选状况、进展条的进展状况等。

  • hasNonActionableSpeakingChildren:含有无法集合、点击可是 HasText 的子 View(如上图通讯录中的 “新的朋友” TextView,便是无法集合、点击可是 HasText 的子 View)。

6、基本上满意了过程5就可以视为可集合了,可是有一些View仅仅是 Focusable,可是却 ”什么话都没得说“ ,对于这种 View 应该是要排除的。故按如下过程做判别:只要是没有子节点的 focusable/clickable/longclickable 的 View,悉数集合 、“会说话的” 悉数集合 6.3 剩下的就不集合了(“不会说话”、“有子节点”)。

7、能到这一步,阐明过程 5 不满意,即该节点是一般的不行集合的 View。可是避免错过一些没有点击事情的 TextView 之类的需求集合,需求再终究做一步判别(这一步也是啥为了确保一切的信息都可以不遗漏);假如没有可集合父节点,但仍然 hasText 或 hasStateDescription,集合该节点。

8、一路闯关到这的 View,就总算逃离 TalkBack 的集合了。

06、总结

为了协助老年人、视障/听障人群等更好地运用微信 App,Android微信完成了适老化及无障碍改造如上。本文首要介绍 Android 微信开发团队依据适老化及无障碍需求,完成的一个协助业务侧进行无障碍功用开发的结构。咱们在介绍了无障碍开发所涉及的2大要点基础知识(读屏辨认View原理和读屏软件后的事情分发原理)之后,为各位展开回顾了咱们结构详细细节和办法。

以上是本次共享悉数内容,欢迎我们在谈论区共享沟通。假如觉得内容有用,欢迎转发~

-End-

原创作者|许怀鑫

技能责编|许怀鑫

藏在微信里的温度,无障碍开发框架分享

现我国现有4471w视障/听障人士,60岁及以上人群达到2.6亿规划。信息无障碍(Web Accessibility)的概念在近几年遭到重视。 信息无障碍是指经过信息化手法弥补身体机能、所在环境等存在的差异,使任何人(无论是健全人仍是残疾人、无论是年轻人仍是老年人)都能相等、便利、安全地获取、交互、运用信息。微信、QQ、腾讯新闻和腾讯地图等运用加适老化元素,配备为老人而设的“关怀形式”;搜狗输入法推出为视障集体量身打造的“保益盲人输入法”……

当说到无障碍,我们第一反应是弱势集体。实际上,无障碍是适用于全民的。每个人都或许有遇障时间。当你手提重物或受伤时,你或许会挑选乘坐无障碍电梯;当你处在喧闹的环境下看视频时,你或许需求经过字幕获取信息……每个人都是无障碍环境的受益者,视障、听障人群、含残疾人、老年人是信息无障碍的要点受益集体。

事情共享:你还见到过哪些让你眼前一亮的信息无障碍案例?

脑洞时间:程序员还可认为信息无障碍做些什么?

欢迎在公众号谈论区聊一聊你的看法。在4月10日前将你的谈论记录截图,发送给腾讯云开发者公众号后台,可收取腾讯云「开发者春季限制红包封面」一个,数量有限先到先得。咱们还将选取点赞量最高的1位朋友,送出腾讯QQ公仔1个。4月10日中午12点开奖。快约请你的开发者朋友们一起来参与吧!

回复「微信」,收取更多微信的技能case和论文资源

藏在微信里的温度,无障碍开发框架分享

阅读原文