Skip to content

Commit

Permalink
[webview_flutter_android] [webview_flutter_wkwebview] Platform implem…
Browse files Browse the repository at this point in the history
…entations for supporting permission requests (#3792)

Platform implementation portion of #3543
  • Loading branch information
bparrishMines authored Apr 21, 2023
1 parent 0939198 commit b9c1d93
Show file tree
Hide file tree
Showing 60 changed files with 2,625 additions and 235 deletions.
4 changes: 4 additions & 0 deletions packages/webview_flutter/webview_flutter_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.6.0

* Adds support for `PlatformWebViewController.setOnPlatformPermissionRequest`.

## 3.5.3

* Bumps gradle from 7.2.2 to 8.0.0.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2501,6 +2501,20 @@ public void onShowFileChooser(
callback.reply(output);
});
}
/** Callback to Dart function `WebChromeClient.onPermissionRequest`. */
public void onPermissionRequest(
@NonNull Long instanceIdArg,
@NonNull Long requestInstanceIdArg,
@NonNull Reply<Void> callback) {
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.WebChromeClientFlutterApi.onPermissionRequest",
getCodec());
channel.send(
new ArrayList<Object>(Arrays.asList(instanceIdArg, requestInstanceIdArg)),
channelReply -> callback.reply(null));
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface WebStorageHostApi {
Expand Down Expand Up @@ -2635,4 +2649,120 @@ public void create(
channelReply -> callback.reply(null));
}
}
/**
* Host API for `PermissionRequest`.
*
* <p>This class may handle instantiating and adding native object instances that are attached to
* a Dart instance or handle method calls on the associated native class or an instance of the
* class.
*
* <p>See https://developer.android.com/reference/android/webkit/PermissionRequest.
*
* <p>Generated interface from Pigeon that represents a handler of messages from Flutter.
*/
public interface PermissionRequestHostApi {
/** Handles Dart method `PermissionRequest.grant`. */
void grant(@NonNull Long instanceId, @NonNull List<String> resources);
/** Handles Dart method `PermissionRequest.deny`. */
void deny(@NonNull Long instanceId);

/** The codec used by PermissionRequestHostApi. */
static @NonNull MessageCodec<Object> getCodec() {
return new StandardMessageCodec();
}
/**
* Sets up an instance of `PermissionRequestHostApi` to handle messages through the
* `binaryMessenger`.
*/
static void setup(
@NonNull BinaryMessenger binaryMessenger, @Nullable PermissionRequestHostApi api) {
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.PermissionRequestHostApi.grant", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message;
Number instanceIdArg = (Number) args.get(0);
List<String> resourcesArg = (List<String>) args.get(1);
try {
api.grant(
(instanceIdArg == null) ? null : instanceIdArg.longValue(), resourcesArg);
wrapped.add(0, null);
} catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.PermissionRequestHostApi.deny", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message;
Number instanceIdArg = (Number) args.get(0);
try {
api.deny((instanceIdArg == null) ? null : instanceIdArg.longValue());
wrapped.add(0, null);
} catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}
/**
* Flutter API for `PermissionRequest`.
*
* <p>This class may handle instantiating and adding Dart instances that are attached to a native
* instance or receiving callback methods from an overridden native class.
*
* <p>See https://developer.android.com/reference/android/webkit/PermissionRequest.
*
* <p>Generated class from Pigeon that represents Flutter messages that can be called from Java.
*/
public static class PermissionRequestFlutterApi {
private final @NonNull BinaryMessenger binaryMessenger;

public PermissionRequestFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {
this.binaryMessenger = argBinaryMessenger;
}

/** Public interface for sending reply. */
@SuppressWarnings("UnknownNullness")
public interface Reply<T> {
void reply(T reply);
}
/** The codec used by PermissionRequestFlutterApi. */
static @NonNull MessageCodec<Object> getCodec() {
return new StandardMessageCodec();
}
/** Create a new Dart instance and add it to the `InstanceManager`. */
public void create(
@NonNull Long instanceIdArg,
@NonNull List<String> resourcesArg,
@NonNull Reply<Void> callback) {
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.PermissionRequestFlutterApi.create", getCodec());
channel.send(
new ArrayList<Object>(Arrays.asList(instanceIdArg, resourcesArg)),
channelReply -> callback.reply(null));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.webviewflutter;

import android.webkit.PermissionRequest;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.PermissionRequestFlutterApi;
import java.util.Arrays;

/**
* Flutter API implementation for `PermissionRequest`.
*
* <p>This class may handle adding native instances that are attached to a Dart instance or passing
* arguments of callbacks methods to a Dart instance.
*/
public class PermissionRequestFlutterApiImpl {
// To ease adding additional methods, this value is added prematurely.
@SuppressWarnings({"unused", "FieldCanBeLocal"})
private final BinaryMessenger binaryMessenger;

private final InstanceManager instanceManager;
private PermissionRequestFlutterApi api;

/**
* Constructs a {@link PermissionRequestFlutterApiImpl}.
*
* @param binaryMessenger used to communicate with Dart over asynchronous messages
* @param instanceManager maintains instances stored to communicate with attached Dart objects
*/
public PermissionRequestFlutterApiImpl(
@NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) {
this.binaryMessenger = binaryMessenger;
this.instanceManager = instanceManager;
api = new PermissionRequestFlutterApi(binaryMessenger);
}

/**
* Stores the `PermissionRequest` instance and notifies Dart to create and store a new
* `PermissionRequest` instance that is attached to this one. If `instance` has already been
* added, this method does nothing.
*/
public void create(
@NonNull PermissionRequest instance,
@NonNull String[] resources,
@NonNull PermissionRequestFlutterApi.Reply<Void> callback) {
if (!instanceManager.containsInstance(instance)) {
api.create(
instanceManager.addHostCreatedInstance(instance), Arrays.asList(resources), callback);
}
}

/**
* Sets the Flutter API used to send messages to Dart.
*
* <p>This is only visible for testing.
*/
@VisibleForTesting
void setApi(@NonNull PermissionRequestFlutterApi api) {
this.api = api;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.webviewflutter;

import android.os.Build;
import android.webkit.PermissionRequest;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.PermissionRequestHostApi;
import java.util.List;
import java.util.Objects;

/**
* Host API implementation for `PermissionRequest`.
*
* <p>This class may handle instantiating and adding native object instances that are attached to a
* Dart instance or handle method calls on the associated native class or an instance of the class.
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class PermissionRequestHostApiImpl implements PermissionRequestHostApi {
// To ease adding additional methods, this value is added prematurely.
@SuppressWarnings({"unused", "FieldCanBeLocal"})
private final BinaryMessenger binaryMessenger;

private final InstanceManager instanceManager;

/**
* Constructs a {@link PermissionRequestHostApiImpl}.
*
* @param binaryMessenger used to communicate with Dart over asynchronous messages
* @param instanceManager maintains instances stored to communicate with attached Dart objects
*/
public PermissionRequestHostApiImpl(
@NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) {
this.binaryMessenger = binaryMessenger;
this.instanceManager = instanceManager;
}

@Override
public void grant(@NonNull Long instanceId, @NonNull List<String> resources) {
getPermissionRequestInstance(instanceId).grant(resources.toArray(new String[0]));
}

@Override
public void deny(@NonNull Long instanceId) {
getPermissionRequestInstance(instanceId).deny();
}

private PermissionRequest getPermissionRequestInstance(@NonNull Long identifier) {
return Objects.requireNonNull(instanceManager.getInstance(identifier));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package io.flutter.plugins.webviewflutter;

import android.os.Build;
import android.webkit.PermissionRequest;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import androidx.annotation.NonNull;
Expand Down Expand Up @@ -71,6 +72,24 @@ public void onShowFileChooser(
callback);
}

/**
* Sends a message to Dart to call `WebChromeClient.onPermissionRequest` on the Dart object
* representing `instance`.
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void onPermissionRequest(
@NonNull WebChromeClient instance,
@NonNull PermissionRequest request,
@NonNull WebChromeClientFlutterApi.Reply<Void> callback) {
new PermissionRequestFlutterApiImpl(binaryMessenger, instanceManager)
.create(request, request.getResources(), reply -> {});

super.onPermissionRequest(
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(instance)),
Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(request)),
callback);
}

private long getIdentifierForClient(WebChromeClient webChromeClient) {
final Long identifier = instanceManager.getIdentifierForStrongReference(webChromeClient);
if (identifier == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.net.Uri;
import android.os.Build;
import android.os.Message;
import android.webkit.PermissionRequest;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
Expand Down Expand Up @@ -76,6 +77,12 @@ public boolean onShowFileChooser(
return currentReturnValueForOnShowFileChooser;
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onPermissionRequest(@NonNull PermissionRequest request) {
flutterApi.onPermissionRequest(this, request, reply -> {});
}

/** Sets return value for {@link #onShowFileChooser}. */
public void setReturnValueForOnShowFileChooser(boolean value) {
returnValueForOnShowFileChooser = value;
Expand Down Expand Up @@ -136,6 +143,7 @@ public boolean shouldOverrideUrlLoading(
return true;
}

// Legacy codepath for < N.
@Override
@SuppressWarnings({"deprecation", "RedundantSuppression"})
public boolean shouldOverrideUrlLoading(WebView windowWebView, String url) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package io.flutter.plugins.webviewflutter;

import android.content.Context;
import android.os.Build;
import android.os.Handler;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand All @@ -19,6 +20,7 @@
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.InstanceManagerHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaObjectHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.PermissionRequestHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebSettingsHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebStorageHostApi;
Expand Down Expand Up @@ -129,6 +131,11 @@ private void setUp(
WebStorageHostApi.setup(
binaryMessenger,
new WebStorageHostApiImpl(instanceManager, new WebStorageHostApiImpl.WebStorageCreator()));

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
PermissionRequestHostApi.setup(
binaryMessenger, new PermissionRequestHostApiImpl(binaryMessenger, instanceManager));
}
}

@Override
Expand Down
Loading

0 comments on commit b9c1d93

Please sign in to comment.