Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 36db005

Browse files
authored
Revert "[macOS] Formalize FlutterViewController's initialization flow, and prohibit replacing (#38981)" (#39144)
This reverts commit e3b2782.
1 parent e3b2782 commit 36db005

14 files changed

+301
-282
lines changed

shell/platform/darwin/macos/framework/Headers/FlutterEngine.h

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
#import <Foundation/Foundation.h>
99

10-
#include <stdint.h>
11-
1210
#import "FlutterBinaryMessenger.h"
1311
#import "FlutterDartProject.h"
1412
#import "FlutterMacros.h"
@@ -17,17 +15,6 @@
1715

1816
// TODO: Merge this file with the iOS FlutterEngine.h.
1917

20-
/**
21-
* The view ID for APIs that don't support multi-view.
22-
*
23-
* Some single-view APIs will eventually be replaced by their multi-view
24-
* variant. During the deprecation period, the single-view APIs will coexist with
25-
* and work with the multi-view APIs as if the other views don't exist. For
26-
* backward compatibility, single-view APIs will always operate the view with
27-
* this ID. Also, the first view assigned to the engine will also have this ID.
28-
*/
29-
extern const uint64_t kFlutterDefaultViewId;
30-
3118
@class FlutterViewController;
3219

3320
/**
@@ -80,15 +67,6 @@ FLUTTER_DARWIN_EXPORT
8067
*
8168
* The default view always has ID kFlutterDefaultViewId, and is the view
8269
* operated by the APIs that do not have a view ID specified.
83-
*
84-
* Setting this field from nil to a non-nil view controller also updates
85-
* the view controller's engine and ID.
86-
*
87-
* Setting this field from non-nil to nil will terminate the engine if
88-
* allowHeadlessExecution is NO.
89-
*
90-
* Setting this field from non-nil to a different non-nil FlutterViewController
91-
* is prohibited and will throw an assertion error.
9270
*/
9371
@property(nonatomic, nullable, weak) FlutterViewController* viewController;
9472

shell/platform/darwin/macos/framework/Headers/FlutterViewController.h

Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,6 @@ typedef NS_ENUM(NSInteger, FlutterMouseTrackingMode) {
2525

2626
/**
2727
* Controls a view that displays Flutter content and manages input.
28-
*
29-
* A FlutterViewController works with a FlutterEngine. Upon creation, the view
30-
* controller is always added to an engine, either a given engine, or it implicitly
31-
* creates an engine and add itself to that engine.
32-
*
33-
* The FlutterEngine assigns each view controller attached to it a unique ID.
34-
* Each view controller corresponds to a view, and the ID is used by the framework
35-
* to specify which view to operate.
36-
*
37-
* A FlutterViewController can also be unattached to an engine after it is manually
38-
* unset from the engine, or transiently during the initialization process.
39-
* An unattached view controller is invalid. Whether the view controller is attached
40-
* can be queried using FlutterViewController#attached.
41-
*
42-
* The FlutterViewController strongly references the FlutterEngine, while
43-
* the engine weakly the view controller. When a FlutterViewController is deallocated,
44-
* it automatically removes itself from its attached engine. When a FlutterEngine
45-
* has no FlutterViewControllers attached, it might shut down itself or not depending
46-
* on its configuration.
4728
*/
4829
FLUTTER_DARWIN_EXPORT
4930
@interface FlutterViewController : NSViewController <FlutterPluginRegistry>
@@ -53,16 +34,6 @@ FLUTTER_DARWIN_EXPORT
5334
*/
5435
@property(nonatomic, nonnull, readonly) FlutterEngine* engine;
5536

56-
/**
57-
* The identifier for this view controller.
58-
*
59-
* The ID is assigned by FlutterEngine when the view controller is attached.
60-
*
61-
* If the view controller is unattached (see FlutterViewController#attached),
62-
* reading this property throws an assertion.
63-
*/
64-
@property(nonatomic, readonly) uint64_t id;
65-
6637
/**
6738
* The style of mouse tracking to use for the view. Defaults to
6839
* FlutterMouseTrackingModeInKeyWindow.
@@ -72,12 +43,6 @@ FLUTTER_DARWIN_EXPORT
7243
/**
7344
* Initializes a controller that will run the given project.
7445
*
75-
* In this initializer, this controller creates an engine, and is attached to
76-
* that engine as the default controller. In this way, this controller can not
77-
* be set to other engines. This initializer is suitable for the first Flutter
78-
* view controller of the app. To use the controller with an existing engine,
79-
* use initWithEngine:nibName:bundle: instead.
80-
*
8146
* @param project The project to run in this view controller. If nil, a default `FlutterDartProject`
8247
* will be used.
8348
*/
@@ -91,8 +56,7 @@ FLUTTER_DARWIN_EXPORT
9156
/**
9257
* Initializes this FlutterViewController with the specified `FlutterEngine`.
9358
*
94-
* This initializer is suitable for both the first Flutter view controller and
95-
* the following ones of the app.
59+
* The initialized viewcontroller will attach itself to the engine as part of this process.
9660
*
9761
* @param engine The `FlutterEngine` instance to attach to. Cannot be nil.
9862
* @param nibName The NIB name to initialize this controller with.
@@ -101,12 +65,6 @@ FLUTTER_DARWIN_EXPORT
10165
- (nonnull instancetype)initWithEngine:(nonnull FlutterEngine*)engine
10266
nibName:(nullable NSString*)nibName
10367
bundle:(nullable NSBundle*)nibBundle NS_DESIGNATED_INITIALIZER;
104-
105-
/**
106-
* Return YES if the view controller is attached to an engine.
107-
*/
108-
- (BOOL)attached;
109-
11068
/**
11169
* Invoked by the engine right before the engine is restarted.
11270
*

shell/platform/darwin/macos/framework/Source/AccessibilityBridgeMacTest.mm

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,26 @@ @implementation AccessibilityBridgeTestEngine
5151
namespace {
5252

5353
// Returns an engine configured for the text fixture resource configuration.
54-
FlutterViewController* CreateTestViewController() {
54+
FlutterEngine* CreateTestEngine() {
5555
NSString* fixtures = @(testing::GetFixturesPath());
5656
FlutterDartProject* project = [[FlutterDartProject alloc]
5757
initWithAssetsPath:fixtures
5858
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
59-
FlutterEngine* engine = [[AccessibilityBridgeTestEngine alloc] initWithName:@"test"
60-
project:project
61-
allowHeadlessExecution:true];
62-
return [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
59+
return [[AccessibilityBridgeTestEngine alloc] initWithName:@"test"
60+
project:project
61+
allowHeadlessExecution:true];
6362
}
6463
} // namespace
6564

6665
TEST(AccessibilityBridgeMacTest, sendsAccessibilityCreateNotificationToWindowOfFlutterView) {
67-
FlutterViewController* viewController = CreateTestViewController();
68-
FlutterEngine* engine = viewController.engine;
66+
FlutterEngine* engine = CreateTestEngine();
67+
NSString* fixtures = @(testing::GetFixturesPath());
68+
FlutterDartProject* project = [[FlutterDartProject alloc]
69+
initWithAssetsPath:fixtures
70+
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
71+
FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project];
6972
[viewController loadView];
73+
[engine setViewController:viewController];
7074

7175
NSWindow* expectedTarget = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
7276
styleMask:NSBorderlessWindowMask
@@ -118,9 +122,14 @@ @implementation AccessibilityBridgeTestEngine
118122
}
119123

120124
TEST(AccessibilityBridgeMacTest, doesNotSendAccessibilityCreateNotificationWhenHeadless) {
121-
FlutterViewController* viewController = CreateTestViewController();
122-
FlutterEngine* engine = viewController.engine;
125+
FlutterEngine* engine = CreateTestEngine();
126+
NSString* fixtures = @(testing::GetFixturesPath());
127+
FlutterDartProject* project = [[FlutterDartProject alloc]
128+
initWithAssetsPath:fixtures
129+
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
130+
FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project];
123131
[viewController loadView];
132+
[engine setViewController:viewController];
124133
// Setting up bridge so that the AccessibilityBridgeMacDelegateSpy
125134
// can query semantics information from.
126135
engine.semanticsEnabled = YES;
@@ -164,9 +173,15 @@ @implementation AccessibilityBridgeTestEngine
164173
}
165174

166175
TEST(AccessibilityBridgeMacTest, doesNotSendAccessibilityCreateNotificationWhenNoWindow) {
167-
FlutterViewController* viewController = CreateTestViewController();
168-
FlutterEngine* engine = viewController.engine;
176+
FlutterEngine* engine = CreateTestEngine();
177+
// Create a view controller without attaching it to a window.
178+
NSString* fixtures = @(testing::GetFixturesPath());
179+
FlutterDartProject* project = [[FlutterDartProject alloc]
180+
initWithAssetsPath:fixtures
181+
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
182+
FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project];
169183
[viewController loadView];
184+
[engine setViewController:viewController];
170185

171186
// Setting up bridge so that the AccessibilityBridgeMacDelegateSpy
172187
// can query semantics information from.

shell/platform/darwin/macos/framework/Source/FlutterCompositor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "flutter/fml/macros.h"
1212
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h"
13+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h"
1314
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h"
1415
#include "flutter/shell/platform/embedder/embedder.h"
1516

shell/platform/darwin/macos/framework/Source/FlutterEngine.mm

Lines changed: 24 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.h"
2020
#include "flutter/shell/platform/embedder/embedder.h"
2121

22-
const uint64_t kFlutterDefaultViewId = 0;
23-
2422
/**
2523
* Constructs and returns a FlutterLocale struct corresponding to |locale|, which must outlive
2624
* the returned struct.
@@ -82,8 +80,6 @@ @interface FlutterEngine () <FlutterBinaryMessenger>
8280
*/
8381
@property(nonatomic, strong) NSMutableArray<NSNumber*>* isResponseValid;
8482

85-
- (nullable FlutterViewController*)viewControllerForId:(uint64_t)viewId;
86-
8783
/**
8884
* Sends the list of user-preferred locales to the Flutter engine.
8985
*/
@@ -217,6 +213,8 @@ @implementation FlutterEngine {
217213
// when the engine is destroyed.
218214
std::unique_ptr<flutter::FlutterCompositor> _macOSCompositor;
219215

216+
FlutterViewEngineProvider* _viewProvider;
217+
220218
// FlutterCompositor is copied and used in embedder.cc.
221219
FlutterCompositor _compositor;
222220

@@ -250,6 +248,7 @@ - (instancetype)initWithName:(NSString*)labelPrefix
250248
_currentMessengerConnection = 1;
251249
_allowHeadlessExecution = allowHeadlessExecution;
252250
_semanticsEnabled = NO;
251+
_viewProvider = [[FlutterViewEngineProvider alloc] initWithEngine:self];
253252
_isResponseValid = [[NSMutableArray alloc] initWithCapacity:1];
254253
[_isResponseValid addObject:@YES];
255254

@@ -412,41 +411,29 @@ - (void)loadAOTData:(NSString*)assetsDir {
412411
}
413412

414413
- (void)setViewController:(FlutterViewController*)controller {
415-
if (_viewController == controller) {
416-
// From nil to nil, or from non-nil to the same controller.
417-
return;
418-
}
419-
if (_viewController == nil && controller != nil) {
420-
// From nil to non-nil.
421-
NSAssert(controller.engine == nil,
422-
@"Failed to set view controller to the engine: "
423-
@"The given FlutterViewController is already attached to an engine %@. "
424-
@"If you wanted to create an FlutterViewController and set it to an existing engine, "
425-
@"you should create it with init(engine:, nibName, bundle:) instead.",
426-
controller.engine);
414+
if (_viewController != controller) {
427415
_viewController = controller;
428-
[_viewController attachToEngine:self withId:kFlutterDefaultViewId];
429-
} else if (_viewController != nil && controller == nil) {
430-
// From non-nil to nil.
431-
[_viewController detachFromEngine];
432-
_viewController = nil;
433-
if (!_allowHeadlessExecution) {
416+
417+
if (_semanticsEnabled && _bridge) {
418+
_bridge->UpdateDefaultViewController(_viewController);
419+
}
420+
421+
if (!controller && !_allowHeadlessExecution) {
434422
[self shutDownEngine];
435423
}
436-
} else {
437-
// From non-nil to a different non-nil view controller.
438-
NSAssert(NO,
439-
@"Failed to set view controller to the engine: "
440-
@"The engine already has a default view controller %@. "
441-
@"If you wanted to make the default view render in a different window, "
442-
@"you should attach the current view controller to the window instead.",
443-
_viewController);
444424
}
445425
}
446426

447427
- (FlutterCompositor*)createFlutterCompositor {
448-
_macOSCompositor = std::make_unique<flutter::FlutterCompositor>(
449-
[[FlutterViewEngineProvider alloc] initWithEngine:self], _platformViewController);
428+
// TODO(richardjcai): Add support for creating a FlutterCompositor
429+
// with a nil _viewController for headless engines.
430+
// https://github.com/flutter/flutter/issues/71606
431+
if (!_viewController) {
432+
return nil;
433+
}
434+
435+
_macOSCompositor =
436+
std::make_unique<flutter::FlutterCompositor>(_viewProvider, _platformViewController);
450437

451438
_compositor = {};
452439
_compositor.struct_size = sizeof(FlutterCompositor);
@@ -552,10 +539,10 @@ - (nonnull NSString*)executableName {
552539
}
553540

554541
- (void)updateWindowMetrics {
555-
if (!_engine || !self.viewController.viewLoaded) {
542+
if (!_engine || !_viewController.viewLoaded) {
556543
return;
557544
}
558-
NSView* view = self.viewController.flutterView;
545+
NSView* view = _viewController.flutterView;
559546
CGRect scaledBounds = [view convertRectToBacking:view.bounds];
560547
CGSize scaledSize = scaledBounds.size;
561548
double pixelRatio = view.bounds.size.width == 0 ? 1 : scaledSize.width / view.bounds.size.width;
@@ -616,17 +603,6 @@ - (FlutterPlatformViewController*)platformViewController {
616603

617604
#pragma mark - Private methods
618605

619-
- (FlutterViewController*)viewControllerForId:(uint64_t)viewId {
620-
// TODO(dkwingsmt): The engine only supports single-view, therefore it
621-
// only processes the default ID. After the engine supports multiple views,
622-
// this method should be able to return the view for any IDs.
623-
NSAssert(viewId == kFlutterDefaultViewId, @"Unexpected view ID %llu", viewId);
624-
if (viewId == kFlutterDefaultViewId) {
625-
return _viewController;
626-
}
627-
return nil;
628-
}
629-
630606
- (void)sendUserLocales {
631607
if (!self.running) {
632608
return;
@@ -703,7 +679,9 @@ - (void)shutDownEngine {
703679
return;
704680
}
705681

706-
[self.viewController.flutterView shutdown];
682+
if (_viewController && _viewController.flutterView) {
683+
[_viewController.flutterView shutdown];
684+
}
707685

708686
FlutterEngineResult result = _embedderAPI.Deinitialize(_engine);
709687
if (result != kSuccess) {

0 commit comments

Comments
 (0)