Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions shell/platform/darwin/ios/framework/Headers/Flutter.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
/**
BREAKING CHANGES:

December 17, 2018:
- Changed designated initializer on FlutterEngine

October 5, 2018:
- Removed FlutterNavigationController.h/.mm
- Changed return signature of `FlutterDartHeadlessCodeRunner.run*` from void
Expand Down
22 changes: 21 additions & 1 deletion shell/platform/darwin/ios/framework/Headers/FlutterEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,28 @@ FLUTTER_EXPORT
* the threads used by this FlutterEngine.
* @param projectOrNil The `FlutterDartProject` to run.
*/
- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)projectOrNil;

/**
* Initialize this FlutterEngine with a `FlutterDartProject`.
*
* If the FlutterDartProject is not specified, the FlutterEngine will attempt to locate
* the project in a default location (the flutter_assets folder in the iOS application
* bundle).
*
* A newly initialized engine will not run the `FlutterDartProject` until either
* `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI:` is called.
*
* @param labelPrefix The label prefix used to identify threads for this instance. Should
* be unique across FlutterEngine instances, and is used in instrumentation to label
* the threads used by this FlutterEngine.
* @param projectOrNil The `FlutterDartProject` to run.
* @param allowHeadlessExecution Whether or not to allow this instance to continue
* running after passing a nil `FlutterViewController` to `-setViewController:`.
*/
- (instancetype)initWithName:(NSString*)labelPrefix
project:(FlutterDartProject*)projectOrNil NS_DESIGNATED_INITIALIZER;
project:(FlutterDartProject*)projectOrNil
allowHeadlessExecution:(BOOL)allowHeadlessExecution NS_DESIGNATED_INITIALIZER;

/**
* The default initializer is not available for this object.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,25 @@ FLUTTER_DEPRECATED("FlutterEngine should be used rather than FlutterHeadlessDart
* be unique across FlutterEngine instances
* @param projectOrNil The `FlutterDartProject` to run.
*/
- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)projectOrNil;

/**
* Iniitalize this FlutterHeadlessDartRunner with a `FlutterDartProject`.
*
* If the FlutterDartProject is not specified, the FlutterHeadlessDartRunner will attempt to locate
* the project in a default location.
*
* A newly initialized engine will not run the `FlutterDartProject` until either
* `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI` is called.
*
* @param labelPrefix The label prefix used to identify threads for this instance. Should
* be unique across FlutterEngine instances
* @param projectOrNil The `FlutterDartProject` to run.
* @param allowHeadlessExecution Must be set to `YES`.
*/
- (instancetype)initWithName:(NSString*)labelPrefix
project:(FlutterDartProject*)projectOrNil NS_DESIGNATED_INITIALIZER;
project:(FlutterDartProject*)projectOrNil
allowHeadlessExecution:(BOOL)allowHeadlessExecution NS_DESIGNATED_INITIALIZER;

/**
* Not recommended for use - will initialize with a default label ("io.flutter.headless")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ FLUTTER_EXPORT
*/
@property(nonatomic, getter=isViewOpaque) BOOL viewOpaque;

/**
* The `FlutterEngine` instance for this view controller.
*/
@property(weak, nonatomic, readonly) FlutterEngine* engine;

@end

#endif // FLUTTER_FLUTTERVIEWCONTROLLER_H_
41 changes: 37 additions & 4 deletions shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,22 @@ @implementation FlutterEngine {
fml::scoped_nsobject<FlutterBasicMessageChannel> _settingsChannel;

int64_t _nextTextureId;

BOOL _allowHeadlessExecution;
}

- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)projectOrNil {
return [self initWithName:labelPrefix project:projectOrNil allowHeadlessExecution:YES];
}

- (instancetype)initWithName:(NSString*)labelPrefix
project:(FlutterDartProject*)projectOrNil
allowHeadlessExecution:(BOOL)allowHeadlessExecution {
self = [super init];
NSAssert(self, @"Super init cannot be nil");
NSAssert(labelPrefix, @"labelPrefix is required");

_allowHeadlessExecution = allowHeadlessExecution;
_labelPrefix = [labelPrefix copy];

_weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterEngine>>(self);
Expand All @@ -76,7 +86,6 @@ - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*
_dartProject.reset([projectOrNil retain]);

_pluginPublications = [NSMutableDictionary new];
_publisher.reset([[FlutterObservatoryPublisher alloc] init]);
_platformViewsController.reset(new shell::FlutterPlatformViewsController());

[self setupChannels];
Expand Down Expand Up @@ -135,7 +144,14 @@ - (void)setViewController:(FlutterViewController*)viewController {
FML_DCHECK(self.iosPlatformView);
_viewController = [viewController getWeakPtr];
self.iosPlatformView->SetOwnerViewController(_viewController);
[self maybeSetupPlatformViewChannels];
if (!viewController && !_allowHeadlessExecution) {
[self resetChannels];

_shell.reset();
_threadHost.Reset();
} else {
[self maybeSetupPlatformViewChannels];
}
}

- (FlutterViewController*)viewController {
Expand Down Expand Up @@ -176,6 +192,20 @@ - (FlutterBasicMessageChannel*)settingsChannel {
return _settingsChannel.get();
}

- (void)resetChannels {
_localizationChannel.reset();
_navigationChannel.reset();
_platformChannel.reset();
_platformViewsChannel.reset();
_textInputChannel.reset();
_lifecycleChannel.reset();
_systemChannel.reset();
_settingsChannel.reset();
}

// If you add a channel, be sure to also update `resetChannels`.
// Channels get a reference to the engine, and therefore need manual
// cleanup for proper collection.
- (void)setupChannels {
_localizationChannel.reset([[FlutterMethodChannel alloc]
initWithName:@"flutter/localization"
Expand Down Expand Up @@ -221,8 +251,6 @@ - (void)setupChannels {
_textInputPlugin.get().textInputDelegate = self;

_platformPlugin.reset([[FlutterPlatformPlugin alloc] initWithEngine:[self getWeakPtr]]);

[self maybeSetupPlatformViewChannels];
}

- (void)maybeSetupPlatformViewChannels {
Expand Down Expand Up @@ -348,6 +376,11 @@ - (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
FML_LOG(ERROR) << "Could not start a shell FlutterEngine with entrypoint: "
<< entrypoint.UTF8String;
} else {
[self setupChannels];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

random blast from the past: didn't we do this on init already? Why do we need to do it again?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it was because the channels could get reset between there and here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how would it though. Looking at the code, it only happens on destroyContext and based on the doc, the object is in an unusable state until it's deallocated. This second setupChannels seems redundant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't remember now and I can't see a code path where this happens. I think we can probably kill one of these - I suspec tthe one in the initializer is wrong because actually using a channel before the engine is launched would be an error.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SG, thanks for double checking

if (!_platformViewsController) {
_platformViewsController.reset(new shell::FlutterPlatformViewsController());
}
_publisher.reset([[FlutterObservatoryPublisher alloc] init]);
[self maybeSetupPlatformViewChannels];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@ @implementation FlutterHeadlessDartRunner {
}

- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)projectOrNil {
return [super initWithName:labelPrefix project:projectOrNil];
return [self initWithName:labelPrefix project:projectOrNil allowHeadlessExecution:YES];
}

- (instancetype)initWithName:(NSString*)labelPrefix
project:(FlutterDartProject*)projectOrNil
allowHeadlessExecution:(BOOL)allowHeadlessExecution {
NSAssert(allowHeadlessExecution == YES,
@"Cannot initialize a FlutterHeadlessDartRunner without headless execution.");
return [super initWithName:labelPrefix
project:projectOrNil
allowHeadlessExecution:allowHeadlessExecution];
}
- (instancetype)init {
return [self initWithName:@"io.flutter.headless" project:nil];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ - (instancetype)initWithProject:(FlutterDartProject*)projectOrNil
if (self) {
_viewOpaque = YES;
_weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterViewController>>(self);
_engine.reset([[FlutterEngine alloc] initWithName:@"io.flutter" project:projectOrNil]);
_engine.reset([[FlutterEngine alloc] initWithName:@"io.flutter"
project:projectOrNil
allowHeadlessExecution:NO]);
_flutterView.reset([[FlutterView alloc] initWithDelegate:_engine opaque:self.isViewOpaque]);
[_engine.get() createShell:nil libraryURI:nil];
_engineNeedsLaunch = YES;
Expand Down Expand Up @@ -116,8 +118,8 @@ - (void)performCommonViewControllerInitialization {
[self setupNotificationCenterObservers];
}

- (fml::scoped_nsobject<FlutterEngine>)engine {
return _engine;
- (FlutterEngine*)engine {
return _engine.get();
}

- (fml::WeakPtr<FlutterViewController>)getWeakPtr {
Expand Down Expand Up @@ -389,9 +391,9 @@ - (void)viewWillAppear:(BOOL)animated {

if (_engineNeedsLaunch) {
[_engine.get() launchEngine:nil libraryURI:nil];
[_engine.get() setViewController:self];
_engineNeedsLaunch = NO;
}
[_engine.get() setViewController:self];

// Only recreate surface on subsequent appearances when viewport metrics are known.
// First time surface creation is done on viewDidLayoutSubviews.
Expand Down Expand Up @@ -423,7 +425,7 @@ - (void)viewDidDisappear:(BOOL)animated {
TRACE_EVENT0("flutter", "viewDidDisappear");
[self surfaceUpdated:NO];
[[_engine.get() lifecycleChannel] sendMessage:@"AppLifecycleState.paused"];

[_engine.get() setViewController:nil];
[super viewDidDisappear:animated];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
- (fml::WeakPtr<FlutterViewController>)getWeakPtr;
- (shell::FlutterPlatformViewsController*)platformViewsController;

@property(readonly) fml::scoped_nsobject<FlutterEngine> engine;

@end

#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEWCONTROLLER_INTERNAL_H_