From a21c97f24d7499144fad1944146ead6583664269 Mon Sep 17 00:00:00 2001 From: Amir Hardon Date: Wed, 31 Oct 2018 11:00:22 -0700 Subject: [PATCH] Move FlutterPlatformViewsController into FlutterEngine. This PR breaks PlatformViewsController's construction dependency on FlutterView, which allows making FlutterEngine its owner instead of FlutterViewController. Also renamed the FlutterScreenshotDelegate to FlutterViewEngineDelegate which is FlutterView's delegate to the engine, and expanded it to provide a view embedder. --- .../ios/framework/Source/FlutterEngine.mm | 34 ++++++++++++------- .../framework/Source/FlutterEngine_Internal.h | 5 ++- .../framework/Source/FlutterPlatformViews.mm | 24 ++++++------- .../Source/FlutterPlatformViews_Internal.h | 11 +++--- .../darwin/ios/framework/Source/FlutterView.h | 8 +++-- .../ios/framework/Source/FlutterView.mm | 30 ++++------------ .../framework/Source/FlutterViewController.mm | 9 ++--- .../Source/FlutterViewController_Internal.h | 2 -- shell/platform/darwin/ios/ios_surface.h | 2 -- shell/platform/darwin/ios/ios_surface_gl.h | 4 +-- shell/platform/darwin/ios/ios_surface_gl.mm | 6 ++-- .../darwin/ios/ios_surface_software.h | 4 +-- .../darwin/ios/ios_surface_software.mm | 6 ++-- 13 files changed, 68 insertions(+), 77 deletions(-) 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