diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 204dba1c6b2db..d72fdfca9f9f5 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -204,6 +204,10 @@ - (void)setViewController:(FlutterViewController*)viewController { } } +- (void)attachView { + self.iosPlatformView->attachView(); +} + - (void)setFlutterViewControllerWillDeallocObserver:(id)observer { if (observer != _flutterViewControllerWillDeallocObserver) { if (_flutterViewControllerWillDeallocObserver) { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h index 573333ea732e6..277950f9d68d0 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h @@ -44,6 +44,7 @@ - (FlutterTextInputPlugin*)textInputPlugin; - (void)launchEngine:(NSString*)entrypoint libraryURI:(NSString*)libraryOrNil; - (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryOrNil; +- (void)attachView; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 1e082ec4ebd97..6a03171e2dce8 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -441,8 +441,8 @@ - (void)surfaceUpdated:(BOOL)appeared { #pragma mark - UIViewController lifecycle notifications -- (void)viewWillAppear:(BOOL)animated { - TRACE_EVENT0("flutter", "viewWillAppear"); +- (void)viewDidLoad { + TRACE_EVENT0("flutter", "viewDidLoad"); if (_engineNeedsLaunch) { [_engine.get() launchEngine:nil libraryURI:nil]; @@ -450,6 +450,16 @@ - (void)viewWillAppear:(BOOL)animated { _engineNeedsLaunch = NO; } + FML_DCHECK([_engine.get() viewController] != nil) + << "FlutterViewController::viewWillAppear:AttachView ViewController was nil"; + [_engine.get() attachView]; + + [super viewDidLoad]; +} + +- (void)viewWillAppear:(BOOL)animated { + TRACE_EVENT0("flutter", "viewWillAppear"); + // Send platform settings to Flutter, e.g., platform brightness. [self onUserSettingsChanged:nil]; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.m b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.m index 31c2bcc077706..09ef7baa023fb 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.m +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.m @@ -11,6 +11,10 @@ FLUTTER_ASSERT_ARC +@interface FlutterEngine () +- (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI; +@end + extern NSNotificationName const FlutterViewControllerWillDealloc; /// A simple mock class for FlutterEngine. @@ -457,4 +461,16 @@ - (void)testWillDeallocNotification { [self waitForExpectations:@[ expectation ] timeout:1.0]; } +- (void)testDoesntLoadViewInInit { + XCTestExpectation* expectation = + [[XCTestExpectation alloc] initWithDescription:@"notification called"]; + FlutterDartProject* project = [[FlutterDartProject alloc] init]; + FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project]; + [engine createShell:@"" libraryURI:@""]; + FlutterViewController* realVC = [[FlutterViewController alloc] initWithEngine:engine + nibName:nil + bundle:nil]; + XCTAssertFalse([realVC isViewLoaded], @"shouldn't have loaded since it hasn't been shown"); +} + @end diff --git a/shell/platform/darwin/ios/platform_view_ios.h b/shell/platform/darwin/ios/platform_view_ios.h index d4cc7b8c519bb..00e9130f70142 100644 --- a/shell/platform/darwin/ios/platform_view_ios.h +++ b/shell/platform/darwin/ios/platform_view_ios.h @@ -34,6 +34,7 @@ class PlatformViewIOS final : public PlatformView { fml::WeakPtr GetOwnerViewController() const; void SetOwnerViewController(fml::WeakPtr owner_controller); + void attachView(); void RegisterExternalTexture(int64_t id, NSObject* texture); diff --git a/shell/platform/darwin/ios/platform_view_ios.mm b/shell/platform/darwin/ios/platform_view_ios.mm index bb37fa9610b2b..3207744c3438d 100644 --- a/shell/platform/darwin/ios/platform_view_ios.mm +++ b/shell/platform/darwin/ios/platform_view_ios.mm @@ -64,20 +64,25 @@ owner_controller_.reset(); }] retain]); - if (owner_controller_) { - ios_surface_ = - [static_cast(owner_controller.get().view) createSurface:gl_context_]; - FML_DCHECK(ios_surface_ != nullptr); - - if (accessibility_bridge_) { - accessibility_bridge_.reset( - new AccessibilityBridge(static_cast(owner_controller_.get().view), this, - [owner_controller.get() platformViewsController])); - } - // Do not call `NotifyCreated()` here - let FlutterViewController take care - // of that when its Viewport is sized. If `NotifyCreated()` is called here, - // it can occasionally get invoked before the viewport is sized resulting in - // a framebuffer that will not be able to completely attach. + if (owner_controller_ && [owner_controller_.get() isViewLoaded]) { + this->attachView(); + } + // Do not call `NotifyCreated()` here - let FlutterViewController take care + // of that when its Viewport is sized. If `NotifyCreated()` is called here, + // it can occasionally get invoked before the viewport is sized resulting in + // a framebuffer that will not be able to completely attach. +} + +void PlatformViewIOS::attachView() { + FML_DCHECK(owner_controller_); + ios_surface_ = + [static_cast(owner_controller_.get().view) createSurface:gl_context_]; + FML_DCHECK(ios_surface_ != nullptr); + + if (accessibility_bridge_) { + accessibility_bridge_.reset( + new AccessibilityBridge(static_cast(owner_controller_.get().view), this, + [owner_controller_.get() platformViewsController])); } }