Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 76b291a

Browse files
authored
Added a plugin method that gets called when the engine is about to be deleted (#16336)
1 parent d5442b8 commit 76b291a

File tree

3 files changed

+55
-9
lines changed

3 files changed

+55
-9
lines changed

shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,19 @@ typedef void (*FlutterPluginRegistrantCallback)(NSObject<FlutterPluginRegistry>*
223223
* @param result A callback for submitting the result of the call.
224224
*/
225225
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
226+
@optional
227+
/**
228+
* Called when a plugin is being removed from a `FlutterEngine`, which is
229+
* usually the result of the `FlutterEngine` being deallocated. This method
230+
* provides the opportunity to do necessary cleanup.
231+
*
232+
* You will only receive this method if you registered your plugin instance with
233+
* the `FlutterEngine` via `-[FlutterPluginRegistry publish:]`.
234+
*
235+
* @param registrar The registrar that was used to publish the plugin.
236+
*
237+
*/
238+
- (void)detachFromEngineForRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar;
226239
@end
227240

228241
#pragma mark -

shell/platform/darwin/ios/framework/Source/FlutterEngine.mm

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,21 @@
2929

3030
NSString* const FlutterDefaultDartEntrypoint = nil;
3131

32+
@interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
33+
@property(nonatomic, assign) FlutterEngine* flutterEngine;
34+
- (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine;
35+
@end
36+
3237
@interface FlutterEngine () <FlutterTextInputDelegate, FlutterBinaryMessenger>
3338
// Maintains a dictionary of plugin names that have registered with the engine. Used by
3439
// FlutterEngineRegistrar to implement a FlutterPluginRegistrar.
3540
@property(nonatomic, readonly) NSMutableDictionary* pluginPublications;
41+
@property(nonatomic, readonly) NSMutableDictionary<NSString*, FlutterEngineRegistrar*>* registrars;
3642

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

41-
@interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
42-
- (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine;
43-
@end
44-
4547
@implementation FlutterEngine {
4648
fml::scoped_nsobject<FlutterDartProject> _dartProject;
4749
flutter::ThreadHost _threadHost;
@@ -98,6 +100,7 @@ - (instancetype)initWithName:(NSString*)labelPrefix
98100
_dartProject.reset([project retain]);
99101

100102
_pluginPublications = [NSMutableDictionary new];
103+
_registrars = [[NSMutableDictionary alloc] init];
101104
_platformViewsController.reset(new flutter::FlutterPlatformViewsController());
102105

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

124127
- (void)dealloc {
128+
/// Notify plugins of dealloc. This should happen first in dealloc since the
129+
/// plugins may be talking to things like the binaryMessenger.
130+
[_pluginPublications enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL* stop) {
131+
if ([object respondsToSelector:@selector(detachFromEngineForRegistrar:)]) {
132+
NSObject<FlutterPluginRegistrar>* registrar = self.registrars[key];
133+
[object detachFromEngineForRegistrar:registrar];
134+
}
135+
}];
136+
137+
/// nil out weak references.
138+
[_registrars
139+
enumerateKeysAndObjectsUsingBlock:^(id key, FlutterEngineRegistrar* registrar, BOOL* stop) {
140+
registrar.flutterEngine = nil;
141+
}];
142+
125143
[_labelPrefix release];
126144
[_pluginPublications release];
145+
[_registrars release];
127146
_binaryMessenger.parent = nil;
128147
[_binaryMessenger release];
129148

@@ -647,7 +666,10 @@ - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
647666
- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
648667
NSAssert(self.pluginPublications[pluginKey] == nil, @"Duplicate plugin key: %@", pluginKey);
649668
self.pluginPublications[pluginKey] = [NSNull null];
650-
return [[[FlutterEngineRegistrar alloc] initWithPlugin:pluginKey flutterEngine:self] autorelease];
669+
FlutterEngineRegistrar* result = [[FlutterEngineRegistrar alloc] initWithPlugin:pluginKey
670+
flutterEngine:self];
671+
self.registrars[pluginKey] = result;
672+
return [result autorelease];
651673
}
652674

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

687709
@implementation FlutterEngineRegistrar {
688710
NSString* _pluginKey;
689-
FlutterEngine* _flutterEngine;
690711
}
691712

692713
- (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine*)flutterEngine {
693714
self = [super init];
694715
NSAssert(self, @"Super init cannot be nil");
695-
_pluginKey = [pluginKey retain];
696-
_flutterEngine = [flutterEngine retain];
716+
_pluginKey = [pluginKey copy];
717+
_flutterEngine = flutterEngine;
697718
return self;
698719
}
699720

700721
- (void)dealloc {
701722
[_pluginKey release];
702-
[_flutterEngine release];
703723
[super dealloc];
704724
}
705725

shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,17 @@ - (void)testSetMessageHandlerBeforeRun {
4747
}]);
4848
}
4949

50+
- (void)testNotifyPluginOfDealloc {
51+
id plugin = OCMProtocolMock(@protocol(FlutterPlugin));
52+
OCMStub([plugin detachFromEngineForRegistrar:[OCMArg any]]);
53+
{
54+
id project = OCMClassMock([FlutterDartProject class]);
55+
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"engine" project:project];
56+
NSObject<FlutterPluginRegistrar>* registrar = [engine registrarForPlugin:@"plugin"];
57+
[registrar publish:plugin];
58+
engine = nil;
59+
}
60+
OCMVerify([plugin detachFromEngineForRegistrar:[OCMArg any]]);
61+
}
62+
5063
@end

0 commit comments

Comments
 (0)