-
Notifications
You must be signed in to change notification settings - Fork 24.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix duplicate accessibilityLabels & app crash on iOS #29801
Conversation
I came across this because one of my customer's apps was freezing the UI and crashing after spending ~10 seconds when trying to read the accessibilityLabel of a view with a "particularly complex and dynamic view hierarchy". I'm still not entirely sure what the app was doing, but I believe this will sidestep the issue entirely. I believe this change will also improve both the accessibility and the testability of RN apps, in addition to fixing that crash. This PR supersedes or fixes facebook#21830, facebook#25963, facebook#24113, facebook#24118, appium/appium#10654, possibly facebook#25220, and probably a few other tickets I haven't identified. Also worth mentioning that there is very similar code in https://github.com/facebook/react-native/blob/master/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm#L489-L515 - I haven't dug into that as much, but I suspect it should probably get the same treatment. If anyone wants, I can include it in this PR.
Let calls to accessibilityLabel go directly to the one inherited from the base class. Fixes the behavior for code like this that wouldn't normally call it in the first place. ```objective-c if ([view respondsToSelector:@selector(accessibilityLabel)]) return view.accessibilityLabel; ```
Hi @nfriedly! Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. If you have received this in error or have any questions, please contact us at cla@fb.com. Thanks! |
Base commit: 54e19a6 |
Base commit: 54e19a6 |
I think @rigdern has a context why those functions are needed. |
@shergin Unfortunately, I don't have context on those functions. They've been in
|
I spent some time testing this in the rn-tester app on a real iPhone (it took me a while to realize that VoiceOver just doesn't work in the simulator), and I have to admit that it seems to make a somewhat worse experience there. A lot of "Possible text" statements prefixing things where it would previously just read the text. And occasionally some text is omitted entirely. So this isn't the accessibility improvement I had hoped it would be. My main goal here is to prevent the crash, which obviously impairs accessibility. I think that can be done without a regression in functionality. Here's a couple of ideas I thought of:
What do you guys think? |
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks! |
A couple of quick updates:
I feel like there might be a better way to build the string also - maybe pass in the NSMutableString instead of creating a new one for each view. I'll experiment with the above when I have time, but I'm not sure when that will be now that the immediate pressure is off. |
Summary
I came across this because one of my customer's apps was freezing and crashing when my code tries to read the
accessibilityLabel
of a view containing a chat component. Because the labels are recursively generated from the text content, any sufficiently long chat ends up with all of the parent views having a ridiculously longaccessibilityLabel
.After 10 seconds of non-responsiveness from trying to generate all of this on the UI thread (when backgrounded), iOS decides the app has crashed and force-closes it.
Before this change, every single view in a RN app returned true for the conditional.
I believe this change will also improve both the accessibility and the testability of RN apps, in addition to fixing that crash.
This change also allows for correct behavior with this code:
Before this change, any RCTView could potentially scan its entire tree and return
nil
.After, only RCTViews that actually have an
accessibilityLabel
set will return one, and ones that don't will be skipped by the above code.This PR supersedes or fixes #21830, #25963, #24113, #24118, appium/appium#10654, possibly #25220, and probably a few other tickets I haven't identified.
The changes in this PR are for
RCTView
. It's worth mentioning that there is very similar code inRCTViewComponentView
- I haven't dug into that as much, but I suspect it should probably get the same treatment. If desired, I can include it in this PR.I also haven't yet reviewed the Android side of things to see what happens there, but whatever the case, the same component structure doesn't seem to be leading to crashes in Android.
I might need to change the documentation too.
Changelog
[iOS] [Removed] - Deleted RCTView's accessibilityLabel wrapper and RCTRecursiveAccessibilityLabel, allowing for default native behavior
Test Plan
This is where I need a little help. What's a good way to test this?
I spent a while digging through the RN iOS tests, I can run the tests, and even step through the harness, but I still don't feel like I fully understand what's happening. I don't have a ton of iOS or RN experience, so it may be something obvious, but I'm just not sure what I'm missing.