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

Makes android embedding to send full uri #41778

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import android.content.res.Configuration;
import android.content.res.Resources.NotFoundException;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.TypedValue;
Expand Down Expand Up @@ -356,7 +357,7 @@ private static String[] getArgsFromIntent(Intent intent) {
private boolean loadIntent(Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_RUN.equals(action)) {
String route = intent.getStringExtra("route");
Uri route = Uri.parse(intent.getStringExtra("route"));
String appBundlePath = intent.getDataString();
if (appBundlePath == null) {
// Fall back to the installation path if no bundle path was specified.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
Expand Down Expand Up @@ -1149,16 +1150,16 @@ public String getDartEntrypointLibraryUri() {
* <p>If this method returns null and the {@code shouldHandleDeeplinking} returns true, the
* initial route is derived from the {@code Intent} through the Intent.getData() instead.
*/
public String getInitialRoute() {
public Uri getInitialRoute() {
if (getIntent().hasExtra(EXTRA_INITIAL_ROUTE)) {
return getIntent().getStringExtra(EXTRA_INITIAL_ROUTE);
return Uri.parse(getIntent().getStringExtra(EXTRA_INITIAL_ROUTE));
}

try {
Bundle metaData = getMetaData();
String desiredInitialRoute =
metaData != null ? metaData.getString(INITIAL_ROUTE_META_DATA_KEY) : null;
return desiredInitialRoute;
return desiredInitialRoute == null ? null : Uri.parse(desiredInitialRoute);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,11 @@ private FlutterEngineGroup.Options addEntrypointOptions(FlutterEngineGroup.Optio
DartExecutor.DartEntrypoint dartEntrypoint =
new DartExecutor.DartEntrypoint(
appBundlePathOverride, host.getDartEntrypointFunctionName());
String initialRoute = host.getInitialRoute();
Uri initialRoute = host.getInitialRoute();
if (initialRoute == null) {
initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
if (initialRoute == null) {
initialRoute = DEFAULT_INITIAL_ROUTE;
initialRoute = Uri.parse(DEFAULT_INITIAL_ROUTE);
}
}
return options
Expand Down Expand Up @@ -484,11 +484,11 @@ private void doInitialFlutterViewRun() {
// So this is expected behavior in many cases.
return;
}
String initialRoute = host.getInitialRoute();
Uri initialRoute = host.getInitialRoute();
if (initialRoute == null) {
initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
if (initialRoute == null) {
initialRoute = DEFAULT_INITIAL_ROUTE;
initialRoute = Uri.parse(DEFAULT_INITIAL_ROUTE);
}
}
@Nullable String libraryUri = host.getDartEntrypointLibraryUri();
Expand Down Expand Up @@ -521,21 +521,9 @@ private void doInitialFlutterViewRun() {
flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint, host.getDartEntrypointArgs());
}

private String maybeGetInitialRouteFromIntent(Intent intent) {
private Uri maybeGetInitialRouteFromIntent(Intent intent) {
if (host.shouldHandleDeeplinking()) {
Uri data = intent.getData();
if (data != null) {
String fullRoute = data.getPath();
if (fullRoute != null && !fullRoute.isEmpty()) {
if (data.getQuery() != null && !data.getQuery().isEmpty()) {
fullRoute += "?" + data.getQuery();
}
if (data.getFragment() != null && !data.getFragment().isEmpty()) {
fullRoute += "#" + data.getFragment();
}
return fullRoute;
}
}
return intent.getData();
}
return null;
}
Expand Down Expand Up @@ -845,8 +833,8 @@ void onNewIntent(@NonNull Intent intent) {
TAG,
"Forwarding onNewIntent() to FlutterEngine and sending pushRouteInformation message.");
flutterEngine.getActivityControlSurface().onNewIntent(intent);
String initialRoute = maybeGetInitialRouteFromIntent(intent);
if (initialRoute != null && !initialRoute.isEmpty()) {
Uri initialRoute = maybeGetInitialRouteFromIntent(intent);
if (initialRoute != null) {
flutterEngine.getNavigationChannel().pushRouteInformation(initialRoute);
}
} else {
Expand Down Expand Up @@ -1049,7 +1037,7 @@ private void ensureAlive() {

/** Returns the initial route that Flutter renders. */
@Nullable
String getInitialRoute();
Uri getInitialRoute();

/**
* Returns the {@link RenderMode} used by the {@link FlutterView} that displays the {@link
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
Expand Down Expand Up @@ -1410,8 +1411,8 @@ public String getAppBundlePath() {
*/
@Override
@Nullable
public String getInitialRoute() {
return getArguments().getString(ARG_INITIAL_ROUTE);
public Uri getInitialRoute() {
return Uri.parse(getArguments().getString(ARG_INITIAL_ROUTE));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
Expand Down Expand Up @@ -415,7 +416,7 @@ private boolean isAttachedToJni() {
/*package*/ FlutterEngine spawn(
@NonNull Context context,
@NonNull DartEntrypoint dartEntrypoint,
@Nullable String initialRoute,
@Nullable Uri initialRoute,
@Nullable List<String> dartEntrypointArgs,
@Nullable PlatformViewsController platformViewsController,
boolean automaticallyRegisterPlugins,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package io.flutter.embedding.engine;

import android.content.Context;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
Expand Down Expand Up @@ -117,7 +118,7 @@ public FlutterEngine createAndRunEngine(
public FlutterEngine createAndRunEngine(
@NonNull Context context,
@Nullable DartEntrypoint dartEntrypoint,
@Nullable String initialRoute) {
@Nullable Uri initialRoute) {
return createAndRunEngine(
new Options(context).setDartEntrypoint(dartEntrypoint).setInitialRoute(initialRoute));
}
Expand All @@ -141,7 +142,7 @@ public FlutterEngine createAndRunEngine(@NonNull Options options) {

Context context = options.getContext();
DartEntrypoint dartEntrypoint = options.getDartEntrypoint();
String initialRoute = options.getInitialRoute();
Uri initialRoute = options.getInitialRoute();
List<String> dartEntrypointArgs = options.getDartEntrypointArgs();
PlatformViewsController platformViewsController = options.getPlatformViewsController();
platformViewsController =
Expand Down Expand Up @@ -218,7 +219,7 @@ public void onEngineWillDestroy() {
public static class Options {
@NonNull private Context context;
@Nullable private DartEntrypoint dartEntrypoint;
@Nullable private String initialRoute;
@Nullable private Uri initialRoute;
@Nullable private List<String> dartEntrypointArgs;
@NonNull private PlatformViewsController platformViewsController;
private boolean automaticallyRegisterPlugins = true;
Expand All @@ -245,7 +246,7 @@ public DartEntrypoint getDartEntrypoint() {
* The name of the initial Flutter `Navigator` `Route` to load. If this is null, it will default
* to the "/" route.
*/
public String getInitialRoute() {
public Uri getInitialRoute() {
return initialRoute;
}

Expand Down Expand Up @@ -294,7 +295,7 @@ public Options setDartEntrypoint(DartEntrypoint dartEntrypoint) {
* @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is
* null, it will default to the "/" route.
*/
public Options setInitialRoute(String initialRoute) {
public Options setInitialRoute(Uri initialRoute) {
this.initialRoute = initialRoute;
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.graphics.ColorSpace;
import android.graphics.ImageDecoder;
import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.os.Build;
import android.os.Looper;
import android.util.Size;
Expand Down Expand Up @@ -429,7 +430,7 @@ public long performNativeAttach(@NonNull FlutterJNI flutterJNI) {
public FlutterJNI spawn(
@Nullable String entrypointFunctionName,
@Nullable String pathToEntrypointFunction,
@Nullable String initialRoute,
@Nullable Uri initialRoute,
@Nullable List<String> entrypointArgs) {
ensureRunningOnMainThread();
ensureAttachedToNative();
Expand All @@ -438,7 +439,7 @@ public FlutterJNI spawn(
nativeShellHolderId,
entrypointFunctionName,
pathToEntrypointFunction,
initialRoute,
initialRoute.toString(),
entrypointArgs);
Preconditions.checkState(
spawnedJNI.nativeShellHolderId != null && spawnedJNI.nativeShellHolderId != 0,
Expand All @@ -461,7 +462,7 @@ private native FlutterJNI nativeSpawn(
* <p>This method must not be invoked if {@code FlutterJNI} is not already attached to native.
*
* <p>Invoking this method will result in the release of all native-side resources that were set
* up during {@link #attachToNative()} or {@link #spawn(String, String, String, List)}, or
* up during {@link #attachToNative()} or {@link #spawn(String, String, Uri, List)}, or
* accumulated thereafter.
*
* <p>It is permissible to re-attach this instance to native after detaching it from native.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package io.flutter.embedding.engine.systemchannels;

import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.Log;
Expand Down Expand Up @@ -35,20 +36,15 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result
}
};

public void setInitialRoute(@NonNull String initialRoute) {
public void setInitialRoute(@NonNull Uri initialRoute) {
Log.v(TAG, "Sending message to set initial route to '" + initialRoute + "'");
channel.invokeMethod("setInitialRoute", initialRoute);
channel.invokeMethod("setInitialRoute", initialRoute.toString());
}

public void pushRoute(@NonNull String route) {
Log.v(TAG, "Sending message to push route '" + route + "'");
channel.invokeMethod("pushRoute", route);
}

public void pushRouteInformation(@NonNull String route) {
public void pushRouteInformation(@NonNull Uri route) {
Log.v(TAG, "Sending message to push route information '" + route + "'");
Map<String, String> message = new HashMap<>();
message.put("location", route);
message.put("location", route.toString());
channel.invokeMethod("pushRouteInformation", message);
}

Expand Down
7 changes: 2 additions & 5 deletions shell/platform/android/io/flutter/view/FlutterView.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.text.format.DateFormat;
Expand Down Expand Up @@ -356,14 +357,10 @@ public void disableTransparentBackground() {
getHolder().setFormat(PixelFormat.OPAQUE);
}

public void setInitialRoute(String route) {
public void setInitialRoute(Uri route) {
navigationChannel.setInitialRoute(route);
}

public void pushRoute(String route) {
navigationChannel.pushRoute(route);
}

public void popRoute() {
navigationChannel.popRoute();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -810,13 +810,13 @@ public void itSendsPushRouteInformationMessageWhenOnNewIntent() {
delegate.onAttach(ctx);

Intent mockIntent = mock(Intent.class);
when(mockIntent.getData()).thenReturn(Uri.parse("http://myApp/custom/route?query=test"));
Uri expected = Uri.parse("http://myApp/custom/route?query=test");
when(mockIntent.getData()).thenReturn(expected);
// Emulate the host and call the method that we expect to be forwarded.
delegate.onNewIntent(mockIntent);

// Verify that the navigation channel was given the push route message.
verify(mockFlutterEngine.getNavigationChannel(), times(1))
.pushRouteInformation("/custom/route?query=test");
verify(mockFlutterEngine.getNavigationChannel(), times(1)).pushRouteInformation(expected);
}

@Test
Expand All @@ -830,16 +830,15 @@ public void itDoesNotSendPushRouteInformationMessageWhenOnNewIntentIsNonHierarch
delegate.onAttach(ctx);

Intent mockIntent = mock(Intent.class);

Uri expected = Uri.parse("mailto:[email protected]");
// mailto: URIs are non-hierarchical
when(mockIntent.getData()).thenReturn(Uri.parse("mailto:[email protected]"));
when(mockIntent.getData()).thenReturn(expected);

// Emulate the host and call the method
delegate.onNewIntent(mockIntent);

// Verify that the navigation channel was not given a push route message.
verify(mockFlutterEngine.getNavigationChannel(), times(0))
.pushRouteInformation("mailto:[email protected]");
verify(mockFlutterEngine.getNavigationChannel(), times(0)).pushRouteInformation(expected);
}

@Test
Expand All @@ -852,15 +851,14 @@ public void itSendsPushRouteInformationMessageWhenOnNewIntentWithQueryParameterA
// The FlutterEngine is set up in onAttach().
delegate.onAttach(ctx);

Uri expected = Uri.parse("http://myApp/custom/route?query=test#fragment");
Intent mockIntent = mock(Intent.class);
when(mockIntent.getData())
.thenReturn(Uri.parse("http://myApp/custom/route?query=test#fragment"));
when(mockIntent.getData()).thenReturn(expected);
// Emulate the host and call the method that we expect to be forwarded.
delegate.onNewIntent(mockIntent);

// Verify that the navigation channel was given the push route message.
verify(mockFlutterEngine.getNavigationChannel(), times(1))
.pushRouteInformation("/custom/route?query=test#fragment");
verify(mockFlutterEngine.getNavigationChannel(), times(1)).pushRouteInformation(expected);
}

@Test
Expand All @@ -873,14 +871,14 @@ public void itSendsPushRouteInformationMessageWhenOnNewIntentWithFragmentNoQuery
// The FlutterEngine is set up in onAttach().
delegate.onAttach(ctx);

Uri expected = Uri.parse("http://myApp/custom/route#fragment");
Intent mockIntent = mock(Intent.class);
when(mockIntent.getData()).thenReturn(Uri.parse("http://myApp/custom/route#fragment"));
when(mockIntent.getData()).thenReturn(expected);
// Emulate the host and call the method that we expect to be forwarded.
delegate.onNewIntent(mockIntent);

// Verify that the navigation channel was given the push route message.
verify(mockFlutterEngine.getNavigationChannel(), times(1))
.pushRouteInformation("/custom/route#fragment");
verify(mockFlutterEngine.getNavigationChannel(), times(1)).pushRouteInformation(expected);
}

@Test
Expand All @@ -893,14 +891,14 @@ public void itSendsPushRouteInformationMessageWhenOnNewIntentNoQueryParameter()
// The FlutterEngine is set up in onAttach().
delegate.onAttach(ctx);

Uri expected = Uri.parse("http://myApp/custom/route");
Intent mockIntent = mock(Intent.class);
when(mockIntent.getData()).thenReturn(Uri.parse("http://myApp/custom/route"));
when(mockIntent.getData()).thenReturn(Uri.parse(expected));
// Emulate the host and call the method that we expect to be forwarded.
delegate.onNewIntent(mockIntent);

// Verify that the navigation channel was given the push route message.
verify(mockFlutterEngine.getNavigationChannel(), times(1))
.pushRouteInformation("/custom/route");
verify(mockFlutterEngine.getNavigationChannel(), times(1)).pushRouteInformation(expected);
}

@Test
Expand Down