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

Conversation

chunhtai
Copy link
Contributor

@chunhtai chunhtai commented Nov 6, 2020

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

            <meta-data android:name="flutter_handle_deeplinking" android:value="true" />
            <intent-filter>
              <action android:name="android.intent.action.VIEW" />
              <category android:name="android.intent.category.DEFAULT" />
              <category android:name="android.intent.category.BROWSABLE" />
              <data android:scheme="http" android:host="flutterbooksample.com" android:pathPrefix="/" />
            </intent-filter>

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.

  • 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.

Reviewer Checklist

Breaking Change

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

if (host.getInitialRoute() != null) {
flutterEngine.getNavigationChannel().setInitialRoute(host.getInitialRoute());
if (initialRoute != null) {
flutterEngine.getNavigationChannel().setInitialRoute(initialRoute);
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 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

initial_route_ = std::move(route->value.GetString());
.

Copy link
Contributor Author

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?

Copy link
Member

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

Copy link
Contributor Author

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.

Copy link
Member

@xster xster Nov 10, 2020

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.

* NavigationChannel.pushRoute}.
*/
@Nullable
boolean shouldHandleDeeplinking();
Copy link
Member

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}
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 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}
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 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.

Copy link
Contributor Author

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?

Copy link
Member

@xster xster Nov 9, 2020

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

Copy link
Contributor Author

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}
Copy link
Member

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());
Copy link
Member

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

@chunhtai chunhtai force-pushed the issues/69786-reland branch from d6f42dd to bc1059c Compare November 10, 2020 18:04
if (initialRoute == null) {
initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
if (initialRoute == null) {
initialRoute = DEFAULT_INITIAL_ROUTE;
Copy link
Contributor Author

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 {
Copy link
Contributor Author

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.

@chunhtai
Copy link
Contributor Author

@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;
Copy link
Member

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) {
Copy link
Member

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 {
Copy link
Member

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
Copy link
Member

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;
Copy link
Member

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 {
Copy link
Member

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.

@chunhtai chunhtai merged commit d97a81c into flutter:master Nov 11, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 12, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 13, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 13, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 13, 2020
chaselatta pushed a commit to chaselatta/engine that referenced this pull request Nov 30, 2020
* 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
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.

Ability to turn off Android deeplink Ensure Android architecture works with deep linking
2 participants