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

Refactor initial route code #19684

Merged
merged 14 commits into from
Aug 12, 2020
Merged

Refactor initial route code #19684

merged 14 commits into from
Aug 12, 2020

Conversation

xster
Copy link
Member

@xster xster commented Jul 12, 2020

Description

Fix flutter/flutter#59895 and persistent UX issues plaguing users with confusing behavior around setInitialRoute.

Deprecate after-the-fact setInitialRoute calls which can easily have no effect. Migrate them as much as possible to constructors.

I'll update the website once this hits stable

Related Issues

Fixes flutter/flutter#59895

Tests

I added the following tests:

Added unit test for engine, integration test for view controller.

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the contributor guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the C++, Objective-C, Java style guides for the engine.
  • I read the tree hygiene wiki page, which explains my responsibilities.
  • I updated/added relevant documentation.
  • All existing and new tests are passing.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read handling breaking changes.

* @param nibBundle The NIB bundle.
*/
- (instancetype)initWithProject:(nullable FlutterDartProject*)project
withInitialRoute:(nullable NSString*)initialRoute
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/withInitialRoute/intialRoute

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, agree

@@ -54,6 +55,7 @@ @implementation FlutterEngine {
flutter::ThreadHost _threadHost;
std::unique_ptr<flutter::Shell> _shell;
NSString* _labelPrefix;
NSString* _initialRoute;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is leaking, please use a property with copy semantics.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how do you mean? We're manually copying and releasing it no?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The releasing of it is conditional. There is still the opportunity for it to leak. It should be cleaned up in the dealloc.

We are copying it, using the property syntax just makes the memory management technique apparent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah understood. PTAL

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lookin good

@@ -367,6 +373,12 @@ - (void)setupChannels {
binaryMessenger:self.binaryMessenger
codec:[FlutterJSONMethodCodec sharedInstance]]);

if ([_initialRoute length] > 0) {
// Flutter isn't ready to receive this method call yet but the channel buffer will cache this.
[_navigationChannel invokeMethod:@"setInitialRoute" arguments:_initialRoute];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably use the variant of invokeMethod that does error checking and print out if there is an error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh true. I agree. Though it looks like we're using the non-callback variant across the embedding code currently. I'd like to keep it consistent and move all call sites if we do.

if ([_initialRoute length] > 0) {
// Flutter isn't ready to receive this method call yet but the channel buffer will cache this.
[_navigationChannel invokeMethod:@"setInitialRoute" arguments:_initialRoute];
[_initialRoute release];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't release something without niling it out.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, thanks


FLUTTER_ASSERT_ARC

@interface FlutterEngineTest : XCTestCase
@end

@interface FlutterEngine (Test) <FlutterBinaryMessenger>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this category in a headers so tests don't have to redeclare this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what implementation style were you thinking? Having something like Source/FlutterEngine.mm, Source/FlutterEngine_Internal.h, Source/FlutterEngine_TestFlutterBinaryMessenger.h, Source/FlutterEngine_TestSomeOtherProtocol.h, Source/FlutterEngineTest.mm?

We might end up with a big list since no other test is using this specific category yet (Y(probably)AGNI).

We can also put all "internals" into one header, but it's not very least-privilege-principle.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think FlutterEngine_Test sounds fine. It would operate like java's visiblefortesting. Everything can just go in there.

I'd say FlutterEngine_Test is like visiblefortesting and FlutterEngine_internal is like package visible methods.


FLUTTER_ASSERT_ARC

@interface FlutterEngineTest : XCTestCase
@end

@interface FlutterEngine (Test) <FlutterBinaryMessenger>
- (void)setBinaryMessenger:binaryMessenger;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declare types.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, thanks

nibName:(nullable NSString*)nibName
bundle:(nullable NSBundle*)nibBundle {
- (instancetype)initWithProject:(FlutterDartProject*)project
withInitialRoute:(NSString*)initialRoute
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/withInitialRoute/initialRoute

Comment on lines +31 to +39
0AC232F424BA71D300A85907 /* SemanticsObjectTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SemanticsObjectTest.mm; sourceTree = "<group>"; };
0AC232F724BA71D300A85907 /* FlutterEngineTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterEngineTest.mm; sourceTree = "<group>"; };
0AC2330324BA71D300A85907 /* accessibility_bridge_test.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = accessibility_bridge_test.mm; sourceTree = "<group>"; };
0AC2330B24BA71D300A85907 /* FlutterTextInputPluginTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlutterTextInputPluginTest.m; sourceTree = "<group>"; };
0AC2330F24BA71D300A85907 /* FlutterBinaryMessengerRelayTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterBinaryMessengerRelayTest.mm; sourceTree = "<group>"; };
0AC2331024BA71D300A85907 /* connection_collection_test.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = connection_collection_test.mm; sourceTree = "<group>"; };
0AC2331224BA71D300A85907 /* FlutterEnginePlatformViewTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterEnginePlatformViewTest.mm; sourceTree = "<group>"; };
0AC2331924BA71D300A85907 /* FlutterPluginAppLifeCycleDelegateTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlutterPluginAppLifeCycleDelegateTest.m; sourceTree = "<group>"; };
0AC2332124BA71D300A85907 /* FlutterViewControllerTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterViewControllerTest.mm; sourceTree = "<group>"; };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this for easy navigation? It's hard to read the xcode project. I'm ok with this but jsut a heads up that the less there is in the xcode project the less there is to conflict.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya, this is pretty optional. I don't feel strongly either way. This is just so people can look at the test they're about to run in this project before they run it (and potentially set breakpoints).

@xster xster force-pushed the rework-setinitialroute branch from 870b9d0 to 93fe293 Compare July 31, 2020 20:23
Copy link
Member Author

@xster xster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for review. Sorry for the slow turnaround.

* @param nibBundle The NIB bundle.
*/
- (instancetype)initWithProject:(nullable FlutterDartProject*)project
withInitialRoute:(nullable NSString*)initialRoute
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, agree

@@ -54,6 +55,7 @@ @implementation FlutterEngine {
flutter::ThreadHost _threadHost;
std::unique_ptr<flutter::Shell> _shell;
NSString* _labelPrefix;
NSString* _initialRoute;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how do you mean? We're manually copying and releasing it no?

if ([_initialRoute length] > 0) {
// Flutter isn't ready to receive this method call yet but the channel buffer will cache this.
[_navigationChannel invokeMethod:@"setInitialRoute" arguments:_initialRoute];
[_initialRoute release];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, thanks

@@ -367,6 +373,12 @@ - (void)setupChannels {
binaryMessenger:self.binaryMessenger
codec:[FlutterJSONMethodCodec sharedInstance]]);

if ([_initialRoute length] > 0) {
// Flutter isn't ready to receive this method call yet but the channel buffer will cache this.
[_navigationChannel invokeMethod:@"setInitialRoute" arguments:_initialRoute];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh true. I agree. Though it looks like we're using the non-callback variant across the embedding code currently. I'd like to keep it consistent and move all call sites if we do.


FLUTTER_ASSERT_ARC

@interface FlutterEngineTest : XCTestCase
@end

@interface FlutterEngine (Test) <FlutterBinaryMessenger>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what implementation style were you thinking? Having something like Source/FlutterEngine.mm, Source/FlutterEngine_Internal.h, Source/FlutterEngine_TestFlutterBinaryMessenger.h, Source/FlutterEngine_TestSomeOtherProtocol.h, Source/FlutterEngineTest.mm?

We might end up with a big list since no other test is using this specific category yet (Y(probably)AGNI).

We can also put all "internals" into one header, but it's not very least-privilege-principle.


FLUTTER_ASSERT_ARC

@interface FlutterEngineTest : XCTestCase
@end

@interface FlutterEngine (Test) <FlutterBinaryMessenger>
- (void)setBinaryMessenger:binaryMessenger;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, thanks

Comment on lines +31 to +39
0AC232F424BA71D300A85907 /* SemanticsObjectTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SemanticsObjectTest.mm; sourceTree = "<group>"; };
0AC232F724BA71D300A85907 /* FlutterEngineTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterEngineTest.mm; sourceTree = "<group>"; };
0AC2330324BA71D300A85907 /* accessibility_bridge_test.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = accessibility_bridge_test.mm; sourceTree = "<group>"; };
0AC2330B24BA71D300A85907 /* FlutterTextInputPluginTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlutterTextInputPluginTest.m; sourceTree = "<group>"; };
0AC2330F24BA71D300A85907 /* FlutterBinaryMessengerRelayTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterBinaryMessengerRelayTest.mm; sourceTree = "<group>"; };
0AC2331024BA71D300A85907 /* connection_collection_test.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = connection_collection_test.mm; sourceTree = "<group>"; };
0AC2331224BA71D300A85907 /* FlutterEnginePlatformViewTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterEnginePlatformViewTest.mm; sourceTree = "<group>"; };
0AC2331924BA71D300A85907 /* FlutterPluginAppLifeCycleDelegateTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlutterPluginAppLifeCycleDelegateTest.m; sourceTree = "<group>"; };
0AC2332124BA71D300A85907 /* FlutterViewControllerTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterViewControllerTest.mm; sourceTree = "<group>"; };
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya, this is pretty optional. I don't feel strongly either way. This is just so people can look at the test they're about to run in this project before they run it (and potentially set breakpoints).

Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM modulo the initalRoute (potential) leak.

* FlutterDefaultInitialRoute (or nil), it will default to the "/" route.
* @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise.
*/
- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: You still have 2 prepositions in your selector, that's non-standard.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@xster xster force-pushed the rework-setinitialroute branch from 6e6a79b to 4fa79b7 Compare August 10, 2020 16:48
@xster xster added the waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land. label Aug 10, 2020
@fluttergithubbot
Copy link
Contributor

This pull request is not suitable for automatic merging in its current state.

  • The status or check suite Mac Web Engine has failed. Please fix the issues identified (or deflake) before re-applying this label.
  • The status or check suite web_tests-6-linux has failed. Please fix the issues identified (or deflake) before re-applying this label.

@fluttergithubbot fluttergithubbot removed the waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land. label Aug 10, 2020
@xster xster force-pushed the rework-setinitialroute branch from 0456c08 to cf93cc7 Compare August 11, 2020 18:38
@xster xster force-pushed the rework-setinitialroute branch from cf93cc7 to 08f4d63 Compare August 11, 2020 19:16
@xster xster added the waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land. label Aug 11, 2020
@fluttergithubbot
Copy link
Contributor

This pull request is not suitable for automatic merging in its current state.

  • The status or check suite Mac iOS Engine has failed. Please fix the issues identified (or deflake) before re-applying this label.

@fluttergithubbot fluttergithubbot removed the waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land. label Aug 11, 2020
…ants, will need a bigger refactor to clean the build and test script later
@xster xster merged commit 8d08e6c into flutter:master Aug 12, 2020
@xster xster deleted the rework-setinitialroute branch August 12, 2020 02:52
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Aug 12, 2020
gaaclarke added a commit to gaaclarke/engine that referenced this pull request Aug 12, 2020
gaaclarke added a commit that referenced this pull request Aug 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

setInitialRoute is broken for iOS add-to-app
4 participants