Skip to content

Commit 359596b

Browse files
author
Chris Yang
committed
[ios] Link PlatformView back to semantics tree (flutter#46471)
The PlatformView does not have a semantics container when added to semantics tree, this PR gives it a semantics container to ensure accessibility traversal works. This fixes flutter/flutter#135504, which is a regression of flutter@b8332e3 Before flutter@b8332e3, the traversal works because the PlatformView is added to the accessibilityElements of the FlutterPlatFormViewSemanticsContainer, which implicitly made the FlutterPlatFormViewSemanticsContainer as the PlatformVIew's AccessibilityContainer. Now we use the PlatformVIew as the nativeAccessibility of the FlutterPlatFormViewSemanticsContainer, we need to expilicitly set the container. This needs to be cherry-picked since the commit caused the regression was cherry-picked in flutter@b8332e3 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 050b907 commit 359596b

12 files changed

+260
-168
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2633,6 +2633,7 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextI
26332633
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.h + ../../../flutter/LICENSE
26342634
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.mm + ../../../flutter/LICENSE
26352635
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelayTest.mm + ../../../flutter/LICENSE
2636+
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTouchInterceptingView_Test.h + ../../../flutter/LICENSE
26362637
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUIPressProxy.h + ../../../flutter/LICENSE
26372638
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUIPressProxy.mm + ../../../flutter/LICENSE
26382639
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUmbrellaImport.m + ../../../flutter/LICENSE
@@ -2654,6 +2655,14 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/KeyCodeMap_I
26542655
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h + ../../../flutter/LICENSE
26552656
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm + ../../../flutter/LICENSE
26562657
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm + ../../../flutter/LICENSE
2658+
<<<<<<< HEAD
2659+
=======
2660+
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h + ../../../flutter/LICENSE
2661+
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest_mrc.mm + ../../../flutter/LICENSE
2662+
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/UIViewController+FlutterScreenAndSceneIfLoaded.h + ../../../flutter/LICENSE
2663+
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/UIViewController+FlutterScreenAndSceneIfLoaded.mm + ../../../flutter/LICENSE
2664+
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/UIViewController_FlutterScreenAndSceneIfLoadedTest.mm + ../../../flutter/LICENSE
2665+
>>>>>>> 250daadbca ([ios] Link PlatformView back to semantics tree (#46471))
26572666
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/VsyncWaiterIosTest.mm + ../../../flutter/LICENSE
26582667
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h + ../../../flutter/LICENSE
26592668
ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm + ../../../flutter/LICENSE
@@ -5328,6 +5337,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInp
53285337
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.h
53295338
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.mm
53305339
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelayTest.mm
5340+
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTouchInterceptingView_Test.h
53315341
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUIPressProxy.h
53325342
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUIPressProxy.mm
53335343
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUmbrellaImport.m
@@ -5349,6 +5359,8 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/KeyCodeMap_Int
53495359
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h
53505360
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm
53515361
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm
5362+
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTestMocks.h
5363+
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest_mrc.mm
53525364
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/VsyncWaiterIosTest.mm
53535365
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h
53545366
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm

shell/platform/darwin/ios/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,11 @@ source_set("ios_test_flutter_mrc") {
225225
"framework/Source/FlutterEngineTest_mrc.mm",
226226
"framework/Source/FlutterPlatformPluginTest.mm",
227227
"framework/Source/FlutterPlatformViewsTest.mm",
228+
"framework/Source/FlutterTouchInterceptingView_Test.h",
228229
"framework/Source/FlutterViewControllerTest_mrc.mm",
229230
"framework/Source/FlutterViewTest.mm",
231+
"framework/Source/SemanticsObjectTestMocks.h",
232+
"framework/Source/SemanticsObjectTest_mrc.mm",
230233
"framework/Source/VsyncWaiterIosTest.mm",
231234
"framework/Source/accessibility_bridge_test.mm",
232235
"platform_message_handler_ios_test.mm",

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,10 +407,15 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect,
407407
}
408408

409409
UIView* FlutterPlatformViewsController::GetPlatformViewByID(int64_t view_id) {
410+
return [GetFlutterTouchInterceptingViewByID(view_id) embeddedView];
411+
}
412+
413+
FlutterTouchInterceptingView* FlutterPlatformViewsController::GetFlutterTouchInterceptingViewByID(
414+
int64_t view_id) {
410415
if (views_.empty()) {
411416
return nil;
412417
}
413-
return [touch_interceptors_[view_id].get() embeddedView];
418+
return touch_interceptors_[view_id].get();
414419
}
415420

416421
long FlutterPlatformViewsController::FindFirstResponderPlatformViewId() {
@@ -958,6 +963,10 @@ @implementation FlutterTouchInterceptingView {
958963
fml::scoped_nsobject<DelayingGestureRecognizer> _delayingRecognizer;
959964
FlutterPlatformViewGestureRecognizersBlockingPolicy _blockingPolicy;
960965
UIView* _embeddedView;
966+
// The used as the accessiblityContainer.
967+
// The `accessiblityContainer` is used in UIKit to determine the parent of this accessibility
968+
// node.
969+
NSObject* _flutterAccessibilityContainer;
961970
}
962971
- (instancetype)initWithEmbeddedView:(UIView*)embeddedView
963972
platformViewsController:
@@ -1036,6 +1045,14 @@ - (void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
10361045
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
10371046
}
10381047

1048+
- (void)setFlutterAccessibilityContainer:(NSObject*)flutterAccessibilityContainer {
1049+
_flutterAccessibilityContainer = flutterAccessibilityContainer;
1050+
}
1051+
1052+
- (id)accessibilityContainer {
1053+
return _flutterAccessibilityContainer;
1054+
}
1055+
10391056
@end
10401057

10411058
@implementation DelayingGestureRecognizer {

shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h"
1212
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
1313
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
14+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTouchInterceptingView_Test.h"
1415
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h"
1516
#import "flutter/shell/platform/darwin/ios/platform_view_ios.h"
1617

@@ -3098,4 +3099,12 @@ - (void)testOnlyPlatformViewsAreRemovedWhenReset {
30983099
XCTAssertEqual(mockFlutterView.subviews.firstObject, someView);
30993100
}
31003101

3102+
- (void)testFlutterTouchInterceptingViewLinksToAccessibilityContainer {
3103+
FlutterTouchInterceptingView* touchInteceptorView =
3104+
[[[FlutterTouchInterceptingView alloc] init] autorelease];
3105+
NSObject* container = [[[NSObject alloc] init] autorelease];
3106+
[touchInteceptorView setFlutterAccessibilityContainer:container];
3107+
XCTAssertEqualObjects([touchInteceptorView accessibilityContainer], container);
3108+
}
3109+
31013110
@end

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h"
1414
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h"
1515
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h"
16+
#import "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h"
1617
#import "flutter/shell/platform/darwin/ios/ios_context.h"
1718
#include "third_party/skia/include/core/SkPictureRecorder.h"
1819

@@ -232,10 +233,17 @@ class FlutterPlatformViewsController {
232233
// Returns the `FlutterPlatformView`'s `view` object associated with the view_id.
233234
//
234235
// If the `FlutterPlatformViewsController` does not contain any `FlutterPlatformView` object or
235-
// a `FlutterPlatformView` object asscociated with the view_id cannot be found, the method
236+
// a `FlutterPlatformView` object associated with the view_id cannot be found, the method
236237
// returns nil.
237238
UIView* GetPlatformViewByID(int64_t view_id);
238239

240+
// Returns the `FlutterTouchInterceptingView` with the view_id.
241+
//
242+
// If the `FlutterPlatformViewsController` does not contain any `FlutterPlatformView` object or
243+
// a `FlutterPlatformView` object associated with the view_id cannot be found, the method
244+
// returns nil.
245+
FlutterTouchInterceptingView* GetFlutterTouchInterceptingViewByID(int64_t view_id);
246+
239247
PostPrerollResult PostPrerollAction(
240248
const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger);
241249

@@ -426,6 +434,9 @@ class FlutterPlatformViewsController {
426434

427435
// Get embedded view
428436
- (UIView*)embeddedView;
437+
438+
// Sets flutterAccessibilityContainer as this view's accessibilityContainer.
439+
- (void)setFlutterAccessibilityContainer:(NSObject*)flutterAccessibilityContainer;
429440
@end
430441

431442
@interface UIView (FirstResponder)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
6+
7+
#ifndef SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_TOUCH_INTERCEPTING_VIEW_TEST_H_
8+
#define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_TOUCH_INTERCEPTING_VIEW_TEST_H_
9+
10+
@interface FlutterTouchInterceptingView (Tests)
11+
- (id)accessibilityContainer;
12+
@end
13+
14+
#endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_TOUCH_INTERCEPTING_VIEW_TESTS_H_

shell/platform/darwin/ios/framework/Source/SemanticsObject.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ constexpr float kScrollExtentMaxForInf = 1000;
1818

1919
@class FlutterCustomAccessibilityAction;
2020
@class FlutterPlatformViewSemanticsContainer;
21+
@class FlutterTouchInterceptingView;
2122

2223
/**
2324
* A node in the iOS semantics tree. This object is a wrapper over a native accessibiliy
@@ -171,7 +172,8 @@ constexpr float kScrollExtentMaxForInf = 1000;
171172

172173
- (instancetype)initWithBridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge
173174
uid:(int32_t)uid
174-
platformView:(UIView*)platformView NS_DESIGNATED_INITIALIZER;
175+
platformView:(FlutterTouchInterceptingView*)platformView
176+
NS_DESIGNATED_INITIALIZER;
175177

176178
@end
177179

shell/platform/darwin/ios/framework/Source/SemanticsObject.mm

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,7 @@ @interface FlutterScrollableSemanticsObject ()
157157
@property(nonatomic, retain) FlutterSemanticsScrollView* scrollView;
158158
@end
159159

160-
@implementation FlutterScrollableSemanticsObject {
161-
fml::scoped_nsobject<SemanticsObjectContainer> _container;
162-
}
160+
@implementation FlutterScrollableSemanticsObject
163161

164162
- (instancetype)initWithBridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge
165163
uid:(int32_t)uid {
@@ -865,9 +863,10 @@ @implementation FlutterPlatformViewSemanticsContainer
865863

866864
- (instancetype)initWithBridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)bridge
867865
uid:(int32_t)uid
868-
platformView:(nonnull UIView*)platformView {
866+
platformView:(nonnull FlutterTouchInterceptingView*)platformView {
869867
if (self = [super initWithBridge:bridge uid:uid]) {
870868
_platformView = [platformView retain];
869+
[platformView setFlutterAccessibilityContainer:self];
871870
}
872871
return self;
873872
}
@@ -882,12 +881,6 @@ - (id)nativeAccessibility {
882881
return _platformView;
883882
}
884883

885-
#pragma mark - UIAccessibilityContainer overrides
886-
887-
- (NSArray*)accessibilityElements {
888-
return @[ _platformView ];
889-
}
890-
891884
@end
892885

893886
@implementation SemanticsObjectContainer {

0 commit comments

Comments
 (0)