diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 7f5ebd1e81932..ef111bef27e23 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -284,6 +284,11 @@ - (void)setupNotificationCenterObservers { name:UIApplicationWillResignActiveNotification object:nil]; + [center addObserver:self + selector:@selector(applicationWillTerminate:) + name:UIApplicationWillTerminateNotification + object:nil]; + [center addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification @@ -816,6 +821,11 @@ - (void)applicationWillResignActive:(NSNotification*)notification { [self goToApplicationLifecycle:@"AppLifecycleState.inactive"]; } +- (void)applicationWillTerminate:(NSNotification*)notification { + [self goToApplicationLifecycle:@"AppLifecycleState.detached"]; + [self.engine destroyContext]; +} + - (void)applicationDidEnterBackground:(NSNotification*)notification { TRACE_EVENT0("flutter", "applicationDidEnterBackground"); [self surfaceUpdated:NO]; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm index 0bb8346572891..bcd3ce1e0a90e 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm @@ -124,6 +124,8 @@ - (void)handlePressEvent:(FlutterUIPressProxy*)press - (void)scrollEvent:(UIPanGestureRecognizer*)recognizer; - (void)updateViewportMetrics; - (void)onUserSettingsChanged:(NSNotification*)notification; +- (void)applicationWillTerminate:(NSNotification*)notification; +- (void)goToApplicationLifecycle:(nonnull NSString*)state; - (void)keyboardWillChangeFrame:(NSNotification*)notification; - (void)startKeyBoardAnimation:(NSTimeInterval)duration; - (void)ensureViewportMetricsIsCorrect; @@ -214,6 +216,20 @@ - (void)testViewDidDisappearDoesntPauseEngineWhenNotTheViewController { OCMReject([viewControllerMock surfaceUpdated:[OCMArg any]]); } +- (void)testAppWillTerminateViewDidDestroyTheEngine { + FlutterEngine* mockEngine = OCMPartialMock([[FlutterEngine alloc] init]); + [mockEngine createShell:@"" libraryURI:@"" initialRoute:nil]; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:mockEngine + nibName:nil + bundle:nil]; + id viewControllerMock = OCMPartialMock(viewController); + OCMStub([viewControllerMock goToApplicationLifecycle:@"AppLifecycleState.detached"]); + OCMStub([mockEngine destroyContext]); + [viewController applicationWillTerminate:nil]; + OCMVerify([viewControllerMock goToApplicationLifecycle:@"AppLifecycleState.detached"]); + OCMVerify([mockEngine destroyContext]); +} + - (void)testViewDidDisappearDoesPauseEngineWhenIsTheViewController { id lifecycleChannel = OCMClassMock([FlutterBasicMessageChannel class]); FlutterEnginePartialMock* mockEngine = [[FlutterEnginePartialMock alloc] init];