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
13 changes: 13 additions & 0 deletions shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,19 @@ typedef void (*FlutterPluginRegistrantCallback)(NSObject<FlutterPluginRegistry>*
* @param result A callback for submitting the result of the call.
*/
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
@optional
/**
* Called when a plugin is being removed from a `FlutterEngine`, which is
* usually the result of the `FlutterEngine` being deallocated. This method
* provides the opportunity to do necessary cleanup.
*
* You will only receive this method if you registered your plugin instance with
* the `FlutterEngine` via `-[FlutterPluginRegistry publish:]`.
*
* @param registrar The registrar that was used to publish the plugin.
*
*/
- (void)detachFromEngineForRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar;
@end

#pragma mark -
Expand Down
38 changes: 29 additions & 9 deletions shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,21 @@

NSString* const FlutterDefaultDartEntrypoint = nil;

@interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
@property(nonatomic, assign) FlutterEngine* flutterEngine;
- (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine;
@end

@interface FlutterEngine () <FlutterTextInputDelegate, FlutterBinaryMessenger>
// Maintains a dictionary of plugin names that have registered with the engine. Used by
// FlutterEngineRegistrar to implement a FlutterPluginRegistrar.
@property(nonatomic, readonly) NSMutableDictionary* pluginPublications;
@property(nonatomic, readonly) NSMutableDictionary<NSString*, FlutterEngineRegistrar*>* registrars;

@property(nonatomic, readwrite, copy) NSString* isolateId;
@property(nonatomic, retain) id<NSObject> flutterViewControllerWillDeallocObserver;
@end

@interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
- (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine;
@end

@implementation FlutterEngine {
fml::scoped_nsobject<FlutterDartProject> _dartProject;
flutter::ThreadHost _threadHost;
Expand Down Expand Up @@ -98,6 +100,7 @@ - (instancetype)initWithName:(NSString*)labelPrefix
_dartProject.reset([project retain]);

_pluginPublications = [NSMutableDictionary new];
_registrars = [[NSMutableDictionary alloc] init];
_platformViewsController.reset(new flutter::FlutterPlatformViewsController());

_binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self];
Expand All @@ -122,8 +125,24 @@ - (instancetype)initWithName:(NSString*)labelPrefix
}

- (void)dealloc {
/// Notify plugins of dealloc. This should happen first in dealloc since the
/// plugins may be talking to things like the binaryMessenger.
[_pluginPublications enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL* stop) {
if ([object respondsToSelector:@selector(detachFromEngineForRegistrar:)]) {
NSObject<FlutterPluginRegistrar>* registrar = self.registrars[key];
[object detachFromEngineForRegistrar:registrar];
}
}];

/// nil out weak references.
[_registrars
enumerateKeysAndObjectsUsingBlock:^(id key, FlutterEngineRegistrar* registrar, BOOL* stop) {
registrar.flutterEngine = nil;
}];

[_labelPrefix release];
[_pluginPublications release];
[_registrars release];
_binaryMessenger.parent = nil;
[_binaryMessenger release];

Expand Down Expand Up @@ -647,7 +666,10 @@ - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
NSAssert(self.pluginPublications[pluginKey] == nil, @"Duplicate plugin key: %@", pluginKey);
self.pluginPublications[pluginKey] = [NSNull null];
return [[[FlutterEngineRegistrar alloc] initWithPlugin:pluginKey flutterEngine:self] autorelease];
FlutterEngineRegistrar* result = [[FlutterEngineRegistrar alloc] initWithPlugin:pluginKey
flutterEngine:self];
self.registrars[pluginKey] = result;
return [result autorelease];
}

- (BOOL)hasPlugin:(NSString*)pluginKey {
Expand Down Expand Up @@ -686,20 +708,18 @@ - (void)setIsGpuDisabled:(BOOL)value {

@implementation FlutterEngineRegistrar {
NSString* _pluginKey;
FlutterEngine* _flutterEngine;
}

- (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine {
self = [super init];
NSAssert(self, @"Super init cannot be nil");
_pluginKey = [pluginKey retain];
_flutterEngine = [flutterEngine retain];
_pluginKey = [pluginKey copy];
_flutterEngine = flutterEngine;
return self;
}

- (void)dealloc {
[_pluginKey release];
[_flutterEngine release];
[super dealloc];
}

Expand Down
13 changes: 13 additions & 0 deletions shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,17 @@ - (void)testSetMessageHandlerBeforeRun {
}]);
}

- (void)testNotifyPluginOfDealloc {
id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
OCMStub([plugin detachFromEngineForRegistrar:[OCMArg any]]);
{
id project = OCMClassMock([FlutterDartProject class]);
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"engine" project:project];
NSObject<FlutterPluginRegistrar>* registrar = [engine registrarForPlugin:@"plugin"];
[registrar publish:plugin];
engine = nil;
}
OCMVerify([plugin detachFromEngineForRegistrar:[OCMArg any]]);
}

@end