Палец натиска тактилен превключвател за достъпност с алено-червен гумен купол върху скандинавска дъбова повърхност, слушалки замъглени отстрани — визуалният знак за сравнението на нативните мобилни API за достъпност.
Image description: Палец натиска тактилен превключвател за достъпност с алено-червен гумен купол върху скандинавска дъбова повърхност, слушалки замъглени отстрани — визуалният знак за сравнението на нативните мобилни API за достъпност.

Инженерно въведение · Мобилни API за достъпност

Нативни мобилни API за достъпност през 2026 г.: UIAccessibility, AccessibilityNode и уебът

Сравнително въведение в iOS UIAccessibility, Android AccessibilityNodeInfo и междуплатформените мостове, които се опитват да ги съгласуват — какво се картографира чисто, какво не, и къде се вписва мобилният уеб.

Нативни мобилни API за достъпност през 2026 г.:
UIAccessibility, AccessibilityNode и уебът

iOS и Android всеки излага напълно функционално дърво за достъпност към екранния четец на платформата — и двете дървета не се съгласяват за нищо отвъд основите на етикета и ролята. Картографирахме всеки примитив, който VoiceOver и TalkBack действително консумират през 2026 г., начина, по който React Native, Flutter и Kotlin Multiplatform се опитват да ги свържат, и мястото, където достъпността на мобилния WebView тихо пада в пропаст.

2
сравнени нативни API
3
междуплатформени мостове
28
картографирани примитива
13 мин четене
Актуализирано май 2026 г.

1. iOS UIAccessibility — етикети, особености, подсказки, стойности

Всяко видимо нещо на iOS екран има или може да има представяне за достъпност. Apple доставя това представяне чрез неформалния протокол UIAccessibility, реализиран от UIView и всяка системна контрола, и чрез UIAccessibilityElement — лек клас, който заделяте за частите на интерфейса си, които са нарисувани, но сами по себе си не са изгледи — знаци в персонализирано нарисувана диаграма, глифове в Core Graphics сцена, региони в CALayer. VoiceOver, Switch Control, Full Keyboard Access и Voice Control всички консумират един и същ протокол; научаването му веднъж ви купува четири помощни технологии.

Протоколът излага четири примитива, които имат значение за почти всеки екран. Етикетът за достъпност е краткото, четимо от човек име на елемента — „Изпрати“, „Профилна снимка на Аша“, „Назад“. Особеностите за достъпност са побитова маска от подобни на роли флагове — .button, .header, .image, .selected, .adjustable, .staticText, .updatesFrequently — които казват на VoiceOver как да се държи около елемента и кои жестове да активира. Стойността за достъпност е низово представяне на текущото състояние („Включено“, „75%“, „Четвъртък, 22 май“). Подсказката за достъпност е по-дългото, незадължително обяснение („Докоснете два пъти, за да отворите визуализатора на снимки“), което VoiceOver произнася след закъснение, ако потребителят не действа само въз основа на етикета.

Четирите примитива се комбинират. Превключвател се чете като етикет + особеност + стойност: „Wi-Fi, бутон превключвател, Включено“. Плъзгач се чете като етикет + особеност + стойност + подсказка: „Сила на звука, регулируема, 60 процента, плъзнете нагоре или надолу, за да регулирате“. Персонализирано нарисувана лента на диаграма се чете като верига от UIAccessibilityElement обекти, всеки с етикет, стойност и рамка вътре в контейнера си. Веригата е повърхността на API — VoiceOver я обхожда линейно, когато потребителят плъзне надясно, и спазва реда, в който публикувате елементите чрез масива accessibilityElements на контейнера.

SwiftUI е същият протокол, с по-приветлива фасада

Модификаторите на изглед .accessibilityLabel(), .accessibilityValue(), .accessibilityHint() и .accessibilityAddTraits() в SwiftUI се компилират до същите UIAccessibility свойства върху основополагащия UIView. SwiftUI добавя и .accessibilityElement(children:), който решава проблема със „знаците в диаграма“ по-декларативно от подхода на UIKit — но контрактът по време на изпълнение, който VoiceOver вижда, е идентичен. Научаването на имената на UIKit все още си струва времето, защото всеки пример на Apple, всеки отговор в Stack Overflow и всеки одит за достъпност говорят с тях.


2. Android AccessibilityNodeInfo — роли, действия, importantForAccessibility

Android поема по различен път. Където iOS закача достъпността към плосък протокол върху всеки изглед, Android сериализира цялото дърво за достъпност като граф от обекти AccessibilityNodeInfo, всеки от които е моментна снимка на изглед в момента, в който пристигне TalkBack заявка. Рамката изгражда моментните снимки лениво; View публикува своя възел, като замества onInitializeAccessibilityNodeInfo() (или, в Compose, чрез задаване на семантични модификатори), а платформата съшива родителско-дъщерните връзки в дърво, което отразява йерархията на изгледите.

Примитивите се различават от iOS по три значими начина. Първо, Android излага роля чрез поле className от тип низ — android.widget.Button, android.widget.CheckBox, android.widget.EditText. TalkBack чете името на класа и решава как да го обяви („бутон“, „поле за отметка“, „поле за редактиране“). Compose превежда своята семантика Role.Button, Role.Checkbox, Role.RadioButton в същото поле. Ролята е по-детайлна от побитовата маска на особеностите на iOS, но и по-твърда — няма „напълно персонализирана“ роля, освен ако не приемете обявяването като „изглед“.

Второ, Android представя интерактивността като набор от действия, прикачени към възела: ACTION_CLICK, ACTION_LONG_CLICK, ACTION_SCROLL_FORWARD, ACTION_SET_TEXT, ACTION_FOCUS и дълъг списък от персонализирани действия, които можете да регистрирате с AccessibilityNodeInfo.AccessibilityAction. TalkBack извежда персонализираните действия чрез ротора „действия“ — потребителят плъзва нагоре с един пръст и чува всяко персонализирано действие по име. iOS има същата концепция (UIAccessibilityCustomAction), но в Android списъкът с действия е повърхността; в iOS повърхността е речникът от жестове.

Трето, Android има importantForAccessibility — изброен тип за всеки изглед (auto, yes, no, noHideDescendants), който контролира дали възелът изобщо се появява в дървото. noHideDescendants е единственият най-мощен инструмент в достъпността на Android и този, който най-често се забравя — той премахва цялото поддърво от обхождането на TalkBack, еквивалентът на aria-hidden=“true” в уеб. iOS няма точен аналог; най-близкото е задаването на accessibilityElements на празен масив върху контейнера, което премахва само преките деца на контейнера, а не цялото поддърво.

Несъответствието при „живия регион“

Android излага ViewCompat.setAccessibilityLiveRegion() с три стойности: none, polite, assertive. Речникът отразява ARIA — почти. TalkBack спазва нивата на учтивост надеждно. iOS няма нищо сравнимо на ниво протокол: обявявате актуализациите, като извиквате UIAccessibility.post(notification: .announcement, argument: “Saved”) — императивно еднократно действие, което не се прикачва към изглед. Междуплатформените мостове трябва да имитират едното върху другото, а несъответствието в импеданса се проявява във всяка рамка, разгледана в раздел 3.


3. Междуплатформени мостове — React Native, Flutter, Kotlin Multiplatform

Всяка междуплатформена мобилна рамка трябва да вземе двата API по-горе и да представи единна, оформена от рамката повърхност. Нито една от тях не успява напълно. Трите подхода доминират пазара през 2026 г. — React Native, Flutter и Kotlin Multiplatform с Compose Multiplatform — всеки от тях е леко различна сделка между изтичане и абстракция.

React Native 0.76
JS мост към нативния UIKit и Android View
Най-явното картографиране — и най-течащото
iOS мостaccessibilityLabel, accessibilityHint, accessibilityRole, accessibilityState върху Pressable и View се картографират почти 1:1 към UIAccessibility — но имената на ролите са речникът на React Native, а не на iOS.
Android мостСъщите JS свойства се картографират към AccessibilityNodeInfo чрез адаптер от страна на Yoga; accessibilityRole=“button” задава className на android.widget.Button.
УловкаСвойството accessibilityLiveRegion е само за Android — в iOS то мълчаливо не прави нищо и трябва да извикате AccessibilityInfo.announceForAccessibility() ръчно.
Flutter 3.27
Персонализирано изобразяване · синтетично дърво за достъпност
Най-еднообразното — и най-непрозрачното
ПодходFlutter изобразява всичко върху Skia платно, така че изгражда собствено дърво от SemanticsNode и го сериализира към платформата при поискване.
iOS пътSemanticsNode обектите се превеждат в UIAccessibilityElement инстанции върху Flutter изгледа, с особености, картографирани от наборите SemanticsAction и SemanticsFlag.
Android пътСъщото дърво от SemanticsNode се сериализира в AccessibilityNodeInfo възли от Android изгледа на Flutter; действията стават AccessibilityActions; живият регион става SemanticsFlag.isLiveRegion.
Kotlin Multiplatform · Compose Multiplatform
Споделена Compose среда · достъпност за всяка цел
Най-новото, с най-много оформени от платформата шевове
ПодходModifier.semantics { } на Compose дефинира роли и действия веднъж; всяка цел превежда същия семантичен блок към собствения си нативен API за достъпност.
iOS целСредата Compose-for-iOS обхожда семантичното дърво и конструира UIAccessibilityElements — но iOS реализацията е по-млада от тази на Android и все още липсват няколко семантични вида.
Android целЗрелият път: семантиката става AccessibilityNodeInfo чрез същия слой compose-ui-semantics, който използва нативният Compose на Android.

Шаблонът във всичките три е един и същ: синтетично, оформено от рамката семантично дърво от едната страна, две оформени от платформата дървета за достъпност от другата, и преводач помежду им, който се справя добре с простите случаи и със сложните — със забележима загуба на точност. Простите случаи — бутон с етикет, изображение с alt текст, заглавие — се преобразуват напред-назад без загуба. Сложните случаи — персонализиран жест с плъзгане с два пръста, диаграма, чиито елементи трябва да са група с възможност за фокус, жив регион, който трябва да се задейства в iOS без обвързана с изглед настройка за учтивост — изтичат речника на основополагащата платформа нагоре в междуплатформения код или просто не успяват да се преведат.

„Първите 80 процента от мобилната достъпност са идентични във всяка рамка. Последните 20 процента са там, където всяка рамка разкрива в кой нативен API тайно мисли.“

— инженерен отдел на Disability World, май 2026 г.

4. Пропастта на WebView — когато достъпността на мобилния уеб тихо се проваля

И iOS, и Android изобразяват уеб съдържание чрез системен WebView — WKWebView в iOS, android.webkit.WebView (или Chrome Custom Tabs) в Android. И в двата случая WebView е черна кутия от гледна точка на хост приложението: приложението вижда един изглед, но екранният четец вижда цялото DOM дърво за достъпност вътре в него. Мостът между двете дървета е мястото, където изненадващо голяма част от мобилната достъпност тихо се обърква.

Механизмът е, на пръв поглед, прост. Когато фокусът на екранен четец влезе в WebView, платформата чете дървото за достъпност на документа директно от браузърния двигател — WebKit в iOS, Blink в Android — и го обхожда като поддърво на дървото на хост приложението. Ролите, етикетите и ARIA атрибутите на уеб се превеждат в речника на платформата в реално време. Елемент button без явна роля вътре в WebView се чете като бутон и на двете платформи; регион aria-live=“polite” се обявява правилно и на двете; aria-label върху връзка се извежда като етикета за достъпност на връзката. През първите три години от живота на мобилния уеб това просто работеше.

Пропастта се появява на три места. Първо, персонализираните жестове, дефинирани в хост приложението — плъзгане с два пръста за отхвърляне, магическо докосване за пускане и пауза — са невидими за съдържанието на WebView; те се задействат върху грешната цел или изобщо не се задействат, когато фокусът е вътре в документа. Второ, UIAccessibilityElement обектите на хост приложението, нарисувани върху WebView (плаваща бутон за действие, персонализирана лента с инструменти), се конкурират с дървото на WebView за реда на обхождане, а резултатният ред на четене е недетерминистичен между iOS версиите. Трето — и това е най-големият единичен режим на провал в достъпността на мобилния уеб — WebView в iOS не спазва нивата на учтивост на aria-live по начина, по който Safari го прави в раздел: системата за обявяване на WKWebView отпада разликата между polite и assertive, така че всяка актуализация на живо се третира като polite независимо от маркировката.

Два изгледа на един и същ DOM
В раздел на Mobile Safari
<div role="alert" aria-live="assertive">
  Connection lost — retrying.
</div>

VoiceOver в обикновен раздел на Safari прекъсва текущото изказване и произнася съобщението незабавно. Учтивостта assertive се спазва от край до край през WebKit.

Вътре в същия DOM в WKWebView
<div role="alert" aria-live="assertive">
  Connection lost — retrying.
</div>

Същата маркировка, същият браузърен двигател — но мостът за достъпност на WKWebView към UIKit понижава обявяването до отложено polite съобщение. Потребителят го чува след закъснение, понякога след като вече е въвел текст в сега счупената форма.

Междуплатформената поправка, която действително работи

За обявявания вътре в WebView единственият надежден междуплатформен шаблон през 2026 г. е да изложите JavaScript мост към хост приложението — миниатюрен postMessage обработчик — и да насочите настоятелните обявявания извън DOM, в хост приложението и обратно през UIAccessibility.post(notification: .announcement, …) в iOS или announceForAccessibility() в Android. aria-live на уеб оцелява само за истински учтиви съобщения, където няколко секунди латентност са приемливи.


5. Таблицата за картографиране — какво на какво съответства

Картографирахме 28 примитива, които VoiceOver и TalkBack действително консумират на практика — обединението на повърхността на протокола iOS UIAccessibility, повърхността на Android AccessibilityNodeInfo и най-използваните междуплатформени свойства на React Native и Flutter. Таблицата по-долу улавя само спорните редове: примитивите, където картографирането е непълно, асиметрично или изненадващо. Редовете, където картографирането е чисто (етикет, роля бутон, роля изображение, заглавие), са пропуснати поради дължина.

ВъзможностiOS UIAccessibilityAndroid AccessibilityNodeInfoReact Native 0.76Flutter 3.27
Текст на подсказка (по-дълго обяснение)accessibilityHinttooltipText (API 28+)accessibilityHint (само iOS)SemanticsProperties.hint
Учтивост на живия регионНяма — само императивно обявяванеsetAccessibilityLiveRegion()accessibilityLiveRegion (само Android)SemanticsFlag.isLiveRegion
Скриване на поддърво от достъпносттаaccessibilityElementsHidden (само децата)importantForAccessibility=“noHideDescendants”accessibilityElementsHidden / importantForAccessibilityджаджа ExcludeSemantics
Персонализирано действие (ротор / меню)UIAccessibilityCustomActionAccessibilityNodeInfo.AccessibilityActionaccessibilityActions + onAccessibilityActionSemanticsAction с персонализиран етикет
Семантика на регулируем елемент / плъзгачUIAccessibilityTraitAdjustable + accessibilityIncrementRangeInfo + ACTION_SCROLL_FORWARDaccessibilityRole=“adjustable” + обработчициSlider излага SemanticsAction.increase
Ниво на заглавиеUIAccessibilityTraitHeader (без ниво)setHeading(true) (без ниво)accessibilityRole=“header” (без ниво)SemanticsProperties.headingLevel (1–6)
Състояние избран / превключенUIAccessibilityTraitSelectedsetSelected(true) + setCheckable()accessibilityState={selected, checked}SemanticsFlag.isSelected
Семантика на група / контейнерshouldGroupAccessibilityChildrensetScreenReaderFocusable(true)accessible={true} върху родителяджаджа MergeSemantics
Обявяване на еднократно съобщениеUIAccessibility.post(.announcement, …)view.announceForAccessibility()AccessibilityInfo.announceForAccessibility()SemanticsService.announce()

Три модела изпъкват от таблицата. Първо, асиметрията около живите региони е единственият най-голям източник на междуплатформено разминаване — Android има настройка за учтивост за всеки изглед, iOS има само глобално императивно обявяване, а всяка рамка по-горе е принудена да лъже за разликата. Второ, нивата на заглавията са единственото място, където Flutter истински надминава и двете нативни платформи; примитивите на iOS и Android знаят само „това е заглавие“, а не „това е H3 под H2“. Трето, примитивът „скрий от достъпността“ е по-гъвкав в Android, отколкото в iOS — noHideDescendants скрива цяло поддърво с един ход, докато iOS изисква да скриете децата на всеки контейнер поотделно.


6. Наръчникът за нативни мобилни приложения

1

Научете нативния речник преди речника на рамката

Всеки междуплатформен мост — React Native, Flutter, Compose Multiplatform — има собствено наименуване на свойствата за достъпност, а всяко от тези имена е лека лъжа за това какво всъщност прави основополагащата платформа. Когато екранен четец не обявява правилно, грешката почти винаги се намира в нативния API, към който рамката е превела, а не в свойството на рамката, което сте задали. Прочетете документацията на UIAccessibility и документацията на AccessibilityNodeInfo поне веднъж; документацията на рамката има смисъл само след това.

2

Тествайте обявяванията на живо специално в iOS

Асиметрията на живия регион от раздел 2 означава, че всеки код, който приема, че aria-live=“assertive” или accessibilityLiveRegion=“assertive” работи, ще се влоши мълчаливо в iOS. Изградете малка тестова среда, която задейства както учтиво, така и настоятелно обявяване и на двете платформи, с VoiceOver и TalkBack на реални устройства, преди да доставите функция, чието потребителско изживяване зависи от това потребителят да чуе промяна на състоянието.

3

Излизайте от WebView за всичко настоятелно

Понижаването на настоятелните обявявания от WKWebView не е грешка, която Apple ще поправи скоро — то е едно и също във всяко iOS издание от 14 нататък. Ако доставяте хибридно приложение, в което потребителят може да срещне фатална грешка вътре в WebView, насочете обявяването през JS мост към хоста и оставете хоста да задейства обявяването на платформата. Само уебът не е достатъчен.

4

Използвайте семантиката „сливане“ или „групиране“ на рамката, а не елемент по елемент

И iOS (shouldGroupAccessibilityChildren), и Android (setScreenReaderFocusable), и Flutter (MergeSemantics) предоставят начин да свиете визуален клъстер — икона плюс етикет плюс стойност — в един елемент за достъпност. Използвайте го. Поведението по подразбиране „всеки лист е елемент с възможност за фокус“ превръща навигационен чип с шест елемента в шест плъзвания на VoiceOver.

5

Одитирайте с Accessibility Inspector и настройките за разработчици на TalkBack

И двете платформи доставят безплатен, официален инспектор за живото дърво за достъпност — Accessibility Inspector на macOS (сдвоен със свързания iOS симулатор или устройство) и наслагването „Покажи фокуса за достъпност“ плюс „Настройки за разработчици“ на Android. Използвайте ги, за да четете дървото на собственото си приложение така, както го вижда екранният четец; не приемайте, че логването за отстраняване на грешки на рамката ви показва същото нещо, което платформата показва на TalkBack.


Заключение: рамката е надолу по веригата от платформата

Изкушаващо е да се вярва — а документацията на рамката насърчава това убеждение — че междуплатформен API за достъпност е единна, унифицирана абстракция над два еквивалентни нативни API. Таблицата за картографиране в раздел 5 опровергава унификацията. Двата нативни API бяха проектирани независимо, от два различни екипа, около два различни мисловни модела за това как екранният четец трябва да обхожда документ; разликите са реални, изтичат през всяка рамка, а изтичането се проявява в частите от потребителското изживяване, които имат най-голямо значение — актуализации на живо, персонализирани жестове, скрити поддървета, йерархии на заглавията.

Добрата новина, след този абзац: основите се картографират. Бутон с етикет, изображение с alt текст, заглавие в горната част на раздел — те се преобразуват напред-назад през всяка рамка и се обявяват правилно на двете платформи. Ако доставяте само тези примитиви, не е нужно да мислите за UIAccessibility или AccessibilityNodeInfo; настройките по подразбиране на рамката са честни. Неприятностите започват, когато потребителският интерфейс започне да прави нещо интересно, което е и моментът, в който достъпността започва да има най-голямо значение.

Наръчникът в раздел 6 е най-краткият вариант на аргумента, който отвежда най-много потребители с увреждания до работещо изживяване: мислете първо в нативни примитиви, тествайте на реални устройства на двете платформи, излизайте от WebView, когато наистина го имате предвид, групирайте листните възли умишлено и използвайте официалните инспектори. Рамката, която сте избрали, помага с първите 80 процента и се отдръпва от пътя ви за последните 20 процента. Тези последни 20 процента са там, където живее потребителят на екранен четец.

„VoiceOver и TalkBack четат два различни документа от един и същ изходен код. Дали потребителят забелязва разликата е мярка за това колко добре сте разбрали платформата под вашата рамка.“

— инженерен отдел на Disability World, май 2026 г.