diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index ef82e14e5f813..79c4d0b40845a 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -44,12 +44,15 @@ @implementation FlutterEngine { fml::WeakPtr _viewController; fml::scoped_nsobject _publisher; + std::unique_ptr _platformViewsController; + // Channels fml::scoped_nsobject _platformPlugin; fml::scoped_nsobject _textInputPlugin; fml::scoped_nsobject _localizationChannel; fml::scoped_nsobject _navigationChannel; fml::scoped_nsobject _platformChannel; + fml::scoped_nsobject _platformViewsChannel; fml::scoped_nsobject _textInputChannel; fml::scoped_nsobject _lifecycleChannel; fml::scoped_nsobject _systemChannel; @@ -73,6 +76,7 @@ - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject* _pluginPublications = [NSMutableDictionary new]; _publisher.reset([[FlutterObservatoryPublisher alloc] init]); + _platformViewsController.reset(new shell::FlutterPlatformViewsController()); [self setupChannels]; @@ -143,6 +147,9 @@ - (FlutterViewController*)viewController { - (FlutterPlatformPlugin*)platformPlugin { return _platformPlugin.get(); } +- (shell::FlutterPlatformViewsController*)platformViewsController { + return _platformViewsController.get(); +} - (FlutterTextInputPlugin*)textInputPlugin { return _textInputPlugin.get(); } @@ -184,6 +191,11 @@ - (void)setupChannels { binaryMessenger:self codec:[FlutterJSONMethodCodec sharedInstance]]); + _platformViewsChannel.reset([[FlutterMethodChannel alloc] + initWithName:@"flutter/platform_views" + binaryMessenger:self + codec:[FlutterStandardMethodCodec sharedInstance]]); + _textInputChannel.reset([[FlutterMethodChannel alloc] initWithName:@"flutter/textinput" binaryMessenger:self @@ -218,6 +230,11 @@ - (void)maybeSetupPlatformViewChannels { [_platformPlugin.get() handleMethodCall:call result:result]; }]; + [_platformViewsChannel.get() + setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { + _platformViewsController->OnMethodCall(call, result); + }]; + [_textInputChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { [_textInputPlugin.get() handleMethodCall:call result:result]; }]; @@ -379,6 +396,10 @@ - (void)performAction:(FlutterTextInputAction)action withClient:(int)client { return _shell->Screenshot(type, base64Encode); } +- (flow::ExternalViewEmbedder*)externalViewEmbedder { + return _platformViewsController.get(); +} + #pragma mark - FlutterBinaryMessenger - (void)sendOnChannel:(NSString*)channel message:(NSData*)message { @@ -514,18 +535,7 @@ - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package { - (void)registerViewFactory:(NSObject*)factory withId:(NSString*)factoryId { - // TODO(amirh/dnfield): this shouldn't need to fail - PlatformViewsController should be - // independent. Dev builds of engine should just fail here. We don't want to fail in release mode - // because this shouldn't ordinarily happen. - FML_DCHECK([_flutterEngine viewController]) - << "Cannot register a view factory on a headless engine."; - if ([_flutterEngine viewController]) { - [[_flutterEngine viewController] platformViewsController]->RegisterViewFactory(factory, - factoryId); - } else { - // Shouldn't ordinarily happen, but at least give warning if it does. - FML_LOG(ERROR) << "Cannot register a view factory on a headless engine."; - } + [_flutterEngine platformViewsController] -> RegisterViewFactory(factory, factoryId); } @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h index 5162f9c3ce078..86d1fc736eb32 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h @@ -7,6 +7,8 @@ #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h" +#import "FlutterPlatformViews_Internal.h" + #include "flutter/fml/memory/weak_ptr.h" #include "flutter/fml/task_runner.h" #include "flutter/lib/ui/window/pointer_data_packet.h" @@ -22,7 +24,7 @@ #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h" -@interface FlutterEngine () +@interface FlutterEngine () - (shell::Shell&)shell; @@ -37,6 +39,7 @@ base64Encode:(bool)base64Encode; - (FlutterPlatformPlugin*)platformPlugin; +- (shell::FlutterPlatformViewsController*)platformViewsController; - (FlutterTextInputPlugin*)textInputPlugin; - (void)launchEngine:(NSString*)entrypoint libraryURI:(NSString*)libraryOrNil; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 6e9895ce07626..cbca478380bd9 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -14,17 +14,8 @@ namespace shell { -FlutterPlatformViewsController::FlutterPlatformViewsController( - NSObject* messenger, - FlutterView* flutter_view) - : flutter_view_([flutter_view retain]) { - channel_.reset([[FlutterMethodChannel alloc] - initWithName:@"flutter/platform_views" - binaryMessenger:messenger - codec:[FlutterStandardMethodCodec sharedInstance]]); - [channel_.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { - OnMethodCall(call, result); - }]; +void FlutterPlatformViewsController::SetFlutterView(UIView* flutter_view) { + flutter_view_.reset(flutter_view); } void FlutterPlatformViewsController::OnMethodCall(FlutterMethodCall* call, FlutterResult& result) { @@ -40,6 +31,15 @@ } void FlutterPlatformViewsController::OnCreate(FlutterMethodCall* call, FlutterResult& result) { + if (!flutter_view_.get()) { + // Right now we assume we have a reference to FlutterView when creating a new view. + // TODO(amirh): support this by setting the refernce to FlutterView when it becomes available. + // https://github.com/flutter/flutter/issues/23787 + result([FlutterError errorWithCode:@"create_failed" + message:@"can't create a view on a headless engine" + details:nil]); + return; + } NSDictionary* args = [call arguments]; long viewId = [args[@"id"] longValue]; @@ -66,7 +66,7 @@ flutterView:flutter_view_] autorelease]; views_[viewId] = fml::scoped_nsobject([view retain]); - FlutterView* flutter_view = flutter_view_.get(); + UIView* flutter_view = flutter_view_.get(); [flutter_view addSubview:views_[viewId].get()]; result(nil); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index e8f7103f1c1db..d52d59bf12d1f 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -5,7 +5,6 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_ -#include "FlutterView.h" #include "flutter/flow/embedded_views.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/common/shell.h" @@ -29,20 +28,22 @@ namespace shell { class FlutterPlatformViewsController : public flow::ExternalViewEmbedder { public: - FlutterPlatformViewsController(NSObject* messenger, - FlutterView* flutter_view); + FlutterPlatformViewsController() = default; + + void SetFlutterView(UIView* flutter_view); void RegisterViewFactory(NSObject* factory, NSString* factoryId); void CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params); + void OnMethodCall(FlutterMethodCall* call, FlutterResult& result); + private: fml::scoped_nsobject channel_; - fml::scoped_nsobject flutter_view_; + fml::scoped_nsobject flutter_view_; std::map>> factories_; std::map> views_; - void OnMethodCall(FlutterMethodCall* call, FlutterResult& result); void OnCreate(FlutterMethodCall* call, FlutterResult& result); void OnDispose(FlutterMethodCall* call, FlutterResult& result); void OnAcceptGesture(FlutterMethodCall* call, FlutterResult& result); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.h b/shell/platform/darwin/ios/framework/Source/FlutterView.h index 8b4bb5a010217..87402b6a2e64d 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.h @@ -9,16 +9,20 @@ #include +#import "FlutterPlatformViews_Internal.h" + #include "flutter/flow/embedded_views.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" -@protocol FlutterScreenshotDelegate +@protocol FlutterViewEngineDelegate - (shell::Rasterizer::Screenshot)takeScreenshot:(shell::Rasterizer::ScreenshotType)type asBase64Encoded:(BOOL)base64Encode; +- (flow::ExternalViewEmbedder*)externalViewEmbedder; + @end @interface FlutterView : UIView @@ -27,7 +31,7 @@ - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; -- (instancetype)initWithDelegate:(id)delegate +- (instancetype)initWithDelegate:(id)delegate opaque:(BOOL)opaque NS_DESIGNATED_INITIALIZER; - (std::unique_ptr)createSurface; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.mm b/shell/platform/darwin/ios/framework/Source/FlutterView.mm index 60e51501d55ed..a6fb0449baa90 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.mm @@ -23,7 +23,7 @@ @interface FlutterView () @implementation FlutterView -id _delegate; +id _delegate; - (instancetype)init { @throw([NSException exceptionWithName:@"FlutterView must initWithDelegate" @@ -43,7 +43,7 @@ - (instancetype)initWithCoder:(NSCoder*)aDecoder { userInfo:nil]); } -- (instancetype)initWithDelegate:(id)delegate opaque:(BOOL)opaque { +- (instancetype)initWithDelegate:(id)delegate opaque:(BOOL)opaque { FML_DCHECK(delegate) << "Delegate must not be nil."; self = [super initWithFrame:CGRectNull]; @@ -55,23 +55,6 @@ - (instancetype)initWithDelegate:(id)delegate opaque: return self; } -- (FlutterViewController*)flutterViewController { - // Find the first view controller in the responder chain and see if it is a FlutterViewController. - for (UIResponder* responder = self.nextResponder; responder != nil; - responder = responder.nextResponder) { - if ([responder isKindOfClass:[UIViewController class]]) { - if ([responder isKindOfClass:[FlutterViewController class]]) { - return reinterpret_cast(responder); - } else { - // Should only happen if a non-FlutterViewController tries to somehow (via dynamic class - // resolution or reparenting) set a FlutterView as its view. - return nil; - } - } - } - return nil; -} - - (void)layoutSubviews { if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { CAEAGLLayer* layer = reinterpret_cast(self.layer); @@ -93,16 +76,15 @@ + (Class)layerClass { } - (std::unique_ptr)createSurface { - ::shell::GetExternalViewEmbedder get_view_embedder = [[^() { - return [[self flutterViewController] viewEmbedder]; - } copy] autorelease]; if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { fml::scoped_nsobject eagl_layer( reinterpret_cast([self.layer retain])); - return std::make_unique(std::move(eagl_layer), get_view_embedder); + return std::make_unique(std::move(eagl_layer), + *[_delegate externalViewEmbedder]); } else { fml::scoped_nsobject layer(reinterpret_cast([self.layer retain])); - return std::make_unique(std::move(layer), get_view_embedder); + return std::make_unique(std::move(layer), + *[_delegate externalViewEmbedder]); } } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 31c91871f88f0..9c160cef29034 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -113,8 +113,6 @@ - (void)performCommonViewControllerInitialization { _statusBarStyle = UIStatusBarStyleDefault; [self setupNotificationCenterObservers]; - _platformViewsController.reset( - new shell::FlutterPlatformViewsController(_engine.get(), _flutterView.get())); } - (fml::scoped_nsobject)engine { @@ -125,10 +123,6 @@ - (void)performCommonViewControllerInitialization { return _weakFactory->GetWeakPtr(); } -- (flow::ExternalViewEmbedder*)viewEmbedder { - return _platformViewsController.get(); -} - - (void)setupNotificationCenterObservers { NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; [center addObserver:self @@ -364,10 +358,11 @@ - (void)surfaceUpdated:(BOOL)appeared { // NotifyCreated/NotifyDestroyed are synchronous and require hops between the UI and GPU thread. if (appeared) { [self installSplashScreenViewCallback]; + [_engine.get() platformViewsController] -> SetFlutterView(_flutterView.get()); [_engine.get() platformView] -> NotifyCreated(); - } else { [_engine.get() platformView] -> NotifyDestroyed(); + [_engine.get() platformViewsController] -> SetFlutterView(nullptr); } } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h index 38c2c9040dd33..79288b396f1d2 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h @@ -19,8 +19,6 @@ @property(readonly) fml::scoped_nsobject engine; -- (flow::ExternalViewEmbedder*)viewEmbedder; - @end #endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEWCONTROLLER_INTERNAL_H_ diff --git a/shell/platform/darwin/ios/ios_surface.h b/shell/platform/darwin/ios/ios_surface.h index c756aae4fba08..8011905db4d68 100644 --- a/shell/platform/darwin/ios/ios_surface.h +++ b/shell/platform/darwin/ios/ios_surface.h @@ -13,8 +13,6 @@ namespace shell { -typedef flow::ExternalViewEmbedder* (^GetExternalViewEmbedder)(void); - class IOSSurface { public: IOSSurface(); diff --git a/shell/platform/darwin/ios/ios_surface_gl.h b/shell/platform/darwin/ios/ios_surface_gl.h index b7b604adb86f7..2c4146a9094b4 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -18,7 +18,7 @@ namespace shell { class IOSSurfaceGL : public IOSSurface, public GPUSurfaceGLDelegate { public: IOSSurfaceGL(fml::scoped_nsobject layer, - ::shell::GetExternalViewEmbedder get_view_embedder); + flow::ExternalViewEmbedder& external_view_embedder); ~IOSSurfaceGL() override; @@ -46,7 +46,7 @@ class IOSSurfaceGL : public IOSSurface, public GPUSurfaceGLDelegate { private: IOSGLContext context_; - fml::scoped_nsprotocol<::shell::GetExternalViewEmbedder> get_view_embedder_; + flow::ExternalViewEmbedder& external_view_embedder_; FML_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceGL); }; diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index e834e352afec0..954e50239fa16 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -10,8 +10,8 @@ namespace shell { IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, - ::shell::GetExternalViewEmbedder get_view_embedder) - : context_(std::move(layer)), get_view_embedder_([get_view_embedder retain]) {} + flow::ExternalViewEmbedder& view_embedder) + : context_(std::move(layer)), external_view_embedder_(view_embedder) {} IOSSurfaceGL::~IOSSurfaceGL() = default; @@ -59,7 +59,7 @@ } flow::ExternalViewEmbedder* IOSSurfaceGL::GetExternalViewEmbedder() { - return get_view_embedder_.get()(); + return &external_view_embedder_; } } // namespace shell diff --git a/shell/platform/darwin/ios/ios_surface_software.h b/shell/platform/darwin/ios/ios_surface_software.h index d0d9ce4049e8a..86eaa16ee210b 100644 --- a/shell/platform/darwin/ios/ios_surface_software.h +++ b/shell/platform/darwin/ios/ios_surface_software.h @@ -17,7 +17,7 @@ namespace shell { class IOSSurfaceSoftware final : public IOSSurface, public GPUSurfaceSoftwareDelegate { public: IOSSurfaceSoftware(fml::scoped_nsobject layer, - ::shell::GetExternalViewEmbedder get_view_embedder); + flow::ExternalViewEmbedder& view_embedder); ~IOSSurfaceSoftware() override; @@ -44,7 +44,7 @@ class IOSSurfaceSoftware final : public IOSSurface, public GPUSurfaceSoftwareDel private: fml::scoped_nsobject layer_; - fml::scoped_nsprotocol<::shell::GetExternalViewEmbedder> get_view_embedder_; + flow::ExternalViewEmbedder& external_view_embedder_; sk_sp sk_surface_; FML_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceSoftware); diff --git a/shell/platform/darwin/ios/ios_surface_software.mm b/shell/platform/darwin/ios/ios_surface_software.mm index c79ce8215f7bc..cb4768a168a2e 100644 --- a/shell/platform/darwin/ios/ios_surface_software.mm +++ b/shell/platform/darwin/ios/ios_surface_software.mm @@ -16,8 +16,8 @@ namespace shell { IOSSurfaceSoftware::IOSSurfaceSoftware(fml::scoped_nsobject layer, - ::shell::GetExternalViewEmbedder get_view_embedder) - : layer_(std::move(layer)), get_view_embedder_([get_view_embedder retain]) { + flow::ExternalViewEmbedder& view_embedder) + : layer_(std::move(layer)), external_view_embedder_(view_embedder) { UpdateStorageSizeIfNecessary(); } @@ -127,7 +127,7 @@ } flow::ExternalViewEmbedder* IOSSurfaceSoftware::GetExternalViewEmbedder() { - return get_view_embedder_.get()(); + return &external_view_embedder_; } } // namespace shell