-
Notifications
You must be signed in to change notification settings - Fork 6k
reland support uri launch in android #22363
Conversation
if (host.getInitialRoute() != null) { | ||
flutterEngine.getNavigationChannel().setInitialRoute(host.getInitialRoute()); | ||
if (initialRoute != null) { | ||
flutterEngine.getNavigationChannel().setInitialRoute(initialRoute); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this has a new semantic now (of the default route being null whereas getInitialRoute used to be non-null). I think it's actually consequential downstream even though it looks like a platform channel
Line 322 in 5772dee
initial_route_ = std::move(route->value.GetString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did a null check before i hand it to the message channel, it will be not null after that point, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No not after the call. I meant before. host.getInitialRoute() previously never returns null as far as I can tell. Now there are opportunities to never call flutterEngine.getNavigationChannel().setInitialRoute
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah you are right, I didn't notice the previous if check does not actually do anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right. And it's consequential since initial route is "special" in that it plugs to a custom piece of memory in the engine and the dart:ui window API connects to that memory directly. Best not to mess with it since it's so entangled.
shell/platform/android/io/flutter/embedding/android/FlutterActivity.java
Show resolved
Hide resolved
* NavigationChannel.pushRoute}. | ||
*/ | ||
@Nullable | ||
boolean shouldHandleDeeplinking(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note the classes on flutteractivity/fragment are the user facing docs. This interface is package private.
* See {@link NewEngineFragmentBuilder#shouldHandleDeeplinking()} and {@link | ||
* CachedEngineFragmentBuilder#shouldHandleDeeplinking()}. | ||
* | ||
* <p>Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't link to package private classes from a public method's doc
@@ -779,8 +780,11 @@ public String getDartEntrypointFunctionName() { | |||
* have control over the incoming {@code Intent}. | |||
* | |||
* <p>Subclasses may override this method to directly control the initial route. | |||
* | |||
* <p>If this method returns null and the {@code shouldHandleDeeplinking()} returns true, the | |||
* {@link FlutterActivityAndFragmentDelegate} retrieves the initial route from the {@code Intent} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't link to package private classes from public methods' docs. The fact that FlutterActivity delegates to a class is an implementation detail and not relevant to the activity's users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just curious, is there a place like api.flutter.dev that shows these doc string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if I understood the question correctly. Do you mean these? https://api.flutter.dev/javadoc/io/flutter/embedding/android/FlutterActivity.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, thanks for the link
@@ -651,8 +667,11 @@ public String getDartEntrypointFunctionName() { | |||
* have control over the incoming {@code Intent}. | |||
* | |||
* <p>Subclasses may override this method to directly control the initial route. | |||
* | |||
* <p>If this method returns null and the {@code shouldHandleDeeplinking()} returns true, the | |||
* {@link FlutterActivityAndFragmentDelegate} retrieves the initial route from the {@code Intent} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same. Don't mention the package private delegate.
@@ -49,6 +51,7 @@ public void itCreatesNewEngineFragmentWithRequestedSettings() { | |||
assertEquals("/custom/route", fragment.getInitialRoute()); | |||
assertArrayEquals(new String[] {}, fragment.getFlutterShellArgs().toArray()); | |||
assertFalse(fragment.shouldAttachEngineToActivity()); | |||
assertTrue(fragment.shouldHandleDeeplinking()); | |||
assertNull(fragment.getCachedEngineId()); | |||
assertTrue(fragment.shouldDestroyEngineWithHost()); | |||
assertEquals(RenderMode.texture, fragment.getRenderMode()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FlutterActivityTest should have a test too
d6f42dd
to
bc1059c
Compare
if (initialRoute == null) { | ||
initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent()); | ||
if (initialRoute == null) { | ||
initialRoute = DEFAULT_INITIAL_ROUTE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made it default to /
, it matches the original behavior
|
||
/** Retrieves the meta data specified in the AndroidManifest.xml. */ | ||
@Nullable | ||
protected Bundle getMetaData() throws PackageManager.NameNotFoundException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refactored this bundle getter out so i can mock metadata during the test.
@xster Thanks for reviews! I addressed all comments. This is ready for another look. |
@@ -894,6 +890,25 @@ protected FlutterEngine getFlutterEngine() { | |||
return delegate.getFlutterEngine(); | |||
} | |||
|
|||
private Bundle cachedMetaData; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, I don't love this. Don't do any of this and just use https://javadoc.io/static/org.mockito/mockito-core/3.2.4/org/mockito/Mockito.html#spy-T-
|
||
/** Mocks the meta data for testing purposes. */ | ||
@VisibleForTesting | ||
public void setMetaData(Bundle metaData) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If your test is in the same package, you don't need public. Just void setMetaData
which implies package private visibility.
But also, don't add this method :)
Just use https://javadoc.io/static/org.mockito/mockito-core/3.2.4/org/mockito/Mockito.html#spy-T- on getMetaData in tests (or just override it in a subclass for the class-under-test).
|
||
/** Retrieves the meta data specified in the AndroidManifest.xml. */ | ||
@Nullable | ||
protected Bundle getMetaData() throws PackageManager.NameNotFoundException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The throw here is a bit burdensome for the subclasser. I would just re-throw it in a RuntimeException since it should be very unusual.
* Whether to handle the deeplinking from the {@code Intent} automatically if the {@code | ||
* getInitialRoute} returns null. | ||
* | ||
* <p>The default implementation looks for the value of the key `flutter_handle_deeplinking` in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Be explicit about the metadata tag. Just saying key value in an AndroidManifest will be very hard to decipher.
@@ -608,6 +628,25 @@ protected String getAppBundlePath() { | |||
return null; | |||
} | |||
|
|||
private Bundle cachedMetaData; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. The testing infrastructure could be simpler.
@@ -894,6 +890,18 @@ protected FlutterEngine getFlutterEngine() { | |||
return delegate.getFlutterEngine(); | |||
} | |||
|
|||
/** Retrieves the meta data specified in the AndroidManifest.xml. */ | |||
@Nullable | |||
protected Bundle getMetaData() throws RuntimeException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah sorry my bad. I hadn't realized it wasn't public and just noticed now that you changed places where it's reading this and they're already catching PackageManager.NameNotFoundException. In that case, I think we can leave it as it was. With this method throwing PackageManager.NameNotFoundException(and in the fragment activity too) and letting places that call it catch PackageManager.NameNotFoundException and do a reasonable fallback. Sorry I misread.
* Revert "Revert "support uri intent launcher in android (flutter#21275)" (flutter#22298)" This reverts commit f61cbc0. * reland support uri launch for android * refactor * update * fix test * addressing comments * addressing comments * revert throw error
Description
The previous PR is reverted due to it being a breaking change. This PR add a flag to turn on and off the new behavior.
To enable deeplinking, just add the following to the android manifest
Related Issues
fixes flutter/flutter#69786
fixes flutter/flutter#21255
Tests
I added the following tests:
Replace this with a list of the tests that you added as part of this PR. A
change in behaviour with no test covering it will likely get reverted
accidentally sooner or later. PRs must include tests for all
changed/updated/fixed behaviors. See testing the engine for instructions on
writing and running engine tests.
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.Reviewer Checklist
Breaking Change
Did any tests fail when you ran them? Please read handling breaking changes.