1# AccessibilityExtensionAbility 2 3Accessibility Kit(无障碍开发服务)通过基于ExtensionAbility框架的AccessibilityExtensionAbility提供无障碍扩展服务,开发者可以基于AccessibilityExtensionAbility模板开发自己的扩展服务,协助用户完成一些快捷的交互过程。 4 5## 如何创建一个无障碍扩展服务 6 7开发者在创建一个无障碍扩展服务时,如工程满足环境要求,开发者可自主选择是否跳过创建工程步骤,在已有工程中新增无障碍扩展服务。一个工程仅支持创建一个无障碍扩展服务。 8本指南以实现以下功能为案例,讲述如何创建无障碍扩展服务,如何调用API接口实现该功能: 9启动辅助功能后,在设备屏幕上绘画“右划后再下划”(rightThenDown)的手势,获取当前界面的全部节点;之后再绘画“左划后再下划”(leftThenDown)的手势,打印所有节点。 10 11### 创建工程 12 13如需新增独立的无障碍扩展服务应用,在DevEco Studio中新建一个API 9以上的Stage工程。 14 15### 新建无障碍扩展服务ets文件 16 17在已创建工程的ets文件夹下创建AccessibilityExtAbility文件夹,在该文件夹下创建AccessibilityExtAbility.ets文件,可在该文件中实现一些回调函数,并加入业务处理逻辑的调用: 18 19```ts 20import { AccessibilityExtensionAbility, AccessibilityEvent } from '@kit.AccessibilityKit'; 21import AccessibilityManager from './AccessibilityManager'; 22 23class AccessibilityExtAbility extends AccessibilityExtensionAbility { 24 onConnect() { 25 console.info(`AccessibilityExtAbility onConnect`); 26 // 执行初始化业务逻辑的操作 27 AccessibilityManager.getInstance().onStart(this.context); 28 } 29 30 onDisconnect() { 31 console.info(`AccessibilityExtAbility onDisconnect`); 32 // 执行资源回收退出业务逻辑的操作 33 AccessibilityManager.getInstance().onStop(); 34 } 35 36 onAccessibilityEvent(accessibilityEvent: AccessibilityEvent) { 37 console.info(`AccessibilityExtAbility onAccessibilityEvent: ${JSON.stringify(accessibilityEvent)}`); 38 // 根据事件信息进行业务逻辑处理 39 AccessibilityManager.getInstance().onEvent(accessibilityEvent); 40 } 41} 42 43export default AccessibilityExtAbility; 44``` 45 46其中,主要定义了以下接口: 47 48| 接口 | 描述 | 49| ---- | ---- | 50| onConnect(): void | 当扩展服务连接时回调。 | 51| onDisconnect(): void | 当扩展服务断开时回调。 | 52| onAccessibilityEvent(event: AccessibilityEvent): void | 当无障碍事件发生时回调。 | 53 54创建AccessibilityManager.ets文件,用于存放业务逻辑代码: 55```ts 56import { 57 AccessibilityElement, 58 AccessibilityEvent, 59 AccessibilityExtensionContext, 60 ElementAttributeKeys 61} from '@kit.AccessibilityKit'; 62 63interface Rect { 64 left: number, 65 top: number, 66 width: number, 67 height: number, 68} 69 70// 想要查询的属性信息 71let wantedAttribute: ElementAttributeKeys[] = ['bundleName', 'text', 'description', 'windowId']; 72type attributeValues = string | number | boolean | AccessibilityElement | AccessibilityElement[] | string[] | Rect; 73 74export default class AccessibilityManager { 75 private static instance: AccessibilityManager; 76 accessibleContext?: AccessibilityExtensionContext; 77 currentPageElementArray: Array<AccessibilityElement> | null = null; 78 79 static getInstance(): AccessibilityManager { 80 if (!AccessibilityManager.instance) { 81 AccessibilityManager.instance = new AccessibilityManager(); 82 } 83 return AccessibilityManager.instance; 84 } 85 86 onStart(context: AccessibilityExtensionContext) { 87 console.info(`AccessibilityManager onStart`); 88 this.accessibleContext = context; 89 } 90 91 onStop() { 92 console.info(`AccessibilityManager onStop`); 93 this.accessibleContext = undefined; 94 } 95 96 onEvent(accessibilityEvent: AccessibilityEvent): void { 97 console.info(`AccessibilityManager onEvent`); 98 switch (accessibilityEvent.eventType) { 99 case 'rightThenDown': 100 // 获取当前页面的所有节点 101 this.getCurrentPageAllElement(); 102 break; 103 case 'leftThenDown': 104 // 打印所有节点 105 this.printAllElementInfo(); 106 break; 107 default: 108 break; 109 } 110 } 111 112 async getCurrentPageAllElement(): Promise<void> { 113 console.info(`AccessibilityManager getCurrentPageAllElement`); 114 let rootElement: AccessibilityElement; 115 if(!this.accessibleContext){ 116 console.error(`AccessibilityManager accessibleContext undefined`); 117 return; 118 } 119 try { 120 rootElement = await this.accessibleContext?.getWindowRootElement(); 121 this.currentPageElementArray = await this.getAttributeValue(rootElement, 'children') as AccessibilityElement[]; 122 } catch (error) { 123 console.error(`AccessibilityExtAbility Failed to getWindowRootElement. Cause:${JSON.stringify(error)}`); 124 } 125 } 126 127 async getElementWantedInfo(accessibilityElement: AccessibilityElement, wantedAttribute: ElementAttributeKeys[]): 128 Promise<string | null> { 129 console.info(`AccessibilityUtils getElementAllInfo`); 130 if (accessibilityElement === null) { 131 console.error(`AccessibilityUtils accessibilityElement is null`); 132 return null; 133 } 134 135 let info = ''; 136 let value: attributeValues | null; 137 for (let name of wantedAttribute) { 138 value = await this.getAttributeValue(accessibilityElement, name); 139 info = info.concat(name + ': ' + value + ' '); 140 } 141 return info; 142 } 143 144 async getAttributeValue(accessibilityElement: AccessibilityElement, key: ElementAttributeKeys): 145 Promise<attributeValues | null> { 146 console.info(`AccessibilityUtils getAttributeValue`); 147 let value: attributeValues; 148 let keys = await accessibilityElement.attributeNames(); 149 let isExit = false; 150 for (let keyString of keys) { 151 if (key == keyString) { 152 isExit = true; 153 } 154 } 155 if (isExit) { 156 try { 157 value = await accessibilityElement.attributeValue(key); 158 return value; 159 } catch (error) { 160 console.error(`AccessibilityUtils Failed to get attributeValue of ${key} . Cause: ${JSON.stringify(error)}`); 161 } 162 } 163 return null; 164 } 165 166 async printAllElementInfo(): Promise<void> { 167 console.info(`AccessibilityManager printAllElementInfo`); 168 if (this.currentPageElementArray === null || this.currentPageElementArray.length === 0) { 169 console.error(`AccessibilityManager currentPageElementArray is null`); 170 return; 171 } 172 let info: string | null = null; 173 for (let index = 0; index < this.currentPageElementArray.length; index++) { 174 info = await this.getElementWantedInfo(this.currentPageElementArray[index], wantedAttribute); 175 console.info(`AccessibilityManager element information: ${info}`); 176 } 177 } 178} 179``` 180 181## 如何处理一个无障碍事件 182 183相关无障碍事件可以在`onAccessibilityEvent()`方法中进行业务逻辑处理,具体事件可参考[AccessibilityEvent](../reference/apis-accessibility-kit/js-apis-application-accessibilityExtensionAbility.md#accessibilityevent)。此处以手势事件`rightThenDown`为例: 184 185```ts 186onAccessibilityEvent(accessibilityEvent: AccessibilityEvent) { 187 console.info('AccessibilityExtAbility onAccessibilityEvent: ' + JSON.stringify(accessibilityEvent)); 188 if (accessibilityEvent.eventType === 'rightThenDown') { 189 console.info('AccessibilityExtAbility onAccessibilityEvent: rightThenDown'); 190 // TODO: 自定义相关逻辑开发 191 } 192} 193``` 194在相应的无障碍事件中,可以使用[辅助功能扩展上下文(AccessibilityExtensionContext)](../reference/apis-accessibility-kit/js-apis-inner-application-accessibilityExtensionContext.md)提供的接口进行扩展开发,包括允许配置辅助应用关注信息类型、查询节点信息、手势注入等。 195 196此外,还可在无障碍扩展服务中对物理按键事件进行处理,具体可参考[onKeyEvent](../reference/apis-accessibility-kit/js-apis-application-accessibilityExtensionAbility.md#accessibilityextensionabilityonkeyevent)。 197 198## 如何声明无障碍扩展服务具备的能力 199 200在完成自定义无障碍扩展服务的逻辑开发后,还需要在工程中Module对应的module.json5文件中加入新增扩展服务的配置信息。 201 202`srcEntry`标签为`extensionAbility`对应的路径。 203`label`标签为`extensionAbility`在已安装扩展服务列表中显示的名称。 204`description`标签为`extensionAbility`在已安装扩展服务详情页的帮助信息。 205`type`标签要按照与无障碍子系统的约定进行配置,需要注意的是该值固定为`accessibility`,否则将无法正常连接。 206 207```json 208"extensionAbilities": [ 209 { 210 "name": "AccessibilityExtAbility", 211 "srcEntry": "./ets/AccessibilityExtAbility/AccessibilityExtAbility.ets", 212 "label": "$string:MainAbility_label", 213 "description": "$string:MainAbility_desc", 214 "type": "accessibility", 215 "metadata": [ 216 { 217 "name": "ohos.accessibleability", 218 "resource": "$profile:accessibility_config" 219 } 220 ] 221 } 222] 223``` 224另外,配置信息中的`accessibility_config`为无障碍扩展服务的具体配置,需要在`resources/base/profile/`下新建`accessibility_config.json`文件,在该文件中声明此无障碍扩展服务具备的[能力类型](../reference/apis-accessibility-kit/js-apis-accessibility.md#capability),根据业务功能合理声明能力类型,本案例中,需要如下声明: 225```json 226{ 227 "accessibilityCapabilities": [ 228 "retrieve", 229 "gesture", 230 "touchGuide" 231 ] 232} 233``` 234## 如何开启自定义的无障碍扩展服务 235 236当前提供设备-设置中的扩展服务管理页的开关按钮来开启/关闭选择的无障碍扩展服务: 237 2381、打开设备设置页面,进入“辅助功能”,“扩展服务”小标题下的“已安装的服务”显示当前安装的扩展服务个数,点击进入,展示安装的扩展服务列表;未安装扩展服务时,“已安装的扩展服务”不可点击,并显示“无服务”。 239 2402、选择需要开启/关闭的扩展服务,通过开关按钮进行扩展服务的开启/关闭。 241 2423、开启时,弹出安全提醒,在倒计时结束后,勾选“我已知晓如上风险,并自愿承担可能导致的后果。”后,可选择“开启”/“不开启”按钮; 关闭时,将开启的开关关闭,即可关闭已开启的扩展服务。 243 244## 相关实例 245 246针对AccessibilityExtensionAbility开发,有以下相关实例可供参考: 247 248- [AccessibilityExtensionAbility示例](https://gitee.com/openharmony/applications_app_samples/tree/master/code/SystemFeature/ApplicationModels/AccessibilityExtAbility) 249