Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[iOS] Fix App crash when use WebView with iOS VoiceOver #52484

Merged
merged 9 commits into from
May 10, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -981,10 +981,6 @@ @implementation FlutterTouchInterceptingView {
fml::scoped_nsobject<DelayingGestureRecognizer> _delayingRecognizer;
FlutterPlatformViewGestureRecognizersBlockingPolicy _blockingPolicy;
UIView* _embeddedView;
// The used as the accessiblityContainer.
// The `accessiblityContainer` is used in UIKit to determine the parent of this accessibility
// node.
NSObject* _flutterAccessibilityContainer;
}
- (instancetype)initWithEmbeddedView:(UIView*)embeddedView
platformViewsController:
Expand Down Expand Up @@ -1063,14 +1059,15 @@ - (void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
}

- (void)setFlutterAccessibilityContainer:(NSObject*)flutterAccessibilityContainer {
_flutterAccessibilityContainer = flutterAccessibilityContainer;
}

- (id)accessibilityContainer {
return _flutterAccessibilityContainer;
}

- (void)dealloc {
[_flutterAccessibilityContainer release];
[super dealloc];
}

@end

@implementation DelayingGestureRecognizer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ class FlutterPlatformViewsController {
- (UIView*)embeddedView;

// Sets flutterAccessibilityContainer as this view's accessibilityContainer.
- (void)setFlutterAccessibilityContainer:(NSObject*)flutterAccessibilityContainer;
@property(nonatomic, retain) id flutterAccessibilityContainer;
@end

@interface UIView (FirstResponder)
Expand Down
5 changes: 2 additions & 3 deletions shell/platform/darwin/ios/framework/Source/SemanticsObject.mm
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,7 @@ - (UIAccessibilityTraits)accessibilityTraits {
@end

@interface FlutterPlatformViewSemanticsContainer ()
@property(nonatomic, retain) UIView* platformView;
@property(nonatomic, assign) UIView* platformView;
@end

@implementation FlutterPlatformViewSemanticsContainer
Expand All @@ -876,14 +876,13 @@ - (instancetype)initWithBridge:(fml::WeakPtr<flutter::AccessibilityBridgeIos>)br
uid:(int32_t)uid
platformView:(nonnull FlutterTouchInterceptingView*)platformView {
if (self = [super initWithBridge:bridge uid:uid]) {
_platformView = [platformView retain];
_platformView = platformView;
[platformView setFlutterAccessibilityContainer:self];
}
return self;
}

- (void)dealloc {
[_platformView release];
_platformView = nil;
Copy link
Contributor

@hellohuanlin hellohuanlin May 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: it's not necessary to nil out the ivar (can remove the whole dealloc method here).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm about to remove this dealloc in #52535, I wouldn't worry about it in this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh actually that's not true, the PR doesn't include SemanticsObject. But I'll get to that one hopefully soon 🙂

[super dealloc];
}
Expand Down
21 changes: 16 additions & 5 deletions shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -994,19 +994,30 @@ - (void)testFlutterPlatformViewSemanticsContainer {
new flutter::testing::MockAccessibilityBridge());
fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
__weak FlutterTouchInterceptingView* weakPlatformView;
__weak FlutterPlatformViewSemanticsContainer* weakContainer;
@autoreleasepool {
FlutterTouchInterceptingView* platformView = [[FlutterTouchInterceptingView alloc] init];
weakPlatformView = platformView;
FlutterPlatformViewSemanticsContainer* container =
[[FlutterPlatformViewSemanticsContainer alloc] initWithBridge:bridge
uid:1
platformView:platformView];
XCTAssertEqualObjects(platformView.accessibilityContainer, container);

@autoreleasepool {
FlutterPlatformViewSemanticsContainer* container =
[[FlutterPlatformViewSemanticsContainer alloc] initWithBridge:bridge
uid:1
platformView:platformView];
weakContainer = container;
XCTAssertEqualObjects(platformView.accessibilityContainer, container);
XCTAssertNotNil(weakPlatformView);
XCTAssertNotNil(weakContainer);
}
// Check the variables are still lived.
// `container` is `retain` in `platformView`, so it will not be nil here.
XCTAssertNotNil(weakPlatformView);
XCTAssertNotNil(weakContainer);
}
// Check if there's no more strong references to `platformView` after container and platformView
// are released.
XCTAssertNil(weakPlatformView);
XCTAssertNil(weakContainer);
}

- (void)testTextInputSemanticsObject {
Expand Down