Skip to content

Commit

Permalink
Added a plugin method that gets called when the engine is about to be…
Browse files Browse the repository at this point in the history
… deleted (flutter#16336)
  • Loading branch information
gaaclarke authored Feb 6, 2020
1 parent d5442b8 commit 76b291a
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 9 deletions.
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

0 comments on commit 76b291a

Please sign in to comment.