From 74503c653d5a6b5b7f99a7ac118792e439b15e92 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 26 Jan 2023 11:55:43 -0800 Subject: [PATCH 01/10] Rebase all --- .../macos/framework/Headers/FlutterEngine.h | 39 +++- .../Headers/FlutterPluginRegistrarMacOS.h | 16 +- .../framework/Headers/FlutterViewController.h | 4 +- .../framework/Source/FlutterCompositor.mm | 4 +- .../framework/Source/FlutterCompositorTest.mm | 8 +- .../macos/framework/Source/FlutterEngine.mm | 190 +++++++++++++++--- .../framework/Source/FlutterEngineTest.mm | 70 +++++++ .../framework/Source/FlutterEngine_Internal.h | 4 +- .../Source/FlutterKeyboardManager.mm | 2 +- .../macos/framework/Source/FlutterRenderer.mm | 8 +- .../framework/Source/FlutterRendererTest.mm | 46 +++-- .../framework/Source/FlutterViewController.mm | 19 +- .../Source/FlutterViewEngineProvider.mm | 14 +- .../Source/FlutterViewEngineProviderTest.mm | 23 ++- .../framework/Source/FlutterViewProvider.h | 9 +- 15 files changed, 365 insertions(+), 91 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h index 957cae047a46f..cf9564dbeaba7 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h @@ -6,6 +6,7 @@ #define FLUTTER_FLUTTERENGINE_H_ #import +#include #include @@ -76,10 +77,11 @@ FLUTTER_DARWIN_EXPORT - (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint; /** - * The default `FlutterViewController` associated with this engine, if any. + * The default `FlutterViewController` of this engine, if any. * - * The default view always has ID kFlutterDefaultViewId, and is the view - * operated by the APIs that do not have a view ID specified. + * The default view is the first view added to the engine, always has ID + * kFlutterDefaultViewId, and is operated by the legacy APIs that do not specify + * view IDs. * * Setting this field from nil to a non-nil view controller also updates * the view controller's engine and ID. @@ -89,9 +91,40 @@ FLUTTER_DARWIN_EXPORT * * Setting this field from non-nil to a different non-nil FlutterViewController * is prohibited and will throw an assertion error. + * + * This method is deprecated. Querying view controllers should use + * viewControllerForId: instead. Assigning or replacing view controllers do not + * have a replacement. Consider addViewController: and removeViewController:. */ @property(nonatomic, nullable, weak) FlutterViewController* viewController; +/** + * Attach a view controller to the engine and associate it with a newly + * generated ID. + * + * The engine holds a weak reference to each attached view controller. + * + * The first added view controller (either with this method or the + * viewController property) will always have ID kFlutterDefaultViewId. + * + * If the given view controller is already attached to an engine, this call + * throws an assertion. + */ +- (void)addViewController:(nonnull FlutterViewController*)viewController; + +/** + * Deassociate the given view controller from this engine. + * + * If the view controller is not associated with this engine, this call throws an + * assertion. + */ +- (void)removeViewController:(nonnull FlutterViewController*)viewController; + +/** + * The `FlutterViewController` associated with the given view ID, if any. + */ +- (nullable FlutterViewController*)viewControllerForId:(uint64_t)viewId; + /** * The `FlutterBinaryMessenger` for communicating with this engine. */ diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h b/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h index c341f2354dcd9..0ff5f7da99592 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h @@ -36,12 +36,20 @@ FLUTTER_DARWIN_EXPORT @property(nonnull, readonly) id textures; /** - * The view displaying Flutter content. May return |nil|, for instance in a headless environment. + * The default view displaying Flutter content. * - * WARNING: If/when multiple Flutter views within the same application are supported (#30701), this - * API will change. + * This method may return |nil|, for instance in a headless environment. + * + * The default view is a special view operated by the legacy single-view APIs. + * This property is deprecated. Its calls should be replaced with viewForId: + * kFlutterDefaultViewId for viewId. + */ +- (nullable NSView*)view; + +/** + * The `NSView` associated with the given view ID, if any. */ -@property(nullable, readonly) NSView* view; +- (nullable NSView*)viewForId:(uint64_t)viewId; /** * Registers |delegate| to receive handleMethodCall:result: callbacks for the given |channel|. diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h index e4d8df7d4c48d..f38cdf843c2c7 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h @@ -89,7 +89,9 @@ FLUTTER_DARWIN_EXPORT NS_DESIGNATED_INITIALIZER; - (nonnull instancetype)initWithCoder:(nonnull NSCoder*)nibNameOrNil NS_DESIGNATED_INITIALIZER; /** - * Initializes this FlutterViewController with the specified `FlutterEngine`. + * Initializes this FlutterViewController with an existing `FlutterEngine`. + * + * The initialized viewcontroller will add itself to the engine as part of this process. * * This initializer is suitable for both the first Flutter view controller and * the following ones of the app. diff --git a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm index 74173158d8c59..a31085f507ce3 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm @@ -19,7 +19,7 @@ // TODO(dkwingsmt): This class only supports single-view for now. As more // classes are gradually converted to multi-view, it should get the view ID // from somewhere. - FlutterView* view = [view_provider_ getView:kFlutterDefaultViewId]; + FlutterView* view = [view_provider_ getDefaultView]; if (!view) { return false; } @@ -37,7 +37,7 @@ bool FlutterCompositor::Present(uint64_t view_id, const FlutterLayer** layers, size_t layers_count) { - FlutterView* view = [view_provider_ getView:view_id]; + FlutterView* view = [view_provider_ getViewForId:view_id]; if (!view) { return false; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm index bd6bf4d57b58b..a26a8345d468b 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm @@ -11,6 +11,8 @@ #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h" #import "flutter/testing/testing.h" +extern const uint64_t kFlutterDefaultViewId; + @interface FlutterViewMockProvider : NSObject { FlutterView* _defaultView; } @@ -30,7 +32,11 @@ - (nonnull instancetype)initWithDefaultView:(nonnull FlutterView*)view { return self; } -- (nullable FlutterView*)getView:(uint64_t)viewId { +- (nullable FlutterView*)getDefaultView { + return [self getViewForId:kFlutterDefaultViewId]; +} + +- (nullable FlutterView*)getViewForId:(uint64_t)viewId { if (viewId == kFlutterDefaultViewId) { return _defaultView; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index 9fc17bd2e0af5..a2afded9c2d1b 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -84,6 +84,29 @@ @interface FlutterEngine () - (nullable FlutterViewController*)viewControllerForId:(uint64_t)viewId; +/** + * An internal method that adds view controller with the given ID. + * + * This method assigns the controller with the ID, puts the controller into the + * map, and does assertions related to the default view ID. + */ +- (void)registerViewController:(FlutterViewController*)controller forId:(uint64_t)viewId; + +/** + * An internal method that removes the view controller with the given ID. + * + * This method clears the ID of the controller, removes the controller from the + * map. This is an no-op if the view ID is not associated with any view + * controllers. + */ +- (void)deregisterViewControllerForId:(uint64_t)viewId; + +/** + * Shuts down the engine if view requirement is not met, and headless execution + * is not allowed. + */ +- (void)shutDownIfNeeded; + /** * Sends the list of user-preferred locales to the Flutter engine. */ @@ -124,6 +147,12 @@ - (void)setUpPlatformViewChannel; */ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result; +/** + * Generate a new unique view ID. + * + * IDs start from kFlutterDefaultViewId. + */ +- (uint64_t)generateViewId; @end #pragma mark - @@ -161,10 +190,18 @@ - (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine } - (NSView*)view { - if (!_flutterEngine.viewController.viewLoaded) { - [_flutterEngine.viewController loadView]; + return [self viewForId:kFlutterDefaultViewId]; +} + +- (NSView*)viewForId:(uint64_t)viewId { + FlutterViewController* controller = [_flutterEngine viewControllerForId:viewId]; + if (controller == nil) { + return nil; } - return _flutterEngine.viewController.flutterView; + if (!controller.viewLoaded) { + [controller loadView]; + } + return controller.flutterView; } - (void)addMethodCallDelegate:(nonnull id)delegate @@ -214,6 +251,9 @@ @implementation FlutterEngine { // when the engine is destroyed. std::unique_ptr _macOSCompositor; + // The information of all views attached to this engine mapped from IDs. + NSMapTable* _viewControllers; + // FlutterCompositor is copied and used in embedder.cc. FlutterCompositor _compositor; @@ -230,6 +270,8 @@ @implementation FlutterEngine { // A method channel for miscellaneous platform functionality. FlutterMethodChannel* _platformChannel; + + int _nextViewId; } - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project { @@ -249,10 +291,12 @@ - (instancetype)initWithName:(NSString*)labelPrefix _semanticsEnabled = NO; _isResponseValid = [[NSMutableArray alloc] initWithCapacity:1]; [_isResponseValid addObject:@YES]; + _nextViewId = kFlutterDefaultViewId; _embedderAPI.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&_embedderAPI); + _viewControllers = [NSMapTable weakToWeakObjectsMapTable]; _renderer = [[FlutterRenderer alloc] initWithFlutterEngine:self]; NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter]; @@ -284,7 +328,7 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { return NO; } - if (!_allowHeadlessExecution && !_viewController) { + if (!_allowHeadlessExecution && [_viewControllers count] == 0) { NSLog(@"Attempted to run an engine with no view controller without headless mode enabled."); return NO; } @@ -374,7 +418,14 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { } [self sendUserLocales]; - [self updateWindowMetrics]; + + // Update window metric for all view controllers. + NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator]; + FlutterViewController* nextViewController; + while ((nextViewController = [viewControllerEnumerator nextObject])) { + [self updateWindowMetricsForViewController:nextViewController]; + } + [self updateDisplayConfig]; // Send the initial user settings such as brightness and text scale factor // to the engine. @@ -408,28 +459,62 @@ - (void)loadAOTData:(NSString*)assetsDir { } } +- (void)registerViewController:(FlutterViewController*)controller forId:(uint64_t)viewId { + NSAssert(controller != nil, @"The controller must not be nil."); + NSAssert(![controller attached], + @"The incoming view controller is already attached to an engine."); + NSAssert([_viewControllers objectForKey:@(viewId)] == nil, @"The requested view ID is occupied."); + // The first view controller is guaranteed to have the fixed default view ID. + NSAssert([_viewControllers count] != 0 || viewId == kFlutterDefaultViewId, + @"The first view controller should have the fixed default view ID, but is " + @"given %lld.", + viewId); + [controller attachToEngine:self withId:viewId]; + NSAssert(controller.id == viewId, @"Failed to assign view ID."); + [_viewControllers setObject:controller forKey:@(viewId)]; +} + +- (void)deregisterViewControllerForId:(uint64_t)viewId { + FlutterViewController* oldController = [self viewControllerForId:viewId]; + if (oldController != nil) { + [oldController detachFromEngine]; + [_viewControllers removeObjectForKey:@(viewId)]; + } +} + +- (void)shutDownIfNeeded { + if ([_viewControllers count] == 0 && !_allowHeadlessExecution) { + [self shutDownEngine]; + } +} + +- (FlutterViewController*)viewControllerForId:(uint64_t)viewId { + FlutterViewController* controller = [_viewControllers objectForKey:@(viewId)]; + NSAssert(controller == nil || controller.id == viewId, + @"The stored controller has unexpected view ID."); + return controller; +} + - (void)setViewController:(FlutterViewController*)controller { - if (_viewController == controller) { + FlutterViewController* currentController = + [_viewControllers objectForKey:@(kFlutterDefaultViewId)]; + if (currentController == controller) { // From nil to nil, or from non-nil to the same controller. return; } - if (_viewController == nil && controller != nil) { + if (currentController == nil && controller != nil) { // From nil to non-nil. NSAssert(controller.engine == nil, @"Failed to set view controller to the engine: " @"The given FlutterViewController is already attached to an engine %@. " @"If you wanted to create an FlutterViewController and set it to an existing engine, " - @"you should create it with init(engine:, nibName, bundle:) instead.", + @"you should use FlutterViewController#init(engine:, nibName, bundle:) instead.", controller.engine); - _viewController = controller; - [_viewController attachToEngine:self withId:kFlutterDefaultViewId]; - } else if (_viewController != nil && controller == nil) { + [self registerViewController:controller forId:kFlutterDefaultViewId]; + } else if (currentController != nil && controller == nil) { // From non-nil to nil. - [_viewController detachFromEngine]; - _viewController = nil; - if (!_allowHeadlessExecution) { - [self shutDownEngine]; - } + [self deregisterViewControllerForId:kFlutterDefaultViewId]; + [self shutDownIfNeeded]; } else { // From non-nil to a different non-nil view controller. NSAssert(NO, @@ -437,10 +522,14 @@ - (void)setViewController:(FlutterViewController*)controller { @"The engine already has a default view controller %@. " @"If you wanted to make the default view render in a different window, " @"you should attach the current view controller to the window instead.", - _viewController); + [_viewControllers objectForKey:@(kFlutterDefaultViewId)]); } } +- (FlutterViewController*)viewController { + return [self viewControllerForId:kFlutterDefaultViewId]; +} + - (FlutterCompositor*)createFlutterCompositor { _macOSCompositor = std::make_unique( [[FlutterViewEngineProvider alloc] initWithEngine:self], _platformViewController); @@ -485,6 +574,22 @@ - (FlutterCompositor*)createFlutterCompositor { #pragma mark - Framework-internal methods +- (void)addViewController:(FlutterViewController*)controller { + uint64_t viewId = [self generateViewId]; + [self registerViewController:controller forId:viewId]; + // TODO(dkwingsmt): Call the embedder API to add a rendering surface for + // this to correctly work. +} + +- (void)removeViewController:(nonnull FlutterViewController*)viewController { + NSAssert([viewController attached] && viewController.engine == self, + @"The given view controller is not associated with this engine."); + [self deregisterViewControllerForId:viewController.id]; + [self shutDownIfNeeded]; + // TODO(dkwingsmt): Call the embedder API to remove the rendering surface for + // this to correctly work. +} + - (BOOL)running { return _engine != nullptr; } @@ -544,11 +649,19 @@ - (nonnull NSString*)executableName { return [[[NSProcessInfo processInfo] arguments] firstObject] ?: @"Flutter"; } -- (void)updateWindowMetrics { - if (!_engine || !self.viewController.viewLoaded) { +- (void)updateWindowMetricsForViewController:(FlutterViewController*)viewController { + if (viewController.id != kFlutterDefaultViewId) { + // TODO(dkwingsmt): The embedder API only supports single-view for now. As + // embedder APIs are converted to multi-view, this method should support any + // views. + return; + } + if (!_engine || !viewController || !viewController.viewLoaded) { return; } - NSView* view = self.viewController.flutterView; + NSAssert([self viewControllerForId:viewController.id] == viewController, + @"The provided view controller is not attached to this engine."); + NSView* view = viewController.flutterView; CGRect scaledBounds = [view convertRectToBacking:view.bounds]; CGSize scaledSize = scaledBounds.size; double pixelRatio = view.bounds.size.width == 0 ? 1 : scaledSize.width / view.bounds.size.width; @@ -579,7 +692,14 @@ - (void)setSemanticsEnabled:(BOOL)enabled { return; } _semanticsEnabled = enabled; - [_viewController notifySemanticsEnabledChanged]; + + // Update all view controllers' bridge. + NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator]; + FlutterViewController* nextViewController; + while ((nextViewController = [viewControllerEnumerator nextObject])) { + [nextViewController notifySemanticsEnabledChanged]; + } + _embedderAPI.UpdateSemanticsEnabled(_engine, _semanticsEnabled); } @@ -595,15 +715,10 @@ - (FlutterPlatformViewController*)platformViewController { #pragma mark - Private methods -- (FlutterViewController*)viewControllerForId:(uint64_t)viewId { - // TODO(dkwingsmt): The engine only supports single-view, therefore it - // only processes the default ID. After the engine supports multiple views, - // this method should be able to return the view for any IDs. - NSAssert(viewId == kFlutterDefaultViewId, @"Unexpected view ID %llu", viewId); - if (viewId == kFlutterDefaultViewId) { - return _viewController; - } - return nil; +- (uint64_t)generateViewId { + uint64_t result = _nextViewId; + _nextViewId += 1; + return result; } - (void)sendUserLocales { @@ -669,8 +784,13 @@ - (void)engineCallbackOnPlatformMessage:(const FlutterPlatformMessage*)message { } - (void)engineCallbackOnPreEngineRestart { - if (_viewController) { - [_viewController onPreEngineRestart]; + NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator]; + FlutterViewController* nextViewController; + while ((nextViewController = [viewControllerEnumerator nextObject])) { + [nextViewController onPreEngineRestart]; + if (nextViewController.id != kFlutterDefaultViewId) { + [_viewControllers removeObjectForKey:@(nextViewController.id)]; + } } } @@ -682,7 +802,11 @@ - (void)shutDownEngine { return; } - [self.viewController.flutterView shutdown]; + NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator]; + FlutterViewController* nextViewController; + while ((nextViewController = [viewControllerEnumerator nextObject])) { + [nextViewController.flutterView shutdown]; + } FlutterEngineResult result = _embedderAPI.Deinitialize(_engine); if (result != kSuccess) { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm index 911ff76a07eb4..d7bb3ce5259e7 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm @@ -614,6 +614,76 @@ - (nonnull NSView*)createWithViewIdentifier:(int64_t)viewId arguments:(nullable rasterThread.join(); } +TEST_F(FlutterEngineTest, ManageControllersIfInitiatedByController) { + NSString* fixtures = @(flutter::testing::GetFixturesPath()); + FlutterDartProject* project = [[FlutterDartProject alloc] + initWithAssetsPath:fixtures + ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; + + FlutterEngine* engine; + FlutterViewController* viewController2; + + @autoreleasepool { + // Create FVC1. + FlutterViewController* viewController1 = + [[FlutterViewController alloc] initWithProject:project]; + EXPECT_EQ(viewController1.id, 0ull); + + engine = viewController1.engine; + // Create FVC2 based on the same engine. + viewController2 = [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; + EXPECT_EQ(engine.viewController, viewController1); + EXPECT_EQ([engine viewControllerForId:0], viewController1); + EXPECT_EQ([engine viewControllerForId:1], viewController2); + } + // FVC1 is deallocated but FVC2 is retained. + + EXPECT_EQ(engine.viewController, nil); + EXPECT_EQ([engine viewControllerForId:0], nil); + EXPECT_EQ([engine viewControllerForId:1], viewController2); + + // Create FVC3. The default view controller will stay nil. + FlutterViewController* viewController3 = + [[FlutterViewController alloc] initWithEngine:viewController2.engine nibName:nil bundle:nil]; + EXPECT_EQ(engine.viewController, nil); + EXPECT_EQ(viewController3.id, 2ull); + EXPECT_EQ([engine viewControllerForId:2], viewController3); +} + +TEST_F(FlutterEngineTest, ManageControllersIfInitiatedByEngine) { + // Don't create the engine with `CreateMockFlutterEngine` because the latter + // introduces memory leakage. + FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"io.flutter" + project:nil + allowHeadlessExecution:NO]; + FlutterViewController* viewController2; + + @autoreleasepool { + FlutterViewController* viewController1 = [[FlutterViewController alloc] initWithEngine:engine + nibName:nil + bundle:nil]; + EXPECT_EQ(viewController1.id, 0ull); + EXPECT_EQ(engine.viewController, viewController1); + + viewController2 = [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; + EXPECT_EQ(viewController2.id, 1ull); + EXPECT_EQ([engine viewControllerForId:0], viewController1); + EXPECT_EQ([engine viewControllerForId:1], viewController2); + } + // FVC1 is deallocated but FVC2 is retained. + + EXPECT_EQ(engine.viewController, nil); + EXPECT_EQ([engine viewControllerForId:0], nil); + EXPECT_EQ([engine viewControllerForId:1], viewController2); + + // Create FVC3. The default view controller will stay nil. + FlutterViewController* viewController3 = + [[FlutterViewController alloc] initWithEngine:viewController2.engine nibName:nil bundle:nil]; + EXPECT_EQ(engine.viewController, nil); + EXPECT_EQ(viewController3.id, 2ull); + EXPECT_EQ([engine viewControllerForId:2], viewController3); +} + } // namespace flutter::testing // NOLINTEND(clang-analyzer-core.StackAddressEscape) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h index 6eed864e6a433..d88d82ad0d385 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h @@ -48,9 +48,9 @@ @property(nonatomic, readonly, nonnull) NSPasteboard* pasteboard; /** - * Informs the engine that the associated view controller's view size has changed. + * Informs the engine that the specified view controller's view size has changed. */ -- (void)updateWindowMetrics; +- (void)updateWindowMetricsForViewController:(nonnull FlutterViewController*)viewController; /** * Dispatches the given pointer event data to engine. diff --git a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm index 78c18dd0b08e0..ad50476a47675 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm @@ -57,7 +57,7 @@ @interface FlutterKeyboardManager () /** * The text input plugin set by initialization. */ -@property(nonatomic) id viewDelegate; +@property(nonatomic, weak) id viewDelegate; /** * The primary responders added by addPrimaryResponder. diff --git a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm index 007a3cce157a5..bb8ac2a91e3da 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm @@ -89,7 +89,7 @@ - (FlutterRendererConfig)createRendererConfig { #pragma mark - Embedder callback implementations. - (FlutterMetalTexture)createTextureForView:(uint64_t)viewId size:(CGSize)size { - FlutterView* view = [_viewProvider getView:viewId]; + FlutterView* view = [_viewProvider getViewForId:viewId]; NSAssert(view != nil, @"Can't create texture on a non-existent view 0x%llx.", viewId); if (view == nil) { // FlutterMetalTexture has texture `null`, therefore is discarded. @@ -99,16 +99,20 @@ - (FlutterMetalTexture)createTextureForView:(uint64_t)viewId size:(CGSize)size { } - (BOOL)present:(uint64_t)viewId texture:(const FlutterMetalTexture*)texture { - FlutterView* view = [_viewProvider getView:viewId]; + NSLog(@"Present %llu", viewId); + FlutterView* view = [_viewProvider getViewForId:viewId]; + NSLog(@"Present View %@", view); if (view == nil) { return NO; } FlutterSurface* surface = [FlutterSurface fromFlutterMetalTexture:texture]; + NSLog(@"Present surface %@", surface); if (surface == nil) { return NO; } FlutterSurfacePresentInfo* info = [[FlutterSurfacePresentInfo alloc] init]; info.surface = surface; + NSLog(@"Present surfaceMgr %@", view.surfaceManager); [view.surfaceManager present:@[ info ] notify:nil]; return YES; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterRendererTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterRendererTest.mm index 01146e1464c02..46da658efd8e6 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterRendererTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterRendererTest.mm @@ -9,37 +9,54 @@ #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" #include "flutter/testing/testing.h" +@interface RendererTestViewController : FlutterViewController +- (void)loadMockFlutterView:(FlutterView*)mockView; +@end + +@implementation RendererTestViewController { + FlutterView* _mockFlutterView; +} + +- (void)loadMockFlutterView:(FlutterView*)mockView { + _mockFlutterView = mockView; + [self loadView]; +} + +- (nonnull FlutterView*)createFlutterViewWithMTLDevice:(id)device + commandQueue:(id)commandQueue { + return _mockFlutterView; +} +@end + namespace flutter::testing { namespace { // Returns an engine configured for the test fixture resource configuration. -FlutterEngine* CreateTestEngine() { +RendererTestViewController* CreateTestViewController() { NSString* fixtures = @(testing::GetFixturesPath()); FlutterDartProject* project = [[FlutterDartProject alloc] initWithAssetsPath:fixtures ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; - return [[FlutterEngine alloc] initWithName:@"test" project:project allowHeadlessExecution:true]; -} - -void SetEngineDefaultView(FlutterEngine* engine, id flutterView) { - id mockFlutterViewController = OCMClassMock([FlutterViewController class]); - OCMStub([mockFlutterViewController flutterView]).andReturn(flutterView); - [engine setViewController:mockFlutterViewController]; + RendererTestViewController* viewController = + [[RendererTestViewController alloc] initWithProject:project]; + return viewController; } } // namespace TEST(FlutterRenderer, PresentDelegatesToFlutterView) { - FlutterEngine* engine = CreateTestEngine(); - FlutterRenderer* renderer = [[FlutterRenderer alloc] initWithFlutterEngine:engine]; + RendererTestViewController* viewController = CreateTestViewController(); + FlutterEngine* engine = viewController.engine; id viewMock = OCMClassMock([FlutterView class]); - SetEngineDefaultView(engine, viewMock); + [viewController loadMockFlutterView:viewMock]; + FlutterRenderer* renderer = [[FlutterRenderer alloc] initWithFlutterEngine:engine]; id surfaceManagerMock = OCMClassMock([FlutterSurfaceManager class]); OCMStub([viewMock surfaceManager]).andReturn(surfaceManagerMock); @@ -61,11 +78,12 @@ void SetEngineDefaultView(FlutterEngine* engine, id flutterView) { } TEST(FlutterRenderer, TextureReturnedByFlutterView) { - FlutterEngine* engine = CreateTestEngine(); - FlutterRenderer* renderer = [[FlutterRenderer alloc] initWithFlutterEngine:engine]; + RendererTestViewController* viewController = CreateTestViewController(); + FlutterEngine* engine = viewController.engine; id viewMock = OCMClassMock([FlutterView class]); - SetEngineDefaultView(engine, viewMock); + [viewController loadMockFlutterView:viewMock]; + FlutterRenderer* renderer = [[FlutterRenderer alloc] initWithFlutterEngine:engine]; id surfaceManagerMock = OCMClassMock([FlutterSurfaceManager class]); OCMStub([viewMock surfaceManager]).andReturn(surfaceManagerMock); diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index 72d67f105e264..994cc8f468d69 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -309,11 +309,12 @@ static void CommonInit(FlutterViewController* controller, FlutterEngine* engine) @"The FlutterViewController is unexpectedly attached to " @"engine %@ before initialization.", controller.engine); - engine.viewController = controller; + [engine addViewController:controller]; NSCAssert(controller.engine != nil, @"The FlutterViewController unexpectedly stays unattached after initialization. " @"In unit tests, this is likely because either the FlutterViewController or " - @"the FlutterEngine is mocked. Please subclass these classes instead."); + @"the FlutterEngine is mocked. Please subclass these classes instead.", + controller.engine, controller.id); controller->_mouseTrackingMode = FlutterMouseTrackingModeInKeyWindow; controller->_textInputPlugin = [[FlutterTextInputPlugin alloc] initWithViewController:controller]; [controller initializeKeyboard]; @@ -355,11 +356,6 @@ - (instancetype)initWithEngine:(nonnull FlutterEngine*)engine nibName:(nullable NSString*)nibName bundle:(nullable NSBundle*)nibBundle { NSAssert(engine != nil, @"Engine is required"); - NSAssert(engine.viewController == nil, - @"The supplied FlutterEngine is already used with FlutterViewController " - "instance. One instance of the FlutterEngine can only be attached to one " - "FlutterViewController at a time. Set FlutterEngine.viewController " - "to nil before attaching it to another FlutterViewController."); self = [super initWithNibName:nibName bundle:nibBundle]; if (self) { @@ -412,7 +408,9 @@ - (void)viewWillDisappear { } - (void)dealloc { - _engine.viewController = nil; + if ([self attached]) { + [_engine removeViewController:self]; + } CFNotificationCenterRef cfCenter = CFNotificationCenterGetDistributedCenter(); CFNotificationCenterRemoveEveryObserver(cfCenter, (__bridge void*)self); } @@ -583,8 +581,7 @@ - (void)configureTrackingArea { - (void)initializeKeyboard { // TODO(goderbauer): Seperate keyboard/textinput stuff into ViewController specific and Engine // global parts. Move the global parts to FlutterEngine. - __weak FlutterViewController* weakSelf = self; - _keyboardManager = [[FlutterKeyboardManager alloc] initWithViewDelegate:weakSelf]; + _keyboardManager = [[FlutterKeyboardManager alloc] initWithViewDelegate:self]; } - (void)dispatchMouseEvent:(nonnull NSEvent*)event { @@ -795,7 +792,7 @@ - (void)onKeyboardLayoutChanged { * Responds to view reshape by notifying the engine of the change in dimensions. */ - (void)viewDidReshape:(NSView*)view { - [_engine updateWindowMetrics]; + [_engine updateWindowMetricsForViewController:self]; } #pragma mark - FlutterPluginRegistry diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.mm index a063784b5e2c9..20b43c32f9ec2 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.mm @@ -22,14 +22,12 @@ - (instancetype)initWithEngine:(FlutterEngine*)engine { return self; } -- (nullable FlutterView*)getView:(uint64_t)viewId { - // TODO(dkwingsmt): This class only supports the first view for now. After - // FlutterEngine supports multi-view, it should get the view associated to the - // ID. - if (viewId == kFlutterDefaultViewId) { - return _engine.viewController.flutterView; - } - return nil; +- (nullable FlutterView*)getDefaultView { + return _engine.viewController.flutterView; +} + +- (nullable FlutterView*)getViewForId:(uint64_t)viewId { + return [_engine viewControllerForId:viewId].flutterView; } @end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderTest.mm index 6a1aa66b69c59..dfab54b66fa57 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderTest.mm @@ -6,6 +6,7 @@ #import #import +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.h" @@ -19,23 +20,29 @@ TEST(FlutterViewEngineProviderUnittests, GetViewReturnsTheCorrectView) { FlutterViewEngineProvider* viewProvider; - id mockEngine = OCMClassMock([FlutterEngine class]); + id mockEngine = CreateMockFlutterEngine(@""); __block id mockFlutterViewController; - OCMStub([mockEngine viewController]).andDo(^(NSInvocation* invocation) { - if (mockFlutterViewController != nil) { - [invocation setReturnValue:&mockFlutterViewController]; - } - }); + OCMStub([mockEngine viewControllerForId:0]) + .ignoringNonObjectArgs() + .andDo(^(NSInvocation* invocation) { + uint64_t viewId; + [invocation getArgument:&viewId atIndex:2]; + if (viewId == 0 /* kFlutterDefaultViewId */) { + if (mockFlutterViewController != nil) { + [invocation setReturnValue:&mockFlutterViewController]; + } + } + }); viewProvider = [[FlutterViewEngineProvider alloc] initWithEngine:mockEngine]; // When the view controller is not set, the returned view is nil. - EXPECT_EQ([viewProvider getView:0], nil); + EXPECT_EQ([viewProvider getViewForId:0], nil); // When the view controller is set, the returned view is the controller's view. mockFlutterViewController = OCMStrictClassMock([FlutterViewController class]); id mockView = OCMStrictClassMock([FlutterView class]); OCMStub([mockFlutterViewController flutterView]).andReturn(mockView); - EXPECT_EQ([viewProvider getView:0], mockView); + EXPECT_EQ([viewProvider getViewForId:0], mockView); } } // namespace flutter::testing diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h b/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h index f873c72266a95..62960fc648b83 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h @@ -15,11 +15,18 @@ extern const uint64_t kFlutterDefaultViewId; */ @protocol FlutterViewProvider +/** + * Get the FlutterView for the default view. + * + * Returns nil if it doesn't exist. + */ +- (nullable FlutterView*)getDefaultView; + /** * Get the FlutterView with the given view ID. * * Returns nil if the ID is invalid. */ -- (nullable FlutterView*)getView:(uint64_t)id; +- (nullable FlutterView*)getViewForId:(uint64_t)id; @end From e249299cb8d92d721bf67acded45df5874d14bd3 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 26 Jan 2023 14:31:45 -0800 Subject: [PATCH 02/10] Do not remove views on hot restart --- .../platform/darwin/macos/framework/Source/FlutterEngine.mm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index a2afded9c2d1b..2ca467789fb0d 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -693,7 +693,7 @@ - (void)setSemanticsEnabled:(BOOL)enabled { } _semanticsEnabled = enabled; - // Update all view controllers' bridge. + // Update all view controllers' bridges. NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator]; FlutterViewController* nextViewController; while ((nextViewController = [viewControllerEnumerator nextObject])) { @@ -788,9 +788,6 @@ - (void)engineCallbackOnPreEngineRestart { FlutterViewController* nextViewController; while ((nextViewController = [viewControllerEnumerator nextObject])) { [nextViewController onPreEngineRestart]; - if (nextViewController.id != kFlutterDefaultViewId) { - [_viewControllers removeObjectForKey:@(nextViewController.id)]; - } } } From f5335eaf714709a1aee9642b1c130c203c6bf6aa Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 26 Jan 2023 14:36:41 -0800 Subject: [PATCH 03/10] Remove log, fix doc --- .../platform/darwin/macos/framework/Source/FlutterEngine.mm | 2 ++ .../darwin/macos/framework/Source/FlutterEngineTest.mm | 5 +++-- .../darwin/macos/framework/Source/FlutterRenderer.mm | 4 ---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index 2ca467789fb0d..db0df6fbe2461 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -252,6 +252,8 @@ @implementation FlutterEngine { std::unique_ptr _macOSCompositor; // The information of all views attached to this engine mapped from IDs. + // + // It can't use NSDictionary, because the values need to be weak references. NSMapTable* _viewControllers; // FlutterCompositor is copied and used in embedder.cc. diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm index d7bb3ce5259e7..55392254b7ce2 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm @@ -651,8 +651,9 @@ - (nonnull NSView*)createWithViewIdentifier:(int64_t)viewId arguments:(nullable } TEST_F(FlutterEngineTest, ManageControllersIfInitiatedByEngine) { - // Don't create the engine with `CreateMockFlutterEngine` because the latter - // introduces memory leakage. + // Don't create the engine with `CreateMockFlutterEngine`, because it adds + // additional references to FlutterViewControllers, which is crucial to this + // test case. FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil allowHeadlessExecution:NO]; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm index bb8ac2a91e3da..4dd967926a049 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm @@ -99,20 +99,16 @@ - (FlutterMetalTexture)createTextureForView:(uint64_t)viewId size:(CGSize)size { } - (BOOL)present:(uint64_t)viewId texture:(const FlutterMetalTexture*)texture { - NSLog(@"Present %llu", viewId); FlutterView* view = [_viewProvider getViewForId:viewId]; - NSLog(@"Present View %@", view); if (view == nil) { return NO; } FlutterSurface* surface = [FlutterSurface fromFlutterMetalTexture:texture]; - NSLog(@"Present surface %@", surface); if (surface == nil) { return NO; } FlutterSurfacePresentInfo* info = [[FlutterSurfacePresentInfo alloc] init]; info.surface = surface; - NSLog(@"Present surfaceMgr %@", view.surfaceManager); [view.surfaceManager present:@[ info ] notify:nil]; return YES; } From fd7d3d9a97257469218e8b1ecc38c577f902be26 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 2 Feb 2023 14:09:41 -0800 Subject: [PATCH 04/10] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com> --- .../platform/darwin/macos/framework/Headers/FlutterEngine.h | 6 ++---- .../darwin/macos/framework/Headers/FlutterViewController.h | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h index cf9564dbeaba7..4cc4a4f3f6c4e 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h @@ -6,7 +6,6 @@ #define FLUTTER_FLUTTERENGINE_H_ #import -#include #include @@ -80,8 +79,7 @@ FLUTTER_DARWIN_EXPORT * The default `FlutterViewController` of this engine, if any. * * The default view is the first view added to the engine, always has ID - * kFlutterDefaultViewId, and is operated by the legacy APIs that do not specify - * view IDs. + * kFlutterDefaultViewId, and is used by legacy APIs that assume a single view. * * Setting this field from nil to a non-nil view controller also updates * the view controller's engine and ID. @@ -113,7 +111,7 @@ FLUTTER_DARWIN_EXPORT - (void)addViewController:(nonnull FlutterViewController*)viewController; /** - * Deassociate the given view controller from this engine. + * Dissociate the given view controller from this engine. * * If the view controller is not associated with this engine, this call throws an * assertion. diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h index f38cdf843c2c7..5979131f7451b 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h @@ -91,7 +91,7 @@ FLUTTER_DARWIN_EXPORT /** * Initializes this FlutterViewController with an existing `FlutterEngine`. * - * The initialized viewcontroller will add itself to the engine as part of this process. + * The initialized view controller will add itself to the engine as part of this process. * * This initializer is suitable for both the first Flutter view controller and * the following ones of the app. From 3ac89d9e722f1cf9d7cf4bb83040d1e4425b6f8a Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 2 Feb 2023 15:10:23 -0800 Subject: [PATCH 05/10] getDefaultView --- .../darwin/macos/framework/Source/FlutterCompositor.mm | 4 ++-- .../macos/framework/Source/FlutterCompositorTest.mm | 6 +----- .../darwin/macos/framework/Source/FlutterRenderer.mm | 4 ++-- .../macos/framework/Source/FlutterViewEngineProvider.mm | 6 +----- .../framework/Source/FlutterViewEngineProviderTest.mm | 4 ++-- .../darwin/macos/framework/Source/FlutterViewProvider.h | 9 +-------- 6 files changed, 9 insertions(+), 24 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm index a31085f507ce3..51b874f47dfbd 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm @@ -19,7 +19,7 @@ // TODO(dkwingsmt): This class only supports single-view for now. As more // classes are gradually converted to multi-view, it should get the view ID // from somewhere. - FlutterView* view = [view_provider_ getDefaultView]; + FlutterView* view = [view_provider_ viewForId:kFlutterDefaultViewId]; if (!view) { return false; } @@ -37,7 +37,7 @@ bool FlutterCompositor::Present(uint64_t view_id, const FlutterLayer** layers, size_t layers_count) { - FlutterView* view = [view_provider_ getViewForId:view_id]; + FlutterView* view = [view_provider_ viewForId:view_id]; if (!view) { return false; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm index a26a8345d468b..4005b176aaf24 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterCompositorTest.mm @@ -32,11 +32,7 @@ - (nonnull instancetype)initWithDefaultView:(nonnull FlutterView*)view { return self; } -- (nullable FlutterView*)getDefaultView { - return [self getViewForId:kFlutterDefaultViewId]; -} - -- (nullable FlutterView*)getViewForId:(uint64_t)viewId { +- (nullable FlutterView*)viewForId:(uint64_t)viewId { if (viewId == kFlutterDefaultViewId) { return _defaultView; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm index 4dd967926a049..d7d2c2fc7d6ac 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterRenderer.mm @@ -89,7 +89,7 @@ - (FlutterRendererConfig)createRendererConfig { #pragma mark - Embedder callback implementations. - (FlutterMetalTexture)createTextureForView:(uint64_t)viewId size:(CGSize)size { - FlutterView* view = [_viewProvider getViewForId:viewId]; + FlutterView* view = [_viewProvider viewForId:viewId]; NSAssert(view != nil, @"Can't create texture on a non-existent view 0x%llx.", viewId); if (view == nil) { // FlutterMetalTexture has texture `null`, therefore is discarded. @@ -99,7 +99,7 @@ - (FlutterMetalTexture)createTextureForView:(uint64_t)viewId size:(CGSize)size { } - (BOOL)present:(uint64_t)viewId texture:(const FlutterMetalTexture*)texture { - FlutterView* view = [_viewProvider getViewForId:viewId]; + FlutterView* view = [_viewProvider viewForId:viewId]; if (view == nil) { return NO; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.mm index 20b43c32f9ec2..95c3aa53e0ee5 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.mm @@ -22,11 +22,7 @@ - (instancetype)initWithEngine:(FlutterEngine*)engine { return self; } -- (nullable FlutterView*)getDefaultView { - return _engine.viewController.flutterView; -} - -- (nullable FlutterView*)getViewForId:(uint64_t)viewId { +- (nullable FlutterView*)viewForId:(uint64_t)viewId { return [_engine viewControllerForId:viewId].flutterView; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderTest.mm index dfab54b66fa57..86c94a70caa60 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProviderTest.mm @@ -36,13 +36,13 @@ viewProvider = [[FlutterViewEngineProvider alloc] initWithEngine:mockEngine]; // When the view controller is not set, the returned view is nil. - EXPECT_EQ([viewProvider getViewForId:0], nil); + EXPECT_EQ([viewProvider viewForId:0], nil); // When the view controller is set, the returned view is the controller's view. mockFlutterViewController = OCMStrictClassMock([FlutterViewController class]); id mockView = OCMStrictClassMock([FlutterView class]); OCMStub([mockFlutterViewController flutterView]).andReturn(mockView); - EXPECT_EQ([viewProvider getViewForId:0], mockView); + EXPECT_EQ([viewProvider viewForId:0], mockView); } } // namespace flutter::testing diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h b/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h index 62960fc648b83..9548b7afab1b8 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h @@ -15,18 +15,11 @@ extern const uint64_t kFlutterDefaultViewId; */ @protocol FlutterViewProvider -/** - * Get the FlutterView for the default view. - * - * Returns nil if it doesn't exist. - */ -- (nullable FlutterView*)getDefaultView; - /** * Get the FlutterView with the given view ID. * * Returns nil if the ID is invalid. */ -- (nullable FlutterView*)getViewForId:(uint64_t)id; +- (nullable FlutterView*)viewForId:(uint64_t)id; @end From 0f44c6d3def593752e2ddacac6adcfb9a935c03b Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 3 Feb 2023 14:26:28 -0800 Subject: [PATCH 06/10] postpone deprecation. Add TODO --- .../macos/framework/Headers/FlutterEngine.h | 26 ---------------- .../Headers/FlutterPluginRegistrarMacOS.h | 4 +-- .../macos/framework/Source/FlutterEngine.mm | 12 ++++++-- .../framework/Source/FlutterEngine_Internal.h | 30 +++++++++++++++++++ 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h index 4cc4a4f3f6c4e..e7e89fb914650 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h @@ -89,35 +89,9 @@ FLUTTER_DARWIN_EXPORT * * Setting this field from non-nil to a different non-nil FlutterViewController * is prohibited and will throw an assertion error. - * - * This method is deprecated. Querying view controllers should use - * viewControllerForId: instead. Assigning or replacing view controllers do not - * have a replacement. Consider addViewController: and removeViewController:. */ @property(nonatomic, nullable, weak) FlutterViewController* viewController; -/** - * Attach a view controller to the engine and associate it with a newly - * generated ID. - * - * The engine holds a weak reference to each attached view controller. - * - * The first added view controller (either with this method or the - * viewController property) will always have ID kFlutterDefaultViewId. - * - * If the given view controller is already attached to an engine, this call - * throws an assertion. - */ -- (void)addViewController:(nonnull FlutterViewController*)viewController; - -/** - * Dissociate the given view controller from this engine. - * - * If the view controller is not associated with this engine, this call throws an - * assertion. - */ -- (void)removeViewController:(nonnull FlutterViewController*)viewController; - /** * The `FlutterViewController` associated with the given view ID, if any. */ diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h b/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h index 0ff5f7da99592..daedcb8773dae 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h @@ -40,9 +40,7 @@ FLUTTER_DARWIN_EXPORT * * This method may return |nil|, for instance in a headless environment. * - * The default view is a special view operated by the legacy single-view APIs. - * This property is deprecated. Its calls should be replaced with viewForId: - * kFlutterDefaultViewId for viewId. + * The default view is a special view operated by single-view APIs. */ - (nullable NSView*)view; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index db0df6fbe2461..5ec0ec01e0cc0 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -357,8 +357,11 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { flutterArguments.platform_message_callback = (FlutterPlatformMessageCallback)OnPlatformMessage; flutterArguments.update_semantics_callback = [](const FlutterSemanticsUpdate* update, void* user_data) { + // TODO(dkwingsmt): This callback only supports single-view, therefore it + // only operates on the default view. To support multi-view, we need a + // way to pass in the ID (probably through FlutterSemanticsUpdate). FlutterEngine* engine = (__bridge FlutterEngine*)user_data; - [engine.viewController updateSemantics:update]; + [[engine viewControllerForId:kFlutterDefaultViewId] updateSemantics:update]; }; flutterArguments.custom_dart_entrypoint = entrypoint.UTF8String; flutterArguments.shutdown_dart_vm_when_done = true; @@ -870,7 +873,12 @@ - (void)applicationWillTerminate:(NSNotification*)notification { - (void)onAccessibilityStatusChanged:(NSNotification*)notification { BOOL enabled = [notification.userInfo[kEnhancedUserInterfaceKey] boolValue]; - [self.viewController onAccessibilityStatusChanged:enabled]; + NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator]; + FlutterViewController* nextViewController; + while ((nextViewController = [viewControllerEnumerator nextObject])) { + [nextViewController onAccessibilityStatusChanged:enabled]; + } + self.semanticsEnabled = enabled; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h index d88d82ad0d385..8b1d0cb745c2f 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h @@ -47,6 +47,36 @@ */ @property(nonatomic, readonly, nonnull) NSPasteboard* pasteboard; +/** + * Attach a view controller to the engine and associate it with a newly + * generated ID. + * + * The engine holds a weak reference to each attached view controller. + * + * The first added view controller (either with this method or the + * viewController property) will always have ID kFlutterDefaultViewId. + * + * If the given view controller is already attached to an engine, this call + * throws an assertion. + * + * TODO(dkwingsmt): Move this method to the public API once stable. This method + * should be a public method but its behavior is "broken" before we implement + * the proper embedder API. See its implementation for detail. + */ +- (void)addViewController:(nonnull FlutterViewController*)viewController; + +/** + * Dissociate the given view controller from this engine. + * + * If the view controller is not associated with this engine, this call throws an + * assertion. + * + * TODO(dkwingsmt): Move this method to the public API once stable. This method + * should be a public method but its behavior is "broken" before we implement + * the proper embedder API. See its implementation for detail. + */ +- (void)removeViewController:(nonnull FlutterViewController*)viewController; + /** * Informs the engine that the specified view controller's view size has changed. */ From 9de96167e9c301de7dec2e2e26438ac5c52c1aa8 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 6 Feb 2023 11:04:22 -0800 Subject: [PATCH 07/10] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com> --- shell/platform/darwin/macos/framework/Source/FlutterEngine.mm | 2 +- .../darwin/macos/framework/Source/FlutterEngine_Internal.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index 5ec0ec01e0cc0..dc62c21d11998 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -85,7 +85,7 @@ @interface FlutterEngine () - (nullable FlutterViewController*)viewControllerForId:(uint64_t)viewId; /** - * An internal method that adds view controller with the given ID. + * An internal method that adds the view controller with the given ID. * * This method assigns the controller with the ID, puts the controller into the * map, and does assertions related to the default view ID. diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h index 8b1d0cb745c2f..1a574fa264e4d 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h @@ -78,7 +78,7 @@ - (void)removeViewController:(nonnull FlutterViewController*)viewController; /** - * Informs the engine that the specified view controller's view size has changed. + * Informs the engine that the specified view controller's window metrics have changed. */ - (void)updateWindowMetricsForViewController:(nonnull FlutterViewController*)viewController; From c05f0e8367aee44ea5991aac93675871bf021e41 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 6 Feb 2023 23:34:13 -0800 Subject: [PATCH 08/10] Change to single --- .../macos/framework/Headers/FlutterEngine.h | 8 +-- .../macos/framework/Source/FlutterEngine.mm | 30 ++-------- .../framework/Source/FlutterEngineTest.mm | 58 ++++++++----------- .../framework/Source/FlutterEngine_Internal.h | 26 ++++----- 4 files changed, 47 insertions(+), 75 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h index e7e89fb914650..e09ee22afb71d 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h @@ -32,6 +32,9 @@ extern const uint64_t kFlutterDefaultViewId; /** * Coordinates a single instance of execution of a Flutter engine. + * + * A FlutterEngine can only be attached with one controller from the native + * code. */ FLUTTER_DARWIN_EXPORT @interface FlutterEngine : NSObject @@ -92,11 +95,6 @@ FLUTTER_DARWIN_EXPORT */ @property(nonatomic, nullable, weak) FlutterViewController* viewController; -/** - * The `FlutterViewController` associated with the given view ID, if any. - */ -- (nullable FlutterViewController*)viewControllerForId:(uint64_t)viewId; - /** * The `FlutterBinaryMessenger` for communicating with this engine. */ diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index dc62c21d11998..481b2aab9997c 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -147,12 +147,6 @@ - (void)setUpPlatformViewChannel; */ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result; -/** - * Generate a new unique view ID. - * - * IDs start from kFlutterDefaultViewId. - */ -- (uint64_t)generateViewId; @end #pragma mark - @@ -293,7 +287,9 @@ - (instancetype)initWithName:(NSString*)labelPrefix _semanticsEnabled = NO; _isResponseValid = [[NSMutableArray alloc] initWithCapacity:1]; [_isResponseValid addObject:@YES]; - _nextViewId = kFlutterDefaultViewId; + // kFlutterDefaultViewId is reserved for the default view. + // All IDs above it are for regular views. + _nextViewId = kFlutterDefaultViewId + 1; _embedderAPI.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&_embedderAPI); @@ -469,11 +465,6 @@ - (void)registerViewController:(FlutterViewController*)controller forId:(uint64_ NSAssert(![controller attached], @"The incoming view controller is already attached to an engine."); NSAssert([_viewControllers objectForKey:@(viewId)] == nil, @"The requested view ID is occupied."); - // The first view controller is guaranteed to have the fixed default view ID. - NSAssert([_viewControllers count] != 0 || viewId == kFlutterDefaultViewId, - @"The first view controller should have the fixed default view ID, but is " - @"given %lld.", - viewId); [controller attachToEngine:self withId:viewId]; NSAssert(controller.id == viewId, @"Failed to assign view ID."); [_viewControllers setObject:controller forKey:@(viewId)]; @@ -517,6 +508,8 @@ - (void)setViewController:(FlutterViewController*)controller { controller.engine); [self registerViewController:controller forId:kFlutterDefaultViewId]; } else if (currentController != nil && controller == nil) { + NSAssert(currentController.id == kFlutterDefaultViewId, + @"The default controller has an unexpected ID %llu", currentController.id); // From non-nil to nil. [self deregisterViewControllerForId:kFlutterDefaultViewId]; [self shutDownIfNeeded]; @@ -580,10 +573,7 @@ - (FlutterCompositor*)createFlutterCompositor { #pragma mark - Framework-internal methods - (void)addViewController:(FlutterViewController*)controller { - uint64_t viewId = [self generateViewId]; - [self registerViewController:controller forId:viewId]; - // TODO(dkwingsmt): Call the embedder API to add a rendering surface for - // this to correctly work. + [self registerViewController:controller forId:kFlutterDefaultViewId]; } - (void)removeViewController:(nonnull FlutterViewController*)viewController { @@ -591,8 +581,6 @@ - (void)removeViewController:(nonnull FlutterViewController*)viewController { @"The given view controller is not associated with this engine."); [self deregisterViewControllerForId:viewController.id]; [self shutDownIfNeeded]; - // TODO(dkwingsmt): Call the embedder API to remove the rendering surface for - // this to correctly work. } - (BOOL)running { @@ -720,12 +708,6 @@ - (FlutterPlatformViewController*)platformViewController { #pragma mark - Private methods -- (uint64_t)generateViewId { - uint64_t result = _nextViewId; - _nextViewId += 1; - return result; -} - - (void)sendUserLocales { if (!self.running) { return; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm index 55392254b7ce2..d3b2be0406001 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm @@ -621,33 +621,29 @@ - (nonnull NSView*)createWithViewIdentifier:(int64_t)viewId arguments:(nullable ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; FlutterEngine* engine; - FlutterViewController* viewController2; + FlutterViewController* viewController1; @autoreleasepool { // Create FVC1. - FlutterViewController* viewController1 = - [[FlutterViewController alloc] initWithProject:project]; + viewController1 = [[FlutterViewController alloc] initWithProject:project]; EXPECT_EQ(viewController1.id, 0ull); engine = viewController1.engine; + engine.viewController = nil; + // Create FVC2 based on the same engine. - viewController2 = [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; - EXPECT_EQ(engine.viewController, viewController1); - EXPECT_EQ([engine viewControllerForId:0], viewController1); - EXPECT_EQ([engine viewControllerForId:1], viewController2); + FlutterViewController* viewController2 = [[FlutterViewController alloc] initWithEngine:engine + nibName:nil + bundle:nil]; + EXPECT_EQ(engine.viewController, viewController2); } - // FVC1 is deallocated but FVC2 is retained. + // FVC2 is deallocated but FVC1 is retained. EXPECT_EQ(engine.viewController, nil); - EXPECT_EQ([engine viewControllerForId:0], nil); - EXPECT_EQ([engine viewControllerForId:1], viewController2); - // Create FVC3. The default view controller will stay nil. - FlutterViewController* viewController3 = - [[FlutterViewController alloc] initWithEngine:viewController2.engine nibName:nil bundle:nil]; - EXPECT_EQ(engine.viewController, nil); - EXPECT_EQ(viewController3.id, 2ull); - EXPECT_EQ([engine viewControllerForId:2], viewController3); + engine.viewController = viewController1; + EXPECT_EQ(engine.viewController, viewController1); + EXPECT_EQ(viewController1.id, 0ull); } TEST_F(FlutterEngineTest, ManageControllersIfInitiatedByEngine) { @@ -657,32 +653,28 @@ - (nonnull NSView*)createWithViewIdentifier:(int64_t)viewId arguments:(nullable FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil allowHeadlessExecution:NO]; - FlutterViewController* viewController2; + FlutterViewController* viewController1; @autoreleasepool { - FlutterViewController* viewController1 = [[FlutterViewController alloc] initWithEngine:engine - nibName:nil - bundle:nil]; + viewController1 = [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; EXPECT_EQ(viewController1.id, 0ull); EXPECT_EQ(engine.viewController, viewController1); - viewController2 = [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; - EXPECT_EQ(viewController2.id, 1ull); - EXPECT_EQ([engine viewControllerForId:0], viewController1); - EXPECT_EQ([engine viewControllerForId:1], viewController2); + engine.viewController = nil; + + FlutterViewController* viewController2 = [[FlutterViewController alloc] initWithEngine:engine + nibName:nil + bundle:nil]; + EXPECT_EQ(viewController2.id, 0ull); + EXPECT_EQ(engine.viewController, viewController2); } - // FVC1 is deallocated but FVC2 is retained. + // FVC2 is deallocated but FVC1 is retained. EXPECT_EQ(engine.viewController, nil); - EXPECT_EQ([engine viewControllerForId:0], nil); - EXPECT_EQ([engine viewControllerForId:1], viewController2); - // Create FVC3. The default view controller will stay nil. - FlutterViewController* viewController3 = - [[FlutterViewController alloc] initWithEngine:viewController2.engine nibName:nil bundle:nil]; - EXPECT_EQ(engine.viewController, nil); - EXPECT_EQ(viewController3.id, 2ull); - EXPECT_EQ([engine viewControllerForId:2], viewController3); + engine.viewController = viewController1; + EXPECT_EQ(engine.viewController, viewController1); + EXPECT_EQ(viewController1.id, 0ull); } } // namespace flutter::testing diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h index 1a574fa264e4d..083889476877f 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h @@ -48,35 +48,35 @@ @property(nonatomic, readonly, nonnull) NSPasteboard* pasteboard; /** - * Attach a view controller to the engine and associate it with a newly - * generated ID. + * Attach a view controller to the engine as its default controller. * - * The engine holds a weak reference to each attached view controller. + * Practically, since FlutterEngine can only be attached with one controller, + * the given controller, if successfully attached, will always have the default + * view ID kFlutterDefaultViewId. * - * The first added view controller (either with this method or the - * viewController property) will always have ID kFlutterDefaultViewId. + * The engine holds a weak reference to the attached view controller. * * If the given view controller is already attached to an engine, this call * throws an assertion. - * - * TODO(dkwingsmt): Move this method to the public API once stable. This method - * should be a public method but its behavior is "broken" before we implement - * the proper embedder API. See its implementation for detail. */ - (void)addViewController:(nonnull FlutterViewController*)viewController; /** * Dissociate the given view controller from this engine. * + * Practically, since FlutterEngine can only be attached with one controller, + * the given controller must be the default view controller. + * * If the view controller is not associated with this engine, this call throws an * assertion. - * - * TODO(dkwingsmt): Move this method to the public API once stable. This method - * should be a public method but its behavior is "broken" before we implement - * the proper embedder API. See its implementation for detail. */ - (void)removeViewController:(nonnull FlutterViewController*)viewController; +/** + * The `FlutterViewController` associated with the given view ID, if any. + */ +- (nullable FlutterViewController*)viewControllerForId:(uint64_t)viewId; + /** * Informs the engine that the specified view controller's window metrics have changed. */ From c2ebe664dcaeafdb415eeaf5298a12dfa3adee17 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 8 Feb 2023 23:39:43 -0800 Subject: [PATCH 09/10] Update FlutterEngine.h --- .../platform/darwin/macos/framework/Headers/FlutterEngine.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h index e09ee22afb71d..7c7bea715893b 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h @@ -79,10 +79,9 @@ FLUTTER_DARWIN_EXPORT - (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint; /** - * The default `FlutterViewController` of this engine, if any. + * The `FlutterViewController` of this engine, if any. * - * The default view is the first view added to the engine, always has ID - * kFlutterDefaultViewId, and is used by legacy APIs that assume a single view. + * This view is used by legacy APIs that assume a single view. * * Setting this field from nil to a non-nil view controller also updates * the view controller's engine and ID. From 0625db733e5dbadff925199f1f867a99ddf7e361 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 8 Feb 2023 23:40:15 -0800 Subject: [PATCH 10/10] Update FlutterEngine_Internal.h --- .../darwin/macos/framework/Source/FlutterEngine_Internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h index 083889476877f..1879cb92dbdab 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h @@ -54,7 +54,7 @@ * the given controller, if successfully attached, will always have the default * view ID kFlutterDefaultViewId. * - * The engine holds a weak reference to the attached view controller. + * The engine holds a weak reference to the attached view controller. * * If the given view controller is already attached to an engine, this call * throws an assertion.