diff --git a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn index 37290b9f827..d9f008ff2a4 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn +++ b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn @@ -255,6 +255,7 @@ shared_library("ios_test_flutter") { ":ios_gpu_configuration", ":ios_test_flutter_mrc", "//flutter/common:common", + "//flutter/lib/ui:ui", "//flutter/shell/platform/darwin/common:framework_shared", "//flutter/shell/platform/embedder:embedder_as_internal_library", "//flutter/third_party/tonic", diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 905fcc0dd67..da09c2d8aca 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -641,7 +641,9 @@ static void sendFakeTouchEvent(FlutterEngine* engine, _engineNeedsLaunch = NO; } - [_engine.get() attachView]; + if ([_engine.get() viewController] == self) { + [_engine.get() attachView]; + } if (@available(iOS 13.4, *)) { _pointerInteraction.reset([[UIPointerInteraction alloc] initWithDelegate:self]); @@ -1005,7 +1007,9 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch) #pragma mark - Handle view resizing - (void)updateViewportMetrics { - [_engine.get() updateViewportMetrics:_viewportMetrics]; + if ([_engine.get() viewController] == self) { + [_engine.get() updateViewportMetrics:_viewportMetrics]; + } } - (CGFloat)statusBarPadding { diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm index 5cb96fd35d7..4cac7322b0e 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm @@ -5,6 +5,7 @@ #import #import +#import "flutter/lib/ui/window/viewport_metrics.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" @@ -67,6 +68,8 @@ class PointerDataPacket {}; libraryURI:(NSString*)libraryURI initialRoute:(NSString*)initialRoute; - (void)dispatchPointerDataPacket:(std::unique_ptr)packet; +- (void)updateViewportMetrics:(flutter::ViewportMetrics)viewportMetrics; +- (void)attachView; @end @interface FlutterEngine (TestLowMemory) @@ -115,6 +118,7 @@ typedef enum UIAccessibilityContrast : NSInteger { - (void)handlePressEvent:(FlutterUIPressProxy*)press nextAction:(void (^)())next API_AVAILABLE(ios(13.4)); - (void)scrollEvent:(UIPanGestureRecognizer*)recognizer; +- (void)updateViewportMetrics; @end @interface FlutterViewControllerTest : XCTestCase @@ -177,6 +181,63 @@ typedef enum UIAccessibilityContrast : NSInteger { XCTAssertNil(weakViewController); } +- (void)testUpdateViewportMetricsDoesntInvokeEngineWhenNotTheViewController { + FlutterEngine* mockEngine = OCMPartialMock([[FlutterEngine alloc] init]); + [mockEngine createShell:@"" libraryURI:@"" initialRoute:nil]; + FlutterViewController* viewControllerA = [[FlutterViewController alloc] initWithEngine:mockEngine + nibName:nil + bundle:nil]; + mockEngine.viewController = nil; + FlutterViewController* viewControllerB = [[FlutterViewController alloc] initWithEngine:mockEngine + nibName:nil + bundle:nil]; + mockEngine.viewController = viewControllerB; + [viewControllerA updateViewportMetrics]; + flutter::ViewportMetrics viewportMetrics; + OCMVerify(never(), [mockEngine updateViewportMetrics:viewportMetrics]); +} + +- (void)testUpdateViewportMetricsDoesInvokeEngineWhenIsTheViewController { + FlutterEngine* mockEngine = OCMPartialMock([[FlutterEngine alloc] init]); + [mockEngine createShell:@"" libraryURI:@"" initialRoute:nil]; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:mockEngine + nibName:nil + bundle:nil]; + mockEngine.viewController = viewController; + [viewController updateViewportMetrics]; + flutter::ViewportMetrics viewportMetrics; + OCMVerify([mockEngine updateViewportMetrics:viewportMetrics]); +} + +- (void)testViewDidLoadDoesntInvokeEngineWhenNotTheViewController { + FlutterEngine* mockEngine = OCMPartialMock([[FlutterEngine alloc] init]); + [mockEngine createShell:@"" libraryURI:@"" initialRoute:nil]; + FlutterViewController* viewControllerA = [[FlutterViewController alloc] initWithEngine:mockEngine + nibName:nil + bundle:nil]; + mockEngine.viewController = nil; + FlutterViewController* viewControllerB = [[FlutterViewController alloc] initWithEngine:mockEngine + nibName:nil + bundle:nil]; + mockEngine.viewController = viewControllerB; + UIView* view = viewControllerA.view; + XCTAssertNotNil(view); + OCMVerify(never(), [mockEngine attachView]); +} + +- (void)testViewDidLoadDoesInvokeEngineWhenIsTheViewController { + FlutterEngine* mockEngine = OCMPartialMock([[FlutterEngine alloc] init]); + [mockEngine createShell:@"" libraryURI:@"" initialRoute:nil]; + mockEngine.viewController = nil; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:mockEngine + nibName:nil + bundle:nil]; + mockEngine.viewController = viewController; + UIView* view = viewController.view; + XCTAssertNotNil(view); + OCMVerify([mockEngine attachView]); +} + - (void)testBinaryMessenger { FlutterViewController* vc = [[FlutterViewController alloc] initWithEngine:self.mockEngine nibName:nil