when resetting FlutterPlatformViewsController, clear out some additional internal state to prevent it from carrying over across a Hot Restart (#164456)
<!-- Thanks for filing a pull request! Reviewers are typically assigned within a week of filing a request. To learn more about code review, see our documentation on Tree Hygiene: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md --> When performing a Hot Restart on iOS in an app that uses PlatformViews, a "recreating_view" PlatformException can be thrown. This happens because some of the state of FlutterPlatformViewsController is not cleared as part of the Hot Restart. Specifically, `self.previousCompositionOrder` will have its previous value from before the Hot Restart. The fix here clears that state as part of the Hot Restart. Fixes https://github.com/flutter/flutter/issues/163935 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
@@ -139,6 +139,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (const flutter::EmbeddedViewParams&)compositionParamsForView:(int64_t)viewId;
|
||||
|
||||
- (std::vector<int64_t>&)previousCompositionOrder;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -675,6 +675,7 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect,
|
||||
[self.platformViews[viewId].root_view removeFromSuperview];
|
||||
}
|
||||
self.platformViews.clear();
|
||||
self.previousCompositionOrder.clear();
|
||||
});
|
||||
|
||||
self.compositionOrder.clear();
|
||||
|
||||
@@ -4458,6 +4458,82 @@ fml::RefPtr<fml::TaskRunner> GetDefaultTaskRunner() {
|
||||
XCTAssertEqual(flutterView.subviews.firstObject, someView);
|
||||
}
|
||||
|
||||
- (void)testResetClearsPreviousCompositionOrder {
|
||||
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
|
||||
|
||||
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
|
||||
/*platform=*/GetDefaultTaskRunner(),
|
||||
/*raster=*/GetDefaultTaskRunner(),
|
||||
/*ui=*/GetDefaultTaskRunner(),
|
||||
/*io=*/GetDefaultTaskRunner());
|
||||
FlutterPlatformViewsController* flutterPlatformViewsController =
|
||||
[[FlutterPlatformViewsController alloc] init];
|
||||
flutterPlatformViewsController.taskRunner = GetDefaultTaskRunner();
|
||||
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
|
||||
/*delegate=*/mock_delegate,
|
||||
/*rendering_api=*/flutter::IOSRenderingAPI::kMetal,
|
||||
/*platform_views_controller=*/flutterPlatformViewsController,
|
||||
/*task_runners=*/runners,
|
||||
/*worker_task_runner=*/nil,
|
||||
/*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
|
||||
|
||||
FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
|
||||
[[FlutterPlatformViewsTestMockFlutterPlatformFactory alloc] init];
|
||||
[flutterPlatformViewsController
|
||||
registerViewFactory:factory
|
||||
withId:@"MockFlutterPlatformView"
|
||||
gestureRecognizersBlockingPolicy:FlutterPlatformViewGestureRecognizersBlockingPolicyEager];
|
||||
FlutterResult result = ^(id result) {
|
||||
};
|
||||
[flutterPlatformViewsController
|
||||
onMethodCall:[FlutterMethodCall methodCallWithMethodName:@"create"
|
||||
arguments:@{
|
||||
@"id" : @2,
|
||||
@"viewType" : @"MockFlutterPlatformView"
|
||||
}]
|
||||
result:result];
|
||||
FlutterPlatformViewsTestMockFlutterViewController* mockFlutterViewController =
|
||||
[[FlutterPlatformViewsTestMockFlutterViewController alloc] init];
|
||||
flutterPlatformViewsController.flutterViewController = mockFlutterViewController;
|
||||
UIView* flutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
|
||||
flutterPlatformViewsController.flutterView = flutterView;
|
||||
// Create embedded view params
|
||||
flutter::MutatorsStack stack;
|
||||
// Layer tree always pushes a screen scale factor to the stack
|
||||
CGFloat screenScale = [mockFlutterViewController flutterScreenIfViewLoaded].scale;
|
||||
SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale);
|
||||
stack.PushTransform(screenScaleMatrix);
|
||||
// Push a translate matrix
|
||||
SkMatrix translateMatrix = SkMatrix::Translate(100, 100);
|
||||
stack.PushTransform(translateMatrix);
|
||||
SkMatrix finalMatrix;
|
||||
finalMatrix.setConcat(screenScaleMatrix, translateMatrix);
|
||||
|
||||
auto embeddedViewParams =
|
||||
std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
|
||||
|
||||
[flutterPlatformViewsController prerollCompositeEmbeddedView:2
|
||||
withParams:std::move(embeddedViewParams)];
|
||||
|
||||
flutter::SurfaceFrame::FramebufferInfo framebuffer_info;
|
||||
auto mock_surface = std::make_unique<flutter::SurfaceFrame>(
|
||||
nullptr, framebuffer_info,
|
||||
[](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
|
||||
[](const flutter::SurfaceFrame& surface_frame) { return true; },
|
||||
/*frame_size=*/SkISize::Make(800, 600), nullptr, /*display_list_fallback=*/true);
|
||||
[flutterPlatformViewsController submitFrame:std::move(mock_surface)
|
||||
withIosContext:std::make_shared<flutter::IOSContextNoop>()];
|
||||
|
||||
// The above code should result in previousCompositionOrder having one viewId in it
|
||||
XCTAssertEqual(flutterPlatformViewsController.previousCompositionOrder.size(), 1ul);
|
||||
|
||||
// reset should clear previousCompositionOrder
|
||||
[flutterPlatformViewsController reset];
|
||||
|
||||
// previousCompositionOrder should now be empty
|
||||
XCTAssertEqual(flutterPlatformViewsController.previousCompositionOrder.size(), 0ul);
|
||||
}
|
||||
|
||||
- (void)testNilPlatformViewDoesntCrash {
|
||||
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user