mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Allow FlutterViewController to be released when not initialized with an engine (flutter/engine#6879)
* Break cycle between FlutterViewController and FlutterEngine
This commit is contained in:
parent
60a0e7aeb4
commit
ea0b78bc5d
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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_
|
||||
|
||||
@ -60,12 +60,22 @@
|
||||
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);
|
||||
@ -76,7 +86,6 @@
|
||||
_dartProject.reset([projectOrNil retain]);
|
||||
|
||||
_pluginPublications = [NSMutableDictionary new];
|
||||
_publisher.reset([[FlutterObservatoryPublisher alloc] init]);
|
||||
_platformViewsController.reset(new shell::FlutterPlatformViewsController());
|
||||
|
||||
[self setupChannels];
|
||||
@ -135,7 +144,14 @@
|
||||
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 {
|
||||
@ -176,6 +192,20 @@
|
||||
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"
|
||||
@ -221,8 +251,6 @@
|
||||
_textInputPlugin.get().textInputDelegate = self;
|
||||
|
||||
_platformPlugin.reset([[FlutterPlatformPlugin alloc] initWithEngine:[self getWeakPtr]]);
|
||||
|
||||
[self maybeSetupPlatformViewChannels];
|
||||
}
|
||||
|
||||
- (void)maybeSetupPlatformViewChannels {
|
||||
@ -348,6 +376,11 @@
|
||||
FML_LOG(ERROR) << "Could not start a shell FlutterEngine with entrypoint: "
|
||||
<< entrypoint.UTF8String;
|
||||
} else {
|
||||
[self setupChannels];
|
||||
if (!_platformViewsController) {
|
||||
_platformViewsController.reset(new shell::FlutterPlatformViewsController());
|
||||
}
|
||||
_publisher.reset([[FlutterObservatoryPublisher alloc] init]);
|
||||
[self maybeSetupPlatformViewChannels];
|
||||
}
|
||||
|
||||
|
||||
@ -28,7 +28,17 @@
|
||||
}
|
||||
|
||||
- (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];
|
||||
|
||||
@ -67,7 +67,9 @@
|
||||
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;
|
||||
@ -116,8 +118,8 @@
|
||||
[self setupNotificationCenterObservers];
|
||||
}
|
||||
|
||||
- (fml::scoped_nsobject<FlutterEngine>)engine {
|
||||
return _engine;
|
||||
- (FlutterEngine*)engine {
|
||||
return _engine.get();
|
||||
}
|
||||
|
||||
- (fml::WeakPtr<FlutterViewController>)getWeakPtr {
|
||||
@ -389,9 +391,9 @@
|
||||
|
||||
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.
|
||||
@ -423,7 +425,7 @@
|
||||
TRACE_EVENT0("flutter", "viewDidDisappear");
|
||||
[self surfaceUpdated:NO];
|
||||
[[_engine.get() lifecycleChannel] sendMessage:@"AppLifecycleState.paused"];
|
||||
|
||||
[_engine.get() setViewController:nil];
|
||||
[super viewDidDisappear:animated];
|
||||
}
|
||||
|
||||
|
||||
@ -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_
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user