盛世宏图 发表于 2024-9-9 08:29:25

鸿蒙Harmony实战:Accessibility Kit应用开发

 前言:

 “Accessibility”译作“信息无障碍”,是指任何人在任何环境下都能平等、方便地获取信息并使用信息。其目标是缩小全社会不同阶层、不同地区、不同年龄、不同健康状况的人群在信息理解、信息交互、信息使用方面的数字鸿沟,使其更加方便地参与社会生活,享受数字发展带来的便利。
Accessibility Kit(无障碍开发服务)提供扩展服务的开放能力,三方可基于此开放能力开发出类似读屏软件的扩展服务,同时也为三方应用提供开放能力,使三方应用可以更好的适配扩展服务,以更好的服务于障碍人群和障碍场景。例如使用读屏软件,用户可以“闻声”当前屏幕内容。
能力范围

1、为三方应用提供获取扩展服务列表、扩展服务启用状态、发送无障碍事故等能力。
2、为扩展服务提供扩展服务框架,允许三方开发类似读屏软件的扩展服务。
框架原理

无障碍扩展服务框架提供在三方应用和和扩展服务之间交换信息的尺度机制。扩展服务通过AAkit向AAMS发出查询或操作哀求,AAMS通过ASACkit向三方应用执行查询或操作哀求,并将执行效果返回给扩展服务。

https://img-blog.csdnimg.cn/img_convert/3ed2b68135c056ef04bd7bfed14ea834.png

[*]Accessibility App:基于无障碍扩展服务框架开发的扩展服务,如视障用户使用的读屏App。
[*]Tartget App:被Accessibility App辅助的三方应用。
[*]AccessibilityAbilityManagerService(AAMS):无障碍扩展服务框架主服务,用于对Accessibility App生命周期举行管理,同时为Accessibility App和Target App提供信息交互的桥梁。
[*]AccessibilityAbility(AAkit):Accessibility App使用AAkit构建扩展服务Ability运行环境,并为Accessibility App提供可查询和操作Target App的接口,如查询节点信息、对节点执行点击/长按操作等。
[*]AccessibilitySystemAbilityClient(ASACkit):Target App通过ASACkit向AAMS发送无障碍事故,如内容变革事故等,同时响应Accessibility App通过AAMS哀求的指令,如查询节点信息、对节点执行点击/长按操作等。
AccessibilityExtensionAbility

Accessibility Kit(无障碍开发服务)通过基于ExtensionAbility框架的AccessibilityExtensionAbility提供无障碍扩展服务,开发者可以基于AccessibilityExtensionAbility模板开发本身的扩展服务,帮助用户完成一些快捷的交互过程。
怎样创建一个无障碍扩展服务

开发者在创建一个无障碍扩展服务时,如工程满足环境要求,开发者可自主选择是否跳过创建工程步骤,在已有工程中新增无障碍扩展服务。一个工程仅支持创建一个无障碍扩展服务。
本指南以实现以下功能为案例,报告怎样创建无障碍扩展服务,怎样调用API接口实现该功能:
启动辅助功能后,在装备屏幕上绘画“右划后再下划”(rightThenDown)的手势,获取当前界面的全部节点;之后再绘画“左划后再下划”(leftThenDown)的手势,打印所有节点。
创建工程

如需新增独立的无障碍扩展服务应用,在DevEco Studio中新建一个API 9以上的Stage工程。
新建无障碍扩展服务ets文件

在已创建工程的ets文件夹下创建AccessibilityExtAbility文件夹,在该文件夹下创建AccessibilityExtAbility.ets文件,可在该文件中实现一些回调函数,并到场业务处理处罚逻辑的调用:
import AccessibilityExtensionAbility, { AccessibilityEvent } from '@ohos.application.AccessibilityExtensionAbility';
import AccessibilityManager from './AccessibilityManager';

class AccessibilityExtAbility extends AccessibilityExtensionAbility {
    onConnect() {
      console.info(`AccessibilityExtAbility onConnect`);
      // 执行初始化业务逻辑的操作
      AccessibilityManager.getInstance().onStart(this.context);
    }

    onDisconnect() {
      console.info(`AccessibilityExtAbility onDisconnect`);
      // 执行资源回收退出业务逻辑的操作
      AccessibilityManager.getInstance().onStop();
    }

    onAccessibilityEvent(accessibilityEvent: AccessibilityEvent) {
      console.info(`AccessibilityExtAbility onAccessibilityEvent: ${JSON.stringify(accessibilityEvent)}`);
      // 根据事件信息进行业务逻辑处理
      AccessibilityManager.getInstance().onEvent(accessibilityEvent);
    }
}

export default AccessibilityExtAbility; 其中,主要定义了以下接口:
接口描述onConnect(): void当扩展服务连接时回调。onDisconnect(): void当扩展服务断开时回调。onAccessibilityEvent(event: AccessibilityEvent): void当无障碍事故发生时回调。 创建AccessibilityManager.ets文件,用于存放业务逻辑代码:
import {
AccessibilityElement,
AccessibilityEvent,
AccessibilityExtensionContext,
ElementAttributeKeys
} from '@ohos.application.AccessibilityExtensionAbility';

interface Rect {
left: number,
top: number,
width: number,
height: number,
}

// 想要查询的属性信息
let wantedAttribute: ElementAttributeKeys[] = ['bundleName', 'text', 'description', 'windowId'];
type attributeValues = string | number | boolean | AccessibilityElement | AccessibilityElement[] | string[] | Rect;

export default class AccessibilityManager {
private static instance: AccessibilityManager;
accessibleContext?: AccessibilityExtensionContext;
currentPageElementArray: Array<AccessibilityElement> | null = null;

static getInstance(): AccessibilityManager {
    if (!AccessibilityManager.instance) {
      AccessibilityManager.instance = new AccessibilityManager();
    }
    return AccessibilityManager.instance;
}

onStart(context: AccessibilityExtensionContext) {
    console.info(`AccessibilityManager onStart`);
    this.accessibleContext = context;
}

onStop() {
    console.info(`AccessibilityManager onStop`);
    this.accessibleContext = undefined;
}

onEvent(accessibilityEvent: AccessibilityEvent): void {
    console.info(`AccessibilityManager onEvent`);
    switch (accessibilityEvent.eventType) {
      case 'rightThenDown':
      // 获取当前页面的所有节点
      this.getCurrentPageAllElement();
      break;
      case 'leftThenDown':
      // 打印所有节点
      this.printAllElementInfo();
      break;
      default:
      break;
    }
}

async getCurrentPageAllElement(): Promise<void> {
    console.info(`AccessibilityManager getCurrentPageAllElement`);
    let rootElement: AccessibilityElement;
    if(!this.accessibleContext){
      console.error(`AccessibilityManager accessibleContext undefined`);
      return;
    }
    try {
      rootElement = await this.accessibleContext?.getWindowRootElement();
      this.currentPageElementArray = await this.getAttributeValue(rootElement, 'children') as AccessibilityElement[];
    } catch (error) {
      console.error(`AccessibilityExtAbility Failed to getWindowRootElement. Cause:${JSON.stringify(error)}`);
    }
}

async getElementWantedInfo(accessibilityElement: AccessibilityElement, wantedAttribute: ElementAttributeKeys[]):
    Promise<string | null> {
    console.info(`AccessibilityUtils getElementAllInfo`);
    if (accessibilityElement === null) {
      console.error(`AccessibilityUtils accessibilityElement is null`);
      return null;
    }

    let info = '';
    let value: attributeValues | null;
    for (let name of wantedAttribute) {
      value = await this.getAttributeValue(accessibilityElement, name);
      info = info.concat(name + ': ' + value + ' ');
    }
    return info;
}

async getAttributeValue(accessibilityElement: AccessibilityElement, key: ElementAttributeKeys):
    Promise<attributeValues | null> {
    console.info(`AccessibilityUtils getAttributeValue`);
    let value: attributeValues;
    let keys = await accessibilityElement.attributeNames();
    let isExit = false;
    for (let keyString of keys) {
      if (key == keyString) {
      isExit = true;
      }
    }
    if (isExit) {
      try {
      value = await accessibilityElement.attributeValue(key);
      return value;
      } catch (error) {
      console.error(`AccessibilityUtils Failed to get attributeValue of ${key} . Cause:${JSON.stringify(error)}`);
      }
    }
    return null;
}

async printAllElementInfo(): Promise<void> {
    console.info(`AccessibilityManager printAllElementInfo`);
    if (this.currentPageElementArray === null || this.currentPageElementArray.length === 0) {
      console.error(`AccessibilityManager currentPageElementArray is null`);
      return;
    }
    let info: string | null = null;
    for (let index = 0; index < this.currentPageElementArray.length; index++) {
      info = await this.getElementWantedInfo(this.currentPageElementArray, wantedAttribute);
      console.info(`AccessibilityManager element information: ${info}`);
    }
}
} 怎样处理处罚一个无障碍事故

干系无障碍事故可以在onAccessibilityEvent()方法中举行业务逻辑处理处罚,此处以手势事故rightThenDown为例:
onAccessibilityEvent(accessibilityEvent: AccessibilityEvent) {
    console.info('AccessibilityExtAbility onAccessibilityEvent: ' + JSON.stringify(accessibilityEvent));
    if (accessibilityEvent.eventType === 'rightThenDown') {
      console.info('AccessibilityExtAbility onAccessibilityEvent: rightThenDown');
      // TODO: 自定义相关逻辑开发
    }
} 在相应的无障碍事故中,可以使用辅助功能扩展上下文(AccessibilityExtensionContext)提供的接口举行扩睁开发,包括允许设置辅助应用关注信息类型、查询节点信息、手势注入等。
此外,还可在无障碍扩展服务中对物理按键事故举行处理处罚
怎样声明无障碍扩展服务具备的能力

在完成自定义无障碍扩展服务的逻辑开发后,还需要在工程中Module对应的module.json5文件中到场新增扩展服务的设置信息。
srcEntry标签为extensionAbility对应的路径。
label标签为extensionAbility在已安装扩展服务列表中显示的名称。
description标签为extensionAbility在已安装扩展服务详情页的帮助信息。
type标签要按照与无障碍子系统的约定举行设置,需要注意的是该值固定为accessibility,否则将无法正常连接。
"extensionAbilities": [
{
    "name": "AccessibilityExtAbility",
    "srcEntry": "./ets/AccessibilityExtAbility/AccessibilityExtAbility.ets",
    "label": "$string:MainAbility_label",
    "description": "$string:MainAbility_desc",
    "type": "accessibility",
    "metadata": [
      {
      "name": "ohos.accessibleability",
      "resource": "$profile:accessibility_config"
      }
    ]
}
] 别的,设置信息中的accessibility_config为无障碍扩展服务的具体设置,需要在resources/base/profile/下新建accessibility_config.json文件,在该文件中声明此无障碍扩展服务具备的能力类型,根据业务功能公道声明能力类型,本案例中,需要如下声明:
{
"accessibilityCapabilities": [
    "retrieve",
    "gesture",
    "touchGuide"
]
} 怎样开启自定义的无障碍扩展服务

当条件供装备-设置中的扩展服务管理页的开关按钮来开启/关闭选择的无障碍扩展服务:
1、打开装备设置页面,进入“辅助功能”,“扩展服务”小标题下的“已安装的服务”显示当前安装的扩展服务个数,点击进入,展示安装的扩展服务列表;未安装扩展服务时,“已安装的扩展服务”不可点击,并显示“无服务”。
2、选择需要开启/关闭的扩展服务,通过开关按钮举行扩展服务的开启/关闭。
3、开启时,弹出安全提醒,在倒计时结束后,勾选“我已知晓如上风险,并志愿承担大概导致的后果。”后,可选择“开启”/“不开启”按钮; 关闭时,将开启的开关关闭,即可关闭已开启的扩展服务。
最后

小编在之前的鸿蒙系统扫盲中,有许多朋侪给我留言,不同的角度的问了一些问题,我显着感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里动手,因为资料太多,太杂,传授的人也多,无从选择。有许多小同伴不知道学习哪些鸿蒙开发技能?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习黑白常有须要的。 
为了确保高效学习,建议规划清晰的学习路线,涵盖以下关键阶段:


 鸿蒙(HarmonyOS NEXT)最新学习路线
https://img-blog.csdnimg.cn/direct/9e1bd404e54e495db25a2e65f9b1baf3.png​
该路线图包罗基础技能、就业必备技能、多媒体技能、六大电商APP、进阶高级技能、实战就业级装备开发,不但补充了华为官网未涉及的办理方案
路线图适合人群:
IT开发人员:想要拓展职业界限
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技能提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技能
2.视频学习资料+学习PDF文档
这份鸿蒙(HarmonyOS NEXT)资料包罗了鸿蒙开发必掌握的核心知识要点,内容包罗了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技能、Napi组件、OpenHarmony内核、(南向驱动、嵌入式等)鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技能知识点。
HarmonyOS Next 最新全套视频教程
https://img-blog.csdnimg.cn/direct/058c674163cf4c8c9e46e6a44f0fc9e6.png
  纯血版鸿蒙全套学习资料(口试、文档、全套视频等)              
https://img-blog.csdnimg.cn/direct/21bf9d9da77840fc9748768d594d232f.png​​
总结
参与鸿蒙开发,你要先认清适合你的方向,假如是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线
https://i-blog.csdnimg.cn/direct/b9faa7874e1a4e1e8ca9a6f365464f17.jpeg



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 鸿蒙Harmony实战:Accessibility Kit应用开发