Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,18 @@ - (void)releaseGesture {
self.delayingRecognizer.state = UIGestureRecognizerStateFailed;
}

- (BOOL)containsWebView:(UIView*)view {
if ([view isKindOfClass:[WKWebView class]]) {
return YES;
}
for (UIView* subview in view.subviews) {
if ([self containsWebView:subview]) {
return YES;
}
}
return NO;
}

- (void)blockGesture {
switch (_blockingPolicy) {
case FlutterPlatformViewGestureRecognizersBlockingPolicyEager:
Expand All @@ -581,7 +593,7 @@ - (void)blockGesture {
// FlutterPlatformViewGestureRecognizersBlockingPolicyEager, but we should try it if a similar
// issue arises for the other policy.
if (@available(iOS 18.2, *)) {
if ([self.embeddedView isKindOfClass:[WKWebView class]]) {
if ([self containsWebView:self.embeddedView]) {
[self removeGestureRecognizer:self.delayingRecognizer];
[self addGestureRecognizer:self.delayingRecognizer];
Comment on lines 597 to 598
Copy link
Member

Choose a reason for hiding this comment

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

Will this cause problems in the views they are gesturing into that are not WKWebViews?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it is possible. That's something that we need to watch out for. But I highly doubt if it is gonna cause real issues

Copy link
Contributor Author

@hellohuanlin hellohuanlin Dec 12, 2024

Choose a reason for hiding this comment

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

We are talking about an odd of combining:

  1. having a setup with webview + another non-web-view subview that also handles gesture
  2. having a flutter overlay layer on top of this non-web-view subview
  3. User touch the area inside non-web-view subview, but outside of the overlay layer

Then we will have this non-web-view subview receive the extra touch when it's not supposed to.

Then even when this happens, I don't think it is a huge problem.

}
Expand Down
105 changes: 105 additions & 0 deletions shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,46 @@ @implementation FlutterPlatformViewsTestNilFlutterPlatformFactory

@end

@interface FlutterPlatformViewsTestMockWrapperWebView : NSObject <FlutterPlatformView>
@property(nonatomic, strong) UIView* view;
@property(nonatomic, assign) BOOL viewCreated;
@end

@implementation FlutterPlatformViewsTestMockWrapperWebView
- (instancetype)init {
if (self = [super init]) {
_view = [[UIView alloc] init];
[_view addSubview:[[WKWebView alloc] init]];
gMockPlatformView = _view;
_viewCreated = NO;
}
return self;
}

- (UIView*)view {
[self checkViewCreatedOnce];
return _view;
}

- (void)checkViewCreatedOnce {
if (self.viewCreated) {
abort();
}
self.viewCreated = YES;
}
@end

@interface FlutterPlatformViewsTestMockWrapperWebViewFactory : NSObject <FlutterPlatformViewFactory>
@end

@implementation FlutterPlatformViewsTestMockWrapperWebViewFactory
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args {
return [[FlutterPlatformViewsTestMockWrapperWebView alloc] init];
}
@end

namespace flutter {
namespace {
class FlutterPlatformViewsTestMockPlatformViewDelegate : public PlatformView::Delegate {
Expand Down Expand Up @@ -3153,6 +3193,71 @@ - (void)testFlutterPlatformViewTouchesEndedOrTouchesCancelledEventDoesNotFailThe
}
}

- (void)
testFlutterPlatformViewBlockGestureUnderEagerPolicyShouldRemoveAndAddBackDelayingRecognizerForWrapperWebView {
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;

flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
/*platform=*/GetDefaultTaskRunner(),
/*raster=*/GetDefaultTaskRunner(),
/*ui=*/GetDefaultTaskRunner(),
/*io=*/GetDefaultTaskRunner());
FlutterPlatformViewsController* flutterPlatformViewsController =
[[FlutterPlatformViewsController alloc] init];
flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner();
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
/*delegate=*/mock_delegate,
/*rendering_api=*/mock_delegate.settings_.enable_impeller
? flutter::IOSRenderingAPI::kMetal
: flutter::IOSRenderingAPI::kSoftware,
/*platform_views_controller=*/flutterPlatformViewsController,
/*task_runners=*/runners,
/*worker_task_runner=*/nil,
/*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());

FlutterPlatformViewsTestMockWrapperWebViewFactory* factory =
[[FlutterPlatformViewsTestMockWrapperWebViewFactory alloc] init];
[flutterPlatformViewsController
registerViewFactory:factory
withId:@"MockWrapperWebView"
gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager];
FlutterResult result = ^(id result) {
};
[flutterPlatformViewsController
onMethodCall:[FlutterMethodCall
methodCallWithMethodName:@"create"
arguments:@{@"id" : @2, @"viewType" : @"MockWrapperWebView"}]
result:result];

XCTAssertNotNil(gMockPlatformView);

// Find touch inteceptor view
UIView* touchInteceptorView = gMockPlatformView;
while (touchInteceptorView != nil &&
![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
touchInteceptorView = touchInteceptorView.superview;
}
XCTAssertNotNil(touchInteceptorView);

XCTAssert(touchInteceptorView.gestureRecognizers.count == 2);
UIGestureRecognizer* delayingRecognizer = touchInteceptorView.gestureRecognizers[0];
UIGestureRecognizer* forwardingRecognizer = touchInteceptorView.gestureRecognizers[1];

XCTAssert([delayingRecognizer isKindOfClass:[FlutterDelayingGestureRecognizer class]]);
XCTAssert([forwardingRecognizer isKindOfClass:[ForwardingGestureRecognizer class]]);

[(FlutterTouchInterceptingView*)touchInteceptorView blockGesture];

if (@available(iOS 18.2, *)) {
// Since we remove and add back delayingRecognizer, it would be reordered to the last.
XCTAssertEqual(touchInteceptorView.gestureRecognizers[0], forwardingRecognizer);
XCTAssertEqual(touchInteceptorView.gestureRecognizers[1], delayingRecognizer);
} else {
XCTAssertEqual(touchInteceptorView.gestureRecognizers[0], delayingRecognizer);
XCTAssertEqual(touchInteceptorView.gestureRecognizers[1], forwardingRecognizer);
}
}

- (void)
testFlutterPlatformViewBlockGestureUnderEagerPolicyShouldNotRemoveAndAddBackDelayingRecognizerForNonWebView {
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
Expand Down
Loading