iOS: Migrate FlutterEngine to ARC (flutter/engine#55590)

Migrates `FlutterEnging` from manual reference counting to ARC. Migrates properties from `retain` to strong and `assign` to `weak` (where referencing an Obj-C object).

No semantic changes, therefore no changes to tests.

Issue: https://github.com/flutter/flutter/issues/137801

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
Chris Bracken 2024-10-04 08:00:30 -07:00 committed by GitHub
parent e1a8f27e21
commit a2ac734e10
5 changed files with 254 additions and 362 deletions

View File

@ -70,7 +70,9 @@ source_set("flutter_framework_source_arc") {
"framework/Source/FlutterDartVMServicePublisher.mm", "framework/Source/FlutterDartVMServicePublisher.mm",
"framework/Source/FlutterEmbedderKeyResponder.h", "framework/Source/FlutterEmbedderKeyResponder.h",
"framework/Source/FlutterEmbedderKeyResponder.mm", "framework/Source/FlutterEmbedderKeyResponder.mm",
"framework/Source/FlutterEngine.mm",
"framework/Source/FlutterEngineGroup.mm", "framework/Source/FlutterEngineGroup.mm",
"framework/Source/FlutterEngine_Internal.h",
"framework/Source/FlutterHeadlessDartRunner.mm", "framework/Source/FlutterHeadlessDartRunner.mm",
"framework/Source/FlutterKeyPrimaryResponder.h", "framework/Source/FlutterKeyPrimaryResponder.h",
"framework/Source/FlutterKeySecondaryResponder.h", "framework/Source/FlutterKeySecondaryResponder.h",
@ -186,8 +188,6 @@ source_set("flutter_framework_source") {
# iOS embedder is migrating to ARC. # iOS embedder is migrating to ARC.
# New files are highly encouraged to be in ARC. # New files are highly encouraged to be in ARC.
# To add new files in ARC, add them to the `flutter_framework_source_arc` target. # To add new files in ARC, add them to the `flutter_framework_source_arc` target.
"framework/Source/FlutterEngine.mm",
"framework/Source/FlutterEngine_Internal.h",
"framework/Source/FlutterViewController.mm", "framework/Source/FlutterViewController.mm",
"framework/Source/FlutterViewController_Internal.h", "framework/Source/FlutterViewController_Internal.h",
"platform_view_ios.h", "platform_view_ios.h",

View File

@ -42,6 +42,8 @@
#import "flutter/shell/platform/darwin/ios/rendering_api_selection.h" #import "flutter/shell/platform/darwin/ios/rendering_api_selection.h"
#include "flutter/shell/profiling/sampling_profiler.h" #include "flutter/shell/profiling/sampling_profiler.h"
FLUTTER_ASSERT_ARC
/// Inheriting ThreadConfigurer and use iOS platform thread API to configure the thread priorities /// Inheriting ThreadConfigurer and use iOS platform thread API to configure the thread priorities
/// Using iOS platform thread API to configure thread priority /// Using iOS platform thread API to configure thread priority
static void IOSPlatformThreadConfigSetter(const fml::Thread::ThreadConfig& config) { static void IOSPlatformThreadConfigSetter(const fml::Thread::ThreadConfig& config) {
@ -88,7 +90,7 @@ NSString* const kFlutterKeyDataChannel = @"flutter/keydata";
static constexpr int kNumProfilerSamplesPerSec = 5; static constexpr int kNumProfilerSamplesPerSec = 5;
@interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar> @interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
@property(nonatomic, assign) FlutterEngine* flutterEngine; @property(nonatomic, weak) FlutterEngine* flutterEngine;
- (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine; - (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine;
@end @end
@ -97,6 +99,14 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
FlutterTextInputDelegate, FlutterTextInputDelegate,
FlutterBinaryMessenger, FlutterBinaryMessenger,
FlutterTextureRegistry> FlutterTextureRegistry>
#pragma mark - Properties
@property(nonatomic, readonly) FlutterDartProject* dartProject;
@property(nonatomic, readonly, copy) NSString* labelPrefix;
@property(nonatomic, readonly, assign) BOOL allowHeadlessExecution;
@property(nonatomic, readonly, assign) BOOL restorationEnabled;
// Maintains a dictionary of plugin names that have registered with the engine. Used by // Maintains a dictionary of plugin names that have registered with the engine. Used by
// FlutterEngineRegistrar to implement a FlutterPluginRegistrar. // FlutterEngineRegistrar to implement a FlutterPluginRegistrar.
@property(nonatomic, readonly) NSMutableDictionary* pluginPublications; @property(nonatomic, readonly) NSMutableDictionary* pluginPublications;
@ -104,55 +114,53 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
@property(nonatomic, readwrite, copy) NSString* isolateId; @property(nonatomic, readwrite, copy) NSString* isolateId;
@property(nonatomic, copy) NSString* initialRoute; @property(nonatomic, copy) NSString* initialRoute;
@property(nonatomic, retain) id<NSObject> flutterViewControllerWillDeallocObserver; @property(nonatomic, strong) id<NSObject> flutterViewControllerWillDeallocObserver;
@property(nonatomic, strong) FlutterDartVMServicePublisher* publisher;
@property(nonatomic, assign) int64_t nextTextureId;
#pragma mark - Channel properties
@property(nonatomic, strong) FlutterPlatformPlugin* platformPlugin;
@property(nonatomic, strong) FlutterTextInputPlugin* textInputPlugin;
@property(nonatomic, strong) FlutterUndoManagerPlugin* undoManagerPlugin;
@property(nonatomic, strong) FlutterSpellCheckPlugin* spellCheckPlugin;
@property(nonatomic, strong) FlutterRestorationPlugin* restorationPlugin;
@property(nonatomic, strong) FlutterMethodChannel* localizationChannel;
@property(nonatomic, strong) FlutterMethodChannel* navigationChannel;
@property(nonatomic, strong) FlutterMethodChannel* restorationChannel;
@property(nonatomic, strong) FlutterMethodChannel* platformChannel;
@property(nonatomic, strong) FlutterMethodChannel* platformViewsChannel;
@property(nonatomic, strong) FlutterMethodChannel* textInputChannel;
@property(nonatomic, strong) FlutterMethodChannel* undoManagerChannel;
@property(nonatomic, strong) FlutterMethodChannel* scribbleChannel;
@property(nonatomic, strong) FlutterMethodChannel* spellCheckChannel;
@property(nonatomic, strong) FlutterBasicMessageChannel* lifecycleChannel;
@property(nonatomic, strong) FlutterBasicMessageChannel* systemChannel;
@property(nonatomic, strong) FlutterBasicMessageChannel* settingsChannel;
@property(nonatomic, strong) FlutterBasicMessageChannel* keyEventChannel;
@property(nonatomic, strong) FlutterMethodChannel* screenshotChannel;
#pragma mark - Embedder API properties #pragma mark - Embedder API properties
@property(nonatomic, assign) BOOL enableEmbedderAPI; @property(nonatomic, assign) BOOL enableEmbedderAPI;
// Function pointers for interacting with the embedder.h API. // Function pointers for interacting with the embedder.h API.
@property(nonatomic) FlutterEngineProcTable& embedderAPI; @property(nonatomic) FlutterEngineProcTable& embedderAPI;
@end @end
@implementation FlutterEngine { @implementation FlutterEngine {
fml::scoped_nsobject<FlutterDartProject> _dartProject;
std::shared_ptr<flutter::ThreadHost> _threadHost; std::shared_ptr<flutter::ThreadHost> _threadHost;
std::unique_ptr<flutter::Shell> _shell; std::unique_ptr<flutter::Shell> _shell;
NSString* _labelPrefix;
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory;
// TODO(cbracken): https://github.com/flutter/flutter/issues/155943
// Migrate to @property(nonatomic, weak).
fml::WeakNSObject<FlutterViewController> _viewController; fml::WeakNSObject<FlutterViewController> _viewController;
fml::scoped_nsobject<FlutterDartVMServicePublisher> _publisher;
std::shared_ptr<flutter::PlatformViewsController> _platformViewsController; std::shared_ptr<flutter::PlatformViewsController> _platformViewsController;
flutter::IOSRenderingAPI _renderingApi; flutter::IOSRenderingAPI _renderingApi;
std::shared_ptr<flutter::ProfilerMetricsIOS> _profiler_metrics; std::shared_ptr<flutter::ProfilerMetricsIOS> _profiler_metrics;
std::shared_ptr<flutter::SamplingProfiler> _profiler; std::shared_ptr<flutter::SamplingProfiler> _profiler;
// Channels
fml::scoped_nsobject<FlutterPlatformPlugin> _platformPlugin;
fml::scoped_nsobject<FlutterTextInputPlugin> _textInputPlugin;
fml::scoped_nsobject<FlutterUndoManagerPlugin> _undoManagerPlugin;
fml::scoped_nsobject<FlutterSpellCheckPlugin> _spellCheckPlugin;
fml::scoped_nsobject<FlutterRestorationPlugin> _restorationPlugin;
fml::scoped_nsobject<FlutterMethodChannel> _localizationChannel;
fml::scoped_nsobject<FlutterMethodChannel> _navigationChannel;
fml::scoped_nsobject<FlutterMethodChannel> _restorationChannel;
fml::scoped_nsobject<FlutterMethodChannel> _platformChannel;
fml::scoped_nsobject<FlutterMethodChannel> _platformViewsChannel;
fml::scoped_nsobject<FlutterMethodChannel> _textInputChannel;
fml::scoped_nsobject<FlutterMethodChannel> _undoManagerChannel;
fml::scoped_nsobject<FlutterMethodChannel> _scribbleChannel;
fml::scoped_nsobject<FlutterMethodChannel> _spellCheckChannel;
fml::scoped_nsobject<FlutterBasicMessageChannel> _lifecycleChannel;
fml::scoped_nsobject<FlutterBasicMessageChannel> _systemChannel;
fml::scoped_nsobject<FlutterBasicMessageChannel> _settingsChannel;
fml::scoped_nsobject<FlutterBasicMessageChannel> _keyEventChannel;
fml::scoped_nsobject<FlutterMethodChannel> _screenshotChannel;
int64_t _nextTextureId;
BOOL _allowHeadlessExecution;
BOOL _restorationEnabled;
FlutterBinaryMessengerRelay* _binaryMessenger; FlutterBinaryMessengerRelay* _binaryMessenger;
FlutterTextureRegistryRelay* _textureRegistry; FlutterTextureRegistryRelay* _textureRegistry;
std::unique_ptr<flutter::ConnectionCollection> _connections; std::unique_ptr<flutter::ConnectionCollection> _connections;
@ -190,29 +198,21 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
_restorationEnabled = restorationEnabled; _restorationEnabled = restorationEnabled;
_allowHeadlessExecution = allowHeadlessExecution; _allowHeadlessExecution = allowHeadlessExecution;
_labelPrefix = [labelPrefix copy]; _labelPrefix = [labelPrefix copy];
_dartProject = project ?: [[FlutterDartProject alloc] init];
_weakFactory = std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(self); _enableEmbedderAPI = _dartProject.settings.enable_embedder_api;
if (project == nil) {
_dartProject.reset([[FlutterDartProject alloc] init]);
} else {
_dartProject.reset([project retain]);
}
_enableEmbedderAPI = _dartProject.get().settings.enable_embedder_api;
if (_enableEmbedderAPI) { if (_enableEmbedderAPI) {
NSLog(@"============== iOS: enable_embedder_api is on =============="); NSLog(@"============== iOS: enable_embedder_api is on ==============");
_embedderAPI.struct_size = sizeof(FlutterEngineProcTable); _embedderAPI.struct_size = sizeof(FlutterEngineProcTable);
FlutterEngineGetProcAddresses(&_embedderAPI); FlutterEngineGetProcAddresses(&_embedderAPI);
} }
if (!EnableTracingIfNecessary([_dartProject.get() settings])) { if (!EnableTracingIfNecessary(_dartProject.settings)) {
NSLog( NSLog(
@"Cannot create a FlutterEngine instance in debug mode without Flutter tooling or " @"Cannot create a FlutterEngine instance in debug mode without Flutter tooling or "
@"Xcode.\n\nTo launch in debug mode in iOS 14+, run flutter run from Flutter tools, run " @"Xcode.\n\nTo launch in debug mode in iOS 14+, run flutter run from Flutter tools, run "
@"from an IDE with a Flutter IDE plugin or run the iOS project from Xcode.\nAlternatively " @"from an IDE with a Flutter IDE plugin or run the iOS project from Xcode.\nAlternatively "
@"profile and release mode apps can be launched from the home screen."); @"profile and release mode apps can be launched from the home screen.");
[self release];
return nil; return nil;
} }
@ -292,35 +292,22 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
object:self object:self
userInfo:nil]; userInfo:nil];
// It will be destroyed and invalidate its weak pointers // nil out weak references.
// before any other members are destroyed. // TODO(cbracken): https://github.com/flutter/flutter/issues/156222
_weakFactory.reset(); // Ensure that FlutterEngineRegistrar is using weak pointers, then eliminate this code.
/// nil out weak references.
[_registrars [_registrars
enumerateKeysAndObjectsUsingBlock:^(id key, FlutterEngineRegistrar* registrar, BOOL* stop) { enumerateKeysAndObjectsUsingBlock:^(id key, FlutterEngineRegistrar* registrar, BOOL* stop) {
registrar.flutterEngine = nil; registrar.flutterEngine = nil;
}]; }];
[_labelPrefix release];
[_initialRoute release];
[_pluginPublications release];
[_registrars release];
_binaryMessenger.parent = nil; _binaryMessenger.parent = nil;
_textureRegistry.parent = nil; _textureRegistry.parent = nil;
[_binaryMessenger release];
[_textureRegistry release];
_textureRegistry = nil;
[_isolateId release];
NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
if (_flutterViewControllerWillDeallocObserver) { if (_flutterViewControllerWillDeallocObserver) {
[center removeObserver:_flutterViewControllerWillDeallocObserver]; [center removeObserver:_flutterViewControllerWillDeallocObserver];
[_flutterViewControllerWillDeallocObserver release];
} }
[center removeObserver:self]; [center removeObserver:self];
[super dealloc];
} }
- (flutter::Shell&)shell { - (flutter::Shell&)shell {
@ -328,10 +315,6 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
return *_shell; return *_shell;
} }
- (fml::WeakNSObject<FlutterEngine>)getWeakNSObject {
return _weakFactory->GetWeakNSObject();
}
- (void)updateViewportMetrics:(flutter::ViewportMetrics)viewportMetrics { - (void)updateViewportMetrics:(flutter::ViewportMetrics)viewportMetrics {
if (!self.platformView) { if (!self.platformView) {
return; return;
@ -429,16 +412,16 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
self.iosPlatformView->SetOwnerViewController(_viewController); self.iosPlatformView->SetOwnerViewController(_viewController);
[self maybeSetupPlatformViewChannels]; [self maybeSetupPlatformViewChannels];
[self updateDisplays]; [self updateDisplays];
_textInputPlugin.get().viewController = viewController; self.textInputPlugin.viewController = viewController;
if (viewController) { if (viewController) {
__block FlutterEngine* blockSelf = self; __weak __block FlutterEngine* weakSelf = self;
self.flutterViewControllerWillDeallocObserver = self.flutterViewControllerWillDeallocObserver =
[[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc [[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc
object:viewController object:viewController
queue:[NSOperationQueue mainQueue] queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification* note) { usingBlock:^(NSNotification* note) {
[blockSelf notifyViewControllerDeallocated]; [weakSelf notifyViewControllerDeallocated];
}]; }];
} else { } else {
self.flutterViewControllerWillDeallocObserver = nil; self.flutterViewControllerWillDeallocObserver = nil;
@ -455,16 +438,15 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
if (_flutterViewControllerWillDeallocObserver) { if (_flutterViewControllerWillDeallocObserver) {
[[NSNotificationCenter defaultCenter] [[NSNotificationCenter defaultCenter]
removeObserver:_flutterViewControllerWillDeallocObserver]; removeObserver:_flutterViewControllerWillDeallocObserver];
[_flutterViewControllerWillDeallocObserver release];
} }
_flutterViewControllerWillDeallocObserver = [observer retain]; _flutterViewControllerWillDeallocObserver = observer;
} }
} }
- (void)notifyViewControllerDeallocated { - (void)notifyViewControllerDeallocated {
[[self lifecycleChannel] sendMessage:@"AppLifecycleState.detached"]; [self.lifecycleChannel sendMessage:@"AppLifecycleState.detached"];
_textInputPlugin.get().viewController = nil; self.textInputPlugin.viewController = nil;
if (!_allowHeadlessExecution) { if (!self.allowHeadlessExecution) {
[self destroyContext]; [self destroyContext];
} else if (_shell) { } else if (_shell) {
flutter::PlatformViewIOS* platform_view = [self iosPlatformView]; flutter::PlatformViewIOS* platform_view = [self iosPlatformView];
@ -472,7 +454,7 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
platform_view->SetOwnerViewController({}); platform_view->SetOwnerViewController({});
} }
} }
[_textInputPlugin.get() resetViewResponder]; [self.textInputPlugin resetViewResponder];
_viewController.reset(); _viewController.reset();
} }
@ -492,88 +474,46 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
return _viewController.get(); return _viewController.get();
} }
- (FlutterPlatformPlugin*)platformPlugin {
return _platformPlugin.get();
}
- (std::shared_ptr<flutter::PlatformViewsController>&)platformViewsController { - (std::shared_ptr<flutter::PlatformViewsController>&)platformViewsController {
return _platformViewsController; return _platformViewsController;
} }
- (FlutterTextInputPlugin*)textInputPlugin {
return _textInputPlugin.get();
}
- (FlutterUndoManagerPlugin*)undoManagerPlugin {
return _undoManagerPlugin.get();
}
- (FlutterRestorationPlugin*)restorationPlugin {
return _restorationPlugin.get();
}
- (FlutterMethodChannel*)localizationChannel {
return _localizationChannel.get();
}
- (FlutterMethodChannel*)navigationChannel {
return _navigationChannel.get();
}
- (FlutterMethodChannel*)restorationChannel {
return _restorationChannel.get();
}
- (FlutterMethodChannel*)platformChannel {
return _platformChannel.get();
}
- (FlutterMethodChannel*)textInputChannel {
return _textInputChannel.get();
}
- (FlutterMethodChannel*)undoManagerChannel {
return _undoManagerChannel.get();
}
- (FlutterMethodChannel*)scribbleChannel {
return _scribbleChannel.get();
}
- (FlutterMethodChannel*)spellCheckChannel {
return _spellCheckChannel.get();
}
- (FlutterBasicMessageChannel*)lifecycleChannel {
return _lifecycleChannel.get();
}
- (FlutterBasicMessageChannel*)systemChannel {
return _systemChannel.get();
}
- (FlutterBasicMessageChannel*)settingsChannel {
return _settingsChannel.get();
}
- (FlutterBasicMessageChannel*)keyEventChannel {
return _keyEventChannel.get();
}
- (NSURL*)observatoryUrl { - (NSURL*)observatoryUrl {
return [_publisher.get() url]; return self.publisher.url;
} }
- (NSURL*)vmServiceUrl { - (NSURL*)vmServiceUrl {
return [_publisher.get() url]; return self.publisher.url;
} }
- (void)resetChannels { - (void)resetChannels {
_localizationChannel.reset(); self.localizationChannel = nil;
_navigationChannel.reset(); self.navigationChannel = nil;
_restorationChannel.reset(); self.restorationChannel = nil;
_platformChannel.reset(); self.platformChannel = nil;
_platformViewsChannel.reset(); self.platformViewsChannel = nil;
_textInputChannel.reset(); self.textInputChannel = nil;
_undoManagerChannel.reset(); self.undoManagerChannel = nil;
_scribbleChannel.reset(); self.scribbleChannel = nil;
_lifecycleChannel.reset(); self.lifecycleChannel = nil;
_systemChannel.reset(); self.systemChannel = nil;
_settingsChannel.reset(); self.settingsChannel = nil;
_keyEventChannel.reset(); self.keyEventChannel = nil;
_spellCheckChannel.reset(); self.spellCheckChannel = nil;
} }
- (void)startProfiler { - (void)startProfiler {
FML_DCHECK(!_threadHost->name_prefix.empty()); FML_DCHECK(!_threadHost->name_prefix.empty());
_profiler_metrics = std::make_shared<flutter::ProfilerMetricsIOS>(); _profiler_metrics = std::make_shared<flutter::ProfilerMetricsIOS>();
__weak FlutterEngine* weakSelf = self;
_profiler = std::make_shared<flutter::SamplingProfiler>( _profiler = std::make_shared<flutter::SamplingProfiler>(
_threadHost->name_prefix.c_str(), _threadHost->profiler_thread->GetTaskRunner(), _threadHost->name_prefix.c_str(), _threadHost->profiler_thread->GetTaskRunner(),
[self]() { return self->_profiler_metrics->GenerateSample(); }, kNumProfilerSamplesPerSec); [weakSelf]() {
FlutterEngine* strongSelf = weakSelf;
return strongSelf ? strongSelf->_profiler_metrics->GenerateSample()
: flutter::ProfileSample{};
},
kNumProfilerSamplesPerSec);
_profiler->Start(); _profiler->Start();
} }
@ -583,119 +523,114 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
- (void)setUpChannels { - (void)setUpChannels {
// This will be invoked once the shell is done setting up and the isolate ID // This will be invoked once the shell is done setting up and the isolate ID
// for the UI isolate is available. // for the UI isolate is available.
fml::WeakNSObject<FlutterEngine> weakSelf = [self getWeakNSObject]; __weak FlutterEngine* weakSelf = self;
[_binaryMessenger setMessageHandlerOnChannel:@"flutter/isolate" [_binaryMessenger setMessageHandlerOnChannel:@"flutter/isolate"
binaryMessageHandler:^(NSData* message, FlutterBinaryReply reply) { binaryMessageHandler:^(NSData* message, FlutterBinaryReply reply) {
if (weakSelf) { if (weakSelf) {
weakSelf.get().isolateId = weakSelf.isolateId =
[[FlutterStringCodec sharedInstance] decode:message]; [[FlutterStringCodec sharedInstance] decode:message];
} }
}]; }];
_localizationChannel.reset([[FlutterMethodChannel alloc] self.localizationChannel =
initWithName:@"flutter/localization" [[FlutterMethodChannel alloc] initWithName:@"flutter/localization"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterJSONMethodCodec sharedInstance]]); codec:[FlutterJSONMethodCodec sharedInstance]];
_navigationChannel.reset([[FlutterMethodChannel alloc] self.navigationChannel =
initWithName:@"flutter/navigation" [[FlutterMethodChannel alloc] initWithName:@"flutter/navigation"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterJSONMethodCodec sharedInstance]]); codec:[FlutterJSONMethodCodec sharedInstance]];
if ([_initialRoute length] > 0) { if ([_initialRoute length] > 0) {
// Flutter isn't ready to receive this method call yet but the channel buffer will cache this. // Flutter isn't ready to receive this method call yet but the channel buffer will cache this.
[_navigationChannel invokeMethod:@"setInitialRoute" arguments:_initialRoute]; [self.navigationChannel invokeMethod:@"setInitialRoute" arguments:_initialRoute];
[_initialRoute release];
_initialRoute = nil; _initialRoute = nil;
} }
_restorationChannel.reset([[FlutterMethodChannel alloc] self.restorationChannel =
initWithName:@"flutter/restoration" [[FlutterMethodChannel alloc] initWithName:@"flutter/restoration"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterStandardMethodCodec sharedInstance]]); codec:[FlutterStandardMethodCodec sharedInstance]];
_platformChannel.reset([[FlutterMethodChannel alloc] self.platformChannel =
initWithName:@"flutter/platform" [[FlutterMethodChannel alloc] initWithName:@"flutter/platform"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterJSONMethodCodec sharedInstance]]); codec:[FlutterJSONMethodCodec sharedInstance]];
_platformViewsChannel.reset([[FlutterMethodChannel alloc] self.platformViewsChannel =
initWithName:@"flutter/platform_views" [[FlutterMethodChannel alloc] initWithName:@"flutter/platform_views"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterStandardMethodCodec sharedInstance]]); codec:[FlutterStandardMethodCodec sharedInstance]];
_textInputChannel.reset([[FlutterMethodChannel alloc] self.textInputChannel =
initWithName:@"flutter/textinput" [[FlutterMethodChannel alloc] initWithName:@"flutter/textinput"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterJSONMethodCodec sharedInstance]]); codec:[FlutterJSONMethodCodec sharedInstance]];
_undoManagerChannel.reset([[FlutterMethodChannel alloc] self.undoManagerChannel =
initWithName:@"flutter/undomanager" [[FlutterMethodChannel alloc] initWithName:@"flutter/undomanager"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterJSONMethodCodec sharedInstance]]); codec:[FlutterJSONMethodCodec sharedInstance]];
_scribbleChannel.reset([[FlutterMethodChannel alloc] self.scribbleChannel =
initWithName:@"flutter/scribble" [[FlutterMethodChannel alloc] initWithName:@"flutter/scribble"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterJSONMethodCodec sharedInstance]]); codec:[FlutterJSONMethodCodec sharedInstance]];
_spellCheckChannel.reset([[FlutterMethodChannel alloc] self.spellCheckChannel =
initWithName:@"flutter/spellcheck" [[FlutterMethodChannel alloc] initWithName:@"flutter/spellcheck"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterStandardMethodCodec sharedInstance]]); codec:[FlutterStandardMethodCodec sharedInstance]];
_lifecycleChannel.reset([[FlutterBasicMessageChannel alloc] self.lifecycleChannel =
initWithName:@"flutter/lifecycle" [[FlutterBasicMessageChannel alloc] initWithName:@"flutter/lifecycle"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterStringCodec sharedInstance]]); codec:[FlutterStringCodec sharedInstance]];
_systemChannel.reset([[FlutterBasicMessageChannel alloc] self.systemChannel =
initWithName:@"flutter/system" [[FlutterBasicMessageChannel alloc] initWithName:@"flutter/system"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterJSONMessageCodec sharedInstance]]); codec:[FlutterJSONMessageCodec sharedInstance]];
_settingsChannel.reset([[FlutterBasicMessageChannel alloc] self.settingsChannel =
initWithName:@"flutter/settings" [[FlutterBasicMessageChannel alloc] initWithName:@"flutter/settings"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterJSONMessageCodec sharedInstance]]); codec:[FlutterJSONMessageCodec sharedInstance]];
_keyEventChannel.reset([[FlutterBasicMessageChannel alloc] self.keyEventChannel =
initWithName:@"flutter/keyevent" [[FlutterBasicMessageChannel alloc] initWithName:@"flutter/keyevent"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterJSONMessageCodec sharedInstance]]); codec:[FlutterJSONMessageCodec sharedInstance]];
FlutterTextInputPlugin* textInputPlugin = [[FlutterTextInputPlugin alloc] initWithDelegate:self]; self.textInputPlugin = [[FlutterTextInputPlugin alloc] initWithDelegate:self];
_textInputPlugin.reset(textInputPlugin); self.textInputPlugin.indirectScribbleDelegate = self;
textInputPlugin.indirectScribbleDelegate = self; [self.textInputPlugin setUpIndirectScribbleInteraction:self.viewController];
[textInputPlugin setUpIndirectScribbleInteraction:self.viewController];
FlutterUndoManagerPlugin* undoManagerPlugin = self.undoManagerPlugin = [[FlutterUndoManagerPlugin alloc] initWithDelegate:self];
[[FlutterUndoManagerPlugin alloc] initWithDelegate:self]; self.platformPlugin = [[FlutterPlatformPlugin alloc] initWithEngine:self];
_undoManagerPlugin.reset(undoManagerPlugin);
_platformPlugin.reset([[FlutterPlatformPlugin alloc] initWithEngine:[self getWeakNSObject]]); self.restorationPlugin =
[[FlutterRestorationPlugin alloc] initWithChannel:self.restorationChannel
restorationEnabled:self.restorationEnabled];
self.spellCheckPlugin = [[FlutterSpellCheckPlugin alloc] init];
_restorationPlugin.reset([[FlutterRestorationPlugin alloc] self.screenshotChannel =
initWithChannel:_restorationChannel.get() [[FlutterMethodChannel alloc] initWithName:@"flutter/screenshot"
restorationEnabled:_restorationEnabled]);
_spellCheckPlugin.reset([[FlutterSpellCheckPlugin alloc] init]);
_screenshotChannel.reset([[FlutterMethodChannel alloc]
initWithName:@"flutter/screenshot"
binaryMessenger:self.binaryMessenger binaryMessenger:self.binaryMessenger
codec:[FlutterStandardMethodCodec sharedInstance]]); codec:[FlutterStandardMethodCodec sharedInstance]];
[_screenshotChannel.get() [self.screenshotChannel setMethodCallHandler:^(FlutterMethodCall* _Nonnull call,
setMethodCallHandler:^(FlutterMethodCall* _Nonnull call, FlutterResult _Nonnull result) { FlutterResult _Nonnull result) {
if (!(weakSelf.get() && weakSelf.get()->_shell && weakSelf.get()->_shell->IsSetup())) { FlutterEngine* strongSelf = weakSelf;
if (!(strongSelf && strongSelf->_shell && strongSelf->_shell->IsSetup())) {
return result([FlutterError return result([FlutterError
errorWithCode:@"invalid_state" errorWithCode:@"invalid_state"
message:@"Requesting screenshot while engine is not running." message:@"Requesting screenshot while engine is not running."
details:nil]); details:nil]);
} }
flutter::Rasterizer::Screenshot screenshot = flutter::Rasterizer::Screenshot screenshot =
[weakSelf.get() screenshot:flutter::Rasterizer::ScreenshotType::SurfaceData [strongSelf screenshot:flutter::Rasterizer::ScreenshotType::SurfaceData base64Encode:NO];
base64Encode:NO];
if (!screenshot.data) { if (!screenshot.data) {
return result([FlutterError errorWithCode:@"failure" return result([FlutterError errorWithCode:@"failure"
message:@"Unable to get screenshot." message:@"Unable to get screenshot."
@ -713,34 +648,29 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
- (void)maybeSetupPlatformViewChannels { - (void)maybeSetupPlatformViewChannels {
if (_shell && self.shell.IsSetup()) { if (_shell && self.shell.IsSetup()) {
FlutterPlatformPlugin* platformPlugin = _platformPlugin.get(); __weak FlutterEngine* weakSelf = self;
[_platformChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[platformPlugin handleMethodCall:call result:result]; [self.platformChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[weakSelf.platformPlugin handleMethodCall:call result:result];
}]; }];
fml::WeakNSObject<FlutterEngine> weakSelf = [self getWeakNSObject]; [self.platformViewsChannel
[_platformViewsChannel.get()
setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
if (weakSelf) { if (weakSelf) {
weakSelf.get().platformViewsController->OnMethodCall(call, result); weakSelf.platformViewsController->OnMethodCall(call, result);
} }
}]; }];
FlutterTextInputPlugin* textInputPlugin = _textInputPlugin.get(); [self.textInputChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[_textInputChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { [weakSelf.textInputPlugin handleMethodCall:call result:result];
[textInputPlugin handleMethodCall:call result:result];
}]; }];
FlutterUndoManagerPlugin* undoManagerPlugin = _undoManagerPlugin.get(); [self.undoManagerChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[_undoManagerChannel.get() [weakSelf.undoManagerPlugin handleMethodCall:call result:result];
setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[undoManagerPlugin handleMethodCall:call result:result];
}]; }];
FlutterSpellCheckPlugin* spellCheckPlugin = _spellCheckPlugin.get(); [self.spellCheckChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[_spellCheckChannel.get() [weakSelf.spellCheckPlugin handleMethodCall:call result:result];
setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[spellCheckPlugin handleMethodCall:call result:result];
}]; }];
} }
} }
@ -754,7 +684,7 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
libraryURI:(NSString*)libraryOrNil libraryURI:(NSString*)libraryOrNil
entrypointArgs:(NSArray<NSString*>*)entrypointArgs { entrypointArgs:(NSArray<NSString*>*)entrypointArgs {
// Launch the Dart application with the inferred run configuration. // Launch the Dart application with the inferred run configuration.
self.shell.RunEngine([_dartProject.get() runConfigurationForEntrypoint:entrypoint self.shell.RunEngine([self.dartProject runConfigurationForEntrypoint:entrypoint
libraryOrNil:libraryOrNil libraryOrNil:libraryOrNil
entrypointArgs:entrypointArgs]); entrypointArgs:entrypointArgs]);
} }
@ -765,8 +695,8 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
[self setUpChannels]; [self setUpChannels];
[self onLocaleUpdated:nil]; [self onLocaleUpdated:nil];
[self updateDisplays]; [self updateDisplays];
_publisher.reset([[FlutterDartVMServicePublisher alloc] self.publisher = [[FlutterDartVMServicePublisher alloc]
initWithEnableVMServicePublication:doesVMServicePublication]); initWithEnableVMServicePublication:doesVMServicePublication];
[self maybeSetupPlatformViewChannels]; [self maybeSetupPlatformViewChannels];
_shell->SetGpuAvailability(_isGpuDisabled ? flutter::GpuAvailability::kUnavailable _shell->SetGpuAvailability(_isGpuDisabled ? flutter::GpuAvailability::kUnavailable
: flutter::GpuAvailability::kAvailable); : flutter::GpuAvailability::kAvailable);
@ -845,7 +775,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
self.initialRoute = initialRoute; self.initialRoute = initialRoute;
auto settings = [_dartProject.get() settings]; auto settings = [self.dartProject settings];
if (initialRoute != nil) { if (initialRoute != nil) {
self.initialRoute = initialRoute; self.initialRoute = initialRoute;
} else if (settings.route.empty() == false) { } else if (settings.route.empty() == false) {
@ -854,24 +784,28 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
FlutterView.forceSoftwareRendering = settings.enable_software_rendering; FlutterView.forceSoftwareRendering = settings.enable_software_rendering;
auto platformData = [_dartProject.get() defaultPlatformData]; auto platformData = [self.dartProject defaultPlatformData];
SetEntryPoint(&settings, entrypoint, libraryURI); SetEntryPoint(&settings, entrypoint, libraryURI);
NSString* threadLabel = [FlutterEngine generateThreadLabel:_labelPrefix]; NSString* threadLabel = [FlutterEngine generateThreadLabel:self.labelPrefix];
_threadHost = std::make_shared<flutter::ThreadHost>(); _threadHost = std::make_shared<flutter::ThreadHost>();
*_threadHost = MakeThreadHost(threadLabel, settings); *_threadHost = MakeThreadHost(threadLabel, settings);
// Lambda captures by pointers to ObjC objects are fine here because the __weak FlutterEngine* weakSelf = self;
// create call is synchronous.
flutter::Shell::CreateCallback<flutter::PlatformView> on_create_platform_view = flutter::Shell::CreateCallback<flutter::PlatformView> on_create_platform_view =
[self](flutter::Shell& shell) { [weakSelf](flutter::Shell& shell) {
[self recreatePlatformViewController]; FlutterEngine* strongSelf = weakSelf;
self->_platformViewsController->SetTaskRunner( if (!strongSelf) {
return std::unique_ptr<flutter::PlatformViewIOS>();
}
[strongSelf recreatePlatformViewController];
strongSelf->_platformViewsController->SetTaskRunner(
shell.GetTaskRunners().GetPlatformTaskRunner()); shell.GetTaskRunners().GetPlatformTaskRunner());
return std::make_unique<flutter::PlatformViewIOS>( return std::make_unique<flutter::PlatformViewIOS>(
shell, self->_renderingApi, self->_platformViewsController, shell.GetTaskRunners(), shell, strongSelf->_renderingApi, strongSelf->_platformViewsController,
shell.GetConcurrentWorkerTaskRunner(), shell.GetIsGpuDisabledSyncSwitch()); shell.GetTaskRunners(), shell.GetConcurrentWorkerTaskRunner(),
shell.GetIsGpuDisabledSyncSwitch());
}; };
flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer = flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
@ -988,7 +922,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
if (_shell) { if (_shell) {
_shell->NotifyLowMemoryWarning(); _shell->NotifyLowMemoryWarning();
} }
[_systemChannel sendMessage:@{@"type" : @"memoryPressure"}]; [self.systemChannel sendMessage:@{@"type" : @"memoryPressure"}];
} }
#pragma mark - Text input delegate #pragma mark - Text input delegate
@ -996,7 +930,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
- (void)flutterTextInputView:(FlutterTextInputView*)textInputView - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
updateEditingClient:(int)client updateEditingClient:(int)client
withState:(NSDictionary*)state { withState:(NSDictionary*)state {
[_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingState" [self.textInputChannel invokeMethod:@"TextInputClient.updateEditingState"
arguments:@[ @(client), state ]]; arguments:@[ @(client), state ]];
} }
@ -1004,14 +938,14 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
updateEditingClient:(int)client updateEditingClient:(int)client
withState:(NSDictionary*)state withState:(NSDictionary*)state
withTag:(NSString*)tag { withTag:(NSString*)tag {
[_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingStateWithTag" [self.textInputChannel invokeMethod:@"TextInputClient.updateEditingStateWithTag"
arguments:@[ @(client), @{tag : state} ]]; arguments:@[ @(client), @{tag : state} ]];
} }
- (void)flutterTextInputView:(FlutterTextInputView*)textInputView - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
updateEditingClient:(int)client updateEditingClient:(int)client
withDelta:(NSDictionary*)delta { withDelta:(NSDictionary*)delta {
[_textInputChannel.get() invokeMethod:@"TextInputClient.updateEditingStateWithDeltas" [self.textInputChannel invokeMethod:@"TextInputClient.updateEditingStateWithDeltas"
arguments:@[ @(client), delta ]]; arguments:@[ @(client), delta ]];
} }
@ -1031,7 +965,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
stateString = @"FloatingCursorDragState.end"; stateString = @"FloatingCursorDragState.end";
break; break;
} }
[_textInputChannel.get() invokeMethod:@"TextInputClient.updateFloatingCursor" [self.textInputChannel invokeMethod:@"TextInputClient.updateFloatingCursor"
arguments:@[ @(client), stateString, position ]]; arguments:@[ @(client), stateString, position ]];
} }
@ -1078,7 +1012,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
actionString = @"TextInputAction.newline"; actionString = @"TextInputAction.newline";
break; break;
} }
[_textInputChannel.get() invokeMethod:@"TextInputClient.performAction" [self.textInputChannel invokeMethod:@"TextInputClient.performAction"
arguments:@[ @(client), actionString ]]; arguments:@[ @(client), actionString ]];
} }
@ -1086,13 +1020,13 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
showAutocorrectionPromptRectForStart:(NSUInteger)start showAutocorrectionPromptRectForStart:(NSUInteger)start
end:(NSUInteger)end end:(NSUInteger)end
withClient:(int)client { withClient:(int)client {
[_textInputChannel.get() invokeMethod:@"TextInputClient.showAutocorrectionPromptRect" [self.textInputChannel invokeMethod:@"TextInputClient.showAutocorrectionPromptRect"
arguments:@[ @(client), @(start), @(end) ]]; arguments:@[ @(client), @(start), @(end) ]];
} }
- (void)flutterTextInputView:(FlutterTextInputView*)textInputView - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
willDismissEditMenuWithTextInputClient:(int)client { willDismissEditMenuWithTextInputClient:(int)client {
[_platformChannel.get() invokeMethod:@"ContextMenu.onDismissSystemContextMenu" [self.platformChannel invokeMethod:@"ContextMenu.onDismissSystemContextMenu"
arguments:@[ @(client) ]]; arguments:@[ @(client) ]];
} }
@ -1102,7 +1036,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
// TODO(justinmc): Switch from the TextInputClient to Scribble channel when // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
// the framework has finished transitioning to the Scribble channel. // the framework has finished transitioning to the Scribble channel.
// https://github.com/flutter/flutter/pull/115296 // https://github.com/flutter/flutter/pull/115296
[_textInputChannel.get() invokeMethod:@"TextInputClient.showToolbar" arguments:@[ @(client) ]]; [self.textInputChannel invokeMethod:@"TextInputClient.showToolbar" arguments:@[ @(client) ]];
} }
- (void)flutterTextInputPlugin:(FlutterTextInputPlugin*)textInputPlugin - (void)flutterTextInputPlugin:(FlutterTextInputPlugin*)textInputPlugin
@ -1112,7 +1046,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
// TODO(justinmc): Switch from the TextInputClient to Scribble channel when // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
// the framework has finished transitioning to the Scribble channel. // the framework has finished transitioning to the Scribble channel.
// https://github.com/flutter/flutter/pull/115296 // https://github.com/flutter/flutter/pull/115296
[_textInputChannel.get() [self.textInputChannel
invokeMethod:@"TextInputClient.focusElement" invokeMethod:@"TextInputClient.focusElement"
arguments:@[ elementIdentifier, @(referencePoint.x), @(referencePoint.y) ] arguments:@[ elementIdentifier, @(referencePoint.x), @(referencePoint.y) ]
result:callback]; result:callback];
@ -1124,7 +1058,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
// TODO(justinmc): Switch from the TextInputClient to Scribble channel when // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
// the framework has finished transitioning to the Scribble channel. // the framework has finished transitioning to the Scribble channel.
// https://github.com/flutter/flutter/pull/115296 // https://github.com/flutter/flutter/pull/115296
[_textInputChannel.get() [self.textInputChannel
invokeMethod:@"TextInputClient.requestElementsInRect" invokeMethod:@"TextInputClient.requestElementsInRect"
arguments:@[ @(rect.origin.x), @(rect.origin.y), @(rect.size.width), @(rect.size.height) ] arguments:@[ @(rect.origin.x), @(rect.origin.y), @(rect.size.width), @(rect.size.height) ]
result:callback]; result:callback];
@ -1134,15 +1068,14 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
// TODO(justinmc): Switch from the TextInputClient to Scribble channel when // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
// the framework has finished transitioning to the Scribble channel. // the framework has finished transitioning to the Scribble channel.
// https://github.com/flutter/flutter/pull/115296 // https://github.com/flutter/flutter/pull/115296
[_textInputChannel.get() invokeMethod:@"TextInputClient.scribbleInteractionBegan" arguments:nil]; [self.textInputChannel invokeMethod:@"TextInputClient.scribbleInteractionBegan" arguments:nil];
} }
- (void)flutterTextInputViewScribbleInteractionFinished:(FlutterTextInputView*)textInputView { - (void)flutterTextInputViewScribbleInteractionFinished:(FlutterTextInputView*)textInputView {
// TODO(justinmc): Switch from the TextInputClient to Scribble channel when // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
// the framework has finished transitioning to the Scribble channel. // the framework has finished transitioning to the Scribble channel.
// https://github.com/flutter/flutter/pull/115296 // https://github.com/flutter/flutter/pull/115296
[_textInputChannel.get() invokeMethod:@"TextInputClient.scribbleInteractionFinished" [self.textInputChannel invokeMethod:@"TextInputClient.scribbleInteractionFinished" arguments:nil];
arguments:nil];
} }
- (void)flutterTextInputView:(FlutterTextInputView*)textInputView - (void)flutterTextInputView:(FlutterTextInputView*)textInputView
@ -1151,7 +1084,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
// TODO(justinmc): Switch from the TextInputClient to Scribble channel when // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
// the framework has finished transitioning to the Scribble channel. // the framework has finished transitioning to the Scribble channel.
// https://github.com/flutter/flutter/pull/115296 // https://github.com/flutter/flutter/pull/115296
[_textInputChannel.get() invokeMethod:@"TextInputClient.insertTextPlaceholder" [self.textInputChannel invokeMethod:@"TextInputClient.insertTextPlaceholder"
arguments:@[ @(client), @(size.width), @(size.height) ]]; arguments:@[ @(client), @(size.width), @(size.height) ]];
} }
@ -1160,7 +1093,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
// TODO(justinmc): Switch from the TextInputClient to Scribble channel when // TODO(justinmc): Switch from the TextInputClient to Scribble channel when
// the framework has finished transitioning to the Scribble channel. // the framework has finished transitioning to the Scribble channel.
// https://github.com/flutter/flutter/pull/115296 // https://github.com/flutter/flutter/pull/115296
[_textInputChannel.get() invokeMethod:@"TextInputClient.removeTextPlaceholder" [self.textInputChannel invokeMethod:@"TextInputClient.removeTextPlaceholder"
arguments:@[ @(client) ]]; arguments:@[ @(client) ]];
} }
@ -1169,7 +1102,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
// When flutter text input view resign first responder, send a message to // When flutter text input view resign first responder, send a message to
// framework to ensure the focus state is correct. This is useful when close // framework to ensure the focus state is correct. This is useful when close
// keyboard from platform side. // keyboard from platform side.
[_textInputChannel.get() invokeMethod:@"TextInputClient.onConnectionClosed" [self.textInputChannel invokeMethod:@"TextInputClient.onConnectionClosed"
arguments:@[ @(client) ]]; arguments:@[ @(client) ]];
// Platform view's first responder detection logic: // Platform view's first responder detection logic:
@ -1197,7 +1130,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
return; return;
} }
[_platformViewsChannel.get() invokeMethod:@"viewFocused" arguments:@(platform_view_id)]; [self.platformViewsChannel invokeMethod:@"viewFocused" arguments:@(platform_view_id)];
}); });
} }
@ -1205,7 +1138,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
- (void)handleUndoWithDirection:(FlutterUndoRedoDirection)direction { - (void)handleUndoWithDirection:(FlutterUndoRedoDirection)direction {
NSString* action = (direction == FlutterUndoRedoDirectionUndo) ? @"undo" : @"redo"; NSString* action = (direction == FlutterUndoRedoDirectionUndo) ? @"undo" : @"redo";
[_undoManagerChannel.get() invokeMethod:@"UndoManagerClient.handleUndo" arguments:@[ action ]]; [self.undoManagerChannel invokeMethod:@"UndoManagerClient.handleUndo" arguments:@[ action ]];
} }
- (UIView<UITextInput>*)activeTextInputView { - (UIView<UITextInput>*)activeTextInputView {
@ -1244,8 +1177,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
// Discard the previous messenger and keep the new one. // Discard the previous messenger and keep the new one.
if (binaryMessenger != _binaryMessenger) { if (binaryMessenger != _binaryMessenger) {
_binaryMessenger.parent = nil; _binaryMessenger.parent = nil;
[_binaryMessenger release]; _binaryMessenger = binaryMessenger;
_binaryMessenger = [binaryMessenger retain];
} }
} }
@ -1317,7 +1249,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
#pragma mark - FlutterTextureRegistry #pragma mark - FlutterTextureRegistry
- (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture { - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture {
int64_t textureId = _nextTextureId++; int64_t textureId = self.nextTextureId++;
self.iosPlatformView->RegisterExternalTexture(textureId, texture); self.iosPlatformView->RegisterExternalTexture(textureId, texture);
return textureId; return textureId;
} }
@ -1350,7 +1282,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
FlutterEngineRegistrar* result = [[FlutterEngineRegistrar alloc] initWithPlugin:pluginKey FlutterEngineRegistrar* result = [[FlutterEngineRegistrar alloc] initWithPlugin:pluginKey
flutterEngine:self]; flutterEngine:self];
self.registrars[pluginKey] = result; self.registrars[pluginKey] = result;
return [result autorelease]; return result;
} }
- (BOOL)hasPlugin:(NSString*)pluginKey { - (BOOL)hasPlugin:(NSString*)pluginKey {
@ -1406,10 +1338,10 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
- (void)onLocaleUpdated:(NSNotification*)notification { - (void)onLocaleUpdated:(NSNotification*)notification {
// Get and pass the user's preferred locale list to dart:ui. // Get and pass the user's preferred locale list to dart:ui.
NSMutableArray<NSString*>* localeData = [[[NSMutableArray alloc] init] autorelease]; NSMutableArray<NSString*>* localeData = [[NSMutableArray alloc] init];
NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages]; NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages];
for (NSString* localeID in preferredLocales) { for (NSString* localeID in preferredLocales) {
NSLocale* locale = [[[NSLocale alloc] initWithLocaleIdentifier:localeID] autorelease]; NSLocale* locale = [[NSLocale alloc] initWithLocaleIdentifier:localeID];
NSString* languageCode = [locale objectForKey:NSLocaleLanguageCode]; NSString* languageCode = [locale objectForKey:NSLocaleLanguageCode];
NSString* countryCode = [locale objectForKey:NSLocaleCountryCode]; NSString* countryCode = [locale objectForKey:NSLocaleCountryCode];
NSString* scriptCode = [locale objectForKey:NSLocaleScriptCode]; NSString* scriptCode = [locale objectForKey:NSLocaleScriptCode];
@ -1446,11 +1378,11 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
initialRoute:(/*nullable*/ NSString*)initialRoute initialRoute:(/*nullable*/ NSString*)initialRoute
entrypointArgs:(/*nullable*/ NSArray<NSString*>*)entrypointArgs { entrypointArgs:(/*nullable*/ NSArray<NSString*>*)entrypointArgs {
NSAssert(_shell, @"Spawning from an engine without a shell (possibly not run)."); NSAssert(_shell, @"Spawning from an engine without a shell (possibly not run).");
FlutterEngine* result = [[FlutterEngine alloc] initWithName:_labelPrefix FlutterEngine* result = [[FlutterEngine alloc] initWithName:self.labelPrefix
project:_dartProject.get() project:self.dartProject
allowHeadlessExecution:_allowHeadlessExecution]; allowHeadlessExecution:self.allowHeadlessExecution];
flutter::RunConfiguration configuration = flutter::RunConfiguration configuration =
[_dartProject.get() runConfigurationForEntrypoint:entrypoint [self.dartProject runConfigurationForEntrypoint:entrypoint
libraryOrNil:libraryURI libraryOrNil:libraryURI
entrypointArgs:entrypointArgs]; entrypointArgs:entrypointArgs];
@ -1489,7 +1421,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
result->_profiler_metrics = _profiler_metrics; result->_profiler_metrics = _profiler_metrics;
result->_isGpuDisabled = _isGpuDisabled; result->_isGpuDisabled = _isGpuDisabled;
[result setUpShell:std::move(shell) withVMServicePublication:NO]; [result setUpShell:std::move(shell) withVMServicePublication:NO];
return [result autorelease]; return result;
} }
- (const flutter::ThreadHost&)threadHost { - (const flutter::ThreadHost&)threadHost {
@ -1497,7 +1429,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
} }
- (FlutterDartProject*)project { - (FlutterDartProject*)project {
return _dartProject.get(); return self.dartProject;
} }
- (BOOL)isUsingImpeller { - (BOOL)isUsingImpeller {
@ -1518,11 +1450,6 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
return self; return self;
} }
- (void)dealloc {
[_pluginKey release];
[super dealloc];
}
- (NSObject<FlutterBinaryMessenger>*)messenger { - (NSObject<FlutterBinaryMessenger>*)messenger {
return _flutterEngine.binaryMessenger; return _flutterEngine.binaryMessenger;
} }

View File

@ -12,7 +12,7 @@
@interface FlutterPlatformPlugin : NSObject @interface FlutterPlatformPlugin : NSObject
- (instancetype)init NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE; + (instancetype)new NS_UNAVAILABLE;
- (instancetype)initWithEngine:(fml::WeakNSObject<FlutterEngine>)engine NS_DESIGNATED_INITIALIZER; - (instancetype)initWithEngine:(FlutterEngine*)engine NS_DESIGNATED_INITIALIZER;
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result; - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
@end @end

View File

@ -82,7 +82,7 @@ static void SetStatusBarStyleForSharedApplication(UIStatusBarStyle style) {
@implementation FlutterPlatformPlugin @implementation FlutterPlatformPlugin
- (instancetype)initWithEngine:(fml::WeakNSObject<FlutterEngine>)engine { - (instancetype)initWithEngine:(FlutterEngine*)engine {
FML_DCHECK(engine) << "engine must be set"; FML_DCHECK(engine) << "engine must be set";
self = [super init]; self = [super init];

View File

@ -37,15 +37,12 @@ FLUTTER_ASSERT_ARC
OCMStub([mockApplication sharedApplication]).andReturn(mockApplication); OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory =
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
[engine runWithEntrypoint:nil]; [engine runWithEntrypoint:nil];
XCTestExpectation* invokeExpectation = XCTestExpectation* invokeExpectation =
[self expectationWithDescription:@"Web search launched with escaped search term"]; [self expectationWithDescription:@"Web search launched with escaped search term"];
FlutterPlatformPlugin* plugin = FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakNSObject()];
FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin); FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.invoke" FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.invoke"
@ -71,15 +68,12 @@ FLUTTER_ASSERT_ARC
OCMStub([mockApplication sharedApplication]).andReturn(mockApplication); OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory =
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
[engine runWithEntrypoint:nil]; [engine runWithEntrypoint:nil];
XCTestExpectation* invokeExpectation = XCTestExpectation* invokeExpectation =
[self expectationWithDescription:@"Web search launched with non escaped search term"]; [self expectationWithDescription:@"Web search launched with non escaped search term"];
FlutterPlatformPlugin* plugin = FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakNSObject()];
FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin); FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.invoke" FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.invoke"
@ -103,8 +97,6 @@ FLUTTER_ASSERT_ARC
- (void)testLookUpCallInitiated { - (void)testLookUpCallInitiated {
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
[engine runWithEntrypoint:nil]; [engine runWithEntrypoint:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory =
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
XCTestExpectation* presentExpectation = XCTestExpectation* presentExpectation =
[self expectationWithDescription:@"Look Up view controller presented"]; [self expectationWithDescription:@"Look Up view controller presented"];
@ -114,8 +106,7 @@ FLUTTER_ASSERT_ARC
bundle:nil]; bundle:nil];
FlutterViewController* mockEngineViewController = OCMPartialMock(engineViewController); FlutterViewController* mockEngineViewController = OCMPartialMock(engineViewController);
FlutterPlatformPlugin* plugin = FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakNSObject()];
FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin); FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"LookUp.invoke" FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"LookUp.invoke"
@ -134,8 +125,6 @@ FLUTTER_ASSERT_ARC
- (void)testShareScreenInvoked { - (void)testShareScreenInvoked {
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
[engine runWithEntrypoint:nil]; [engine runWithEntrypoint:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory =
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
XCTestExpectation* presentExpectation = XCTestExpectation* presentExpectation =
[self expectationWithDescription:@"Share view controller presented"]; [self expectationWithDescription:@"Share view controller presented"];
@ -149,8 +138,7 @@ FLUTTER_ASSERT_ARC
animated:YES animated:YES
completion:nil]); completion:nil]);
FlutterPlatformPlugin* plugin = FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakNSObject()];
FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin); FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Share.invoke" FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Share.invoke"
@ -169,8 +157,6 @@ FLUTTER_ASSERT_ARC
- (void)testShareScreenInvokedOnIPad { - (void)testShareScreenInvokedOnIPad {
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
[engine runWithEntrypoint:nil]; [engine runWithEntrypoint:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory =
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
XCTestExpectation* presentExpectation = XCTestExpectation* presentExpectation =
[self expectationWithDescription:@"Share view controller presented on iPad"]; [self expectationWithDescription:@"Share view controller presented on iPad"];
@ -187,8 +173,7 @@ FLUTTER_ASSERT_ARC
id mockTraitCollection = OCMClassMock([UITraitCollection class]); id mockTraitCollection = OCMClassMock([UITraitCollection class]);
OCMStub([mockTraitCollection userInterfaceIdiom]).andReturn(UIUserInterfaceIdiomPad); OCMStub([mockTraitCollection userInterfaceIdiom]).andReturn(UIUserInterfaceIdiomPad);
FlutterPlatformPlugin* plugin = FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakNSObject()];
FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin); FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Share.invoke" FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Share.invoke"
@ -207,10 +192,7 @@ FLUTTER_ASSERT_ARC
- (void)testClipboardHasCorrectStrings { - (void)testClipboardHasCorrectStrings {
[UIPasteboard generalPasteboard].string = nil; [UIPasteboard generalPasteboard].string = nil;
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory = FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
FlutterPlatformPlugin* plugin =
[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakNSObject()];
XCTestExpectation* setStringExpectation = [self expectationWithDescription:@"setString"]; XCTestExpectation* setStringExpectation = [self expectationWithDescription:@"setString"];
FlutterResult resultSet = ^(id result) { FlutterResult resultSet = ^(id result) {
@ -246,10 +228,7 @@ FLUTTER_ASSERT_ARC
- (void)testClipboardSetDataToNullDoNotCrash { - (void)testClipboardSetDataToNullDoNotCrash {
[UIPasteboard generalPasteboard].string = nil; [UIPasteboard generalPasteboard].string = nil;
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory = FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
FlutterPlatformPlugin* plugin =
[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakNSObject()];
XCTestExpectation* setStringExpectation = [self expectationWithDescription:@"setData"]; XCTestExpectation* setStringExpectation = [self expectationWithDescription:@"setData"];
FlutterResult resultSet = ^(id result) { FlutterResult resultSet = ^(id result) {
@ -280,10 +259,7 @@ FLUTTER_ASSERT_ARC
[[UINavigationController alloc] initWithRootViewController:flutterViewController]; [[UINavigationController alloc] initWithRootViewController:flutterViewController];
UITabBarController* tabBarController = [[UITabBarController alloc] init]; UITabBarController* tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = @[ navigationController ]; tabBarController.viewControllers = @[ navigationController ];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory = FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
FlutterPlatformPlugin* plugin =
[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakNSObject()];
id navigationControllerMock = OCMPartialMock(navigationController); id navigationControllerMock = OCMPartialMock(navigationController);
OCMStub([navigationControllerMock popViewControllerAnimated:YES]); OCMStub([navigationControllerMock popViewControllerAnimated:YES]);
@ -303,12 +279,9 @@ FLUTTER_ASSERT_ARC
- (void)testWhetherDeviceHasLiveTextInputInvokeCorrectly { - (void)testWhetherDeviceHasLiveTextInputInvokeCorrectly {
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil]; FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" project:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory =
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
XCTestExpectation* invokeExpectation = XCTestExpectation* invokeExpectation =
[self expectationWithDescription:@"isLiveTextInputAvailableInvoke"]; [self expectationWithDescription:@"isLiveTextInputAvailableInvoke"];
FlutterPlatformPlugin* plugin = FlutterPlatformPlugin* plugin = [[FlutterPlatformPlugin alloc] initWithEngine:engine];
[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakNSObject()];
FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin); FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
FlutterMethodCall* methodCall = FlutterMethodCall* methodCall =
[FlutterMethodCall methodCallWithMethodName:@"LiveText.isLiveTextInputAvailable" [FlutterMethodCall methodCallWithMethodName:@"LiveText.isLiveTextInputAvailable"
@ -331,8 +304,6 @@ FLUTTER_ASSERT_ARC
[engine runWithEntrypoint:nil]; [engine runWithEntrypoint:nil];
FlutterViewController* flutterViewController = FlutterViewController* flutterViewController =
[[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory =
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
XCTAssertFalse(flutterViewController.prefersStatusBarHidden); XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
// Update to hidden. // Update to hidden.
@ -371,8 +342,6 @@ FLUTTER_ASSERT_ARC
[engine runWithEntrypoint:nil]; [engine runWithEntrypoint:nil];
FlutterViewController* flutterViewController = FlutterViewController* flutterViewController =
[[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory =
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
XCTAssertFalse(flutterViewController.prefersStatusBarHidden); XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
// Update to hidden. // Update to hidden.
@ -420,8 +389,6 @@ FLUTTER_ASSERT_ARC
[engine runWithEntrypoint:nil]; [engine runWithEntrypoint:nil];
FlutterViewController* flutterViewController = FlutterViewController* flutterViewController =
[[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory =
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
// Update to hidden. // Update to hidden.
FlutterPlatformPlugin* plugin = [engine platformPlugin]; FlutterPlatformPlugin* plugin = [engine platformPlugin];
@ -471,8 +438,6 @@ FLUTTER_ASSERT_ARC
[engine runWithEntrypoint:nil]; [engine runWithEntrypoint:nil];
FlutterViewController* flutterViewController = FlutterViewController* flutterViewController =
[[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil]; [[FlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
std::unique_ptr<fml::WeakNSObjectFactory<FlutterEngine>> _weakFactory =
std::make_unique<fml::WeakNSObjectFactory<FlutterEngine>>(engine);
XCTAssertFalse(flutterViewController.prefersStatusBarHidden); XCTAssertFalse(flutterViewController.prefersStatusBarHidden);
FlutterPlatformPlugin* plugin = [engine platformPlugin]; FlutterPlatformPlugin* plugin = [engine platformPlugin];