From 5fb4a538ac34544b7883d272d1ba8617902c2688 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 16 Jun 2022 22:52:19 +0200 Subject: [PATCH] [macos] [NSViewController viewWillAppear] can be called multiple times (#34072) Fixes https://github.com/flutter/flutter/issues/105963 --- .../framework/Source/FlutterViewController.mm | 6 +++++- .../framework/Source/FlutterViewControllerTest.mm | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index 19c9911e03bcf..1badc52346b16 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -429,7 +429,11 @@ - (BOOL)launchEngine { // ViewController as a listener for a keyUp event before it's handled by NSApplication, and should // NOT modify the event to avoid any unexpected behavior. - (void)listenForMetaModifiedKeyUpEvents { - NSAssert(_keyUpMonitor == nil, @"_keyUpMonitor was already created"); + if (_keyUpMonitor != nil) { + // It is possible for [NSViewController viewWillAppear] to be invoked multiple times + // in a row. https://github.com/flutter/flutter/issues/105963 + return; + } FlutterViewController* __weak weakSelf = self; _keyUpMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index 538c29d8fc3ab..7d29c1811b32e 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -22,6 +22,7 @@ - (bool)testKeyEventsAreNotPropagatedIfHandled; - (bool)testFlagsChangedEventsArePropagatedIfNotHandled; - (bool)testKeyboardIsRestartedOnEngineRestart; - (bool)testTrackpadGesturesAreSentToFramework; +- (bool)testViewWillAppearCalledMultipleTimes; + (void)respondFalseForSendEvent:(const FlutterKeyEvent&)event callback:(nullable FlutterKeyEventCallback)callback @@ -134,6 +135,10 @@ + (void)respondFalseForSendEvent:(const FlutterKeyEvent&)event ASSERT_TRUE([[FlutterViewControllerTestObjC alloc] testTrackpadGesturesAreSentToFramework]); } +TEST(FlutterViewControllerTest, testViewWillAppearCalledMultipleTimes) { + ASSERT_TRUE([[FlutterViewControllerTestObjC alloc] testViewWillAppearCalledMultipleTimes]); +} + } // namespace flutter::testing @implementation FlutterViewControllerTestObjC @@ -518,4 +523,14 @@ - (bool)testTrackpadGesturesAreSentToFramework { return true; } +- (bool)testViewWillAppearCalledMultipleTimes { + id engineMock = OCMClassMock([FlutterEngine class]); + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock + nibName:@"" + bundle:nil]; + [viewController viewWillAppear]; + [viewController viewWillAppear]; + return true; +} + @end