2026 में Android पर एक्सेसिबिलिटी: एक TalkBack और Compose semantics चेकलिस्ट जो वाकई काम करती है
2026 के लिए एक व्यावहारिक Android एक्सेसिबिलिटी चेकलिस्ट — TalkBack, Compose semantics, टच टारगेट, और रिलीज़ से पहले हर स्क्रीन पर जो टेस्टिंग पास मैं करता हूं।
Android पर एक्सेसिबिलिटी को आमतौर पर रिलीज़-पूर्व चेकलिस्ट की एक चीज़ की तरह ट्रीट किया जाता है, जिसे UI “पूरा” हो जाने के बाद जबरन जोड़ा जाता है। यह क्रम उल्टा है, और इसका असर दिखता है: semantics को ध्यान में रखे बिना बनाई गई स्क्रीन को बाद में ठीक करने में घंटों लगते हैं, जबकि शुरू से semantics के साथ बनाई गई वही स्क्रीन लगभग कोई अतिरिक्त कीमत नहीं मांगती। यह वह चेकलिस्ट है जिसे मैं वाकई फॉलो करता हूं — कोई पॉलिसी डॉक्यूमेंट नहीं, बल्कि उन चीज़ों की सूची जो मैं Compose UI लिखते समय करता हूं, साथ ही रिलीज़ से पहले की टेस्टिंग पास।
बाद में ठीक करना महंगा क्यों है, और शुरू से बनाना क्यों नहीं
TalkBack, Android का स्क्रीन रीडर, पिक्सेल नहीं पढ़ता — यह उस semantics ट्री को पढ़ता है जिसे Compose आपके UI के साथ-साथ जनरेट करता है। अगर स्क्रीन लिखते समय आप कभी इस ट्री के बारे में नहीं सोचते, तो TalkBack आखिरकार कच्चे इंप्लीमेंटेशन डिटेल्स पढ़ने लगता है: सिर्फ आइकन वाला बटन “Button” के रूप में अनाउंस होता है, एक डेकोरेटिव इमेज “Image” के रूप में अनाउंस होती है, और तीन अलग-अलग composables वाली एक row एक वाक्य के बजाय तीन अलग-अलग रुकावटों के रूप में अनाउंस होती है। इसे बाद में ठीक करने का मतलब है हर composable पर वापस जाकर पूछना “इसे असल में क्या कहना चाहिए,” जो पहली बार यही सवाल पूछने से धीमा है।
समाधान यह है कि semantics को Modifier चेन के अंत में जोड़े गए बाद के विचार की तरह नहीं, बल्कि कंपोनेंट के API के हिस्से की तरह ट्रीट करें।
चेकलिस्ट
1. हर नॉन-टेक्स्ट कंट्रोल में एक contentDescription है — या बिल्कुल नहीं
अगर किसी बटन पर दिखने वाला टेक्स्ट है, तो रिडंडेंट डिस्क्रिप्शन न जोड़ें — TalkBack पहले से ही वह टेक्स्ट पढ़ता है, और डुप्लीकेट डिस्क्रिप्शन उसे दो बार पढ़वा देता है। अगर बटन सिर्फ आइकन वाला है, तो डिस्क्रिप्शन अनिवार्य है:
IconButton(onClick = { onDelete(item.id) }) {
Icon(
imageVector = Icons.Default.Delete,
contentDescription = stringResource(R.string.delete_item, item.name)
)
}
पूरी तरह डेकोरेटिव इमेजेस को स्पष्ट रूप से contentDescription = null दिया जाता है। बिना किसी डिस्क्रिप्शन वाली इमेज फिर भी “unlabeled image” के रूप में अनाउंस होती है, जो चुप्पी से भी बदतर है।
2. संबंधित कंटेंट को mergeDescendants से ग्रुप करें
टाइटल, सबटाइटल और एक बैज वाला कार्ड डिफ़ॉल्ट रूप से तीन अलग-अलग TalkBack रुकावटों के रूप में पढ़ा जाता है, यानी एक row सुनने के लिए तीन स्वाइप। ग्रुप को इस तरह रैप करें कि वह एक ही यूनिट के रूप में अनाउंस हो:
Row(
modifier = Modifier.semantics(mergeDescendants = true) {}
) {
Text(title)
Text(subtitle)
Badge { Text(status) }
}
इसे TalkBack ऑन करके और स्क्रीन पर एक बार स्वाइप करके टेस्ट करें। अगर एक लॉजिकल row को सुनने में एक से ज़्यादा स्वाइप लगती है, तो उसे मर्ज करने की ज़रूरत है।
3. टच टारगेट 48dp के होते हैं, आइकन के विज़ुअल साइज़ के नहीं
बिना पैडिंग के 24dp का आइकन 24dp का टच टारगेट होता है, जो एक्सेसिबिलिटी गाइडलाइंस और कम डेक्सटेरिटी वाले किसी भी व्यक्ति के लिए बुनियादी usability, दोनों में फेल हो जाता है। मौजूदा Compose में Modifier.minimumInteractiveComponentSize() बिना मैनुअल पैडिंग कैलकुलेशन के इसे संभाल लेता है — इसे सिर्फ उन आइकनों पर नहीं, जो रिव्यू में तंग महसूस होते हैं, बल्कि हर टैप करने योग्य आइकन पर लगाएं।
4. स्टेट को सिर्फ रंग से कम्युनिकेट न करें
किसी इनवैलिड फील्ड पर लाल बॉर्डर कलरब्लाइंड यूज़र के लिए अदृश्य है और TalkBack यूज़र के लिए अनाउंस नहीं होता। सिर्फ रंग पर निर्भर हर सिग्नल को टेक्स्ट या आइकन बदलाव के साथ जोड़ें: फील्ड के नीचे एक एरर मैसेज, लेबल के पास एक एरर आइकन। यह देखने वाले यूज़र के लिए भी बेहतर UX है जो जल्दी में नज़र दौड़ा रहा है — सिर्फ रंग को समझने में एक शब्द से ज़्यादा ध्यान लगता है।
5. बिना क्लिक बदलने वाले कंटेंट के लिए लाइव रीजन
अगर यूज़र के अमाउंट टाइप करने के बाद कोई टोटल अपडेट होता है, तो TalkBack इसे तब तक नोटिस नहीं करेगा जब तक composable को लाइव रीजन के रूप में मार्क न किया जाए:
Text(
text = "Total: $formattedTotal",
modifier = Modifier.semantics { liveRegion = LiveRegionMode.Polite }
)
Polite मौजूदा अनाउंसमेंट के खत्म होने का इंतज़ार करता है; Assertive बीच में टोक देता है। Assertive का इस्तेमाल कम करें — किसी ऐसी एरर के लिए जिसे तुरंत ध्यान चाहिए, न कि बदलते रहने वाले टोटल के लिए।
टेस्टिंग पास
कोड रिव्यू शायद वाकई मायने रखने वाली चीज़ों का आधा ही पकड़ पाती है, क्योंकि इनमें से ज़्यादातर समस्याएं तभी साफ दिखती हैं जब स्क्रीन रीडर ऑन हो। किसी स्क्रीन को रिलीज़ करने से पहले, मैं तीन चेक करता हूं:
- TalkBack के साथ, पूरी स्क्रीन पर स्वाइप करते हुए, डिस्प्ले बंद करके, सिर्फ सुनते हुए। अगर मैं सिर्फ अनाउंसमेंट से यह नहीं बता पाता कि कोई कंट्रोल क्या करता है, तो उसे बेहतर डिस्क्रिप्शन चाहिए।
- Accessibility Scanner (Google का स्टैंडअलोन ऐप) टच टारगेट साइज़ और कंट्रास्ट रेशियो के लिए — यह दोनों को अपने आप फ्लैग करता है और सटीक composable की ओर इशारा करता है।
- सिस्टम सेटिंग्स में 200% फॉन्ट स्केल। इस स्केल पर टेक्स्ट का ट्रंकेट होना, ओवरलैप होना या क्लिप होना एक बग है, कोई एज-केस नहीं — असल यूज़र्स का एक अच्छा-खासा हिस्सा हमेशा के लिए बढ़ा हुआ फॉन्ट साइज़ इस्तेमाल करता है।
यह कुछ ऐप्स के लिए दूसरों से ज़्यादा मायने रखता है। मेडिकेशन रिमाइंडर ऐप OldSchool एक बड़ी उम्र के यूज़र बेस की ओर झुका हुआ है, जहां बड़े फॉन्ट स्केल और स्क्रीन रीडर बिल्कुल भी एज-केस नहीं हैं — वे मीडियन के काफी करीब हैं। चेकलिस्ट को एक बार कंपोनेंट लाइब्रेरी में बना लेने से मुझे ऐप के बढ़ने के साथ इसे स्क्रीन-दर-स्क्रीन दोबारा निकालने की ज़रूरत नहीं पड़ी।
निष्कर्ष
किसी प्रोजेक्ट के आखिर में किया गया एक्सेसिबिलिटी काम महंगा होता है क्योंकि यह करेक्टिव होता है — किसी को कमी नोटिस करनी पड़ती है, फिर वापस जाकर हर स्क्रीन को अलग-अलग ठीक करना पड़ता है। हर composable लिखने के साथ-साथ किया गया एक्सेसिबिलिटी काम लगभग मुफ़्त होता है, क्योंकि सवाल (“यह क्या अनाउंस होता है,” “यह एक रुकावट है या तीन,” “टच टारगेट असली है या नहीं”) कोड को देखते हुए ही कुछ सेकंड में जवाब मिल जाते हैं। चेकलिस्ट को रिलीज़ वीक की फायर ड्रिल की तरह नहीं, बल्कि नई स्क्रीन के लिए एक आदत की तरह ट्रीट करें, और यह चेकलिस्ट रहना ही बंद कर देगी।
// संबंधित पठन
जर्नल से और भी
Android का In-App Review API: बिना परेशान किए रेटिंग माँगना
Google के In-App Review API की एक व्यावहारिक गाइड — यह असल में कैसे काम करता है, इसे कब ट्रिगर करना चाहिए, और सामान्य 'हमें रेट करें' पॉपअप आपकी Play Store रेटिंग को चुपचाप कैसे नुकसान पहुँचा रहा है।
Android ऐप शॉर्टकट्स और Quick Settings Tiles: बिना ऐप खोले पानी लॉग करना
Android के डायनामिक ShortcutManager API और TileService की एक व्यावहारिक गाइड — कैसे एक-टैप एक्शन को पूरी तरह ऐप को छोड़कर काम करने दें, साथ ही वे गड़बड़ियाँ जो ज़्यादातर इम्प्लीमेंटेशन को फँसा देती हैं।
2026 में Android पर फोरग्राउंड सर्विस टाइप्स: वह चुनना जो आपके फीचर पर सच में लागू हो
Android के फोरग्राउंड सर्विस टाइप प्रतिबंधों की एक व्यावहारिक गाइड — dataSync, mediaPlayback, specialUse, shortService — और बिना मारे या रिजेक्ट हुए सही वाला कैसे चुनें।