Android AccessibilityService

Victor·2026년 2월 2일

1. AccessibilityService 개요

AccessibilityService는 기본적으로 장애가 있는 사용자가 안드로이드 기기 및 앱을 사용하는 것을 돕기 위해 설계되었습니다. 이 서비스는 백그라운드에서 실행되며, 사용자 인터페이스의 상태 변화가 발생할 때 Android Framework의 시스템 프로세스인 system_server로부터 콜백을 전달받습니다. 이때 AccessibilityEvent가 발생하며 시스템과 통신하게 됩니다.

2. 생명주기

접근성 서비스의 생명주기는 시스템에 의해 독점적으로 관리되며 표준 서비스 생명주기를 따릅니다.

  • 시작 : 사용자가 설정에서 서비스를 명시적으로 켰을 때, 즉 사용자에 의해서만 트리거됩니다. 이후 시스템이 서비스에 바인딩되면 onServiceConnected()가 호출됩니다.

  • 종료 : 사용자가 설정에서 직접 서비스를 끄거나, 서비스 내부에서 AccessibilityService.disableSelf()를 호출할 때 종료됩니다.

  • 보안 : AndroidManifest.xml 선언 시 BIND_ACCESSIBILITY_SERVICE 권한을 요청해야 합니다. 이는 오직 시스템만이 해당 서비스에 바인딩할 수 있도록 보장하기 위함입니다.

3. 선언

AccessibilityService를 사용하기 위해서는 AndroidManifest.xml에 다른 서비스처럼 등록해야 하지만, 반드시 다음 두 가지 사항을 준수해야 합니다.

  1. 서비스는 android.content.Intent를 처리할 수 있도록 선언되어야 하며, 이를 위해 intent-filter 설정이 필요합니다.
  2. BIND_ACCESSIBILITY_SERVICE 권한을 반드시 요청해야 합니다. 이 권한은 Android Framework의 시스템 프로세스인 system_server만이 해당 서비스에 바인딩할 수 있도록 보장하며, 만약 이 설정이 누락되면 시스템은 해당 접근성 서비스를 무시합니다.

4. 설정

서비스가 시스템에 어떻게, 그리고 언제 실행될지 알려주기 위해 다음과 같은 구성 변수들을 고려해야 합니다.

  • 이벤트 응답 : 서비스가 어떠한 이벤트 유형에 응답하고 반응할 것인지 결정해야 합니다.

  • 활성화 범위 : 서비스가 모든 앱에 대해 활성화되어야 하는지, 혹은 특정 패키지 명칭을 가진 앱에서만 동작해야 하는지 설정합니다.

  • 피드백 방식 : 서비스가 사용자에게 제공할 서로 다른 피드백 유형(음성, 진동 등)이 무엇인지 지정합니다.

서비스가 특정 유형의 접근성 이벤트를 수신하도록 설정하는 데는 두 가지 방법이 있습니다.

1. 정적 방법

먼저 XML 파일을 사용하여 서비스를 구성하는 것입니다. canRetrieveWindowContent와 같은 특정 구성 옵션은 XML을 사용하여 서비스를 구성하는 경우에만 사용할 수 있습니다.

XML 파일을 가리키는 meta-data 태그를 매니페스트에서의 접근성서비스 선언에 추가합니다.

2. 동적 방법

setServiceInfo()를 호출하여 언제든지 동적으로 서비스 구성을 변경할 수 있습니다.
이는 onServiceConnected() 메서드를 오버라이드하여 설정할 수 있습니다.

4. 접근성 서비스 메서드

접근성 서비스는 AccessibilityService 클래스를 확장하고 특정 메서드들을 오버라이드해야 합니다. 이 메서드들은 안드로이드 시스템이 호출하는 순서에 따라 나열됩니다.

  1. 서비스 시작 시 : onServiceConnected()

  2. 실행 중 : onAccessibilityEvent(), onInterrupt()

  3. 종료 시 : onUnbind()

주요 메서드

  • onServiceConnected() (선택 사항)

    시스템이 사용자의 접근성 서비스에 연결될 때 이 메서드를 호출합니다.
    서비스를 위한 일회성 설정(one-time setup) 단계를 수행하는 데 사용됩니다.

  • onAccessibilityEvent() (필수 사항)

    서비스에 지정된 이벤트 필터링 매개변수와 일치하는 AccessibilityEvent를 시스템이 감지하면 이 메서드를 호출합니다.
    시스템이 이 메서드를 호출할 때 관련 AccessibilityEvent를 전달하며, 서비스는 이를 해석하여 사용자에게 피드백을 제공합니다.
    서비스의 수명 주기 동안 여러 번 호출될 수 있습니다.

  • onInterrupt() (필수 사항)

    시스템이 서비스가 제공 중인 피드백을 중단(interrupt)하고자 할 때 이 메서드를 호출합니다.
    마찬가지로 서비스 수명 주기 동안 여러 번 호출될 수 있습니다.

  • onUnbind() (선택 사항)

    시스템이 접근성 서비스를 종료하려고 할 때 이 메서드를 호출합니다.
    리소스 해제 등 일회성 종료 절차를 수행하는 데 사용됩니다.

5. 접근성 이벤트 등록

접근성 서비스 설정의 가장 중요한 기능 중 하나는 서비스가 처리할 수 있는 접근성 이벤트의 유형을 지정하는 것입니다. 이 정보를 구체적으로 지정함으로써 여러 접근성 서비스가 서로 협력할 수 있으며, 특정 앱의 특정 이벤트 유형만 처리할 수 있는 유연성을 갖게 됩니다.

주요 필터링 기준

  • 패키지 이름 (Package names)

    서비스가 처리하고자 하는 앱의 패키지 이름을 지정합니다.

    • 정적 방식 : XML 설정 파일에서 android:packageNames 속성에 쉼표로 구분된 목록을 작성합니다.

    • 동적 방식 : 코드 내에서 AccessibilityServiceInfo.packageNames 멤버를 사용합니다.

    이 매개변수를 생략하면, 서비스는 모든 앱의 접근성 이벤트에 대해 사용 가능한 것으로 간주됩니다.

  • 이벤트 유형 (Event types)

    서비스가 처리하기를 원하는 접근성 이벤트의 유형을 지정합니다.

    • 정적 방식 : XML 파일에서 android:accessibilityEventTypes 속성을 사용하며, | 문자로 이벤트를 구분합니다 (예: typeViewClicked|typeViewFocused).

    • 동적 방식 : 코드 내에서 AccessibilityServiceInfo.eventTypes 멤버를 통해 설정할 수 있습니다.

6. 화면 컨텐츠 탐색

서비스는 화면의 구조를 파악하고 그 위에 시각적 요소를 추가할 수 있습니다.

  • 화면 탐색 : 화면 콘텐츠는 AccessibilityWindowInfo 및 AccessibilityNodeInfo 객체의 트리 구조로 표현됩니다. 이 기능을 사용하려면 SERVICE_META_DATA가 참조하는 XML 리소스를 통한 설정이 반드시 필요합니다.

  • 주의사항 : 서비스가 노드 계층 구조가 변경되었음을 인지하지 못할 수 있으며, 윈도우 콘텐츠는 언제든지 변경될 수 있음으로 인해 오래된 정보를 가질 가능성이 있습니다.

7. 접근성 오버레이 그리기

  • 접근성 오버레이의 역할 및 활용
    AccessibilityService는 Android Framework의 시스템 프로세스인 system_server와의 상호작용을 통해 기존 화면 콘텐츠 위에 오버레이를 그릴 수 있습니다. 이 기능은 주로 화면의 아이템을 시각적으로 강조하거나, 사용자가 서비스와 직접 상호작용할 수 있는 방법을 제공하여 서비스의 동작을 커스텀하는 데 사용됩니다.

  • 오버레이 부착 방식 및 위치 제어

    오버레이는 목적에 따라 특정 윈도우 또는 디스플레이 자체에 부착할 수 있습니다.

    1. 윈도우에 부착된 오버레이는 윈도우가 움직이거나 크기가 변해도 그 안에서 동일한 상대적 위치를 유지하합니다.

    2. 디스플레이에 부착된 오버레이는 해당 디스플레이의 활성 윈도우와 독립적으로 존재합니다. 특정 UI 요소의 위치에 오버레이를 정확히 배치하기 위해서는 AccessibilityNodeInfo.getBoundsInWindow를 호출하여 윈도우 좌표 기준의 경계값을 구해야 합니다.

8. 알림 전략

성능 최적화를 위해 이벤트 전달 속도를 제어해야 합니다.
이벤트 생성은 비용이 큰 프로세스 간 통신(IPC)을 통해 이루어집니다.
따라서 timeout 설정을 활용하여 이벤트가 클라이언트에 너무 빈번하게 전달되는 것을 방지하는 것이 중요합니다.


참고

0개의 댓글