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

Commit a46b721

Browse files
author
Chris Yang
authored
Add warning message when PlatformView's origin is not 0 (#35501)
1 parent 6cf036c commit a46b721

15 files changed

Lines changed: 117 additions & 78 deletions

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,25 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree {
454454
void FlutterPlatformViewsController::CompositeWithParams(int view_id,
455455
const EmbeddedViewParams& params) {
456456
CGRect frame = CGRectMake(0, 0, params.sizePoints().width(), params.sizePoints().height());
457-
UIView* touchInterceptor = touch_interceptors_[view_id].get();
457+
FlutterTouchInterceptingView* touchInterceptor = touch_interceptors_[view_id].get();
458+
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
459+
FML_DCHECK(CGPointEqualToPoint([touchInterceptor embeddedView].frame.origin, CGPointZero));
460+
if (non_zero_origin_views_.find(view_id) == non_zero_origin_views_.end() &&
461+
!CGPointEqualToPoint([touchInterceptor embeddedView].frame.origin, CGPointZero)) {
462+
non_zero_origin_views_.insert(view_id);
463+
NSLog(
464+
@"A Embedded PlatformView's origin is not CGPointZero.\n"
465+
" View id: %@\n"
466+
" View info: \n %@ \n"
467+
"A non-zero origin might cause undefined behavior.\n"
468+
"See https://github.com/flutter/flutter/issues/109700 for more details.\n"
469+
"If you are the author of the PlatformView, please update the implementation of the "
470+
"PlatformView to have a (0, 0) origin.\n"
471+
"If you have a valid case of using a non-zero origin, "
472+
"please leave a comment at https://github.com/flutter/flutter/issues/109700 with details.",
473+
@(view_id), [touchInterceptor embeddedView]);
474+
}
475+
#endif
458476
touchInterceptor.layer.transform = CATransform3DIdentity;
459477
touchInterceptor.frame = frame;
460478
touchInterceptor.alpha = 1;

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,14 @@ class FlutterPlatformViewsController {
307307

308308
// WeakPtrFactory must be the last member.
309309
std::unique_ptr<fml::WeakPtrFactory<FlutterPlatformViewsController>> weak_factory_;
310+
311+
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
312+
// A set to keep track of embedded views that does not have (0, 0) origin.
313+
// An insertion triggers a warning message about non-zero origin logged on the debug console.
314+
// See https://github.com/flutter/flutter/issues/109700 for details.
315+
std::unordered_set<int64_t> non_zero_origin_views_;
316+
#endif
317+
310318
FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewsController);
311319
};
312320

testing/scenario_app/ios/Scenarios/Scenarios/TextPlatformView.m

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ @interface TextPlatformView () <TestGestureRecognizerDelegate>
6565
@end
6666

6767
@implementation TextPlatformView {
68+
UIView* _containerView;
6869
UITextView* _textView;
6970
FlutterMethodChannel* _channel;
7071
BOOL _viewCreated;
@@ -75,18 +76,26 @@ - (instancetype)initWithFrame:(CGRect)frame
7576
arguments:(id _Nullable)args
7677
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
7778
if ([super init]) {
78-
_textView = [[UITextView alloc] initWithFrame:CGRectMake(50.0, 50.0, 250.0, 100.0)];
79-
_textView.textColor = UIColor.blueColor;
79+
_containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 250, 100)];
80+
_containerView.backgroundColor = UIColor.lightGrayColor;
81+
_containerView.clipsToBounds = YES;
82+
_containerView.accessibilityIdentifier = @"platform_view";
83+
84+
_textView = [[UITextView alloc] initWithFrame:CGRectMake(50.0, 50.0, 250, 100)];
8085
_textView.backgroundColor = UIColor.lightGrayColor;
86+
_textView.textColor = UIColor.blueColor;
8187
[_textView setFont:[UIFont systemFontOfSize:52]];
8288
_textView.text = args;
83-
_textView.accessibilityIdentifier = @"platform_view";
89+
_textView.autoresizingMask =
90+
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
91+
[_containerView addSubview:_textView];
8492

8593
TestTapGestureRecognizer* gestureRecognizer =
8694
[[TestTapGestureRecognizer alloc] initWithTarget:self action:@selector(platformViewTapped)];
8795

8896
[_textView addGestureRecognizer:gestureRecognizer];
8997
gestureRecognizer.testTapGestureRecognizerDelegate = self;
98+
9099
_textView.accessibilityLabel = @"";
91100

92101
_viewCreated = NO;
@@ -100,7 +109,7 @@ - (UIView*)view {
100109
abort();
101110
}
102111
_viewCreated = YES;
103-
return _textView;
112+
return _containerView;
104113
}
105114

106115
- (void)platformViewTapped {

testing/scenario_app/ios/Scenarios/ScenariosUITests/PlatformViewGestureRecognizerTests.m

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,25 @@ - (void)testRejectPolicyUtilTouchesEnded {
2828
XCUIElement* element = evaluatedObject;
2929
return [element.identifier hasPrefix:@"platform_view"];
3030
}];
31-
XCUIElement* platformView = [app.textViews elementMatchingPredicate:predicateToFindPlatformView];
32-
if (![platformView waitForExistenceWithTimeout:kSecondsToWaitForPlatformView]) {
31+
XCUIElement* textView =
32+
[app.otherElements elementMatchingPredicate:predicateToFindPlatformView].textViews.firstMatch;
33+
if (![textView waitForExistenceWithTimeout:kSecondsToWaitForPlatformView]) {
3334
NSLog(@"%@", app.debugDescription);
34-
XCTFail(@"Failed due to not able to find any platformView with %@ seconds",
35+
XCTFail(@"Failed due to not able to find any textView with %@ seconds",
3536
@(kSecondsToWaitForPlatformView));
3637
}
3738

38-
XCTAssertNotNil(platformView);
39-
XCTAssertEqualObjects(platformView.label, @"");
39+
XCTAssertNotNil(textView);
40+
XCTAssertEqualObjects(textView.label, @"");
4041

4142
NSPredicate* predicate =
4243
[NSPredicate predicateWithFormat:@"label == %@", @"-gestureTouchesBegan-gestureTouchesEnded"];
4344
XCTNSPredicateExpectation* exception =
44-
[[XCTNSPredicateExpectation alloc] initWithPredicate:predicate object:platformView];
45+
[[XCTNSPredicateExpectation alloc] initWithPredicate:predicate object:textView];
4546

46-
[platformView tap];
47+
[textView tap];
4748
[self waitForExpectations:@[ exception ] timeout:kSecondsToWaitForPlatformView];
48-
XCTAssertEqualObjects(platformView.label, @"-gestureTouchesBegan-gestureTouchesEnded");
49+
XCTAssertEqualObjects(textView.label, @"-gestureTouchesBegan-gestureTouchesEnded");
4950
}
5051

5152
- (void)testRejectPolicyEager {
@@ -59,15 +60,16 @@ - (void)testRejectPolicyEager {
5960
XCUIElement* element = evaluatedObject;
6061
return [element.identifier hasPrefix:@"platform_view"];
6162
}];
62-
XCUIElement* platformView = [app.textViews elementMatchingPredicate:predicateToFindPlatformView];
63-
if (![platformView waitForExistenceWithTimeout:kSecondsToWaitForPlatformView]) {
63+
XCUIElement* textView =
64+
[app.otherElements elementMatchingPredicate:predicateToFindPlatformView].textViews.firstMatch;
65+
if (![textView waitForExistenceWithTimeout:kSecondsToWaitForPlatformView]) {
6466
NSLog(@"%@", app.debugDescription);
65-
XCTFail(@"Failed due to not able to find any platformView with %@ seconds",
67+
XCTFail(@"Failed due to not able to find any textView with %@ seconds",
6668
@(kSecondsToWaitForPlatformView));
6769
}
6870

69-
XCTAssertNotNil(platformView);
70-
XCTAssertEqualObjects(platformView.label, @"");
71+
XCTAssertNotNil(textView);
72+
XCTAssertEqualObjects(textView.label, @"");
7173

7274
NSPredicate* predicate =
7375
[NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject,
@@ -76,11 +78,11 @@ - (void)testRejectPolicyEager {
7678
return [view.label containsString:@"-gestureTouchesBegan"];
7779
}];
7880
XCTNSPredicateExpectation* exception =
79-
[[XCTNSPredicateExpectation alloc] initWithPredicate:predicate object:platformView];
81+
[[XCTNSPredicateExpectation alloc] initWithPredicate:predicate object:textView];
8082

81-
[platformView tap];
83+
[textView tap];
8284
[self waitForExpectations:@[ exception ] timeout:kSecondsToWaitForPlatformView];
83-
XCTAssertTrue([platformView.label containsString:@"-gestureTouchesBegan"]);
85+
XCTAssertTrue([textView.label containsString:@"-gestureTouchesBegan"]);
8486
}
8587

8688
- (void)testAccept {
@@ -94,26 +96,27 @@ - (void)testAccept {
9496
XCUIElement* element = evaluatedObject;
9597
return [element.identifier hasPrefix:@"platform_view"];
9698
}];
97-
XCUIElement* platformView = [app.textViews elementMatchingPredicate:predicateToFindPlatformView];
98-
if (![platformView waitForExistenceWithTimeout:kSecondsToWaitForPlatformView]) {
99+
XCUIElement* textView =
100+
[app.otherElements elementMatchingPredicate:predicateToFindPlatformView].textViews.firstMatch;
101+
if (![textView waitForExistenceWithTimeout:kSecondsToWaitForPlatformView]) {
99102
NSLog(@"%@", app.debugDescription);
100-
XCTFail(@"Failed due to not able to find any platformView with %@ seconds",
103+
XCTFail(@"Failed due to not able to find any textView with %@ seconds",
101104
@(kSecondsToWaitForPlatformView));
102105
}
103106

104-
XCTAssertNotNil(platformView);
105-
XCTAssertEqualObjects(platformView.label, @"");
107+
XCTAssertNotNil(textView);
108+
XCTAssertEqualObjects(textView.label, @"");
106109

107110
NSPredicate* predicate = [NSPredicate
108111
predicateWithFormat:@"label == %@",
109112
@"-gestureTouchesBegan-gestureTouchesEnded-platformViewTapped"];
110113
XCTNSPredicateExpectation* exception =
111-
[[XCTNSPredicateExpectation alloc] initWithPredicate:predicate object:platformView];
114+
[[XCTNSPredicateExpectation alloc] initWithPredicate:predicate object:textView];
112115

113-
[platformView tap];
116+
[textView tap];
114117

115118
[self waitForExpectations:@[ exception ] timeout:kSecondsToWaitForPlatformView];
116-
XCTAssertEqualObjects(platformView.label,
119+
XCTAssertEqualObjects(textView.label,
117120
@"-gestureTouchesBegan-gestureTouchesEnded-platformViewTapped");
118121
}
119122

@@ -128,30 +131,31 @@ - (void)testGestureWithMaskViewBlockingPlatformView {
128131
XCUIElement* element = evaluatedObject;
129132
return [element.identifier hasPrefix:@"platform_view"];
130133
}];
131-
XCUIElement* platformView = [app.textViews elementMatchingPredicate:predicateToFindPlatformView];
132-
if (![platformView waitForExistenceWithTimeout:kSecondsToWaitForPlatformView]) {
134+
XCUIElement* textView =
135+
[app.otherElements elementMatchingPredicate:predicateToFindPlatformView].textViews.firstMatch;
136+
if (![textView waitForExistenceWithTimeout:kSecondsToWaitForPlatformView]) {
133137
NSLog(@"%@", app.debugDescription);
134138
XCTFail(@"Failed due to not able to find any platformView with %@ seconds",
135139
@(kSecondsToWaitForPlatformView));
136140
}
137141

138-
XCTAssertNotNil(platformView);
139-
XCTAssertEqualObjects(platformView.label, @"");
142+
XCTAssertNotNil(textView);
143+
XCTAssertEqualObjects(textView.label, @"");
140144

141145
NSPredicate* predicate = [NSPredicate
142146
predicateWithFormat:@"label == %@",
143147
@"-gestureTouchesBegan-gestureTouchesEnded-platformViewTapped"];
144148
XCTNSPredicateExpectation* exception =
145-
[[XCTNSPredicateExpectation alloc] initWithPredicate:predicate object:platformView];
149+
[[XCTNSPredicateExpectation alloc] initWithPredicate:predicate object:textView];
146150

147151
XCUICoordinate* coordinate =
148152
[self getNormalizedCoordinate:app
149-
point:CGVectorMake(platformView.frame.origin.x + 10,
150-
platformView.frame.origin.y + 10)];
153+
point:CGVectorMake(textView.frame.origin.x + 10,
154+
textView.frame.origin.y + 10)];
151155
[coordinate tap];
152156

153157
[self waitForExpectations:@[ exception ] timeout:kSecondsToWaitForPlatformView];
154-
XCTAssertEqualObjects(platformView.label,
158+
XCTAssertEqualObjects(textView.label,
155159
@"-gestureTouchesBegan-gestureTouchesEnded-platformViewTapped");
156160
}
157161

0 commit comments

Comments
 (0)