많은 Android 사용자는 다양한 방식으로 휴대폰과 상호작용하게 되는 다양한 상황에 처해 있습니다. 시각, 청각 또는 기타 신체적 이유로 인해 Android 스마트폰을 사용할 수 없는 사용자를 위해 Android는 이러한 사용자가 기기를 보다 쉽게 조작할 수 있도록 문자 음성 변환, 촉각 피드백, 제스처 조작, 트랙볼 등의 접근성 기능과 서비스를 제공합니다. 및 핸들 작업. 개발자는 사운드 프롬프트, 물리적 피드백, 기타 선택적 작동 모드 등 애플리케이션의 유용성을 향상시킬 수 있는 자체 접근성 서비스를 구축할 수 있습니다.
구체적인 구현은 AccessibilityService 서비스를 통해 백그라운드에서 실행되고 AccessibilityEvent를 통해 지정된 이벤트에 대한 콜백을 수신하는 것입니다. 이러한 이벤트는 인터페이스에서 사용자에 의한 일부 상태 전환(예: 포커스 변경, 버튼 클릭 등)을 나타냅니다. 이러한 서비스에는 선택적으로 활성 창의 내용을 요청하는 기능이 있을 수 있습니다. 간단히 말해, AccessibilityService는 모니터링하는 콘텐츠가 변경되면 백그라운드 서비스의 콜백 메서드가 호출되는 백그라운드 모니터링 서비스입니다.
자체 서비스 클래스를 작성하고 onServiceConnected() 메서드, onAccessibilityEvent() 메서드 및 onInterrupt() 메서드를 재정의합니다.
public class QHBAccessibilityService extends AccessibilityService {
/**
* 当启动服务的时候就会被调用
*/
@ Override
protected void onServiceConnected () {
super . onServiceConnected ();
}
/**
* 监听窗口变化的回调
*/
@ Override
public void onAccessibilityEvent ( AccessibilityEvent event ) {
int eventType = event . getEventType ();
//根据事件回调类型进行处理
}
/**
* 中断服务的回调
*/
@ Override
public void onInterrupt () {
}
}
다음은 AccessibilityService에서 일반적으로 사용되는 메소드를 소개합니다.
백그라운드 서비스이므로 매니페스트에서 서비스 정보를 구성해야 합니다.
< service
android : name = " .AccessibilityService.QHBAccessibilityService "
android : enabled = " true "
android : exported = " true "
android : label = " @string/label "
android : permission = " android.permission.BIND_ACCESSIBILITY_SERVICE " >
< intent-filter >
< action android : name = " android.accessibilityservice.AccessibilityService " />
</ intent-filter >
</ service >
주의해야 할 점: 정보 구성 오류로 인해 서비스가 응답하지 않게 됩니다.
서비스 매개변수 구성이란 지정된 유형의 이벤트 승인, 지정된 패키지 수신, 창 콘텐츠 검색, 이벤트 유형의 시간 가져오기 등을 구성하는 것을 의미합니다. 서비스 매개변수를 구성하는 방법에는 두 가지가 있습니다.
xml 파일을 지정하려면 원본 매니페스트에 메타데이터 태그를 추가하세요.
< service
android : name = " .AccessibilityService.QHBAccessibilityService "
android : enabled = " true "
android : exported = " true "
android : label = " @string/label "
android : permission = " android.permission.BIND_ACCESSIBILITY_SERVICE " >
< intent-filter >
< action android : name = " android.accessibilityservice.AccessibilityService " />
</ intent-filter >
< meta-data
android : name = " android.accessibilityservice "
android : resource = " @xml/accessibility_service_config " />
</ service >
다음은accessibility_service_config 파일의 구성입니다.
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< accessibility-service xmlns : android = " http://schemas.android.com/apk/res/android "
android : accessibilityEventTypes = " typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged|typeWindowsChanged "
android : accessibilityFeedbackType = " feedbackGeneric "
android : accessibilityFlags = " flagDefault "
android : canRetrieveWindowContent = " true "
android : description = " @string/description "
android : notificationTimeout = " 100 "
android : packageNames = " com.tencent.mm " />
다음은 xml 매개변수에 대한 소개입니다.
accessibilityEventTypes: 서비스가 관심을 갖는 인터페이스의 변경 사항, 즉 창 열기, 슬라이딩, 포커스 변경, 길게 누르기 등 어떤 이벤트가 알림을 받는지 나타냅니다. 구체적인 값은 AccessibilityEvent 클래스에서 찾을 수 있습니다. 예를 들어 typeAllMask는 모든 이벤트 알림을 수락한다는 의미입니다.
접근성FeedbackType: 음성 재생, 진동 등 피드백 방식을 나타냅니다.
canRetrieveWindowContent: 서비스가 활성 창의 콘텐츠에 액세스할 수 있는지 여부를 나타냅니다. 즉, 서비스에서 양식 콘텐츠를 가져오려면 해당 값을 true로 설정해야 합니다.
설명: 아래 그림과 같이 접근성 기능에 대한 설명입니다.
notificationTimeout: 이벤트를 수락하는 시간 간격, 일반적으로 100으로 설정됩니다.
packageNames: 서비스가 이벤트를 모니터링하는 데 사용되는 패키지를 나타냅니다. 여기서는 WeChat의 패키지 이름을 예로 들어 보겠습니다.
코드를 통해 AccessibilityService에 대한 AccessibilityServiceInfo 정보를 구성합니다. 여기서는 설정을 위한 메서드로 추출할 수 있습니다.
private void settingAccessibilityInfo () {
String [] packageNames = { "com.tencent.mm" };
AccessibilityServiceInfo mAccessibilityServiceInfo = new AccessibilityServiceInfo ();
// 响应事件的类型,这里是全部的响应事件(长按,单击,滑动等)
mAccessibilityServiceInfo . eventTypes = AccessibilityEvent . TYPES_ALL_MASK ;
// 反馈给用户的类型,这里是语音提示
mAccessibilityServiceInfo . feedbackType = AccessibilityServiceInfo . FEEDBACK_SPOKEN ;
// 过滤的包名
mAccessibilityServiceInfo . packageNames = packageNames ;
setServiceInfo ( mAccessibilityServiceInfo );
}
여기에는 AccessibilityServiceInfo 클래스가 포함됩니다. AccessibilityServiceInfo 클래스는 구성 및 xml 속성에 대한 많은 상수 필드를 포함합니다.
여기서는 접근성 기능에서 이 기능을 수동으로 켜야 합니다. 그렇지 않으면 다음 코드를 통해 시스템의 접근성 기능 목록을 열 수 있습니다.
Intent intent = new Intent ( Settings . ACTION_ACCESSIBILITY_SETTINGS );
startActivity ( intent );
이벤트의 알림바와 인터페이스를 모니터링하므로 지정된 packageNames의 알림바나 인터페이스가 변경되면 onAccessibilityEvent를 통해 이벤트가 다시 호출된 후 이벤트가 처리됩니다.
@ Override
public void onAccessibilityEvent ( AccessibilityEvent event ) {
int eventType = event . getEventType ();
//根据事件回调类型进行处理
switch ( eventType ) {
//当通知栏发生改变时
case AccessibilityEvent . TYPE_NOTIFICATION_STATE_CHANGED :
break ;
//当窗口的状态发生改变时
case AccessibilityEvent . TYPE_WINDOW_STATE_CHANGED :
break ;
}
}
WeChat에서 알림을 받으면 상태 표시줄에 푸시 메시지가 도착하며, 이번에는 TYPE_NOTIFICATION_STATE_CHANGED에 의해 모니터링되며 내부 내용이 실행됩니다. TYPE_WINDOW_STATE_CHANGED에 의해 모니터링됩니다.
접근성이벤트 메서드
인터페이스 창 변경 사항을 얻은 후에는 이때 제어 노드를 얻어야 합니다. 전체 창의 노드는 기본적으로 트리 구조로 되어 있으며, 노드 정보는 다음과 같이 동작합니다.
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow ();
//通过文本找到对应的节点集合
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByText ( text );
//通过控件ID找到对应的节点集合,如com.tencent.mm:id/gd
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByViewId ( clickId );
노드 정보를 얻은 후에는 제어 노드에서 시뮬레이션된 클릭, 길게 누르기 및 기타 작업을 수행할 수 있습니다. AccessibilityNodeInfo 클래스는 시뮬레이션된 작업을 수행할 수 있도록 PerformAction() 메서드를 제공합니다. 공식 문서를 참조하세요. . 일반적으로 사용되는 작업은 여기에 나열되어 있습니다.
//模拟点击
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_CLICK );
//模拟长按
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_LONG_CLICK );
//模拟获取焦点
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_FOCUS );
//模拟粘贴
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_PASTE );
휴대폰이 USB 케이블에 연결되면 Android Device Monitor에서 장치를 선택하고 UI Automator 도구용 Dump View Hierarchy를 엽니다. 이를 통해 제어 정보를 얻을 수 있습니다.
Q:
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
는 항상 null 포인터를 보고합니다. A: 나는 또한 당신과 같은 문제가 발생했다고 생각합니다. 방금 코드에서 구성을 시작했는데 이 android:canRetrieveWindowContent="true를 작성하지 않은 것 같습니다. "라고 했는데 그렇지 않더군요. android:canRetrieveWindowContent="true"에 해당하는 설정을 찾아서 xml로 구성하도록 변경했더니 괜찮더군요.
Q: 이러한 클래스 이름 com.tencent.mm.ui.LauncherUI를 어떻게 얻나요? A: String className = event.getClassName().toString(); Log를 사용하여 인쇄하고 WeChat을 열어 로그 정보를 확인하세요.
원문: Hensen_님의 블로그