From ee103a5a08ebd8c783c5dfcb98af393f50e1e51b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E6=B4=B5=E9=94=8B?= Date: Wed, 22 Nov 2023 18:49:13 -0600 Subject: [PATCH 1/3] Fix not being able to hide iOS status bar via setEnabledSystemUIMode (#48271) Fix https://github.com/flutter/flutter/issues/138604 and https://github.com/flutter/flutter/issues/138671 Related PR https://github.com/flutter/engine/pull/45351 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style (cherry picked from commit bec0dacaae419e798056f2eebdf9b69e80c252df) --- .../framework/Source/FlutterPlatformPlugin.mm | 4 +- .../Source/FlutterPlatformPluginTest.mm | 89 +++++++++++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm index 722571bda0a03..2b007974afe89 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm @@ -41,7 +41,7 @@ using namespace flutter; static void SetStatusBarHiddenForSharedApplication(BOOL hidden) { -#if APPLICATION_EXTENSION_API_ONLY +#if not APPLICATION_EXTENSION_API_ONLY [UIApplication sharedApplication].statusBarHidden = hidden; #else FML_LOG(WARNING) << "Application based status bar styling is not available in app extension."; @@ -49,7 +49,7 @@ static void SetStatusBarHiddenForSharedApplication(BOOL hidden) { } static void SetStatusBarStyleForSharedApplication(UIStatusBarStyle style) { -#if APPLICATION_EXTENSION_API_ONLY +#if not APPLICATION_EXTENSION_API_ONLY // Note: -[UIApplication setStatusBarStyle] is deprecated in iOS9 // in favor of delegating to the view controller. [[UIApplication sharedApplication] setStatusBarStyle:style]; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm index 73cc460b351f3..cd600c6724e5e 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm @@ -368,4 +368,93 @@ - (void)testViewControllerBasedStatusBarHiddenUpdate { [bundleMock stopMocking]; } +- (void)testStatusBarHiddenUpdate { + id bundleMock = OCMPartialMock([NSBundle mainBundle]); + OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"]) + .andReturn(@NO); + id mockApplication = OCMClassMock([UIApplication class]); + OCMStub([mockApplication sharedApplication]).andReturn(mockApplication); + + // Enabling system UI overlays to update status bar. + FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; + [engine runWithEntrypoint:nil]; + FlutterViewController* flutterViewController = + [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; + std::unique_ptr> _weakFactory = + std::make_unique>(engine); + + // Update to hidden. + FlutterPlatformPlugin* plugin = [engine platformPlugin]; + + XCTestExpectation* enableSystemUIOverlaysCalled = + [self expectationWithDescription:@"setEnabledSystemUIOverlays"]; + FlutterResult resultSet = ^(id result) { + [enableSystemUIOverlaysCalled fulfill]; + }; + FlutterMethodCall* methodCallSet = + [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays" + arguments:@[ @"SystemUiOverlay.bottom" ]]; + [plugin handleMethodCall:methodCallSet result:resultSet]; + [self waitForExpectationsWithTimeout:1 handler:nil]; +#if not APPLICATION_EXTENSION_API_ONLY + OCMVerify([mockApplication setStatusBarHidden:YES]); +#endif + + // Update to shown. + XCTestExpectation* enableSystemUIOverlaysCalled2 = + [self expectationWithDescription:@"setEnabledSystemUIOverlays"]; + FlutterResult resultSet2 = ^(id result) { + [enableSystemUIOverlaysCalled2 fulfill]; + }; + FlutterMethodCall* methodCallSet2 = + [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setEnabledSystemUIOverlays" + arguments:@[ @"SystemUiOverlay.top" ]]; + [plugin handleMethodCall:methodCallSet2 result:resultSet2]; + [self waitForExpectationsWithTimeout:1 handler:nil]; +#if not APPLICATION_EXTENSION_API_ONLY + OCMVerify([mockApplication setStatusBarHidden:NO]); +#endif + + [flutterViewController deregisterNotifications]; + [mockApplication stopMocking]; + [bundleMock stopMocking]; +} + +- (void)testStatusBarStyle { + id bundleMock = OCMPartialMock([NSBundle mainBundle]); + OCMStub([bundleMock objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"]) + .andReturn(@NO); + id mockApplication = OCMClassMock([UIApplication class]); + OCMStub([mockApplication sharedApplication]).andReturn(mockApplication); + + FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; + [engine runWithEntrypoint:nil]; + FlutterViewController* flutterViewController = + [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; + std::unique_ptr> _weakFactory = + std::make_unique>(engine); + XCTAssertFalse(flutterViewController.prefersStatusBarHidden); + + FlutterPlatformPlugin* plugin = [engine platformPlugin]; + + XCTestExpectation* enableSystemUIModeCalled = + [self expectationWithDescription:@"setSystemUIOverlayStyle"]; + FlutterResult resultSet = ^(id result) { + [enableSystemUIModeCalled fulfill]; + }; + FlutterMethodCall* methodCallSet = + [FlutterMethodCall methodCallWithMethodName:@"SystemChrome.setSystemUIOverlayStyle" + arguments:@{@"statusBarBrightness" : @"Brightness.dark"}]; + [plugin handleMethodCall:methodCallSet result:resultSet]; + [self waitForExpectationsWithTimeout:1 handler:nil]; + +#if not APPLICATION_EXTENSION_API_ONLY + OCMVerify([mockApplication setStatusBarStyle:UIStatusBarStyleLightContent]); +#endif + + [flutterViewController deregisterNotifications]; + [mockApplication stopMocking]; + [bundleMock stopMocking]; +} + @end From 07965ac1a0f88a439a550396b9ff5f7197ec535f Mon Sep 17 00:00:00 2001 From: LinXunFeng Date: Tue, 28 Nov 2023 00:31:56 +0800 Subject: [PATCH 2/3] Replace WeakNSObjectFactory with WeakPtrFactory --- .../ios/framework/Source/FlutterPlatformPluginTest.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm index cd600c6724e5e..b5bca32fad0dc 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm @@ -380,8 +380,8 @@ - (void)testStatusBarHiddenUpdate { [engine runWithEntrypoint:nil]; FlutterViewController* flutterViewController = [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; - std::unique_ptr> _weakFactory = - std::make_unique>(engine); + std::unique_ptr> _weakFactory = + std::make_unique>(engine); // Update to hidden. FlutterPlatformPlugin* plugin = [engine platformPlugin]; @@ -431,8 +431,8 @@ - (void)testStatusBarStyle { [engine runWithEntrypoint:nil]; FlutterViewController* flutterViewController = [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; - std::unique_ptr> _weakFactory = - std::make_unique>(engine); + std::unique_ptr> _weakFactory = + std::make_unique>(engine); XCTAssertFalse(flutterViewController.prefersStatusBarHidden); FlutterPlatformPlugin* plugin = [engine platformPlugin]; From ac20104288a66b83b8f3e09729d86d472823f5c8 Mon Sep 17 00:00:00 2001 From: LinXunFeng Date: Wed, 29 Nov 2023 11:26:36 +0800 Subject: [PATCH 3/3] Adding autorelease --- .../ios/framework/Source/FlutterPlatformPluginTest.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm index b5bca32fad0dc..5736d4c5619e9 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm @@ -376,10 +376,10 @@ - (void)testStatusBarHiddenUpdate { OCMStub([mockApplication sharedApplication]).andReturn(mockApplication); // Enabling system UI overlays to update status bar. - FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; + FlutterEngine* engine = [[[FlutterEngine alloc] initWithName:@"test" project:nil] autorelease]; [engine runWithEntrypoint:nil]; FlutterViewController* flutterViewController = - [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; + [[[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil] autorelease]; std::unique_ptr> _weakFactory = std::make_unique>(engine); @@ -427,10 +427,10 @@ - (void)testStatusBarStyle { id mockApplication = OCMClassMock([UIApplication class]); OCMStub([mockApplication sharedApplication]).andReturn(mockApplication); - FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; + FlutterEngine* engine = [[[FlutterEngine alloc] initWithName:@"test" project:nil] autorelease]; [engine runWithEntrypoint:nil]; FlutterViewController* flutterViewController = - [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; + [[[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil] autorelease]; std::unique_ptr> _weakFactory = std::make_unique>(engine); XCTAssertFalse(flutterViewController.prefersStatusBarHidden);