Skip to main content

Accessibility API Updates

· 12 min read
Ziqi Chen
Student at UC Berkeley

동기

기술이 발전하고 모바일 앱이 일상생활에서 점점 더 중요해짐에 따라, 접근성 있는 애플리케이션을 만드는 필요성도 그만큼 커졌다.

React Native의 제한된 접근성 API는 개발자들에게 항상 큰 고민거리였다. 그래서 우리는 더 포괄적인 모바일 애플리케이션을 쉽게 만들 수 있도록 접근성 API를 몇 가지 업데이트했다.

기존 API의 문제점

문제 1: 완전히 다르지만 유사한 두 가지 props - accessibilityComponentType (Android)와 accessibilityTraits (iOS)

accessibilityComponentTypeaccessibilityTraits는 각각 Android의 TalkBack과 iOS의 VoiceOver에게 사용자가 상호작용하는 UI 엘리먼트의 종류를 알려주는 프로퍼티이다. 이 두 프로퍼티의 가장 큰 문제점은 다음과 같다:

  1. 두 프로퍼티는 사용 방법이 다르지만 동일한 목적을 가지고 있다. 기존 API에서는 두 프로퍼티가 플랫폼별로 분리되어 있어 불편할 뿐만 아니라 많은 개발자에게 혼란을 주었다. iOS의 accessibilityTraits는 17가지 값을 지원하는 반면, Android의 accessibilityComponentType는 단 4가지 값만 허용한다. 또한, 두 프로퍼티의 값은 대부분 겹치지 않는다. 심지어 입력 타입도 다르다. accessibilityTraits는 트레이트 배열이나 단일 트레이트를 전달할 수 있지만, accessibilityComponentType는 단일 값만 허용한다.
  2. Android의 기능이 매우 제한적이다. 기존 프로퍼티를 사용할 때 TalkBack이 인식할 수 있는 UI 엘리먼트는 "button", "radiobutton_checked", "radiobutton_unchecked" 뿐이었다.

문제 2: 접근성 힌트 부재

접근성 힌트는 TalkBack이나 VoiceOver를 사용하는 사용자가 접근성 엘리먼트에 액션을 수행할 때 어떤 일이 일어날지 이해하는 데 도움을 준다. 이러한 힌트는 설정 패널에서 켜거나 끌 수 있다. 이전에는 React Native의 API가 접근성 힌트를 전혀 지원하지 않았다.

문제 3: 반전 색상 무시하기

시각 장애를 가진 일부 사용자는 화면 대비를 높이기 위해 휴대폰에서 색상을 반전시켜 사용한다. 애플은 iOS에서 특정 뷰를 무시할 수 있는 API를 제공한다. 이를 통해 사용자가 반전 색상 설정을 켜도 이미지와 비디오가 왜곡되지 않는다. 그러나 이 API는 현재 React Native에서 지원되지 않는다.

새로운 API 설계

첫 번째 해결책: accessibilityComponentType (안드로이드)와 accessibilityTraits (iOS) 통합

accessibilityComponentTypeaccessibilityTraits 사이의 혼란을 해결하기 위해, 두 속성을 단일 속성으로 통합하기로 결정했다. 이는 두 속성이 기술적으로 동일한 기능을 목표로 했기 때문에 합리적이었다. 이를 통해 개발자는 접근성 기능을 구현할 때 플랫폼별 세부 사항을 고민할 필요가 없어졌다.

배경

iOS에서는 UIAccessibilityTraits를 모든 NSObject에 설정할 수 있는 속성이다. 자바스크립트 속성을 통해 전달된 17개의 트레이트는 Objective-C의 UIAccessibilityTraits 요소로 매핑된다. 각 트레이트는 long int로 표현되며, 설정된 모든 트레이트는 OR 연산으로 결합된다.

반면 안드로이드에서 AccessibilityComponentType는 React Native에서 만든 개념으로, 안드로이드의 속성과 직접적으로 매핑되지 않는다. 접근성은 접근성 델리게이트를 통해 처리된다. 각 뷰는 기본 접근성 델리게이트를 가지고 있다. 접근성 액션을 커스텀하려면 새로운 접근성 델리게이트를 생성하고, 커스텀하려는 특정 메서드를 오버라이드한 후, 해당 뷰의 접근성 델리게이트를 새 델리게이트로 설정해야 한다. 개발자가 AccessibilityComponentType를 설정하면, 네이티브 코드는 전달된 컴포넌트를 기반으로 새로운 델리게이트를 생성하고, 뷰에 해당 접근성 델리게이트를 설정한다.

변경 사항

새로운 속성을 위해 두 속성의 상위 집합을 만들기로 했다. 기존 속성인 accessibilityTraits를 주로 모델로 삼기로 결정했는데, 이는 accessibilityTraits가 훨씬 더 많은 값을 가지고 있기 때문이다. 안드로이드에서 이 트레이트의 기능은 접근성 델리게이트를 수정함으로써 폴리필로 구현된다.

accessibilityTraits는 iOS에서 설정할 수 있는 17개의 UIAccessibilityTraits 값을 가지고 있다. 하지만 이 중 일부는 새로운 속성에 포함하지 않았다. 이는 일부 트레이트를 설정했을 때의 효과가 잘 알려져 있지 않고, 많은 값이 실제로 거의 사용되지 않기 때문이다.

UIAccessibilityTraits 값은 일반적으로 두 가지 목적 중 하나를 가진다. UI 엘리먼트의 역할을 설명하거나, UI 엘리먼트의 상태를 설명한다. 우리가 관찰한 이전 속성의 사용 사례 대부분은 일반적으로 하나의 역할을 나타내는 값을 사용하고, 이를 "state selected", "state disabled" 또는 둘 다와 결합했다. 따라서 두 개의 새로운 접근성 속성을 만들기로 결정했다: accessibilityRoleaccessibilityState.

accessibilityRole

새로운 속성인 accessibilityRole은 Talkback이나 Voiceover에 UI 엘리먼트의 역할을 알려준다. 이 속성은 다음 값 중 하나를 가질 수 있다:

  • none
  • button
  • link
  • search
  • image
  • keyboardkey
  • text
  • adjustable
  • header
  • summary
  • imagebutton

이 속성은 하나의 값만 전달할 수 있다. 일반적으로 UI 엘리먼트는 논리적으로 이 중 하나 이상의 역할을 가지지 않기 때문이다. 예외는 이미지와 버튼이므로, 두 가지를 결합한 imagebutton 역할을 추가했다.

accessibilityStates

새로운 속성인 accessibilityStates는 Talkback이나 Voiceover에 UI 엘리먼트의 상태를 알려준다. 이 속성은 다음 값 중 하나 또는 둘 다를 포함하는 배열을 가진다:

  • selected
  • disabled

두 번째 해결책: 접근성 힌트 추가

이를 위해 accessibilityHint라는 새로운 속성을 추가했다. 이 속성을 설정하면 Talkback이나 Voiceover가 사용자에게 힌트를 읽어준다.

accessibilityHint

이 속성은 String 형태로 읽을 접근성 힌트를 받는다.

iOS에서는 이 속성을 설정하면 뷰의 해당 네이티브 속성인 AccessibilityHint가 설정된다. 이후 iPhone에서 접근성 힌트가 켜져 있으면 Voiceover가 이 힌트를 읽는다.

Android에서는 이 속성을 설정하면 힌트 값이 접근성 라벨 끝에 추가된다. 이 구현의 장점은 iOS의 힌트 동작을 모방한다는 점이지만, 단점은 iOS처럼 설정에서 이 힌트를 끌 수 없다는 것이다.

Android에서 이렇게 결정한 이유는 일반적으로 접근성 힌트가 특정 동작(예: 클릭)에 해당하기 때문이며, 플랫폼 간 동작을 일관되게 유지하고 싶었다.

문제 3의 해결책

accessibilityIgnoresInvertColors

애플의 AccessibilityIgnoresInvertColors API를 자바스크립트로 노출했다. 이제 색상 반전을 원하지 않는 뷰(예: 이미지)에서 이 속성을 true로 설정하면 색상이 반전되지 않는다.

새로운 사용법

이 새로운 속성들은 React Native 0.57 버전부터 사용할 수 있다.

업그레이드 방법

현재 accessibilityComponentTypeaccessibilityTraits를 사용하고 있다면, 새로운 속성으로 업그레이드하는 방법을 단계별로 안내한다.

1. jscodeshift 사용하기

가장 간단한 사용 사례는 jscodeshift 스크립트를 실행하여 해결할 수 있다.

스크립트는 다음 인스턴스를 대체한다:

accessibilityTraits=“trait”
accessibilityTraits={[“trait”]}

다음과 같이 변경한다:

accessibilityRole= “trait”

또한 이 스크립트는 AccessibilityComponentType 인스턴스를 제거한다. (AccessibilityComponentType을 설정한 모든 곳에서 AccessibilityTraits도 함께 설정했다고 가정한다.)

2. 수동 코드 변환 사용하기

AccessibilityTraits를 사용했지만 AccessibilityRole에 해당하는 값이 없는 경우, 그리고 AccessibilityTraits에 여러 특성이 전달된 경우에는 수동으로 코드를 변환해야 한다.

일반적으로,

accessibilityTraits= {["button", "selected"]}

위 코드를 아래와 같이 수동으로 교체한다.

accessibilityRole="button"
accessibilityStates={["selected"]}

이러한 속성들은 이미 Facebook 코드베이스에서 사용되고 있다. Facebook의 코드 변환은 놀랍도록 간단했다. jscodeshift 스크립트가 약 절반의 인스턴스를 수정했고, 나머지 절반은 수동으로 수정했다. 전체 과정은 몇 시간도 걸리지 않았다.

업데이트된 API가 유용하게 쓰이길 바란다! 그리고 계속해서 앱을 접근 가능하게 만들길 바란다! #포용성