안드로이드 앱 접근성 트리 디버깅하기 1부 – 디버깅의 장점과 활용 예제
안녕하세요, 엔비전스입니다.
접근성 문제를 테스트하고 해결방안을 제시할 때 스크린 리더, 확대 프로그램, 스위치 제어 등과 같은 보조기술을 직접 사용하여 테스트하는 것과 더불어 중요한 것 중 하나는 해당 접근성 이슈와 관련된 소스코드를 대략적으로 분석하는 것입니다. 이렇게 하면 접근성 문제가 스크린 리더와 같은 보조기술 자체의 지원 문제인지 혹은 관련 코드 상의 문제인지 등에 대해 조금 더 명확한 분석이 가능하므로 각 플랫폼별 개발 방법에 맞는 해결방안 리포트가 가능합니다.
그래서 상대적으로 잘 알려져 있지 않은 모바일 웹페이지에서의 소스코드 리뷰 방법과 브라우저별로 각 DOM 요소를 보조기술에 어떻게 뿌려주는지를 확인할 수 있는 접근성 트리를 체크하는 방법에 대해 두 차례에 걸쳐 널리 블로그를 통해 다루었습니다.
그런데 이미 개발된 앱을 다운로드해 스마트폰에 설치하고 접근성을 테스트하는 모바일 네이티브 앱의 경우에는 웹과 달리 관련 소스코드를 소스 보기 등을 통해 리뷰할 수 없기 때문에 정확한 접근성 진단이 어려운 경우가 많습니다. 이를 조금이나마 해결하기 위해 ‘접근성 트리 디버깅’ 관련 아티클을 작성하게 되었습니다. 접근성 트리 디버깅을 활용하면 완벽하진 않지만 접근성에 이슈가 있는 부분의 접근성 트리를 확인하고 만약 안드로이드 혹은 iOS에 대한 접근성과 관련된 코드에 대한 지식이 있다면 대략적인 오류 내용을 확인할 수 있기 때문입니다. 따라서 이번 아티클에서는 안드로이드에서 접근성 트리를 확인하는 방법에 대해 다루어 보도록 하겠습니다. 1부에서는 디버깅 결과물에 대한 예제와 활용법에 대해, 2부에서는 구체적으로 디버깅을 하는 방법과 유의사항에 대해 다룹니다.
안드로이드에서의 접근성 트리 디버깅 옵션
2부 섹션에서 자세히 다루겠지만 안드로이드에서 접근성 트리 디버깅을 사용하려면 명령 프롬프트(터미널) 기능을 활용해야 합니다.
안드로이드 접근성 트리 디버깅은 크게 두 가지 타입으로 나누어집니다.
- 시스템 자체적으로 혹은 sendAccessibilityEvent와 같은 메서드를 사용하여 발생되는 접근성 이벤트 영역을 제외한 현재 위치한 윈도의 화면에 표시되거나 화면에 표시되지 않더라도 접근성 서비스가 인식할 수 있는 각각의 view에 대한 정보 확인(adb logcat TreeDebug *:s 명령 사용): 해당 옵션을 사용하면 TalkBack이 포커스 할 수 있는 각 view에 대한 정보 확인이 가능합니다. 여기서의 정보는 view의 이름(예: TextView, ToggleButton, ImageView 등), 화면에 보이는 텍스트 정보 유무, 대체 텍스트 정보 유무, 하드웨어 키보드에서의 포커스 가능 유무, 클릭 혹은 길게 클릭 가능 속성 유무 등이 포함됩니다. 다음은 TextView와 Button, ImageButton, 탭 위젯, 그리고 해당 화면의 activity 레이블에 대한 정보를 디버깅한 예제입니다.
- 버튼 요소 디버깅: 12-20 12:45:01.066 7231 7231 V TreeDebug: (45018)843.Button:(42, 995 - 295, 1121):TEXT{PURCHASE}:FAC:focusable:clickable:supportsTextLocation. 설명: 요소 유형은 버튼, 화면에 보여지는 텍스트는 purchase, 하드웨어키보드에서 화살표나 탭 키를 눌러 해당 요소에 포커스 가능, 이중탭할 수 있음.
- 이미지 버튼 요소 디버깅: 12-20 17:39:04.905 7231 7231 V TreeDebug: (38344)896.ImageButton:(42, 645 - 168, 771):CD{이미지버튼에 대체 텍스트 추가}:FaC:focusable:clickable:accessibilityFocused. 설명: 요소 유형은 ImageButton, 대체 텍스트는 이미지버튼에 대체 텍스트 추가, 이중탭하여 실행할 수 있음, 하드웨어 키보드로 포커스 가능, 현재 접근성 포커스가 해당 요소에 있음.
- 일반 텍스트 뷰: 12-20 17:58:18.104 7231 7231 V TreeDebug: (41250)919.TextView:(327, 306 - 443, 357):TEXT{silence}:a:accessibilityFocused:supportsTextLocation. 설명: 화면에 보이는 텍스트는 silence, 현재 접근성 초점이 해당 요소에 있음.
- 탭 위젯 디버깅: 12-20 18:06:37.949 7231 7231 V TreeDebug: (83547)932.ActionBar$Tab:(0, 684 - 189, 810):FaC:focusable:selected:clickable:accessibilityFocused
12-20 18:06:37.949 7231 7231 V TreeDebug: (85469)932.TextView:(45, 721 - 143, 772):TEXT{TAB 1}:A:selected:supportsTextLocation. 설명: 사용된 클래스는 ActionBar와 TextView, 요소의 상태는 선택됨, 화면에 보이지는 텍스트는 tab 1, 하드웨어 키보드로 포커스 가능, 이중 탭하여 실행할 수 있음, 접근성 초점이 해당 요소에 있음. 디버깅 코드를 통해서는 각 view가 속한 상, 하위 계층 관계를 알 수 없지만 탭 요소를 가진 ActionBar에는 탭에 대한 텍스트 정보가 없고 그 아래의 TextView에 탭 요소에 대한 텍스트가 포함된 것으로 보아 TextView는 actionbar의 하위 요소임을 알 수 있습니다. - Activity 제목 디버깅: 12-23 14:18:10.725 7231 7231 V TreeDebug: Window: AccessibilityWindowInfo[title=accessibility test, id=1974, type=TYPE_APPLICATION, layer=0, bounds=Rect(0, 117 - 1080, 2280), focused=true, active=true, pictureInPicture=false, hasParent=false, isAnchored=false, hasChildren=false]. 설명: activity 제목은 accessibility test.
- 접근성 이벤트를 포함한 모든 요소 확인: TalkBack과 같은 접근성 서비스를 사용하여 화면을 탐색하면 접근성 서비스 자체에서 수많은 접근성 이벤트를 발생시킵니다. 발생시키는 이벤트 리스트로는 TYPE_WINDOW_STATE_CHANGED, TYPE_VIEW_FOCUSED 등을 포함하여 25가지의 이벤트가 존재하며 커스텀 컨트롤 UI를 사용하거나 접근성 서비스가 변경된 화면 레이아웃 정보 등을 인지하지 못할 경우에는 수동으로 이러한 이벤트를 발생시켜 주어야 합니다. 따라서 접근성 이벤트 디버깅을 사용하면 특정 제스처 혹은 동작에 의해 어떤 접근성 이벤트가 발생했는지 확인이 가능합니다. 다음은 몇 가지 이벤트에 대한 예시입니다.
- 12-23 14:50:00.962 7231 7231 V A11yEventProcessor: A11yEventDumper: EventType: TYPE_WINDOW_STATE_CHANGED; Text: [general title activity];. 설명: ‘general title activity’ 버튼을 이중 탭하여 해당 화면으로 진입하였을 때 WINDOW_STATE_CHANGED 타입 접근성 이벤트가 발생하여 general title activity 텍스트를 자동으로 읽어줌.
- 12-23 15:39:51.942 7231 7231 V ParseTreeCommentNode: Getting output refreshSourceNode for event TYPE_WINDOW_CONTENT_CHANGED. 설명: ViewPager class를 활용한 멀티 페이지뷰 화면에서 사용자가 두 손가락 오른쪽으로 쓸기 제스처로 화면을 스크롤 했을 때 발생한 이벤트로서 이때 변경된 콘텐츠를 자동으로 읽어주는 것은 없었기에 이벤트 자체만 발생함.
※ 접근성 이벤트 디버깅은 사실상 매초마다 발생하기 때문에 이러한 접근성 이벤트를 정확하게 찾아 디버깅하기는 쉽지 않습니다. 따라서 접근성 디버깅은 대부분 1번에서 언급한 화면에 표시되는 view들을 디버깅하는 목적으로 주로 사용됩니다.
그러나 2번에서 언급한 이벤트 디버깅을 통해 각 이벤트 타입에 따라 TalkBack이 어떻게 동작하는지, 화면의 레이아웃 및 화면 변화에 따라 어떤 이벤트 타입을 발생시키는 것이 적절한지 등을 확인하는 목적으로 사용할 수 있습니다.
예를 들어 미디어 플레이어에서 재생 버튼을 누르면 일시 정지 버튼으로 텍스트가 바뀌었음에도 TalkBack에서 이를 알려주지 않는다고 가정해 봅시다. 일반적으로 버튼의 텍스트가 변경되는 경우에는 변경된 텍스트를 읽어 주어야 하므로 TYPE_VIEW_SELECTED 이벤트를 발생시켜 변경된 버튼 텍스트를 읽어주게 되는데 이를 디버깅을 통해 알고 있었다면 버튼 텍스트가 변경되었음에도 TYPE_VIEW_SELECTED 이벤트가 발생하지 않아 이를 읽어주지 못하므로 sendAccessibilityEvent 메서드를 활용하여 개선할 수 있음을 리포트 할 수 있을 것입니다.
디버깅 코드 활용 예제
이처럼 접근성 트리 디버깅 코드를 통해 대략적인 관련 코드 유추가 가능합니다. 그러나 중요한 것은 이러한 코드를 어떻게 접근성 진단에 활용할 수 있는가 하는 것입니다.
다음의 몇 가지 예를 살펴보겠습니다.
- 하드웨어 키보드로 탭 키를 눌렀을 때 실행할 수 있는 특정 view에 포커스 되지 않아 디버깅 코드를 살펴보니 TextView로 되어 있는 경우: TextView에 android:focusable=”true” 속성 추가해 달라고 리포트 할 수 있음.
- EditText 편집 영역에서 TalkBack의 로컬 컨텍스트 메뉴를 열어보니 편집 옵션이 없어 디버깅 코드를 분석하여 EditText에 android:hint가 아닌 contentDescription 속성이 부여되어 있는 것을 확인: android:hint 혹은 AccessibilityNodeInfo의 setHintTExt 속성 사용을 리포트 해결방안에 추가할 수 있음.
- 톡백에서 특정 view를 ‘제목’이라고 읽어 주었으나 TalkBack에서 제공하는 제목 단위로 이동 시에는 해당 view가 탐색되지 않아 디버깅해보니 ‘제목’을 대체 텍스트로 추가한 것을 확인: android:accessibilityHeading=”true” 속성 사용을 권고할 수 있음.
지금까지 안드로이드 접근성 트리 디버깅이란 무엇인지, 적용된 예제와 활용법에 대해 알아보았습니다. 다음 아티클에서는 구체적으로 디버깅을 하는 방법과 주의사항에 대해 살펴보겠습니다.