From b1e7a2283f131d68c910a632d30e0cf9607ec12f Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 15 Oct 2021 00:33:42 -0700 Subject: [PATCH 01/54] finish pigeon apis --- .../android/build.gradle | 4 + .../GeneratedAndroidWebView.java | 1290 +++++++++++++++++ .../generatePigeons.sh | 5 + .../lib/src/android_webview.dart | 155 ++ .../lib/src/android_webview.pigeon.dart | 1159 +++++++++++++++ .../lib/src/android_webview_api_impls.dart | 22 + .../lib/src/instance_manager.dart | 24 + .../pigeons/android_webview.dart | 160 ++ .../webview_flutter_android/pubspec.yaml | 1 + 9 files changed, 2820 insertions(+) create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java create mode 100755 packages/webview_flutter/webview_flutter_android/generatePigeons.sh create mode 100644 packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart create mode 100644 packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart create mode 100644 packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart create mode 100644 packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart create mode 100644 packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart diff --git a/packages/webview_flutter/webview_flutter_android/android/build.gradle b/packages/webview_flutter/webview_flutter_android/android/build.gradle index 4a164317c60f..ef1485a765d0 100644 --- a/packages/webview_flutter/webview_flutter_android/android/build.gradle +++ b/packages/webview_flutter/webview_flutter_android/android/build.gradle @@ -42,6 +42,10 @@ android { testImplementation 'androidx.test:core:1.3.0' } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } testOptions { unitTests.includeAndroidResources = true diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java new file mode 100644 index 000000000000..9b6b199adda6 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -0,0 +1,1290 @@ +// Autogenerated from Pigeon (v1.0.7), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +package io.flutter.plugins.webviewflutter; + +import io.flutter.plugin.common.BasicMessageChannel; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.MessageCodec; +import io.flutter.plugin.common.StandardMessageCodec; +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.HashMap; + +/** Generated class from Pigeon. */ +@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"}) +public class GeneratedAndroidWebView { + + /** Generated class from Pigeon that represents data sent in messages. */ + public static class WebResourceRequestData { + private String url; + public String getUrl() { return url; } + public void setUrl(String setterArg) { this.url = setterArg; } + + private Boolean isForMainFrame; + public Boolean getIsForMainFrame() { return isForMainFrame; } + public void setIsForMainFrame(Boolean setterArg) { this.isForMainFrame = setterArg; } + + private Boolean isRedirect; + public Boolean getIsRedirect() { return isRedirect; } + public void setIsRedirect(Boolean setterArg) { this.isRedirect = setterArg; } + + private Boolean hasGesture; + public Boolean getHasGesture() { return hasGesture; } + public void setHasGesture(Boolean setterArg) { this.hasGesture = setterArg; } + + private String method; + public String getMethod() { return method; } + public void setMethod(String setterArg) { this.method = setterArg; } + + private Map requestHeaders; + public Map getRequestHeaders() { return requestHeaders; } + public void setRequestHeaders(Map setterArg) { this.requestHeaders = setterArg; } + + Map toMap() { + Map toMapResult = new HashMap<>(); + toMapResult.put("url", url); + toMapResult.put("isForMainFrame", isForMainFrame); + toMapResult.put("isRedirect", isRedirect); + toMapResult.put("hasGesture", hasGesture); + toMapResult.put("method", method); + toMapResult.put("requestHeaders", requestHeaders); + return toMapResult; + } + static WebResourceRequestData fromMap(Map map) { + WebResourceRequestData fromMapResult = new WebResourceRequestData(); + Object url = map.get("url"); + fromMapResult.url = (String)url; + Object isForMainFrame = map.get("isForMainFrame"); + fromMapResult.isForMainFrame = (Boolean)isForMainFrame; + Object isRedirect = map.get("isRedirect"); + fromMapResult.isRedirect = (Boolean)isRedirect; + Object hasGesture = map.get("hasGesture"); + fromMapResult.hasGesture = (Boolean)hasGesture; + Object method = map.get("method"); + fromMapResult.method = (String)method; + Object requestHeaders = map.get("requestHeaders"); + fromMapResult.requestHeaders = (Map)requestHeaders; + return fromMapResult; + } + } + + /** Generated class from Pigeon that represents data sent in messages. */ + public static class WebResourceErrorData { + private Long errorCode; + public Long getErrorCode() { return errorCode; } + public void setErrorCode(Long setterArg) { this.errorCode = setterArg; } + + private String description; + public String getDescription() { return description; } + public void setDescription(String setterArg) { this.description = setterArg; } + + Map toMap() { + Map toMapResult = new HashMap<>(); + toMapResult.put("errorCode", errorCode); + toMapResult.put("description", description); + return toMapResult; + } + static WebResourceErrorData fromMap(Map map) { + WebResourceErrorData fromMapResult = new WebResourceErrorData(); + Object errorCode = map.get("errorCode"); + fromMapResult.errorCode = (errorCode == null) ? null : ((errorCode instanceof Integer) ? (Integer)errorCode : (Long)errorCode); + Object description = map.get("description"); + fromMapResult.description = (String)description; + return fromMapResult; + } + } + + public interface Result { + void success(T result); + void error(Throwable error); + } + private static class WebViewHostApiCodec extends StandardMessageCodec { + public static final WebViewHostApiCodec INSTANCE = new WebViewHostApiCodec(); + private WebViewHostApiCodec() {} + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + public interface WebViewHostApi { + void create(Long instanceId, Boolean useHybridComposition); + void dispose(Long instanceId); + void loadUrl(Long instanceId, String url, Map headers); + String getUrl(Long instanceId); + Boolean canGoBack(Long instanceId); + Boolean canGoForward(Long instanceId); + void goBack(Long instanceId); + void goForward(Long instanceId); + void reload(Long instanceId); + void clearCache(Long instanceId, Boolean includeDiskFiles); + void evaluateJavascript(Long instanceId, String javascriptString, Result result); + String getTitle(Long instanceId); + void scrollTo(Long instanceId, Long x, Long y); + void scrollBy(Long instanceId, Long x, Long y); + Long getScrollX(Long instanceId); + Long getScrollY(Long instanceId); + void setWebContentsDebuggingEnabled(Boolean enabled); + void setWebViewClient(Long instanceId, Long webViewClientInstanceId); + void addJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); + void removeJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); + + /** The codec used by WebViewHostApi. */ + static MessageCodec getCodec() { + return WebViewHostApiCodec.INSTANCE; + } + + /** Sets up an instance of `WebViewHostApi` to handle messages through the `binaryMessenger`. */ + static void setup(BinaryMessenger binaryMessenger, WebViewHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean useHybridCompositionArg = (Boolean)args.get(1); + if (useHybridCompositionArg == null) { + throw new NullPointerException("useHybridCompositionArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), useHybridCompositionArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.dispose", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.loadUrl", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String urlArg = (String)args.get(1); + if (urlArg == null) { + throw new NullPointerException("urlArg unexpectedly null."); + } + Map headersArg = (Map)args.get(2); + if (headersArg == null) { + throw new NullPointerException("headersArg unexpectedly null."); + } + api.loadUrl(instanceIdArg.longValue(), urlArg, headersArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getUrl", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String output = api.getUrl(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoBack", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean output = api.canGoBack(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoForward", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean output = api.canGoForward(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goBack", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.goBack(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goForward", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.goForward(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.reload", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.reload(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.clearCache", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean includeDiskFilesArg = (Boolean)args.get(1); + if (includeDiskFilesArg == null) { + throw new NullPointerException("includeDiskFilesArg unexpectedly null."); + } + api.clearCache(instanceIdArg.longValue(), includeDiskFilesArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.evaluateJavascript", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String javascriptStringArg = (String)args.get(1); + if (javascriptStringArg == null) { + throw new NullPointerException("javascriptStringArg unexpectedly null."); + } + Result resultCallback = new Result() { + public void success(String result) { + wrapped.put("result", result); + reply.reply(wrapped); + } + public void error(Throwable error) { + wrapped.put("error", wrapError(error)); + reply.reply(wrapped); + } + }; + + api.evaluateJavascript(instanceIdArg.longValue(), javascriptStringArg, resultCallback); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + reply.reply(wrapped); + } + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getTitle", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String output = api.getTitle(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollTo", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number xArg = (Number)args.get(1); + if (xArg == null) { + throw new NullPointerException("xArg unexpectedly null."); + } + Number yArg = (Number)args.get(2); + if (yArg == null) { + throw new NullPointerException("yArg unexpectedly null."); + } + api.scrollTo(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollBy", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number xArg = (Number)args.get(1); + if (xArg == null) { + throw new NullPointerException("xArg unexpectedly null."); + } + Number yArg = (Number)args.get(2); + if (yArg == null) { + throw new NullPointerException("yArg unexpectedly null."); + } + api.scrollBy(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollX", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Long output = api.getScrollX(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollY", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Long output = api.getScrollY(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Boolean enabledArg = (Boolean)args.get(0); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setWebContentsDebuggingEnabled(enabledArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebViewClient", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number webViewClientInstanceIdArg = (Number)args.get(1); + if (webViewClientInstanceIdArg == null) { + throw new NullPointerException("webViewClientInstanceIdArg unexpectedly null."); + } + api.setWebViewClient(instanceIdArg.longValue(), webViewClientInstanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number javaScriptChannelInstanceIdArg = (Number)args.get(1); + if (javaScriptChannelInstanceIdArg == null) { + throw new NullPointerException("javaScriptChannelInstanceIdArg unexpectedly null."); + } + api.addJavaScriptChannel(instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number javaScriptChannelInstanceIdArg = (Number)args.get(1); + if (javaScriptChannelInstanceIdArg == null) { + throw new NullPointerException("javaScriptChannelInstanceIdArg unexpectedly null."); + } + api.removeJavaScriptChannel(instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + private static class WebViewSettingsHostApiCodec extends StandardMessageCodec { + public static final WebViewSettingsHostApiCodec INSTANCE = new WebViewSettingsHostApiCodec(); + private WebViewSettingsHostApiCodec() {} + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + public interface WebViewSettingsHostApi { + void create(Long instanceId, Long webViewInstanceId); + void dispose(Long instanceId); + void setDomStorageEnabled(Long instanceId, Boolean flag); + void setJavaScriptCanOpenWindowsAutomatically(Long instanceId, Boolean flag); + void setSupportMultipleWindows(Long instanceId, Boolean support); + void setJavaScriptEnabled(Long instanceId, Boolean flag); + void setUserAgentString(Long instanceId, String userAgentString); + void setMediaPlaybackRequiresUserGesture(Long instanceId, Boolean require); + + /** The codec used by WebViewSettingsHostApi. */ + static MessageCodec getCodec() { + return WebViewSettingsHostApiCodec.INSTANCE; + } + + /** Sets up an instance of `WebViewSettingsHostApi` to handle messages through the `binaryMessenger`. */ + static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number webViewInstanceIdArg = (Number)args.get(1); + if (webViewInstanceIdArg == null) { + throw new NullPointerException("webViewInstanceIdArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), webViewInstanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.dispose", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setDomStorageEnabled", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean)args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setDomStorageEnabled(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean)args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setJavaScriptCanOpenWindowsAutomatically(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setSupportMultipleWindows", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean supportArg = (Boolean)args.get(1); + if (supportArg == null) { + throw new NullPointerException("supportArg unexpectedly null."); + } + api.setSupportMultipleWindows(instanceIdArg.longValue(), supportArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setJavaScriptEnabled", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean)args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setJavaScriptEnabled(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setUserAgentString", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String userAgentStringArg = (String)args.get(1); + if (userAgentStringArg == null) { + throw new NullPointerException("userAgentStringArg unexpectedly null."); + } + api.setUserAgentString(instanceIdArg.longValue(), userAgentStringArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setMediaPlaybackRequiresUserGesture", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean requireArg = (Boolean)args.get(1); + if (requireArg == null) { + throw new NullPointerException("requireArg unexpectedly null."); + } + api.setMediaPlaybackRequiresUserGesture(instanceIdArg.longValue(), requireArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + private static class JavaScriptChannelHostApiCodec extends StandardMessageCodec { + public static final JavaScriptChannelHostApiCodec INSTANCE = new JavaScriptChannelHostApiCodec(); + private JavaScriptChannelHostApiCodec() {} + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + public interface JavaScriptChannelHostApi { + void create(Long instanceId, String channelName); + void dispose(Long instanceId); + + /** The codec used by JavaScriptChannelHostApi. */ + static MessageCodec getCodec() { + return JavaScriptChannelHostApiCodec.INSTANCE; + } + + /** Sets up an instance of `JavaScriptChannelHostApi` to handle messages through the `binaryMessenger`. */ + static void setup(BinaryMessenger binaryMessenger, JavaScriptChannelHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String channelNameArg = (String)args.get(1); + if (channelNameArg == null) { + throw new NullPointerException("channelNameArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), channelNameArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.dispose", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + private static class JavaScriptChannelFlutterApiCodec extends StandardMessageCodec { + public static final JavaScriptChannelFlutterApiCodec INSTANCE = new JavaScriptChannelFlutterApiCodec(); + private JavaScriptChannelFlutterApiCodec() {} + } + + /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ + public static class JavaScriptChannelFlutterApi { + private final BinaryMessenger binaryMessenger; + public JavaScriptChannelFlutterApi(BinaryMessenger argBinaryMessenger){ + this.binaryMessenger = argBinaryMessenger; + } + public interface Reply { + void reply(T reply); + } + static MessageCodec getCodec() { + return JavaScriptChannelFlutterApiCodec.INSTANCE; + } + + public void postMessage(Long instanceIdArg, String messageArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, messageArg)), channelReply -> { + callback.reply(null); + }); + } + } + private static class WebViewClientHostApiCodec extends StandardMessageCodec { + public static final WebViewClientHostApiCodec INSTANCE = new WebViewClientHostApiCodec(); + private WebViewClientHostApiCodec() {} + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + public interface WebViewClientHostApi { + void create(Long instanceId, Boolean autoFailShouldOverrideUrlLoading); + void dispose(Long instanceId); + + /** The codec used by WebViewClientHostApi. */ + static MessageCodec getCodec() { + return WebViewClientHostApiCodec.INSTANCE; + } + + /** Sets up an instance of `WebViewClientHostApi` to handle messages through the `binaryMessenger`. */ + static void setup(BinaryMessenger binaryMessenger, WebViewClientHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean autoFailShouldOverrideUrlLoadingArg = (Boolean)args.get(1); + if (autoFailShouldOverrideUrlLoadingArg == null) { + throw new NullPointerException("autoFailShouldOverrideUrlLoadingArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), autoFailShouldOverrideUrlLoadingArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.dispose", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + private static class WebViewClientFlutterApiCodec extends StandardMessageCodec { + public static final WebViewClientFlutterApiCodec INSTANCE = new WebViewClientFlutterApiCodec(); + private WebViewClientFlutterApiCodec() {} + @Override + protected Object readValueOfType(byte type, ByteBuffer buffer) { + switch (type) { + case (byte)128: + return WebResourceErrorData.fromMap((Map) readValue(buffer)); + + case (byte)129: + return WebResourceRequestData.fromMap((Map) readValue(buffer)); + + case (byte)130: + return WebResourceRequestData.fromMap((Map) readValue(buffer)); + + default: + return super.readValueOfType(type, buffer); + + } + } + @Override + protected void writeValue(ByteArrayOutputStream stream, Object value) { + if (value instanceof WebResourceErrorData) { + stream.write(128); + writeValue(stream, ((WebResourceErrorData) value).toMap()); + } else + if (value instanceof WebResourceRequestData) { + stream.write(129); + writeValue(stream, ((WebResourceRequestData) value).toMap()); + } else + if (value instanceof WebResourceRequestData) { + stream.write(130); + writeValue(stream, ((WebResourceRequestData) value).toMap()); + } else +{ + super.writeValue(stream, value); + } + } + } + + /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ + public static class WebViewClientFlutterApi { + private final BinaryMessenger binaryMessenger; + public WebViewClientFlutterApi(BinaryMessenger argBinaryMessenger){ + this.binaryMessenger = argBinaryMessenger; + } + public interface Reply { + void reply(T reply); + } + static MessageCodec getCodec() { + return WebViewClientFlutterApiCodec.INSTANCE; + } + + public void onPageStarted(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { + callback.reply(null); + }); + } + public void onPageFinished(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { + callback.reply(null); + }); + } + public void onReceivedRequestError(Long instanceIdArg, Long webViewInstanceIdArg, WebResourceRequestData requestArg, WebResourceErrorData errorArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg, errorArg)), channelReply -> { + callback.reply(null); + }); + } + public void onReceivedError(Long instanceIdArg, Long webViewInstanceIdArg, Long errorCodeArg, String descriptionArg, String failingUrlArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, errorCodeArg, descriptionArg, failingUrlArg)), channelReply -> { + callback.reply(null); + }); + } + public void shouldOverrideRequestLoading(Long instanceIdArg, Long webViewInstanceIdArg, WebResourceRequestData requestArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg)), channelReply -> { + callback.reply(null); + }); + } + public void shouldOverrideUrlLoading(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { + callback.reply(null); + }); + } + } + private static class DownloadListenerHostApiCodec extends StandardMessageCodec { + public static final DownloadListenerHostApiCodec INSTANCE = new DownloadListenerHostApiCodec(); + private DownloadListenerHostApiCodec() {} + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + public interface DownloadListenerHostApi { + void create(Long instanceId); + void dispose(Long instanceId); + + /** The codec used by DownloadListenerHostApi. */ + static MessageCodec getCodec() { + return DownloadListenerHostApiCodec.INSTANCE; + } + + /** Sets up an instance of `DownloadListenerHostApi` to handle messages through the `binaryMessenger`. */ + static void setup(BinaryMessenger binaryMessenger, DownloadListenerHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.create(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.dispose", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + private static class DownloadListenerFlutterApiCodec extends StandardMessageCodec { + public static final DownloadListenerFlutterApiCodec INSTANCE = new DownloadListenerFlutterApiCodec(); + private DownloadListenerFlutterApiCodec() {} + } + + /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ + public static class DownloadListenerFlutterApi { + private final BinaryMessenger binaryMessenger; + public DownloadListenerFlutterApi(BinaryMessenger argBinaryMessenger){ + this.binaryMessenger = argBinaryMessenger; + } + public interface Reply { + void reply(T reply); + } + static MessageCodec getCodec() { + return DownloadListenerFlutterApiCodec.INSTANCE; + } + + public void onDownloadStart(Long instanceIdArg, String urlArg, String userAgentArg, String contentDispositionArg, String mimetypeArg, Long contentLengthArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, urlArg, userAgentArg, contentDispositionArg, mimetypeArg, contentLengthArg)), channelReply -> { + callback.reply(null); + }); + } + } + private static Map wrapError(Throwable exception) { + Map errorMap = new HashMap<>(); + errorMap.put("message", exception.toString()); + errorMap.put("code", exception.getClass().getSimpleName()); + errorMap.put("details", null); + return errorMap; + } +} diff --git a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh new file mode 100755 index 000000000000..d6598017cbda --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh @@ -0,0 +1,5 @@ +flutter pub run pigeon \ +--input pigeons/android_webview.dart \ +--dart_out lib/src/android_webview.pigeon.dart \ +--java_out ./android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java \ +--java_package io.flutter.plugins.webviewflutter diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart new file mode 100644 index 000000000000..ed23fc885213 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -0,0 +1,155 @@ +// 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. + +import 'android_webview_api_impls.dart'; +import 'instance_manager.dart'; + +// TODO: This can be removed once pigeon supports null values. +// Workaround since pigeon doesn't support null values. +const String _nullStringIdentifier = ''; + +/// An Android View that displays web pages. +/// +/// **Basic usage** +/// In most cases, we recommend using a standard web browser, like Chrome, to +/// deliver content to the user. To learn more about web browsers, read the +/// guide on invoking a browser with +/// [url_launcher](https://pub.dev/packages/url_launcher). +/// +/// WebView objects allow you to display web content as part of your wiget +/// layout, but lack some of the features of fully-developed browsers. A WebView +/// is useful when you need increased control over the UI and advanced +/// configuration options that will allow you to embed web pages in a +/// specially-designed environment for your app. +/// +/// To learn more about WebView and alternatives for serving web content, read +/// the documentation on +/// [Web-based content](https://developer.android.com/guide/webapps). +class WebView { + /// Constructs a new WebView. + WebView({this.useHybridComposition = false}) { + _api.createFromInstance(this, useHybridComposition); + } + + static final WebViewHostApiImpl _api = WebViewHostApiImpl(); + int get _instanceId => InstanceManager.instance.getInstanceId(this)!; + + final bool useHybridComposition; + + /// Loads the given URL with additional HTTP headers, specified as a map from name to value. + /// + /// Note that if this map contains any of the headers that are set by default + /// by this WebView, such as those controlling caching, accept types or the + /// User-Agent, their values may be overridden by this WebView's defaults. + /// + /// Also see compatibility note on [evaluateJavascript]. + Future loadUrl(String url, Map headers) { + return _api.loadUrl(_instanceId, url, headers); + } + + /// Gets the URL for the current page. + /// + /// This is not always the same as the URL passed to + /// [WebViewClient.onPageStarted] because although the load for that URL has + /// begun, the current page may not have changed. + /// + /// Returns null if no page has been loaded. + Future getUrl() async { + final String result = await _api.getUrl(_instanceId); + if (result == _nullStringIdentifier) return null; + return result; + } + + /// Whether this WebView has a back history item. + Future canGoBack() { + return _api.canGoBack(_instanceId); + } + + /// Whether this WebView has a forward history item. + Future canGoForward() { + return _api.canGoForward(_instanceId); + } + + /// Goes back in the history of this WebView. + Future goBack() { + return _api.goBack(_instanceId); + } + + /// Goes forward in the history of this WebView. + Future goForward() { + return _api.goForward(_instanceId); + } + + /// Reloads the current URL. + Future reload() { + return _api.reload(_instanceId); + } + + /// Clears the resource cache. + /// + /// Note that the cache is per-application, so this will clear the cache for + /// all WebViews used. + Future clearCache(bool includeDiskFiles) { + return _api.clearCache(_instanceId, includeDiskFiles); + } + + // TODO: Update documentation once addJavascriptInterface is added. + /// Asynchronously evaluates JavaScript in the context of the currently displayed page. + /// + /// If non-null, the returned value will be any result returned from that + /// execution. + /// + /// Compatibility note. Applications targeting Android versions N or later, + /// JavaScript state from an empty WebView is no longer persisted across + /// navigations like [loadUrl]. For example, global variables and functions + /// defined before calling [loadUrl]) will not exist in the loaded page. + Future evaluateJavascript(String javascriptString) async { + final String result = await _api.evaluateJavascript( + _instanceId, + javascriptString, + ); + if (result == _nullStringIdentifier) return null; + return result; + } + + // TODO: Update documentation when WebViewClient.onReceivedTitle is added. + /// Gets the title for the current page. + /// + /// Returns null if no page has been loaded. + Future getTitle() async { + final String result = await _api.getTitle(_instanceId); + if (result == _nullStringIdentifier) return null; + return result; + } + + // TODO: Update documentation when onScrollChanged is added. + /// Set the scrolled position of your view. + Future scrollTo(int x, int y) { + return _api.scrollTo(_instanceId, x, y); + } + + // TODO: Update documentation when onScrollChanged is added. + /// Move the scrolled position of your view. + Future scrollBy(int x, int y) { + return _api.scrollBy(_instanceId, x, y); + } + + /// Return the scrolled left position of this view. + /// + /// This is the left edge of the displayed part of your view. You do not + /// need to draw any pixels farther left, since those are outside of the frame + /// of your view on screen. + Future getScrollX() { + return _api.getScrollX(_instanceId); + } + + /// Return the scrolled top position of this view. + /// + /// This is the top edge of the displayed part of your view. You do not need + /// to draw any pixels above it, since those are outside of the frame of your + /// view on screen. + Future getScrollY() { + return _api.getScrollY(_instanceId); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart new file mode 100644 index 000000000000..e83b1c6f2964 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -0,0 +1,1159 @@ +// Autogenerated from Pigeon (v1.0.7), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name +// @dart = 2.12 +import 'dart:async'; +import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; + +import 'package:flutter/foundation.dart' show WriteBuffer, ReadBuffer; +import 'package:flutter/services.dart'; + +class WebResourceRequestData { + String? url; + bool? isForMainFrame; + bool? isRedirect; + bool? hasGesture; + String? method; + Map? requestHeaders; + + Object encode() { + final Map pigeonMap = {}; + pigeonMap['url'] = url; + pigeonMap['isForMainFrame'] = isForMainFrame; + pigeonMap['isRedirect'] = isRedirect; + pigeonMap['hasGesture'] = hasGesture; + pigeonMap['method'] = method; + pigeonMap['requestHeaders'] = requestHeaders; + return pigeonMap; + } + + static WebResourceRequestData decode(Object message) { + final Map pigeonMap = message as Map; + return WebResourceRequestData() + ..url = pigeonMap['url'] as String? + ..isForMainFrame = pigeonMap['isForMainFrame'] as bool? + ..isRedirect = pigeonMap['isRedirect'] as bool? + ..hasGesture = pigeonMap['hasGesture'] as bool? + ..method = pigeonMap['method'] as String? + ..requestHeaders = (pigeonMap['requestHeaders'] as Map?)?.cast(); + } +} + +class WebResourceErrorData { + int? errorCode; + String? description; + + Object encode() { + final Map pigeonMap = {}; + pigeonMap['errorCode'] = errorCode; + pigeonMap['description'] = description; + return pigeonMap; + } + + static WebResourceErrorData decode(Object message) { + final Map pigeonMap = message as Map; + return WebResourceErrorData() + ..errorCode = pigeonMap['errorCode'] as int? + ..description = pigeonMap['description'] as String?; + } +} + +class _WebViewHostApiCodec extends StandardMessageCodec { + const _WebViewHostApiCodec(); +} + +class WebViewHostApi { + /// Constructor for [WebViewHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + WebViewHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _WebViewHostApiCodec(); + + Future create(int arg_instanceId, bool arg_useHybridComposition) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.create', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_useHybridComposition]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future dispose(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.dispose', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future loadUrl(int arg_instanceId, String arg_url, Map arg_headers) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.loadUrl', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_url, arg_headers]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future getUrl(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getUrl', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as String?)!; + } + } + + Future canGoBack(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.canGoBack', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as bool?)!; + } + } + + Future canGoForward(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.canGoForward', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as bool?)!; + } + } + + Future goBack(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.goBack', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future goForward(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.goForward', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future reload(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.reload', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future clearCache(int arg_instanceId, bool arg_includeDiskFiles) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.clearCache', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_includeDiskFiles]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future evaluateJavascript(int arg_instanceId, String arg_javascriptString) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.evaluateJavascript', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_javascriptString]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as String?)!; + } + } + + Future getTitle(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getTitle', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as String?)!; + } + } + + Future scrollTo(int arg_instanceId, int arg_x, int arg_y) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.scrollTo', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_x, arg_y]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future scrollBy(int arg_instanceId, int arg_x, int arg_y) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.scrollBy', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_x, arg_y]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future getScrollX(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getScrollX', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as int?)!; + } + } + + Future getScrollY(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getScrollY', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as int?)!; + } + } + + Future setWebContentsDebuggingEnabled(bool arg_enabled) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_enabled]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setWebViewClient(int arg_instanceId, int arg_webViewClientInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.setWebViewClient', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_webViewClientInstanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future addJavaScriptChannel(int arg_instanceId, int arg_javaScriptChannelInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_javaScriptChannelInstanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future removeJavaScriptChannel(int arg_instanceId, int arg_javaScriptChannelInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_javaScriptChannelInstanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + +class _WebViewSettingsHostApiCodec extends StandardMessageCodec { + const _WebViewSettingsHostApiCodec(); +} + +class WebViewSettingsHostApi { + /// Constructor for [WebViewSettingsHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + WebViewSettingsHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _WebViewSettingsHostApiCodec(); + + Future create(int arg_instanceId, int arg_webViewInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.create', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_webViewInstanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future dispose(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.dispose', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setDomStorageEnabled(int arg_instanceId, bool arg_flag) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.setDomStorageEnabled', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_flag]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setJavaScriptCanOpenWindowsAutomatically(int arg_instanceId, bool arg_flag) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_flag]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setSupportMultipleWindows(int arg_instanceId, bool arg_support) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.setSupportMultipleWindows', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_support]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setJavaScriptEnabled(int arg_instanceId, bool arg_flag) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.setJavaScriptEnabled', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_flag]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setUserAgentString(int arg_instanceId, String arg_userAgentString) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.setUserAgentString', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_userAgentString]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setMediaPlaybackRequiresUserGesture(int arg_instanceId, bool arg_require) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.setMediaPlaybackRequiresUserGesture', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_require]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + +class _JavaScriptChannelHostApiCodec extends StandardMessageCodec { + const _JavaScriptChannelHostApiCodec(); +} + +class JavaScriptChannelHostApi { + /// Constructor for [JavaScriptChannelHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + JavaScriptChannelHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _JavaScriptChannelHostApiCodec(); + + Future create(int arg_instanceId, String arg_channelName) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.JavaScriptChannelHostApi.create', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_channelName]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future dispose(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.JavaScriptChannelHostApi.dispose', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + +class _JavaScriptChannelFlutterApiCodec extends StandardMessageCodec { + const _JavaScriptChannelFlutterApiCodec(); +} +abstract class JavaScriptChannelFlutterApi { + static const MessageCodec codec = _JavaScriptChannelFlutterApiCodec(); + + void postMessage(int instanceId, String message); + static void setup(JavaScriptChannelFlutterApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null, expected non-null int.'); + final String? arg_message = args[1] as String?; + assert(arg_message != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null, expected non-null String.'); + api.postMessage(arg_instanceId!, arg_message!); + return; + }); + } + } + } +} + +class _WebViewClientHostApiCodec extends StandardMessageCodec { + const _WebViewClientHostApiCodec(); +} + +class WebViewClientHostApi { + /// Constructor for [WebViewClientHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + WebViewClientHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _WebViewClientHostApiCodec(); + + Future create(int arg_instanceId, bool arg_autoFailShouldOverrideUrlLoading) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientHostApi.create', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_autoFailShouldOverrideUrlLoading]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future dispose(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientHostApi.dispose', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + +class _WebViewClientFlutterApiCodec extends StandardMessageCodec { + const _WebViewClientFlutterApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is WebResourceErrorData) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else + if (value is WebResourceRequestData) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else + if (value is WebResourceRequestData) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else +{ + super.writeValue(buffer, value); + } + } + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return WebResourceErrorData.decode(readValue(buffer)!); + + case 129: + return WebResourceRequestData.decode(readValue(buffer)!); + + case 130: + return WebResourceRequestData.decode(readValue(buffer)!); + + default: + return super.readValueOfType(type, buffer); + + } + } +} +abstract class WebViewClientFlutterApi { + static const MessageCodec codec = _WebViewClientFlutterApiCodec(); + + void onPageStarted(int instanceId, int webViewInstanceId, String url); + void onPageFinished(int instanceId, int webViewInstanceId, String url); + void onReceivedRequestError(int instanceId, int webViewInstanceId, WebResourceRequestData request, WebResourceErrorData error); + void onReceivedError(int instanceId, int webViewInstanceId, int errorCode, String description, String failingUrl); + void shouldOverrideRequestLoading(int instanceId, int webViewInstanceId, WebResourceRequestData request); + void shouldOverrideUrlLoading(int instanceId, int webViewInstanceId, String url); + static void setup(WebViewClientFlutterApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null int.'); + final String? arg_url = args[2] as String?; + assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null String.'); + api.onPageStarted(arg_instanceId!, arg_webViewInstanceId!, arg_url!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null int.'); + final String? arg_url = args[2] as String?; + assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null String.'); + api.onPageFinished(arg_instanceId!, arg_webViewInstanceId!, arg_url!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null int.'); + final WebResourceRequestData? arg_request = args[2] as WebResourceRequestData?; + assert(arg_request != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null WebResourceRequestData.'); + final WebResourceErrorData? arg_error = args[3] as WebResourceErrorData?; + assert(arg_error != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null WebResourceErrorData.'); + api.onReceivedRequestError(arg_instanceId!, arg_webViewInstanceId!, arg_request!, arg_error!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); + final int? arg_errorCode = args[2] as int?; + assert(arg_errorCode != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); + final String? arg_description = args[3] as String?; + assert(arg_description != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null String.'); + final String? arg_failingUrl = args[4] as String?; + assert(arg_failingUrl != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null String.'); + api.onReceivedError(arg_instanceId!, arg_webViewInstanceId!, arg_errorCode!, arg_description!, arg_failingUrl!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading was null, expected non-null int.'); + final WebResourceRequestData? arg_request = args[2] as WebResourceRequestData?; + assert(arg_request != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading was null, expected non-null WebResourceRequestData.'); + api.shouldOverrideRequestLoading(arg_instanceId!, arg_webViewInstanceId!, arg_request!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading was null, expected non-null int.'); + final String? arg_url = args[2] as String?; + assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading was null, expected non-null String.'); + api.shouldOverrideUrlLoading(arg_instanceId!, arg_webViewInstanceId!, arg_url!); + return; + }); + } + } + } +} + +class _DownloadListenerHostApiCodec extends StandardMessageCodec { + const _DownloadListenerHostApiCodec(); +} + +class DownloadListenerHostApi { + /// Constructor for [DownloadListenerHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + DownloadListenerHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _DownloadListenerHostApiCodec(); + + Future create(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.DownloadListenerHostApi.create', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future dispose(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.DownloadListenerHostApi.dispose', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + +class _DownloadListenerFlutterApiCodec extends StandardMessageCodec { + const _DownloadListenerFlutterApiCodec(); +} +abstract class DownloadListenerFlutterApi { + static const MessageCodec codec = _DownloadListenerFlutterApiCodec(); + + void onDownloadStart(int instanceId, String url, String userAgent, String contentDisposition, String mimetype, int contentLength); + static void setup(DownloadListenerFlutterApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null int.'); + final String? arg_url = args[1] as String?; + assert(arg_url != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + final String? arg_userAgent = args[2] as String?; + assert(arg_userAgent != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + final String? arg_contentDisposition = args[3] as String?; + assert(arg_contentDisposition != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + final String? arg_mimetype = args[4] as String?; + assert(arg_mimetype != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + final int? arg_contentLength = args[5] as int?; + assert(arg_contentLength != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null int.'); + api.onDownloadStart(arg_instanceId!, arg_url!, arg_userAgent!, arg_contentDisposition!, arg_mimetype!, arg_contentLength!); + return; + }); + } + } + } +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart new file mode 100644 index 000000000000..52ac797ee2cb --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -0,0 +1,22 @@ +import 'android_webview.dart'; +import 'android_webview.pigeon.dart'; +import 'instance_manager.dart'; + +class WebViewHostApiImpl extends WebViewHostApi { + Future createFromInstance( + WebView webView, + bool useHybridComposition, + ) async { + final int? instanceId = InstanceManager.instance.tryAddInstance(webView); + if (instanceId != null) { + return create(instanceId, useHybridComposition); + } + } + + Future disposeFromInstance(WebView webView) async { + final int? instanceId = InstanceManager.instance.removeInstance(webView); + if (instanceId != null) { + return dispose(instanceId); + } + } +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart new file mode 100644 index 000000000000..a53da3fb5548 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart @@ -0,0 +1,24 @@ +class InstanceManager { + Map _instanceIdToInstances = {}; + Map _instancesToInstanceId = {}; + + static int _nextInstanceId = 0; + + static final InstanceManager instance = InstanceManager(); + + int? tryAddInstance(Object instance) { + + } + + int? removeInstance(Object instance) { + + } + + Object? getInstance(int instanceId) { + + } + + int? getInstanceId(Object instance) { + + } +} \ No newline at end of file diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart new file mode 100644 index 000000000000..25b1be33a3d6 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -0,0 +1,160 @@ +// 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. + +import 'package:pigeon/pigeon.dart'; + +class WebResourceRequestData { + String? url; + bool? isForMainFrame; + bool? isRedirect; + bool? hasGesture; + String? method; + Map? requestHeaders; +} + +class WebResourceErrorData { + int? errorCode; + String? description; +} + +@HostApi() +abstract class WebViewHostApi { + void create(int instanceId, bool useHybridComposition); + + void dispose(int instanceId); + + void loadUrl( + int instanceId, + String url, + Map headers, + ); + + String getUrl(int instanceId); + + bool canGoBack(int instanceId); + + bool canGoForward(int instanceId); + + void goBack(int instanceId); + + void goForward(int instanceId); + + void reload(int instanceId); + + void clearCache(int instanceId, bool includeDiskFiles); + + @async + String evaluateJavascript( + int instanceId, + String javascriptString, + ); + + String getTitle(int instanceId); + + void scrollTo(int instanceId, int x, int y); + + void scrollBy(int instanceId, int x, int y); + + int getScrollX(int instanceId); + + int getScrollY(int instanceId); + + void setWebContentsDebuggingEnabled(bool enabled); + + void setWebViewClient(int instanceId, int webViewClientInstanceId); + + void addJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId); + + void removeJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId); +} + +@HostApi() +abstract class WebViewSettingsHostApi { + void create(int instanceId, int webViewInstanceId); + + void dispose(int instanceId); + + void setDomStorageEnabled(int instanceId, bool flag); + + void setJavaScriptCanOpenWindowsAutomatically(int instanceId, bool flag); + + void setSupportMultipleWindows(int instanceId, bool support); + + void setJavaScriptEnabled(int instanceId, bool flag); + + void setUserAgentString(int instanceId, String userAgentString); + + void setMediaPlaybackRequiresUserGesture(int instanceId, bool require); +} + +@HostApi() +abstract class JavaScriptChannelHostApi { + void create(int instanceId, String channelName); + + void dispose(int instanceId); +} + +@FlutterApi() +abstract class JavaScriptChannelFlutterApi { + void postMessage(int instanceId, String message); +} + +@HostApi() +abstract class WebViewClientHostApi { + void create(int instanceId, bool autoFailShouldOverrideUrlLoading); + + void dispose(int instanceId); +} + +@FlutterApi() +abstract class WebViewClientFlutterApi { + void onPageStarted(int instanceId, int webViewInstanceId, String url); + + void onPageFinished(int instanceId, int webViewInstanceId, String url); + + void onReceivedRequestError( + int instanceId, + int webViewInstanceId, + WebResourceRequestData request, + WebResourceErrorData error, + ); + + void onReceivedError( + int instanceId, + int webViewInstanceId, + int errorCode, + String description, + String failingUrl, + ); + + void shouldOverrideRequestLoading( + int instanceId, + int webViewInstanceId, + WebResourceRequestData request, + ); + + void shouldOverrideUrlLoading( + int instanceId, + int webViewInstanceId, + String url, + ); +} + +@HostApi() +abstract class DownloadListenerHostApi { + void create(int instanceId); + void dispose(int instanceId); +} + +@FlutterApi() +abstract class DownloadListenerFlutterApi { + void onDownloadStart( + int instanceId, + String url, + String userAgent, + String contentDisposition, + String mimetype, + int contentLength, + ); +} diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 36f186087c08..04511e670d4c 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -27,5 +27,6 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter + pigeon: 1.0.7 pedantic: ^1.10.0 From 768fd4ce706687a38864b42a90055aa1420a98c2 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 15 Oct 2021 01:07:04 -0700 Subject: [PATCH 02/54] update android webview and code gen --- .../GeneratedAndroidWebView.java | 35 +++++++ .../lib/src/android_webview.dart | 47 +++++---- .../lib/src/android_webview.pigeon.dart | 95 +++++++++++++++++++ .../lib/src/android_webview_api_impls.dart | 78 ++++++++++++++- .../pigeons/android_webview.dart | 10 ++ 5 files changed, 244 insertions(+), 21 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index 9b6b199adda6..84eb286d8930 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -1186,6 +1186,41 @@ public void shouldOverrideUrlLoading(Long instanceIdArg, Long webViewInstanceIdA callback.reply(null); }); } + public void setSupportZoom(Long instanceIdArg, Boolean supportArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.setSupportZoom", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, supportArg)), channelReply -> { + callback.reply(null); + }); + } + public void setLoadWithOverviewMode(Long instanceIdArg, Boolean overviewArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.setLoadWithOverviewMode", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, overviewArg)), channelReply -> { + callback.reply(null); + }); + } + public void setUseWideViewPort(Long instanceIdArg, Boolean useArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.setUseWideViewPort", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, useArg)), channelReply -> { + callback.reply(null); + }); + } + public void setDisplayZoomControls(Long instanceIdArg, Boolean enabledArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.setDisplayZoomControls", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, enabledArg)), channelReply -> { + callback.reply(null); + }); + } + public void setBuiltInZoomControls(Long instanceIdArg, Boolean enabledArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.setBuiltInZoomControls", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, enabledArg)), channelReply -> { + callback.reply(null); + }); + } } private static class DownloadListenerHostApiCodec extends StandardMessageCodec { public static final DownloadListenerHostApiCodec INSTANCE = new DownloadListenerHostApiCodec(); diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index ed23fc885213..11d290f2e0be 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/widgets.dart' show AndroidViewSurface; + import 'android_webview_api_impls.dart'; -import 'instance_manager.dart'; // TODO: This can be removed once pigeon supports null values. // Workaround since pigeon doesn't support null values. @@ -33,10 +34,22 @@ class WebView { } static final WebViewHostApiImpl _api = WebViewHostApiImpl(); - int get _instanceId => InstanceManager.instance.getInstanceId(this)!; + /// Whether the [WebView] will be rendered with an [AndroidViewSurface]. + /// + /// This implementation uses hybrid composition to render the WebView Widget. + /// This comes at the cost of some performance on Android versions below 10. + /// See + /// https://flutter.dev/docs/development/platform-integration/platform-views#performance + /// for more information. + /// + /// Defaults to false. final bool useHybridComposition; + static Future setWebContentsDebuggingEnabled(bool enabled) { + return _api.setWebContentsDebuggingEnabled(enabled); + } + /// Loads the given URL with additional HTTP headers, specified as a map from name to value. /// /// Note that if this map contains any of the headers that are set by default @@ -45,7 +58,7 @@ class WebView { /// /// Also see compatibility note on [evaluateJavascript]. Future loadUrl(String url, Map headers) { - return _api.loadUrl(_instanceId, url, headers); + return _api.loadUrlFromInstance(this, url, headers); } /// Gets the URL for the current page. @@ -56,34 +69,34 @@ class WebView { /// /// Returns null if no page has been loaded. Future getUrl() async { - final String result = await _api.getUrl(_instanceId); + final String result = await _api.getUrlFromInstance(this); if (result == _nullStringIdentifier) return null; return result; } /// Whether this WebView has a back history item. Future canGoBack() { - return _api.canGoBack(_instanceId); + return _api.canGoBackFromInstance(this); } /// Whether this WebView has a forward history item. Future canGoForward() { - return _api.canGoForward(_instanceId); + return _api.canGoForwardFromInstance(this); } /// Goes back in the history of this WebView. Future goBack() { - return _api.goBack(_instanceId); + return _api.goBackFromInstance(this); } /// Goes forward in the history of this WebView. Future goForward() { - return _api.goForward(_instanceId); + return _api.goForwardFromInstance(this); } /// Reloads the current URL. Future reload() { - return _api.reload(_instanceId); + return _api.reloadFromInstance(this); } /// Clears the resource cache. @@ -91,7 +104,7 @@ class WebView { /// Note that the cache is per-application, so this will clear the cache for /// all WebViews used. Future clearCache(bool includeDiskFiles) { - return _api.clearCache(_instanceId, includeDiskFiles); + return _api.clearCacheFromInstance(this, includeDiskFiles); } // TODO: Update documentation once addJavascriptInterface is added. @@ -105,8 +118,8 @@ class WebView { /// navigations like [loadUrl]. For example, global variables and functions /// defined before calling [loadUrl]) will not exist in the loaded page. Future evaluateJavascript(String javascriptString) async { - final String result = await _api.evaluateJavascript( - _instanceId, + final String result = await _api.evaluateJavascriptFromInstance( + this, javascriptString, ); if (result == _nullStringIdentifier) return null; @@ -118,7 +131,7 @@ class WebView { /// /// Returns null if no page has been loaded. Future getTitle() async { - final String result = await _api.getTitle(_instanceId); + final String result = await _api.getTitleFromInstance(this); if (result == _nullStringIdentifier) return null; return result; } @@ -126,13 +139,13 @@ class WebView { // TODO: Update documentation when onScrollChanged is added. /// Set the scrolled position of your view. Future scrollTo(int x, int y) { - return _api.scrollTo(_instanceId, x, y); + return _api.scrollToFromInstance(this, x, y); } // TODO: Update documentation when onScrollChanged is added. /// Move the scrolled position of your view. Future scrollBy(int x, int y) { - return _api.scrollBy(_instanceId, x, y); + return _api.scrollByFromInstance(this, x, y); } /// Return the scrolled left position of this view. @@ -141,7 +154,7 @@ class WebView { /// need to draw any pixels farther left, since those are outside of the frame /// of your view on screen. Future getScrollX() { - return _api.getScrollX(_instanceId); + return _api.getScrollXFromInstance(this); } /// Return the scrolled top position of this view. @@ -150,6 +163,6 @@ class WebView { /// to draw any pixels above it, since those are outside of the frame of your /// view on screen. Future getScrollY() { - return _api.getScrollY(_instanceId); + return _api.getScrollYFromInstance(this); } } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart index e83b1c6f2964..9b6024286f08 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -930,6 +930,11 @@ abstract class WebViewClientFlutterApi { void onReceivedError(int instanceId, int webViewInstanceId, int errorCode, String description, String failingUrl); void shouldOverrideRequestLoading(int instanceId, int webViewInstanceId, WebResourceRequestData request); void shouldOverrideUrlLoading(int instanceId, int webViewInstanceId, String url); + void setSupportZoom(int instanceId, bool support); + void setLoadWithOverviewMode(int instanceId, bool overview); + void setUseWideViewPort(int instanceId, bool use); + void setDisplayZoomControls(int instanceId, bool enabled); + void setBuiltInZoomControls(int instanceId, bool enabled); static void setup(WebViewClientFlutterApi? api) { { const BasicMessageChannel channel = BasicMessageChannel( @@ -1057,6 +1062,96 @@ abstract class WebViewClientFlutterApi { }); } } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.setSupportZoom', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setSupportZoom was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setSupportZoom was null, expected non-null int.'); + final bool? arg_support = args[1] as bool?; + assert(arg_support != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setSupportZoom was null, expected non-null bool.'); + api.setSupportZoom(arg_instanceId!, arg_support!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.setLoadWithOverviewMode', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setLoadWithOverviewMode was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setLoadWithOverviewMode was null, expected non-null int.'); + final bool? arg_overview = args[1] as bool?; + assert(arg_overview != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setLoadWithOverviewMode was null, expected non-null bool.'); + api.setLoadWithOverviewMode(arg_instanceId!, arg_overview!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.setUseWideViewPort', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setUseWideViewPort was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setUseWideViewPort was null, expected non-null int.'); + final bool? arg_use = args[1] as bool?; + assert(arg_use != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setUseWideViewPort was null, expected non-null bool.'); + api.setUseWideViewPort(arg_instanceId!, arg_use!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.setDisplayZoomControls', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setDisplayZoomControls was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setDisplayZoomControls was null, expected non-null int.'); + final bool? arg_enabled = args[1] as bool?; + assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setDisplayZoomControls was null, expected non-null bool.'); + api.setDisplayZoomControls(arg_instanceId!, arg_enabled!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.setBuiltInZoomControls', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setBuiltInZoomControls was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setBuiltInZoomControls was null, expected non-null int.'); + final bool? arg_enabled = args[1] as bool?; + assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setBuiltInZoomControls was null, expected non-null bool.'); + api.setBuiltInZoomControls(arg_instanceId!, arg_enabled!); + return; + }); + } + } } } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index 52ac797ee2cb..f9344690cd80 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -2,21 +2,91 @@ import 'android_webview.dart'; import 'android_webview.pigeon.dart'; import 'instance_manager.dart'; +int _getInstanceId(Object instance) => + InstanceManager.instance.getInstanceId(instance)!; + class WebViewHostApiImpl extends WebViewHostApi { Future createFromInstance( - WebView webView, + WebView instance, bool useHybridComposition, ) async { - final int? instanceId = InstanceManager.instance.tryAddInstance(webView); + final int? instanceId = InstanceManager.instance.tryAddInstance(instance); if (instanceId != null) { return create(instanceId, useHybridComposition); } } - Future disposeFromInstance(WebView webView) async { - final int? instanceId = InstanceManager.instance.removeInstance(webView); + Future disposeFromInstance(WebView instance) async { + final int? instanceId = InstanceManager.instance.removeInstance(instance); if (instanceId != null) { return dispose(instanceId); } } + + Future loadUrlFromInstance( + WebView instance, + String url, + Map headers, + ) { + return loadUrl(_getInstanceId(instance), url, headers); + } + + Future getUrlFromInstance(WebView instance) { + return getUrl(_getInstanceId(instance)); + } + + Future canGoBackFromInstance(WebView instance) { + return canGoBack(_getInstanceId(instance)); + } + + Future canGoForwardFromInstance(WebView instance) { + return canGoForward(_getInstanceId(instance)); + } + + Future goBackFromInstance(WebView instance) { + return goBack(_getInstanceId(instance)); + } + + Future goForwardFromInstance(WebView instance) { + return goForward(_getInstanceId(instance)); + } + + Future reloadFromInstance(WebView instance) { + return reload(_getInstanceId(instance)); + } + + Future clearCacheFromInstance(WebView instance, bool includeDiskFiles) { + return clearCache(_getInstanceId(instance), includeDiskFiles); + } + + Future evaluateJavascriptFromInstance( + WebView instance, + String javascriptString, + ) { + return evaluateJavascript(_getInstanceId(instance), javascriptString); + } + + Future getTitleFromInstance(WebView instance) { + return getTitle(_getInstanceId(instance)); + } + + Future scrollToFromInstance(WebView instance, int x, int y) { + return scrollTo(_getInstanceId(instance), x, y); + } + + Future scrollByFromInstance(WebView instance, int x, int y) { + return scrollBy(_getInstanceId(instance), x, y); + } + + Future getScrollXFromInstance(WebView instance) { + return getScrollX(_getInstanceId(instance)); + } + + Future getScrollYFromInstance(WebView instance) { + return getScrollY(_getInstanceId(instance)); + } +} + +class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { + //Future createFromInst } diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart index 25b1be33a3d6..b45686be4762 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -139,6 +139,16 @@ abstract class WebViewClientFlutterApi { int webViewInstanceId, String url, ); + + void setSupportZoom(int instanceId, bool support); + + void setLoadWithOverviewMode(int instanceId, bool overview); + + void setUseWideViewPort(int instanceId, bool use); + + void setDisplayZoomControls(int instanceId, bool enabled); + + void setBuiltInZoomControls(int instanceId, bool enabled); } @HostApi() From 2199127fbb35150be6fc637baafa189dd3fad79b Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 15 Oct 2021 01:26:46 -0700 Subject: [PATCH 03/54] make apis testable --- .../lib/src/android_webview.dart | 23 +++-- .../lib/src/android_webview_api_impls.dart | 95 +++++++++++++++++-- .../lib/src/instance_manager.dart | 2 - 3 files changed, 106 insertions(+), 14 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index 11d290f2e0be..ff23bf87ba02 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -6,8 +6,9 @@ import 'package:flutter/widgets.dart' show AndroidViewSurface; import 'android_webview_api_impls.dart'; -// TODO: This can be removed once pigeon supports null values. -// Workaround since pigeon doesn't support null values. +// TODO(bparrishMines): This can be removed once pigeon supports null values. +// Workaround to represent null Strings since pigeon doesn't support null +// values. const String _nullStringIdentifier = ''; /// An Android View that displays web pages. @@ -46,6 +47,8 @@ class WebView { /// Defaults to false. final bool useHybridComposition; + late final WebViewSettings webViewSettings = WebViewSettings._(this); + static Future setWebContentsDebuggingEnabled(bool enabled) { return _api.setWebContentsDebuggingEnabled(enabled); } @@ -107,7 +110,7 @@ class WebView { return _api.clearCacheFromInstance(this, includeDiskFiles); } - // TODO: Update documentation once addJavascriptInterface is added. + // TODO(bparrishMines): Update documentation once addJavascriptInterface is added. /// Asynchronously evaluates JavaScript in the context of the currently displayed page. /// /// If non-null, the returned value will be any result returned from that @@ -126,7 +129,7 @@ class WebView { return result; } - // TODO: Update documentation when WebViewClient.onReceivedTitle is added. + // TODO(bparrishMines): Update documentation when WebViewClient.onReceivedTitle is added. /// Gets the title for the current page. /// /// Returns null if no page has been loaded. @@ -136,13 +139,13 @@ class WebView { return result; } - // TODO: Update documentation when onScrollChanged is added. + // TODO(bparrishMines): Update documentation when onScrollChanged is added. /// Set the scrolled position of your view. Future scrollTo(int x, int y) { return _api.scrollToFromInstance(this, x, y); } - // TODO: Update documentation when onScrollChanged is added. + // TODO(bparrishMines): Update documentation when onScrollChanged is added. /// Move the scrolled position of your view. Future scrollBy(int x, int y) { return _api.scrollByFromInstance(this, x, y); @@ -166,3 +169,11 @@ class WebView { return _api.getScrollYFromInstance(this); } } + +class WebViewSettings { + WebViewSettings._(WebView webView) { + _api.createFromInstance(this, webView); + } + + static final WebViewSettingsHostApiImpl _api = WebViewSettingsHostApiImpl(); +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index f9344690cd80..70603e9efff2 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -2,22 +2,30 @@ import 'android_webview.dart'; import 'android_webview.pigeon.dart'; import 'instance_manager.dart'; -int _getInstanceId(Object instance) => - InstanceManager.instance.getInstanceId(instance)!; +final InstanceManager _instanceManager = InstanceManager(); class WebViewHostApiImpl extends WebViewHostApi { + WebViewHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? _instanceManager; + } + + late final InstanceManager instanceManager; + + int _getInstanceId(Object instance) => + instanceManager.getInstanceId(instance)!; + Future createFromInstance( WebView instance, bool useHybridComposition, ) async { - final int? instanceId = InstanceManager.instance.tryAddInstance(instance); + final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { return create(instanceId, useHybridComposition); } } Future disposeFromInstance(WebView instance) async { - final int? instanceId = InstanceManager.instance.removeInstance(instance); + final int? instanceId = instanceManager.removeInstance(instance); if (instanceId != null) { return dispose(instanceId); } @@ -66,7 +74,7 @@ class WebViewHostApiImpl extends WebViewHostApi { return evaluateJavascript(_getInstanceId(instance), javascriptString); } - Future getTitleFromInstance(WebView instance) { + Future getTitleFromInstance(WebView instance) { return getTitle(_getInstanceId(instance)); } @@ -88,5 +96,80 @@ class WebViewHostApiImpl extends WebViewHostApi { } class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { - //Future createFromInst + WebViewSettingsHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? _instanceManager; + } + + late final InstanceManager instanceManager; + + int _getInstanceId(Object instance) => + instanceManager.getInstanceId(instance)!; + + Future createFromInstance( + WebViewSettings instance, + WebView webView, + ) async { + final int? instanceId = instanceManager.tryAddInstance(instance); + if (instanceId != null) { + return create(instanceId, _getInstanceId(webView)); + } + } + + Future disposeFromInstance(WebViewSettings instance) async { + final int? instanceId = instanceManager.removeInstance(instance); + if (instanceId != null) { + return dispose(instanceId); + } + } + + Future setDomStorageEnabledFromInstance( + WebViewSettings instance, + bool flag, + ) { + return setDomStorageEnabled(_getInstanceId(instance), flag); + } + + Future setJavaScriptCanOpenWindowsAutomaticallyFromInstance( + WebViewSettings instance, + bool flag, + ) { + return setJavaScriptCanOpenWindowsAutomatically( + _getInstanceId(instance), + flag, + ); + } + + Future setSupportMultipleWindowsFromInstance( + WebViewSettings instance, + bool support, + ) { + return setSupportMultipleWindows(_getInstanceId(instance), support); + } + + Future setJavaScriptEnabledFromInstance( + WebViewSettings instance, + bool flag, + ) { + return setJavaScriptCanOpenWindowsAutomatically( + _getInstanceId(instance), + flag, + ); + } + + Future setUserAgentStringFromInstance( + WebViewSettings instance, + String userAgentString, + ) { + return setUserAgentString(_getInstanceId(instance), userAgentString); + } + + Future setMediaPlaybackRequiresUserGestureFromInstance( + WebViewSettings instance, + bool require, + ) { + return setMediaPlaybackRequiresUserGesture( + _getInstanceId(instance), + require, + ); + } } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart index a53da3fb5548..bc5db71fd6b3 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart @@ -4,8 +4,6 @@ class InstanceManager { static int _nextInstanceId = 0; - static final InstanceManager instance = InstanceManager(); - int? tryAddInstance(Object instance) { } From 4a082ebb7f68f7661a94fb1f4d7333b5293c8eca Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 15 Oct 2021 11:25:30 -0700 Subject: [PATCH 04/54] finish basic implementation of api impls --- .../GeneratedAndroidWebView.java | 209 ++++++++-- .../lib/src/android_webview.dart | 75 ++++ .../lib/src/android_webview.pigeon.dart | 233 ++++++----- .../lib/src/android_webview_api_impls.dart | 368 ++++++++++++++++-- .../lib/src/instance_manager.dart | 1 + .../pigeons/android_webview.dart | 22 +- 6 files changed, 737 insertions(+), 171 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index 84eb286d8930..58d6d20910da 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -130,6 +130,7 @@ public interface WebViewHostApi { void setWebViewClient(Long instanceId, Long webViewClientInstanceId); void addJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); void removeJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); + void setDownloadListener(Long instanceId, Long listenerInstanceId); /** The codec used by WebViewHostApi. */ static MessageCodec getCodec() { @@ -676,6 +677,34 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setDownloadListener", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number listenerInstanceIdArg = (Number)args.get(1); + if (listenerInstanceIdArg == null) { + throw new NullPointerException("listenerInstanceIdArg unexpectedly null."); + } + api.setDownloadListener(instanceIdArg.longValue(), listenerInstanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } } } private static class WebViewSettingsHostApiCodec extends StandardMessageCodec { @@ -693,6 +722,11 @@ public interface WebViewSettingsHostApi { void setJavaScriptEnabled(Long instanceId, Boolean flag); void setUserAgentString(Long instanceId, String userAgentString); void setMediaPlaybackRequiresUserGesture(Long instanceId, Boolean require); + void setSupportZoom(Long instanceId, Boolean support); + void setLoadWithOverviewMode(Long instanceId, Boolean overview); + void setUseWideViewPort(Long instanceId, Boolean use); + void setDisplayZoomControls(Long instanceId, Boolean enabled); + void setBuiltInZoomControls(Long instanceId, Boolean enabled); /** The codec used by WebViewSettingsHostApi. */ static MessageCodec getCodec() { @@ -921,6 +955,146 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setSupportZoom", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean supportArg = (Boolean)args.get(1); + if (supportArg == null) { + throw new NullPointerException("supportArg unexpectedly null."); + } + api.setSupportZoom(instanceIdArg.longValue(), supportArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setLoadWithOverviewMode", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean overviewArg = (Boolean)args.get(1); + if (overviewArg == null) { + throw new NullPointerException("overviewArg unexpectedly null."); + } + api.setLoadWithOverviewMode(instanceIdArg.longValue(), overviewArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setUseWideViewPort", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean useArg = (Boolean)args.get(1); + if (useArg == null) { + throw new NullPointerException("useArg unexpectedly null."); + } + api.setUseWideViewPort(instanceIdArg.longValue(), useArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setDisplayZoomControls", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean enabledArg = (Boolean)args.get(1); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setDisplayZoomControls(instanceIdArg.longValue(), enabledArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setBuiltInZoomControls", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean enabledArg = (Boolean)args.get(1); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setBuiltInZoomControls(instanceIdArg.longValue(), enabledArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } } } private static class JavaScriptChannelHostApiCodec extends StandardMessageCodec { @@ -1186,41 +1360,6 @@ public void shouldOverrideUrlLoading(Long instanceIdArg, Long webViewInstanceIdA callback.reply(null); }); } - public void setSupportZoom(Long instanceIdArg, Boolean supportArg, Reply callback) { - BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.setSupportZoom", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, supportArg)), channelReply -> { - callback.reply(null); - }); - } - public void setLoadWithOverviewMode(Long instanceIdArg, Boolean overviewArg, Reply callback) { - BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.setLoadWithOverviewMode", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, overviewArg)), channelReply -> { - callback.reply(null); - }); - } - public void setUseWideViewPort(Long instanceIdArg, Boolean useArg, Reply callback) { - BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.setUseWideViewPort", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, useArg)), channelReply -> { - callback.reply(null); - }); - } - public void setDisplayZoomControls(Long instanceIdArg, Boolean enabledArg, Reply callback) { - BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.setDisplayZoomControls", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, enabledArg)), channelReply -> { - callback.reply(null); - }); - } - public void setBuiltInZoomControls(Long instanceIdArg, Boolean enabledArg, Reply callback) { - BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.setBuiltInZoomControls", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, enabledArg)), channelReply -> { - callback.reply(null); - }); - } } private static class DownloadListenerHostApiCodec extends StandardMessageCodec { public static final DownloadListenerHostApiCodec INSTANCE = new DownloadListenerHostApiCodec(); diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index ff23bf87ba02..ddb5e394d389 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -177,3 +177,78 @@ class WebViewSettings { static final WebViewSettingsHostApiImpl _api = WebViewSettingsHostApiImpl(); } + +abstract class JavaScriptChannel { + JavaScriptChannel(this.channelName); + + final String channelName; + + void postMessage(String message); +} + +abstract class WebViewClient { + void onPageStarted(WebView webView, String url); + + void onPageFinished(WebView webView, String url); + + void onReceivedRequestError( + WebView webView, + WebResourceRequest request, + WebResourceError error, + ); + + void onReceivedError( + WebView webView, + int errorCode, + String description, + String failingUrl, + ); + + void shouldOverrideRequestLoading( + WebView webView, + WebResourceRequest request, + ); + + void shouldOverrideUrlLoading( + WebView webView, + String url, + ); +} + +abstract class DownloadListener { + void onDownloadStart( + String url, + String userAgent, + String contentDisposition, + String mimetype, + int contentLength, + ); +} + +class WebResourceRequest { + WebResourceRequest({ + required this.url, + required this.isForMainFrame, + required this.isRedirect, + required this.hasGesture, + required this.method, + required this.requestHeaders, + }); + + final String url; + final isForMainFrame; + final bool? isRedirect; + final bool hasGesture; + final String method; + final Map requestHeaders; +} + +class WebResourceError { + WebResourceError({ + required this.errorCode, + required this.description, + }); + + final int errorCode; + final String description; +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart index 9b6024286f08..21b4b913b900 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -531,6 +531,29 @@ class WebViewHostApi { return; } } + + Future setDownloadListener(int arg_instanceId, int arg_listenerInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.setDownloadListener', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_listenerInstanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } } class _WebViewSettingsHostApiCodec extends StandardMessageCodec { @@ -730,6 +753,121 @@ class WebViewSettingsHostApi { return; } } + + Future setSupportZoom(int arg_instanceId, bool arg_support) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.setSupportZoom', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_support]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setLoadWithOverviewMode(int arg_instanceId, bool arg_overview) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.setLoadWithOverviewMode', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_overview]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setUseWideViewPort(int arg_instanceId, bool arg_use) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.setUseWideViewPort', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_use]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setDisplayZoomControls(int arg_instanceId, bool arg_enabled) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.setDisplayZoomControls', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_enabled]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setBuiltInZoomControls(int arg_instanceId, bool arg_enabled) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewSettingsHostApi.setBuiltInZoomControls', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_enabled]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } } class _JavaScriptChannelHostApiCodec extends StandardMessageCodec { @@ -930,11 +1068,6 @@ abstract class WebViewClientFlutterApi { void onReceivedError(int instanceId, int webViewInstanceId, int errorCode, String description, String failingUrl); void shouldOverrideRequestLoading(int instanceId, int webViewInstanceId, WebResourceRequestData request); void shouldOverrideUrlLoading(int instanceId, int webViewInstanceId, String url); - void setSupportZoom(int instanceId, bool support); - void setLoadWithOverviewMode(int instanceId, bool overview); - void setUseWideViewPort(int instanceId, bool use); - void setDisplayZoomControls(int instanceId, bool enabled); - void setBuiltInZoomControls(int instanceId, bool enabled); static void setup(WebViewClientFlutterApi? api) { { const BasicMessageChannel channel = BasicMessageChannel( @@ -1062,96 +1195,6 @@ abstract class WebViewClientFlutterApi { }); } } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientFlutterApi.setSupportZoom', codec); - if (api == null) { - channel.setMessageHandler(null); - } else { - channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setSupportZoom was null.'); - final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setSupportZoom was null, expected non-null int.'); - final bool? arg_support = args[1] as bool?; - assert(arg_support != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setSupportZoom was null, expected non-null bool.'); - api.setSupportZoom(arg_instanceId!, arg_support!); - return; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientFlutterApi.setLoadWithOverviewMode', codec); - if (api == null) { - channel.setMessageHandler(null); - } else { - channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setLoadWithOverviewMode was null.'); - final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setLoadWithOverviewMode was null, expected non-null int.'); - final bool? arg_overview = args[1] as bool?; - assert(arg_overview != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setLoadWithOverviewMode was null, expected non-null bool.'); - api.setLoadWithOverviewMode(arg_instanceId!, arg_overview!); - return; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientFlutterApi.setUseWideViewPort', codec); - if (api == null) { - channel.setMessageHandler(null); - } else { - channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setUseWideViewPort was null.'); - final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setUseWideViewPort was null, expected non-null int.'); - final bool? arg_use = args[1] as bool?; - assert(arg_use != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setUseWideViewPort was null, expected non-null bool.'); - api.setUseWideViewPort(arg_instanceId!, arg_use!); - return; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientFlutterApi.setDisplayZoomControls', codec); - if (api == null) { - channel.setMessageHandler(null); - } else { - channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setDisplayZoomControls was null.'); - final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setDisplayZoomControls was null, expected non-null int.'); - final bool? arg_enabled = args[1] as bool?; - assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setDisplayZoomControls was null, expected non-null bool.'); - api.setDisplayZoomControls(arg_instanceId!, arg_enabled!); - return; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientFlutterApi.setBuiltInZoomControls', codec); - if (api == null) { - channel.setMessageHandler(null); - } else { - channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setBuiltInZoomControls was null.'); - final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setBuiltInZoomControls was null, expected non-null int.'); - final bool? arg_enabled = args[1] as bool?; - assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.setBuiltInZoomControls was null, expected non-null bool.'); - api.setBuiltInZoomControls(arg_instanceId!, arg_enabled!); - return; - }); - } - } } } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index 70603e9efff2..fefca888629a 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -2,18 +2,13 @@ import 'android_webview.dart'; import 'android_webview.pigeon.dart'; import 'instance_manager.dart'; -final InstanceManager _instanceManager = InstanceManager(); - class WebViewHostApiImpl extends WebViewHostApi { WebViewHostApiImpl({InstanceManager? instanceManager}) { - this.instanceManager = instanceManager ?? _instanceManager; + this.instanceManager = instanceManager ?? InstanceManager.instance; } late final InstanceManager instanceManager; - int _getInstanceId(Object instance) => - instanceManager.getInstanceId(instance)!; - Future createFromInstance( WebView instance, bool useHybridComposition, @@ -36,82 +31,123 @@ class WebViewHostApiImpl extends WebViewHostApi { String url, Map headers, ) { - return loadUrl(_getInstanceId(instance), url, headers); + return loadUrl(instanceManager.getInstanceId(instance)!, url, headers); } Future getUrlFromInstance(WebView instance) { - return getUrl(_getInstanceId(instance)); + return getUrl(instanceManager.getInstanceId(instance)!); } Future canGoBackFromInstance(WebView instance) { - return canGoBack(_getInstanceId(instance)); + return canGoBack(instanceManager.getInstanceId(instance)!); } Future canGoForwardFromInstance(WebView instance) { - return canGoForward(_getInstanceId(instance)); + return canGoForward(instanceManager.getInstanceId(instance)!); } Future goBackFromInstance(WebView instance) { - return goBack(_getInstanceId(instance)); + return goBack(instanceManager.getInstanceId(instance)!); } Future goForwardFromInstance(WebView instance) { - return goForward(_getInstanceId(instance)); + return goForward(instanceManager.getInstanceId(instance)!); } Future reloadFromInstance(WebView instance) { - return reload(_getInstanceId(instance)); + return reload(instanceManager.getInstanceId(instance)!); } Future clearCacheFromInstance(WebView instance, bool includeDiskFiles) { - return clearCache(_getInstanceId(instance), includeDiskFiles); + return clearCache( + instanceManager.getInstanceId(instance)!, + includeDiskFiles, + ); } Future evaluateJavascriptFromInstance( WebView instance, String javascriptString, ) { - return evaluateJavascript(_getInstanceId(instance), javascriptString); + return evaluateJavascript( + instanceManager.getInstanceId(instance)!, javascriptString); } Future getTitleFromInstance(WebView instance) { - return getTitle(_getInstanceId(instance)); + return getTitle(instanceManager.getInstanceId(instance)!); } Future scrollToFromInstance(WebView instance, int x, int y) { - return scrollTo(_getInstanceId(instance), x, y); + return scrollTo(instanceManager.getInstanceId(instance)!, x, y); } Future scrollByFromInstance(WebView instance, int x, int y) { - return scrollBy(_getInstanceId(instance), x, y); + return scrollBy(instanceManager.getInstanceId(instance)!, x, y); } Future getScrollXFromInstance(WebView instance) { - return getScrollX(_getInstanceId(instance)); + return getScrollX(instanceManager.getInstanceId(instance)!); } Future getScrollYFromInstance(WebView instance) { - return getScrollY(_getInstanceId(instance)); + return getScrollY(instanceManager.getInstanceId(instance)!); + } + + Future setWebViewClientFromInstance( + WebView instance, + WebViewClient webViewClient, + ) { + return setWebViewClient( + instanceManager.getInstanceId(instance)!, + instanceManager.getInstanceId(webViewClient)!, + ); + } + + Future addJavaScriptChannelFromInstance( + WebView instance, + JavaScriptChannel javaScriptChannel, + ) { + return addJavaScriptChannel( + instanceManager.getInstanceId(instance)!, + instanceManager.getInstanceId(javaScriptChannel)!, + ); + } + + Future removeJavaScriptChannelFromInstance( + WebView instance, + JavaScriptChannel javaScriptChannel, + ) { + return removeJavaScriptChannel( + instanceManager.getInstanceId(instance)!, + instanceManager.getInstanceId(javaScriptChannel)!, + ); + } + + Future setDownloadListenerFromInstance( + WebView instance, + DownloadListener listener, + ) { + return setDownloadListener( + instanceManager.getInstanceId(instance)!, + instanceManager.getInstanceId(listener)!, + ); } } class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { WebViewSettingsHostApiImpl({InstanceManager? instanceManager}) { - this.instanceManager = instanceManager ?? _instanceManager; + this.instanceManager = instanceManager ?? InstanceManager.instance; } late final InstanceManager instanceManager; - int _getInstanceId(Object instance) => - instanceManager.getInstanceId(instance)!; - Future createFromInstance( WebViewSettings instance, WebView webView, ) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { - return create(instanceId, _getInstanceId(webView)); + return create(instanceId, instanceManager.getInstanceId(webView)!); } } @@ -126,7 +162,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { WebViewSettings instance, bool flag, ) { - return setDomStorageEnabled(_getInstanceId(instance), flag); + return setDomStorageEnabled(instanceManager.getInstanceId(instance)!, flag); } Future setJavaScriptCanOpenWindowsAutomaticallyFromInstance( @@ -134,7 +170,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { bool flag, ) { return setJavaScriptCanOpenWindowsAutomatically( - _getInstanceId(instance), + instanceManager.getInstanceId(instance)!, flag, ); } @@ -143,7 +179,8 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { WebViewSettings instance, bool support, ) { - return setSupportMultipleWindows(_getInstanceId(instance), support); + return setSupportMultipleWindows( + instanceManager.getInstanceId(instance)!, support); } Future setJavaScriptEnabledFromInstance( @@ -151,7 +188,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { bool flag, ) { return setJavaScriptCanOpenWindowsAutomatically( - _getInstanceId(instance), + instanceManager.getInstanceId(instance)!, flag, ); } @@ -160,7 +197,10 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { WebViewSettings instance, String userAgentString, ) { - return setUserAgentString(_getInstanceId(instance), userAgentString); + return setUserAgentString( + instanceManager.getInstanceId(instance)!, + userAgentString, + ); } Future setMediaPlaybackRequiresUserGestureFromInstance( @@ -168,8 +208,274 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { bool require, ) { return setMediaPlaybackRequiresUserGesture( - _getInstanceId(instance), + instanceManager.getInstanceId(instance)!, require, ); } + + Future setSupportZoomFromInstance( + WebViewSettings instance, + bool support, + ) { + return setSupportZoom(instanceManager.getInstanceId(instance)!, support); + } + + Future setLoadWithOverviewModeFromInstance( + WebViewSettings instance, + bool overview, + ) { + return setLoadWithOverviewMode( + instanceManager.getInstanceId(instance)!, + overview, + ); + } + + Future setUseWideViewPortFromInstance( + WebViewSettings instance, + bool use, + ) { + return setUseWideViewPort(instanceManager.getInstanceId(instance)!, use); + } + + Future setDisplayZoomControlsFromInstance( + WebViewSettings instance, + bool enabled, + ) { + return setDisplayZoomControls( + instanceManager.getInstanceId(instance)!, + enabled, + ); + } + + Future setBuiltInZoomControlsFromInstance( + WebViewSettings instance, + bool enabled, + ) { + return setBuiltInZoomControls( + instanceManager.getInstanceId(instance)!, + enabled, + ); + } +} + +class JavaScriptChannelHostApiImpl extends JavaScriptChannelHostApi { + JavaScriptChannelHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + late final InstanceManager instanceManager; + + Future createFromInstance( + JavaScriptChannel instance, + String channelName, + ) async { + final int? instanceId = instanceManager.tryAddInstance(instance); + if (instanceId != null) { + return create(instanceId, channelName); + } + } + + Future disposeFromInstance(JavaScriptChannel instance) async { + final int? instanceId = instanceManager.removeInstance(instance); + if (instanceId != null) { + return dispose(instanceId); + } + } +} + +class JavaScriptChannelFlutterApiImpl extends JavaScriptChannelFlutterApi { + JavaScriptChannelHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + late final InstanceManager instanceManager; + + @override + void postMessage(int instanceId, String message) { + final JavaScriptChannel instance = + instanceManager.getInstance(instanceId) as JavaScriptChannel; + instance.postMessage(message); + } +} + +class WebViewClientHostApiImpl extends WebViewClientHostApi { + WebViewClientHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + late final InstanceManager instanceManager; + + Future createFromInstance( + WebViewClient instance, + bool autoFailShouldOverrideUrlLoading, + ) async { + final int? instanceId = instanceManager.tryAddInstance(instance); + if (instanceId != null) { + return create(instanceId, autoFailShouldOverrideUrlLoading); + } + } + + Future disposeFromInstance(WebViewClient instance) async { + final int? instanceId = instanceManager.removeInstance(instance); + if (instanceId != null) { + return dispose(instanceId); + } + } +} + +class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { + WebViewClientFlutterApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + late final InstanceManager instanceManager; + + @override + void onPageFinished(int instanceId, int webViewInstanceId, String url) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.onPageFinished( + instanceManager.getInstance(webViewInstanceId) as WebView, + url, + ); + } + + @override + void onPageStarted(int instanceId, int webViewInstanceId, String url) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.onPageStarted( + instanceManager.getInstance(webViewInstanceId) as WebView, + url, + ); + } + + @override + void onReceivedError( + int instanceId, + int webViewInstanceId, + int errorCode, + String description, + String failingUrl, + ) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.onReceivedError( + instanceManager.getInstance(webViewInstanceId) as WebView, + errorCode, + description, + failingUrl, + ); + } + + @override + void onReceivedRequestError( + int instanceId, + int webViewInstanceId, + WebResourceRequestData request, + WebResourceErrorData error, + ) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.onReceivedRequestError( + instanceManager.getInstance(webViewInstanceId) as WebView, + WebResourceRequest( + url: request.url!, + isForMainFrame: request.isForMainFrame!, + isRedirect: request.isRedirect, + hasGesture: request.hasGesture!, + method: request.method!, + requestHeaders: request.requestHeaders!.cast(), + ), + WebResourceError( + errorCode: error.errorCode!, + description: error.description!, + ), + ); + } + + @override + void shouldOverrideRequestLoading( + int instanceId, + int webViewInstanceId, + WebResourceRequestData request, + ) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.shouldOverrideRequestLoading( + instanceManager.getInstance(webViewInstanceId) as WebView, + WebResourceRequest( + url: request.url!, + isForMainFrame: request.isForMainFrame!, + isRedirect: request.isRedirect, + hasGesture: request.hasGesture!, + method: request.method!, + requestHeaders: request.requestHeaders!.cast(), + ), + ); + } + + @override + void shouldOverrideUrlLoading( + int instanceId, + int webViewInstanceId, + String url, + ) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.shouldOverrideUrlLoading( + instanceManager.getInstance(webViewInstanceId) as WebView, + url, + ); + } +} + +class DownloadListenerHostApiImpl extends DownloadListenerHostApi { + DownloadListenerHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + late final InstanceManager instanceManager; + + Future createFromInstance(DownloadListener instance) async { + final int? instanceId = instanceManager.tryAddInstance(instance); + if (instanceId != null) { + return create(instanceId); + } + } + + Future disposeFromInstance(DownloadListener instance) async { + final int? instanceId = instanceManager.removeInstance(instance); + if (instanceId != null) { + return dispose(instanceId); + } + } +} + +class DownloadListenerFlutterApiImpl extends DownloadListenerFlutterApi { + DownloadListenerFlutterApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + late final InstanceManager instanceManager; + + @override + void onDownloadStart( + int instanceId, + String url, + String userAgent, + String contentDisposition, + String mimetype, + int contentLength, + ) { + final DownloadListener instance = + instanceManager.getInstance(instanceId) as DownloadListener; + instance.onDownloadStart( + url, + userAgent, + contentDisposition, + mimetype, + contentLength, + ); + } } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart index bc5db71fd6b3..baa395a111ba 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart @@ -3,6 +3,7 @@ class InstanceManager { Map _instancesToInstanceId = {}; static int _nextInstanceId = 0; + static final InstanceManager instance = InstanceManager(); int? tryAddInstance(Object instance) { diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart index b45686be4762..6cd7db3c0f79 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -67,6 +67,8 @@ abstract class WebViewHostApi { void addJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId); void removeJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId); + + void setDownloadListener(int instanceId, int listenerInstanceId); } @HostApi() @@ -86,6 +88,16 @@ abstract class WebViewSettingsHostApi { void setUserAgentString(int instanceId, String userAgentString); void setMediaPlaybackRequiresUserGesture(int instanceId, bool require); + + void setSupportZoom(int instanceId, bool support); + + void setLoadWithOverviewMode(int instanceId, bool overview); + + void setUseWideViewPort(int instanceId, bool use); + + void setDisplayZoomControls(int instanceId, bool enabled); + + void setBuiltInZoomControls(int instanceId, bool enabled); } @HostApi() @@ -139,16 +151,6 @@ abstract class WebViewClientFlutterApi { int webViewInstanceId, String url, ); - - void setSupportZoom(int instanceId, bool support); - - void setLoadWithOverviewMode(int instanceId, bool overview); - - void setUseWideViewPort(int instanceId, bool use); - - void setDisplayZoomControls(int instanceId, bool enabled); - - void setBuiltInZoomControls(int instanceId, bool enabled); } @HostApi() From e8e6d515f1ad5dc79fc5c08bf41dfd36b392ec49 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Sat, 16 Oct 2021 11:39:13 -0700 Subject: [PATCH 05/54] finish api documentation --- .../GeneratedAndroidWebView.java | 10 +- .../lib/src/android_webview.dart | 363 +++++++++++++++++- .../lib/src/android_webview.pigeon.dart | 4 +- .../lib/src/android_webview_api_impls.dart | 39 +- .../lib/src/instance_manager.dart | 4 + .../pigeons/android_webview.dart | 2 +- 6 files changed, 379 insertions(+), 43 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index 58d6d20910da..fcfc7bab2e89 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -1201,7 +1201,7 @@ private WebViewClientHostApiCodec() {} /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ public interface WebViewClientHostApi { - void create(Long instanceId, Boolean autoFailShouldOverrideUrlLoading); + void create(Long instanceId, Boolean shouldOverrideUrlLoading); void dispose(Long instanceId); /** The codec used by WebViewClientHostApi. */ @@ -1223,11 +1223,11 @@ static void setup(BinaryMessenger binaryMessenger, WebViewClientHostApi api) { if (instanceIdArg == null) { throw new NullPointerException("instanceIdArg unexpectedly null."); } - Boolean autoFailShouldOverrideUrlLoadingArg = (Boolean)args.get(1); - if (autoFailShouldOverrideUrlLoadingArg == null) { - throw new NullPointerException("autoFailShouldOverrideUrlLoadingArg unexpectedly null."); + Boolean shouldOverrideUrlLoadingArg = (Boolean)args.get(1); + if (shouldOverrideUrlLoadingArg == null) { + throw new NullPointerException("shouldOverrideUrlLoadingArg unexpectedly null."); } - api.create(instanceIdArg.longValue(), autoFailShouldOverrideUrlLoadingArg); + api.create(instanceIdArg.longValue(), shouldOverrideUrlLoadingArg); wrapped.put("result", null); } catch (Error | RuntimeException exception) { diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index ddb5e394d389..5874c7ab311e 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -31,11 +31,15 @@ const String _nullStringIdentifier = ''; class WebView { /// Constructs a new WebView. WebView({this.useHybridComposition = false}) { - _api.createFromInstance(this, useHybridComposition); + _api.createFromInstance(this); } static final WebViewHostApiImpl _api = WebViewHostApiImpl(); + WebViewClient? _currentWebViewClient; + DownloadListener? _currentDownloadListener; + Set _javaScriptChannels = {}; + /// Whether the [WebView] will be rendered with an [AndroidViewSurface]. /// /// This implementation uses hybrid composition to render the WebView Widget. @@ -47,8 +51,14 @@ class WebView { /// Defaults to false. final bool useHybridComposition; - late final WebViewSettings webViewSettings = WebViewSettings._(this); + /// The [WebSettings] object used to control the settings for this WebView. + late final WebViewSettings settings = WebViewSettings._(this); + /// Enables debugging of web contents (HTML / CSS / JavaScript) loaded into any WebViews of this application. + /// + /// This flag can be enabled in order to facilitate debugging of web layouts + /// and JavaScript code running inside WebViews. Please refer to [WebView] + /// documentation for the debugging guide. The default is false. static Future setWebContentsDebuggingEnabled(bool enabled) { return _api.setWebContentsDebuggingEnabled(enabled); } @@ -168,35 +178,326 @@ class WebView { Future getScrollY() { return _api.getScrollYFromInstance(this); } + + /// Sets the [WebViewClient] that will receive various notifications and requests. + /// + /// This will replace the current handler. + Future setWebViewClient(WebViewClient webViewClient) async { + final WebViewClient? currentWebViewClient = _currentWebViewClient; + if (currentWebViewClient != null) { + // ignore: unawaited_futures + WebViewClient._api.disposeFromInstance(currentWebViewClient); + } + + // ignore: unawaited_futures + WebViewClient._api.createFromInstance(webViewClient); + _currentWebViewClient = webViewClient; + return _api.setWebViewClientFromInstance(this, webViewClient); + } + + /// Injects the supplied [JavascriptChannel] into this WebView. + /// + /// The object is injected into all frames of the web page, including all the + /// iframes, using the supplied name. This allows the object's methods to + /// be accessed from JavaScript. + /// + /// Note that injected objects will not appear in JavaScript until the page is + /// next (re)loaded. JavaScript should be enabled before injecting the object. + /// For example: + /// + /// ```dart + /// webview.settings.setJavaScriptEnabled(true); + /// webView.addJavascriptChannel(JavScriptChannel("injectedObject")); + /// webView.loadUrl("about:blank", {}); + /// webView.loadUrl("javascript:injectedObject.postMessage("Hello, World!")", {}); + /// ``` + /// + /// **Important** + /// * Because the object is exposed to all the frames, any frame could obtain + /// the object name and call methods on it. There is no way to tell the + /// calling frame's origin from the app side, so the app must not assume that + /// the caller is trustworthy unless the app can guarantee that no third party + /// content is ever loaded into the WebView even inside an iframe. + Future addJavaScriptChannel(JavaScriptChannel javaScriptChannel) async { + // ignore: unawaited_futures + JavaScriptChannel._api.createFromInstance(javaScriptChannel); + _javaScriptChannels.add(javaScriptChannel); + return _api.addJavaScriptChannelFromInstance(this, javaScriptChannel); + } + + /// Removes a previously injected [JavaScriptChannel] from this WebView. + /// + /// Note that the removal will not be reflected in JavaScript until the page + /// is next (re)loaded. See [addJavaScriptChannel]. + Future removeJavaScriptChannel(JavaScriptChannel javaScriptChannel) { + JavaScriptChannel._api.disposeFromInstance(javaScriptChannel); + _javaScriptChannels.remove(javaScriptChannel); + return _api.removeJavaScriptChannelFromInstance(this, javaScriptChannel); + } + + /// Registers the interface to be used when content can not be handled by the rendering engine, and should be downloaded instead. + /// + /// This will replace the current handler. + Future setDownloadListener(DownloadListener listener) { + final DownloadListener? currentDownloadListener = _currentDownloadListener; + if (currentDownloadListener != null) { + DownloadListener._api.disposeFromInstance(currentDownloadListener); + } + + DownloadListener._api.createFromInstance(listener); + _currentDownloadListener = listener; + return _api.setDownloadListenerFromInstance(this, listener); + } } +/// Manages settings state for a [WebView]. +/// +/// When a WebView is first created, it obtains a set of default settings. These +/// default settings will be returned from any getter call. A WebSettings object +/// obtained from [WebView.settings] is tied to the life of the WebView. If a +/// WebView has been destroyed, any method call on [WebSettings] will throw an +/// Exception. class WebViewSettings { - WebViewSettings._(WebView webView) { - _api.createFromInstance(this, webView); + WebViewSettings._(this.webView) { + _api.createFromInstance(this); } + /// The webView instance this is attached to. + final WebView webView; + static final WebViewSettingsHostApiImpl _api = WebViewSettingsHostApiImpl(); + + /// Sets whether the DOM storage API is enabled. + /// + /// The default value is false. + Future setDomStorageEnabled(bool flag) { + return _api.setDomStorageEnabledFromInstance(this, flag); + } + + /// Tells JavaScript to open windows automatically. + /// + /// This applies to the JavaScript function `window.open()`. The default is + /// false. + Future setJavaScriptCanOpenWindowsAutomatically(bool flag) { + return _api.setJavaScriptCanOpenWindowsAutomaticallyFromInstance( + this, + flag, + ); + } + + // TODO(bparrishMines): Update documentation when WebChromeClient.onCreateWindow is added. + /// Sets whether the WebView should supports multiple windows. + /// + /// The default is false. + Future setSupportMultipleWindows(bool support) { + return _api.setSupportZoomFromInstance(this, support); + } + + /// Tells the WebView to enable JavaScript execution. + /// + /// The default is false. + Future setJavaScriptEnabled(bool flag) { + return _api.setJavaScriptEnabledFromInstance(this, flag); + } + + /// Sets the WebView's user-agent string. + /// + /// If the string is empty, the system default value will be used. Note that + /// starting from KITKAT Android version, changing the user-agent while + /// loading a web page causes WebView to initiate loading once again. + Future setUserAgentString(String userAgentString) { + return _api.setUserAgentStringFromInstance(this, userAgentString); + } + + /// Sets whether the WebView requires a user gesture to play media. + /// + /// The default is true. + Future setMediaPlaybackRequiresUserGesture(bool require) { + return _api.setMediaPlaybackRequiresUserGestureFromInstance(this, require); + } + + // TODO(bparrishMines): Update documentation when WebView.zoomIn and WebView.zoomOut are added. + /// Sets whether the WebView should support zooming using its on-screen zoom controls and gestures. + /// + /// The particular zoom mechanisms that should be used can be set with + /// [setBuiltInZoomControls]. + /// + /// The default is true. + Future setSupportZoom(bool support) { + return _api.setSupportZoomFromInstance(this, support); + } + + /// Sets whether the WebView loads pages in overview mode, that is, zooms out the content to fit on screen by width. + /// + /// This setting is taken into account when the content width is greater than + /// the width of the WebView control, for example, when [setUseWideViewPort] + /// is enabled. + /// + /// The default is false. + Future setLoadWithOverviewMode(bool overview) { + return _api.setLoadWithOverviewModeFromInstance(this, overview); + } + + /// Sets whether the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. + /// + /// When the value of the setting is false, the layout width is always set to + /// the width of the WebView control in device-independent (CSS) pixels. When + /// the value is true and the page contains the viewport meta tag, the value + /// of the width specified in the tag is used. If the page does not contain + /// the tag or does not provide a width, then a wide viewport will be used. + Future setUseWideViewPort(bool use) { + return _api.setUseWideViewPortFromInstance(this, use); + } + + // TODO(bparrishMines): Update documentation when ZoomButtonsController is added. + /// Sets whether the WebView should display on-screen zoom controls when using the built-in zoom mechanisms. + /// + /// See [setBuiltInZoomControls]. The default is true. However, on-screen zoom + /// controls are deprecated in Android so it's recommended to set this to + /// false. + Future setDisplayZoomControls(bool enabled) { + return _api.setDisplayZoomControlsFromInstance(this, enabled); + } + + // TODO(bparrishMines): Update documentation when ZoomButtonsController is added. + /// Sets whether the WebView should use its built-in zoom mechanisms. + /// + /// The built-in zoom mechanisms comprise on-screen zoom controls, which are + /// displayed over the WebView's content, and the use of a pinch gesture to + /// control zooming. Whether or not these on-screen controls are displayed can + /// be set with [setDisplayZoomControls]. The default is false. + /// + /// The built-in mechanisms are the only currently supported zoom mechanisms, + /// so it is recommended that this setting is always enabled. However, + /// on-screen zoom controls are deprecated in Android so it's recommended to + /// disable [setDisplayZoomControls]. + Future setBuiltInZoomControls(bool enabled) { + return _api.setBuiltInZoomControlsFromInstance(this, enabled); + } } +/// Exposes a channel to receive calls from javaScript. +/// +/// See [WebView.addJavaScriptChannel]. abstract class JavaScriptChannel { + /// Constructs a [JavaScriptChannel]. JavaScriptChannel(this.channelName); + static final JavaScriptChannelHostApiImpl _api = + JavaScriptChannelHostApiImpl(); + + /// Used to identify this object to receive messages from javaScript. final String channelName; + /// Callback method when javaScript calls `postMessage` on the object instance passed. void postMessage(String message); } +/// Receive various notifications and requests for [WebView]. abstract class WebViewClient { + /// Constructs a [WebViewClient]. + WebViewClient({this.shouldOverrideUrlLoading = true}); + + /// User authentication failed on server. + static const int errorAuthentication = 0xfffffffc; + + /// Malformed URL. + static const int errorBadUrl = 0xfffffff4; + + /// Failed to connect to the server. + static const int errorConnect = 0xfffffffa; + + /// Failed to perform SSL handshake. + static const int errorFailedSslHandshake = 0xfffffff5; + + /// Generic file error. + static const int errorFile = 0xfffffff3; + + /// File not found. + static const int errorFileNotFound = 0xfffffff2; + + /// Server or proxy hostname lookup failed. + static const int errorHostLookup = 0xfffffffe; + + /// Failed to read or write to the server. + static const int errorIO = 0xfffffff9; + + /// User authentication failed on proxy. + static const int errorProxyAuthentication = 0xfffffffb; + + /// Too many redirects. + static const int errorRedirectLoop = 0xfffffff7; + + /// Connection timed out. + static const int errorTimeout = 0xfffffff8; + + /// Too many requests during this load. + static const int errorTooManyRequests = 0xfffffff1; + + /// Generic error. + static const int errorUnknown = 0xffffffff; + + /// Resource load was canceled by Safe Browsing. + static const int errorUnsafeResource = 0xfffffff0; + + /// Unsupported authentication scheme (not basic or digest). + static const int errorUnsupportedAuthScheme = 0xfffffffd; + + /// Unsupported URI scheme. + static const int errorUnsupportedScheme = 0xfffffff6; + + static final WebViewClientHostApiImpl _api = WebViewClientHostApiImpl(); + + /// Whether loading a url should be overridden. + /// + /// In Java, `shouldOverrideUrlLoading()` and `shouldOverrideRequestLoading()` + /// callbacks must synchronously return a boolean. This sets the default + /// return value. + /// + /// Setting [shouldOverrideUrlLoading] to true causes the current [WebView] to + /// abort loading the URL, while returning false causes the [WebView] to + /// continue loading the URL as usual. [requestLoading] or [urlLoading] will + /// still be called either way. + /// + /// Defaults to true. + final bool shouldOverrideUrlLoading; + + /// Notify the host application that a page has started loading. + /// + /// This method is called once for each main frame load so a page with iframes + /// or framesets will call onPageStarted one time for the main frame. This + /// also means that [onPageStarted] will not be called when the contents of an + /// embedded frame changes, i.e. clicking a link whose target is an iframe, it + /// will also not be called for fragment navigations (navigations to + /// #fragment_id). void onPageStarted(WebView webView, String url); + // TODO(bparrishMines): Update documentation when WebView.postVisualStateCallback is added. + /// Notify the host application that a page has finished loading. + /// + /// This method is called only for main frame. Receiving an [onPageFinished] + /// callback does not guarantee that the next frame drawn by WebView will + /// reflect the state of the DOM at this point. void onPageFinished(WebView webView, String url); + /// Report web resource loading error to the host application. + /// + /// These errors usually indicate inability to connect to the server. Note + /// that unlike the deprecated version of the callback, the new version will + /// be called for any resource (iframe, image, etc.), not just for the main + /// page. Thus, it is recommended to perform minimum required work in this + /// callback. void onReceivedRequestError( WebView webView, WebResourceRequest request, WebResourceError error, ); + /// Report an error to the host application. + /// + /// These errors are unrecoverable (i.e. the main resource is unavailable). + /// The errorCode parameter corresponds to one of the error* constants. + @Deprecated('Only called on Android version < 23.') void onReceivedError( WebView webView, int errorCode, @@ -204,18 +505,32 @@ abstract class WebViewClient { String failingUrl, ); - void shouldOverrideRequestLoading( - WebView webView, - WebResourceRequest request, - ); - - void shouldOverrideUrlLoading( - WebView webView, - String url, - ); + // TODO(bparrishMines): Update documentation once synchronous url handling is supported. + /// When a URL is about to be loaded in the current [WebView]. + /// + /// If a [WebViewClient] is not provided, by default [WebView] will ask + /// Activity Manager to choose the proper handler for the URL. If a + /// [WebViewClient] is provided, setting [shouldOverrideUrlLoading] to true + /// causes the current [WebView] to abort loading the URL, while returning + /// false causes the [WebView] to continue loading the URL as usual. + void requestLoading(WebView webView, WebResourceRequest request); + + // TODO(bparrishMines): Update documentation once synchronous url handling is supported. + /// When a URL is about to be loaded in the current [WebView]. + /// + /// If a [WebViewClient] is not provided, by default [WebView] will ask + /// Activity Manager to choose the proper handler for the URL. If a + /// [WebViewClient] is provided, setting [shouldOverrideUrlLoading] to true + /// causes the current [WebView] to abort loading the URL, while returning + /// false causes the [WebView] to continue loading the URL as usual. + void urlLoading(WebView webView, String url); } +/// The interface to be used when content can not be handled by the rendering engine for [WebView], and should be downloaded instead. abstract class DownloadListener { + static final DownloadListenerHostApiImpl _api = DownloadListenerHostApiImpl(); + + /// Notify the host application that a file should be downloaded. void onDownloadStart( String url, String userAgent, @@ -225,7 +540,9 @@ abstract class DownloadListener { ); } +/// Encompasses parameters to the [WebViewClient.requestLoading] method. class WebResourceRequest { + /// Constructs a [WebResourceRequest]. WebResourceRequest({ required this.url, required this.isForMainFrame, @@ -235,20 +552,40 @@ class WebResourceRequest { required this.requestHeaders, }); + /// Gets the URL for which the resource request was made. final String url; + + /// Gets whether the request was made in order to fetch the main frame's document. final isForMainFrame; + + /// Gets whether the request was a result of a server-side redirect. + /// + /// Only supported on Android version >= 23. final bool? isRedirect; + + /// Gets whether a gesture (such as a click) was associated with the request. final bool hasGesture; + + /// Gets the method associated with the request, for example "GET". final String method; + + /// Gets the headers associated with the request. final Map requestHeaders; } +/// Encapsulates information about errors occurred during loading of web resources. +/// +/// See [WebViewClient.onReceivedRequestError]. class WebResourceError { + /// Constructs a [WebResourceError]. WebResourceError({ required this.errorCode, required this.description, }); + /// The integer code of the error (e.g. [WebViewClient.errorAuthentication]. final int errorCode; + + /// Describes the error. final String description; } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart index 21b4b913b900..c1bd5f4a0659 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -974,11 +974,11 @@ class WebViewClientHostApi { static const MessageCodec codec = _WebViewClientHostApiCodec(); - Future create(int arg_instanceId, bool arg_autoFailShouldOverrideUrlLoading) async { + Future create(int arg_instanceId, bool arg_shouldOverrideUrlLoading) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.WebViewClientHostApi.create', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = - await channel.send([arg_instanceId, arg_autoFailShouldOverrideUrlLoading]) as Map?; + await channel.send([arg_instanceId, arg_shouldOverrideUrlLoading]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index fefca888629a..0c1422655097 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -1,3 +1,7 @@ +// 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. + import 'android_webview.dart'; import 'android_webview.pigeon.dart'; import 'instance_manager.dart'; @@ -9,13 +13,10 @@ class WebViewHostApiImpl extends WebViewHostApi { late final InstanceManager instanceManager; - Future createFromInstance( - WebView instance, - bool useHybridComposition, - ) async { + Future createFromInstance(WebView instance) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { - return create(instanceId, useHybridComposition); + return create(instanceId, instance.useHybridComposition); } } @@ -141,13 +142,13 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { late final InstanceManager instanceManager; - Future createFromInstance( - WebViewSettings instance, - WebView webView, - ) async { + Future createFromInstance(WebViewSettings instance) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { - return create(instanceId, instanceManager.getInstanceId(webView)!); + return create( + instanceId, + instanceManager.getInstanceId(instance.webView)!, + ); } } @@ -265,13 +266,10 @@ class JavaScriptChannelHostApiImpl extends JavaScriptChannelHostApi { late final InstanceManager instanceManager; - Future createFromInstance( - JavaScriptChannel instance, - String channelName, - ) async { + Future createFromInstance(JavaScriptChannel instance) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { - return create(instanceId, channelName); + return create(instanceId, instance.channelName); } } @@ -305,13 +303,10 @@ class WebViewClientHostApiImpl extends WebViewClientHostApi { late final InstanceManager instanceManager; - Future createFromInstance( - WebViewClient instance, - bool autoFailShouldOverrideUrlLoading, - ) async { + Future createFromInstance(WebViewClient instance) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { - return create(instanceId, autoFailShouldOverrideUrlLoading); + return create(instanceId, instance.shouldOverrideUrlLoading); } } @@ -402,7 +397,7 @@ class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { ) { final WebViewClient instance = instanceManager.getInstance(instanceId) as WebViewClient; - instance.shouldOverrideRequestLoading( + instance.requestLoading( instanceManager.getInstance(webViewInstanceId) as WebView, WebResourceRequest( url: request.url!, @@ -423,7 +418,7 @@ class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { ) { final WebViewClient instance = instanceManager.getInstance(instanceId) as WebViewClient; - instance.shouldOverrideUrlLoading( + instance.urlLoading( instanceManager.getInstance(webViewInstanceId) as WebView, url, ); diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart index baa395a111ba..464234da802d 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart @@ -1,3 +1,7 @@ +// 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. + class InstanceManager { Map _instanceIdToInstances = {}; Map _instancesToInstanceId = {}; diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart index 6cd7db3c0f79..b9343dad9c48 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -114,7 +114,7 @@ abstract class JavaScriptChannelFlutterApi { @HostApi() abstract class WebViewClientHostApi { - void create(int instanceId, bool autoFailShouldOverrideUrlLoading); + void create(int instanceId, bool shouldOverrideUrlLoading); void dispose(int instanceId); } From d902acbf384f0c81700b9ee3e9dccf4bff3b80ca Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Sat, 16 Oct 2021 15:04:13 -0700 Subject: [PATCH 06/54] finish dart documentation --- .../lib/src/android_webview_api_impls.dart | 63 +++++++++++++++++++ .../lib/src/instance_manager.dart | 33 +++++++--- 2 files changed, 89 insertions(+), 7 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index 0c1422655097..0fec31cf9d06 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -6,13 +6,17 @@ import 'android_webview.dart'; import 'android_webview.pigeon.dart'; import 'instance_manager.dart'; +/// Host api implementation for [WebView]. class WebViewHostApiImpl extends WebViewHostApi { + /// Constructs a [WebViewHostApiImpl]. WebViewHostApiImpl({InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? InstanceManager.instance; } + /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; + /// Helper method to convert instances ids to objects. Future createFromInstance(WebView instance) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { @@ -20,6 +24,7 @@ class WebViewHostApiImpl extends WebViewHostApi { } } + /// Helper method to convert instances ids to objects. Future disposeFromInstance(WebView instance) async { final int? instanceId = instanceManager.removeInstance(instance); if (instanceId != null) { @@ -27,6 +32,7 @@ class WebViewHostApiImpl extends WebViewHostApi { } } + /// Helper method to convert instances ids to objects. Future loadUrlFromInstance( WebView instance, String url, @@ -35,30 +41,37 @@ class WebViewHostApiImpl extends WebViewHostApi { return loadUrl(instanceManager.getInstanceId(instance)!, url, headers); } + /// Helper method to convert instances ids to objects. Future getUrlFromInstance(WebView instance) { return getUrl(instanceManager.getInstanceId(instance)!); } + /// Helper method to convert instances ids to objects. Future canGoBackFromInstance(WebView instance) { return canGoBack(instanceManager.getInstanceId(instance)!); } + /// Helper method to convert instances ids to objects. Future canGoForwardFromInstance(WebView instance) { return canGoForward(instanceManager.getInstanceId(instance)!); } + /// Helper method to convert instances ids to objects. Future goBackFromInstance(WebView instance) { return goBack(instanceManager.getInstanceId(instance)!); } + /// Helper method to convert instances ids to objects. Future goForwardFromInstance(WebView instance) { return goForward(instanceManager.getInstanceId(instance)!); } + /// Helper method to convert instances ids to objects. Future reloadFromInstance(WebView instance) { return reload(instanceManager.getInstanceId(instance)!); } + /// Helper method to convert instances ids to objects. Future clearCacheFromInstance(WebView instance, bool includeDiskFiles) { return clearCache( instanceManager.getInstanceId(instance)!, @@ -66,6 +79,7 @@ class WebViewHostApiImpl extends WebViewHostApi { ); } + /// Helper method to convert instances ids to objects. Future evaluateJavascriptFromInstance( WebView instance, String javascriptString, @@ -74,26 +88,32 @@ class WebViewHostApiImpl extends WebViewHostApi { instanceManager.getInstanceId(instance)!, javascriptString); } + /// Helper method to convert instances ids to objects. Future getTitleFromInstance(WebView instance) { return getTitle(instanceManager.getInstanceId(instance)!); } + /// Helper method to convert instances ids to objects. Future scrollToFromInstance(WebView instance, int x, int y) { return scrollTo(instanceManager.getInstanceId(instance)!, x, y); } + /// Helper method to convert instances ids to objects. Future scrollByFromInstance(WebView instance, int x, int y) { return scrollBy(instanceManager.getInstanceId(instance)!, x, y); } + /// Helper method to convert instances ids to objects. Future getScrollXFromInstance(WebView instance) { return getScrollX(instanceManager.getInstanceId(instance)!); } + /// Helper method to convert instances ids to objects. Future getScrollYFromInstance(WebView instance) { return getScrollY(instanceManager.getInstanceId(instance)!); } + /// Helper method to convert instances ids to objects. Future setWebViewClientFromInstance( WebView instance, WebViewClient webViewClient, @@ -104,6 +124,7 @@ class WebViewHostApiImpl extends WebViewHostApi { ); } + /// Helper method to convert instances ids to objects. Future addJavaScriptChannelFromInstance( WebView instance, JavaScriptChannel javaScriptChannel, @@ -114,6 +135,7 @@ class WebViewHostApiImpl extends WebViewHostApi { ); } + /// Helper method to convert instances ids to objects. Future removeJavaScriptChannelFromInstance( WebView instance, JavaScriptChannel javaScriptChannel, @@ -124,6 +146,7 @@ class WebViewHostApiImpl extends WebViewHostApi { ); } + /// Helper method to convert instances ids to objects. Future setDownloadListenerFromInstance( WebView instance, DownloadListener listener, @@ -135,13 +158,17 @@ class WebViewHostApiImpl extends WebViewHostApi { } } +/// Host api implementation for [WebViewSettings]. class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { + /// Constructs a [WebViewSettingsHostApiImpl]. WebViewSettingsHostApiImpl({InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? InstanceManager.instance; } + /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; + /// Helper method to convert instances ids to objects. Future createFromInstance(WebViewSettings instance) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { @@ -152,6 +179,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { } } + /// Helper method to convert instances ids to objects. Future disposeFromInstance(WebViewSettings instance) async { final int? instanceId = instanceManager.removeInstance(instance); if (instanceId != null) { @@ -159,6 +187,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { } } + /// Helper method to convert instances ids to objects. Future setDomStorageEnabledFromInstance( WebViewSettings instance, bool flag, @@ -166,6 +195,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { return setDomStorageEnabled(instanceManager.getInstanceId(instance)!, flag); } + /// Helper method to convert instances ids to objects. Future setJavaScriptCanOpenWindowsAutomaticallyFromInstance( WebViewSettings instance, bool flag, @@ -176,6 +206,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { ); } + /// Helper method to convert instances ids to objects. Future setSupportMultipleWindowsFromInstance( WebViewSettings instance, bool support, @@ -184,6 +215,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { instanceManager.getInstanceId(instance)!, support); } + /// Helper method to convert instances ids to objects. Future setJavaScriptEnabledFromInstance( WebViewSettings instance, bool flag, @@ -194,6 +226,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { ); } + /// Helper method to convert instances ids to objects. Future setUserAgentStringFromInstance( WebViewSettings instance, String userAgentString, @@ -204,6 +237,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { ); } + /// Helper method to convert instances ids to objects. Future setMediaPlaybackRequiresUserGestureFromInstance( WebViewSettings instance, bool require, @@ -214,6 +248,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { ); } + /// Helper method to convert instances ids to objects. Future setSupportZoomFromInstance( WebViewSettings instance, bool support, @@ -221,6 +256,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { return setSupportZoom(instanceManager.getInstanceId(instance)!, support); } + /// Helper method to convert instances ids to objects. Future setLoadWithOverviewModeFromInstance( WebViewSettings instance, bool overview, @@ -231,6 +267,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { ); } + /// Helper method to convert instances ids to objects. Future setUseWideViewPortFromInstance( WebViewSettings instance, bool use, @@ -238,6 +275,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { return setUseWideViewPort(instanceManager.getInstanceId(instance)!, use); } + /// Helper method to convert instances ids to objects. Future setDisplayZoomControlsFromInstance( WebViewSettings instance, bool enabled, @@ -248,6 +286,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { ); } + /// Helper method to convert instances ids to objects. Future setBuiltInZoomControlsFromInstance( WebViewSettings instance, bool enabled, @@ -259,13 +298,17 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { } } +/// Host api implementation for [JavaScriptChannel]. class JavaScriptChannelHostApiImpl extends JavaScriptChannelHostApi { + /// Constructs a [JavaScriptChannelHostApiImpl]. JavaScriptChannelHostApiImpl({InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? InstanceManager.instance; } + /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; + /// Helper method to convert instances ids to objects. Future createFromInstance(JavaScriptChannel instance) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { @@ -273,6 +316,7 @@ class JavaScriptChannelHostApiImpl extends JavaScriptChannelHostApi { } } + /// Helper method to convert instances ids to objects. Future disposeFromInstance(JavaScriptChannel instance) async { final int? instanceId = instanceManager.removeInstance(instance); if (instanceId != null) { @@ -281,11 +325,14 @@ class JavaScriptChannelHostApiImpl extends JavaScriptChannelHostApi { } } +/// Flutter api implementation for [JavaScriptChannel]. class JavaScriptChannelFlutterApiImpl extends JavaScriptChannelFlutterApi { + /// Constructs a [JavaScriptChannelFlutterApiImpl]. JavaScriptChannelHostApiImpl({InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? InstanceManager.instance; } + /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; @override @@ -296,13 +343,17 @@ class JavaScriptChannelFlutterApiImpl extends JavaScriptChannelFlutterApi { } } +/// Host api implementation for [WebViewClient]. class WebViewClientHostApiImpl extends WebViewClientHostApi { + /// Constructs a [WebViewClientHostApiImpl]. WebViewClientHostApiImpl({InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? InstanceManager.instance; } + /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; + /// Helper method to convert instances ids to objects. Future createFromInstance(WebViewClient instance) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { @@ -310,6 +361,7 @@ class WebViewClientHostApiImpl extends WebViewClientHostApi { } } + /// Helper method to convert instances ids to objects. Future disposeFromInstance(WebViewClient instance) async { final int? instanceId = instanceManager.removeInstance(instance); if (instanceId != null) { @@ -318,11 +370,14 @@ class WebViewClientHostApiImpl extends WebViewClientHostApi { } } +/// Flutter api implementation for [WebViewClient]. class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { + /// Constructs a [WebViewClientFlutterApiImpl]. WebViewClientFlutterApiImpl({InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? InstanceManager.instance; } + /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; @override @@ -425,13 +480,17 @@ class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { } } +/// Host api implementation for [DownloadListener]. class DownloadListenerHostApiImpl extends DownloadListenerHostApi { + /// Constructs a [DownloadListenerHostApiImpl]. DownloadListenerHostApiImpl({InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? InstanceManager.instance; } + /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; + /// Helper method to convert instances ids to objects. Future createFromInstance(DownloadListener instance) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { @@ -439,6 +498,7 @@ class DownloadListenerHostApiImpl extends DownloadListenerHostApi { } } + /// Helper method to convert instances ids to objects. Future disposeFromInstance(DownloadListener instance) async { final int? instanceId = instanceManager.removeInstance(instance); if (instanceId != null) { @@ -447,11 +507,14 @@ class DownloadListenerHostApiImpl extends DownloadListenerHostApi { } } +/// Flutter api implementation for [DownloadListener]. class DownloadListenerFlutterApiImpl extends DownloadListenerFlutterApi { + /// Constructs a [DownloadListenerFlutterApiImpl]. DownloadListenerFlutterApiImpl({InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? InstanceManager.instance; } + /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; @override diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart index 464234da802d..bafe0ae00fdb 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart @@ -2,26 +2,45 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +/// Maintains instances stored to communicate with java objects. class InstanceManager { - Map _instanceIdToInstances = {}; - Map _instancesToInstanceId = {}; + Map _instanceIdsToInstances = {}; + Map _instancesToInstanceIds = {}; static int _nextInstanceId = 0; + + /// Global instance of [InstanceManager]. static final InstanceManager instance = InstanceManager(); + /// Add a new instance with instanceId. int? tryAddInstance(Object instance) { - + if (_instancesToInstanceIds.containsKey(instance)) { + return null; + } + + final int instanceId = _nextInstanceId++; + _instancesToInstanceIds[instance] = instanceId; + _instanceIdsToInstances[instanceId] = instance; + return instanceId; } + /// Remove the instance from the manager. int? removeInstance(Object instance) { - + final int? instanceId = _instancesToInstanceIds[instance]; + if (instanceId != null) { + _instancesToInstanceIds.remove(instance); + _instanceIdsToInstances.remove(instanceId); + } + return instanceId; } + /// Retrieve the Object paired with instanceId. Object? getInstance(int instanceId) { - + return _instanceIdsToInstances[instanceId]; } + /// Retrieve the instanceId paired with instance. int? getInstanceId(Object instance) { - + return _instancesToInstanceIds[instance]; } -} \ No newline at end of file +} From 7e0f5a7c580856a3c9defb6af90630b29b565506 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 18 Oct 2021 00:37:52 -0700 Subject: [PATCH 07/54] android impl --- .../DownloadListenerHostApiImpl.java | 30 +++ .../GeneratedAndroidWebView.java | 50 ++--- .../webviewflutter/InputAwareWebView.java | 2 +- .../webviewflutter/InstanceManager.java | 34 +++ .../webviewflutter/JavaScriptChannel.java | 2 +- .../JavaScriptChannelHostApiImpl.java | 34 +++ .../WebViewClientHostApiImpl.java | 102 +++++++++ .../webviewflutter/WebViewHostApiImpl.java | 202 ++++++++++++++++++ .../WebViewSettingsHostApiImpl.java | 89 ++++++++ .../lib/src/android_webview.dart | 10 +- .../lib/src/android_webview.pigeon.dart | 66 +++--- .../lib/src/android_webview_api_impls.dart | 38 ++-- .../pigeons/android_webview.dart | 10 +- 13 files changed, 578 insertions(+), 91 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewSettingsHostApiImpl.java diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java new file mode 100644 index 000000000000..2ec499c546d9 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java @@ -0,0 +1,30 @@ +package io.flutter.plugins.webviewflutter; + +import android.webkit.DownloadListener; + +public class DownloadListenerHostApiImpl implements GeneratedAndroidWebView.DownloadListenerHostApi { + private final InstanceManager instanceManager; + private final GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi; + + DownloadListenerHostApiImpl(InstanceManager instanceManager, GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { + this.instanceManager = instanceManager; + this.downloadListenerFlutterApi = downloadListenerFlutterApi; + } + + @Override + public void create(Long instanceId) { + final DownloadListener downloadListener = (url, userAgent, contentDisposition, mimetype, contentLength) -> downloadListenerFlutterApi.onDownloadStart(instanceId, + url, + userAgent, + contentDisposition, + mimetype, + contentLength, + reply -> {}); + instanceManager.addInstance(downloadListener, instanceId); + } + + @Override + public void dispose(Long instanceId) { + instanceManager.removeInstanceId(instanceId); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index fcfc7bab2e89..a790e6f722b5 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -707,13 +707,13 @@ public void error(Throwable error) { } } } - private static class WebViewSettingsHostApiCodec extends StandardMessageCodec { - public static final WebViewSettingsHostApiCodec INSTANCE = new WebViewSettingsHostApiCodec(); - private WebViewSettingsHostApiCodec() {} + private static class WebSettingsHostApiCodec extends StandardMessageCodec { + public static final WebSettingsHostApiCodec INSTANCE = new WebSettingsHostApiCodec(); + private WebSettingsHostApiCodec() {} } /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ - public interface WebViewSettingsHostApi { + public interface WebSettingsHostApi { void create(Long instanceId, Long webViewInstanceId); void dispose(Long instanceId); void setDomStorageEnabled(Long instanceId, Boolean flag); @@ -728,16 +728,16 @@ public interface WebViewSettingsHostApi { void setDisplayZoomControls(Long instanceId, Boolean enabled); void setBuiltInZoomControls(Long instanceId, Boolean enabled); - /** The codec used by WebViewSettingsHostApi. */ + /** The codec used by WebSettingsHostApi. */ static MessageCodec getCodec() { - return WebViewSettingsHostApiCodec.INSTANCE; + return WebSettingsHostApiCodec.INSTANCE; } - /** Sets up an instance of `WebViewSettingsHostApi` to handle messages through the `binaryMessenger`. */ - static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { + /** Sets up an instance of `WebSettingsHostApi` to handle messages through the `binaryMessenger`. */ + static void setup(BinaryMessenger binaryMessenger, WebSettingsHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.create", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.create", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -765,7 +765,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.dispose", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.dispose", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -789,7 +789,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setDomStorageEnabled", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -817,7 +817,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -845,7 +845,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setSupportMultipleWindows", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -873,7 +873,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setJavaScriptEnabled", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -901,7 +901,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setUserAgentString", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -929,7 +929,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setMediaPlaybackRequiresUserGesture", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -957,7 +957,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setSupportZoom", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -985,7 +985,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setLoadWithOverviewMode", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -1013,7 +1013,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setUseWideViewPort", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -1041,7 +1041,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setDisplayZoomControls", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -1069,7 +1069,7 @@ static void setup(BinaryMessenger binaryMessenger, WebViewSettingsHostApi api) { } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewSettingsHostApi.setBuiltInZoomControls", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { Map wrapped = new HashMap<>(); @@ -1346,16 +1346,16 @@ public void onReceivedError(Long instanceIdArg, Long webViewInstanceIdArg, Long callback.reply(null); }); } - public void shouldOverrideRequestLoading(Long instanceIdArg, Long webViewInstanceIdArg, WebResourceRequestData requestArg, Reply callback) { + public void requestLoading(Long instanceIdArg, Long webViewInstanceIdArg, WebResourceRequestData requestArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading", getCodec()); channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg)), channelReply -> { callback.reply(null); }); } - public void shouldOverrideUrlLoading(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + public void urlLoading(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading", getCodec()); channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { callback.reply(null); }); diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java index 51b2a3809fff..0a4cb3effd29 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java @@ -25,7 +25,7 @@ * *

See also {@link ThreadedInputConnectionProxyAdapterView}. */ -final class InputAwareWebView extends WebView { +class InputAwareWebView extends WebView { private static final String TAG = "InputAwareWebView"; private View threadedInputConnectionProxyView; private ThreadedInputConnectionProxyAdapterView proxyAdapterView; diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java new file mode 100644 index 000000000000..023b38a516c5 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java @@ -0,0 +1,34 @@ +package io.flutter.plugins.webviewflutter; + +import java.util.HashMap; +import java.util.Map; + +class InstanceManager { + private final Map instanceIdsToInstances = new HashMap<>(); + private final Map instancesToInstanceIds = new HashMap<>(); + + /** Add a new instance with instanceId. */ + void addInstance(Object instance, Long instanceId) { + instancesToInstanceIds.put(instance, instanceId); + instanceIdsToInstances.put(instanceId, instance); + } + + /** Remove the instance from the manager. */ + Object removeInstanceId(Long instanceId) { + final Object instance = instanceIdsToInstances.remove(instanceId); + if (instance != null) { + instancesToInstanceIds.remove(instance); + } + return instance; + } + + /** Retrieve the Object paired with instanceId. */ + Object getInstance(Long instanceId) { + return instanceIdsToInstances.get(instanceId); + } + + /** Retrieve the instanceId paired with instance. */ + Long getInstanceId(Object instance) { + return instancesToInstanceIds.get(instance); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java index 4d596351b3d0..2f987c0f86b3 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java @@ -19,7 +19,7 @@ */ class JavaScriptChannel { private final MethodChannel methodChannel; - private final String javaScriptChannelName; + final String javaScriptChannelName; private final Handler platformThreadHandler; /** diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java new file mode 100644 index 000000000000..bc00ade10632 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -0,0 +1,34 @@ +package io.flutter.plugins.webviewflutter; + +import android.os.Handler; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; + +public class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.JavaScriptChannelHostApi { + private final InstanceManager instanceManager; + private final JavaScriptChannelFlutterApi javaScriptChannelFlutterApi; + private final Handler platformThreadHandler; + + JavaScriptChannelHostApiImpl(InstanceManager instanceManager, + JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, + Handler platformThreadHandler) { + this.instanceManager = instanceManager; + this.javaScriptChannelFlutterApi = javaScriptChannelFlutterApi; + this.platformThreadHandler = platformThreadHandler; + } + + @Override + public void create(Long instanceId, String channelName) { + final JavaScriptChannel javaScriptChannel = new JavaScriptChannel(null, channelName, platformThreadHandler) { + @Override + public void postMessage(String message) { + javaScriptChannelFlutterApi.postMessage(instanceId, message, reply -> { }); + } + }; + instanceManager.addInstance(javaScriptChannel, instanceId); + } + + @Override + public void dispose(Long instanceId) { + instanceManager.removeInstanceId(instanceId); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java new file mode 100644 index 000000000000..af21e5c43791 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java @@ -0,0 +1,102 @@ +package io.flutter.plugins.webviewflutter; + +import android.graphics.Bitmap; +import android.os.Build; +import android.webkit.WebResourceError; +import android.webkit.WebResourceRequest; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import androidx.annotation.RequiresApi; + +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientFlutterApi; + +public class WebViewClientHostApiImpl implements GeneratedAndroidWebView.WebViewClientHostApi { + private final InstanceManager instanceManager; + private final WebViewClientFlutterApi webViewClientFlutterApi; + + WebViewClientHostApiImpl(InstanceManager instanceManager, WebViewClientFlutterApi webViewClientFlutterApi) { + this.instanceManager = instanceManager; + this.webViewClientFlutterApi = webViewClientFlutterApi; + } + + @Override + public void create(Long instanceId, Boolean shouldOverrideUrlLoading) { + final WebViewClient webViewClient = new WebViewClient() { + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + webViewClientFlutterApi.onPageStarted(instanceId, instanceManager.getInstanceId(view), url, reply -> { }); + } + + @Override + public void onPageFinished(WebView view, String url) { + webViewClientFlutterApi.onPageFinished(instanceId, instanceManager.getInstanceId(view), url, reply -> { }); + } + + @RequiresApi(api = Build.VERSION_CODES.M) + @Override + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { + final GeneratedAndroidWebView.WebResourceRequestData requestData = new GeneratedAndroidWebView.WebResourceRequestData(); + requestData.setUrl(request.getUrl().toString()); + requestData.setIsForMainFrame(request.isForMainFrame()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + requestData.setIsRedirect(request.isRedirect()); + } + requestData.setHasGesture(request.hasGesture()); + requestData.setMethod(request.getMethod()); + requestData.setRequestHeaders(request.getRequestHeaders()); + + final GeneratedAndroidWebView.WebResourceErrorData errorData = new GeneratedAndroidWebView.WebResourceErrorData(); + errorData.setErrorCode((long) error.getErrorCode()); + errorData.setDescription(error.getDescription().toString()); + + webViewClientFlutterApi.onReceivedRequestError(instanceId, + instanceManager.getInstanceId(view), + requestData, + errorData, reply -> { }); + } + + @Override + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + webViewClientFlutterApi.onReceivedError(instanceId, + instanceManager.getInstanceId(view), + (long) errorCode, description, + failingUrl, reply -> { }); + } + + @RequiresApi(api = Build.VERSION_CODES.M) + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + final GeneratedAndroidWebView.WebResourceRequestData requestData = new GeneratedAndroidWebView.WebResourceRequestData(); + requestData.setUrl(request.getUrl().toString()); + requestData.setIsForMainFrame(request.isForMainFrame()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + requestData.setIsRedirect(request.isRedirect()); + } + requestData.setHasGesture(request.hasGesture()); + requestData.setMethod(request.getMethod()); + requestData.setRequestHeaders(request.getRequestHeaders()); + + webViewClientFlutterApi.requestLoading(instanceId, + instanceManager.getInstanceId(view), + requestData, reply -> {}); + return shouldOverrideUrlLoading; + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + webViewClientFlutterApi.urlLoading(instanceId, + instanceManager.getInstanceId(view), + url, + reply -> {}); + return shouldOverrideUrlLoading; + } + }; + instanceManager.addInstance(webViewClient, instanceId); + } + + @Override + public void dispose(Long instanceId) { + instanceManager.removeInstanceId(instanceId); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java new file mode 100644 index 000000000000..26ef3cfeb755 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -0,0 +1,202 @@ +package io.flutter.plugins.webviewflutter; + +import android.content.Context; +import android.view.View; +import android.webkit.DownloadListener; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import androidx.annotation.NonNull; + +import java.util.Map; + +import io.flutter.plugin.platform.PlatformView; + +class WebViewHostApiImpl implements GeneratedAndroidWebView.WebViewHostApi { + private final InstanceManager instanceManager; + private final Context context; + + private static class WebViewImpl extends WebView implements PlatformView { + public WebViewImpl(Context context) { + super(context); + } + + @Override + public View getView() { + return this; + } + + @Override + public void dispose() { + destroy(); + } + } + + private static class InputAwareWebViewImpl extends InputAwareWebView implements PlatformView { + InputAwareWebViewImpl(Context context, View containerView) { + super(context, containerView); + } + + @Override + public View getView() { + return this; + } + + @Override + public void onFlutterViewAttached(@NonNull View flutterView) { + setContainerView(flutterView); + } + + @Override + public void onFlutterViewDetached() { + setContainerView(null); + } + + @Override + public void dispose() { + dispose(); + destroy(); + } + + @Override + public void onInputConnectionLocked() { + lockInputConnection(); + } + + @Override + public void onInputConnectionUnlocked() { + unlockInputConnection(); + } + } + + WebViewHostApiImpl(InstanceManager instanceManager, Context context) { + this.instanceManager = instanceManager; + this.context = context; + } + + @Override + public void create(Long instanceId, Boolean useHybridComposition) { + final WebView webView = useHybridComposition ? new WebViewImpl(context) : new InputAwareWebViewImpl(context, null); + instanceManager.addInstance(webView, instanceId); + } + + @Override + public void dispose(Long instanceId) { + instanceManager.removeInstanceId(instanceId); + } + + @Override + public void loadUrl(Long instanceId, String url, Map headers) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.loadUrl(url, headers); + } + + @Override + public String getUrl(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return webView.getUrl(); + } + + @Override + public Boolean canGoBack(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return webView.canGoBack(); + } + + @Override + public Boolean canGoForward(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return webView.canGoForward(); + } + + @Override + public void goBack(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.goBack(); + } + + @Override + public void goForward(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.goForward(); + } + + @Override + public void reload(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.reload(); + } + + @Override + public void clearCache(Long instanceId, Boolean includeDiskFiles) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.clearCache(includeDiskFiles); + } + + @Override + public void evaluateJavascript(Long instanceId, String javascriptString, GeneratedAndroidWebView.Result result) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.evaluateJavascript(javascriptString, result::success); + } + + @Override + public String getTitle(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return webView.getTitle(); + } + + @Override + public void scrollTo(Long instanceId, Long x, Long y) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.scrollTo(x.intValue(), y.intValue()); + } + + @Override + public void scrollBy(Long instanceId, Long x, Long y) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.scrollBy(x.intValue(), y.intValue()); + } + + @Override + public Long getScrollX(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return (long) webView.getScrollX(); + } + + @Override + public Long getScrollY(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return (long) webView.getScrollY(); + } + + @Override + public void setWebContentsDebuggingEnabled(Boolean enabled) { + WebView.setWebContentsDebuggingEnabled(enabled); + } + + @Override + public void setWebViewClient(Long instanceId, Long webViewClientInstanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.setWebViewClient((WebViewClient) instanceManager.getInstance(webViewClientInstanceId)); + } + + @Override + public void addJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + final JavaScriptChannel javaScriptChannel = (JavaScriptChannel) instanceManager.getInstance(javaScriptChannelInstanceId); + webView.addJavascriptInterface(javaScriptChannel, javaScriptChannel.javaScriptChannelName); + } + + @Override + public void removeJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + final JavaScriptChannel javaScriptChannel = (JavaScriptChannel) instanceManager.getInstance(javaScriptChannelInstanceId); + webView.removeJavascriptInterface(javaScriptChannel.javaScriptChannelName); + } + + @Override + public void setDownloadListener(Long instanceId, Long listenerInstanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.setDownloadListener((DownloadListener) instanceManager.getInstance(listenerInstanceId)); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewSettingsHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewSettingsHostApiImpl.java new file mode 100644 index 000000000000..24b0586c8aeb --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewSettingsHostApiImpl.java @@ -0,0 +1,89 @@ +package io.flutter.plugins.webviewflutter; + +import android.webkit.WebSettings; +import android.webkit.WebView; + +class WebViewSettingsHostApiImpl implements GeneratedAndroidWebView.WebSettingsHostApi { + private final InstanceManager instanceManager; + + WebViewSettingsHostApiImpl(InstanceManager instanceManager) { + this.instanceManager = instanceManager; + } + + @Override + public void create(Long instanceId, Long webViewInstanceId) { + final WebView webView = (WebView) instanceManager.getInstance(webViewInstanceId); + instanceManager.addInstance(webView.getSettings(), instanceId); + } + + @Override + public void dispose(Long instanceId) { + instanceManager.removeInstanceId(instanceId); + } + + @Override + public void setDomStorageEnabled(Long instanceId, Boolean flag) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setDomStorageEnabled(flag); + } + + @Override + public void setJavaScriptCanOpenWindowsAutomatically(Long instanceId, Boolean flag) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setJavaScriptCanOpenWindowsAutomatically(flag); + } + + @Override + public void setSupportMultipleWindows(Long instanceId, Boolean support) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setSupportMultipleWindows(support); + } + + @Override + public void setJavaScriptEnabled(Long instanceId, Boolean flag) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setJavaScriptEnabled(flag); + } + + @Override + public void setUserAgentString(Long instanceId, String userAgentString) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setUserAgentString(userAgentString); + } + + @Override + public void setMediaPlaybackRequiresUserGesture(Long instanceId, Boolean require) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setMediaPlaybackRequiresUserGesture(require); + } + + @Override + public void setSupportZoom(Long instanceId, Boolean support) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setSupportZoom(support); + } + + @Override + public void setLoadWithOverviewMode(Long instanceId, Boolean overview) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setLoadWithOverviewMode(overview); + } + + @Override + public void setUseWideViewPort(Long instanceId, Boolean use) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setUseWideViewPort(use); + } + + @Override + public void setDisplayZoomControls(Long instanceId, Boolean enabled) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setDisplayZoomControls(enabled); + } + + @Override + public void setBuiltInZoomControls(Long instanceId, Boolean enabled) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setBuiltInZoomControls(enabled); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index 5874c7ab311e..3f7bd1866d1c 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -52,7 +52,7 @@ class WebView { final bool useHybridComposition; /// The [WebSettings] object used to control the settings for this WebView. - late final WebViewSettings settings = WebViewSettings._(this); + late final WebSettings settings = WebSettings._(this); /// Enables debugging of web contents (HTML / CSS / JavaScript) loaded into any WebViews of this application. /// @@ -257,15 +257,15 @@ class WebView { /// obtained from [WebView.settings] is tied to the life of the WebView. If a /// WebView has been destroyed, any method call on [WebSettings] will throw an /// Exception. -class WebViewSettings { - WebViewSettings._(this.webView) { +class WebSettings { + WebSettings._(this.webView) { _api.createFromInstance(this); } /// The webView instance this is attached to. final WebView webView; - static final WebViewSettingsHostApiImpl _api = WebViewSettingsHostApiImpl(); + static final WebSettingsHostApiImpl _api = WebSettingsHostApiImpl(); /// Sets whether the DOM storage API is enabled. /// @@ -560,7 +560,7 @@ class WebResourceRequest { /// Gets whether the request was a result of a server-side redirect. /// - /// Only supported on Android version >= 23. + /// Only supported on Android version >= 24. final bool? isRedirect; /// Gets whether a gesture (such as a click) was associated with the request. diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart index c1bd5f4a0659..109f82e5a8a3 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -556,23 +556,23 @@ class WebViewHostApi { } } -class _WebViewSettingsHostApiCodec extends StandardMessageCodec { - const _WebViewSettingsHostApiCodec(); +class _WebSettingsHostApiCodec extends StandardMessageCodec { + const _WebSettingsHostApiCodec(); } -class WebViewSettingsHostApi { - /// Constructor for [WebViewSettingsHostApi]. The [binaryMessenger] named argument is +class WebSettingsHostApi { + /// Constructor for [WebSettingsHostApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - WebViewSettingsHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + WebSettingsHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; final BinaryMessenger? _binaryMessenger; - static const MessageCodec codec = _WebViewSettingsHostApiCodec(); + static const MessageCodec codec = _WebSettingsHostApiCodec(); Future create(int arg_instanceId, int arg_webViewInstanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.create', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.create', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_webViewInstanceId]) as Map?; if (replyMap == null) { @@ -595,7 +595,7 @@ class WebViewSettingsHostApi { Future dispose(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.dispose', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.dispose', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -618,7 +618,7 @@ class WebViewSettingsHostApi { Future setDomStorageEnabled(int arg_instanceId, bool arg_flag) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.setDomStorageEnabled', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_flag]) as Map?; if (replyMap == null) { @@ -641,7 +641,7 @@ class WebViewSettingsHostApi { Future setJavaScriptCanOpenWindowsAutomatically(int arg_instanceId, bool arg_flag) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_flag]) as Map?; if (replyMap == null) { @@ -664,7 +664,7 @@ class WebViewSettingsHostApi { Future setSupportMultipleWindows(int arg_instanceId, bool arg_support) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.setSupportMultipleWindows', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_support]) as Map?; if (replyMap == null) { @@ -687,7 +687,7 @@ class WebViewSettingsHostApi { Future setJavaScriptEnabled(int arg_instanceId, bool arg_flag) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.setJavaScriptEnabled', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_flag]) as Map?; if (replyMap == null) { @@ -710,7 +710,7 @@ class WebViewSettingsHostApi { Future setUserAgentString(int arg_instanceId, String arg_userAgentString) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.setUserAgentString', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_userAgentString]) as Map?; if (replyMap == null) { @@ -733,7 +733,7 @@ class WebViewSettingsHostApi { Future setMediaPlaybackRequiresUserGesture(int arg_instanceId, bool arg_require) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.setMediaPlaybackRequiresUserGesture', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_require]) as Map?; if (replyMap == null) { @@ -756,7 +756,7 @@ class WebViewSettingsHostApi { Future setSupportZoom(int arg_instanceId, bool arg_support) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.setSupportZoom', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_support]) as Map?; if (replyMap == null) { @@ -779,7 +779,7 @@ class WebViewSettingsHostApi { Future setLoadWithOverviewMode(int arg_instanceId, bool arg_overview) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.setLoadWithOverviewMode', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_overview]) as Map?; if (replyMap == null) { @@ -802,7 +802,7 @@ class WebViewSettingsHostApi { Future setUseWideViewPort(int arg_instanceId, bool arg_use) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.setUseWideViewPort', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_use]) as Map?; if (replyMap == null) { @@ -825,7 +825,7 @@ class WebViewSettingsHostApi { Future setDisplayZoomControls(int arg_instanceId, bool arg_enabled) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.setDisplayZoomControls', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_enabled]) as Map?; if (replyMap == null) { @@ -848,7 +848,7 @@ class WebViewSettingsHostApi { Future setBuiltInZoomControls(int arg_instanceId, bool arg_enabled) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewSettingsHostApi.setBuiltInZoomControls', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls', codec, binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId, arg_enabled]) as Map?; if (replyMap == null) { @@ -1066,8 +1066,8 @@ abstract class WebViewClientFlutterApi { void onPageFinished(int instanceId, int webViewInstanceId, String url); void onReceivedRequestError(int instanceId, int webViewInstanceId, WebResourceRequestData request, WebResourceErrorData error); void onReceivedError(int instanceId, int webViewInstanceId, int errorCode, String description, String failingUrl); - void shouldOverrideRequestLoading(int instanceId, int webViewInstanceId, WebResourceRequestData request); - void shouldOverrideUrlLoading(int instanceId, int webViewInstanceId, String url); + void requestLoading(int instanceId, int webViewInstanceId, WebResourceRequestData request); + void urlLoading(int instanceId, int webViewInstanceId, String url); static void setup(WebViewClientFlutterApi? api) { { const BasicMessageChannel channel = BasicMessageChannel( @@ -1157,40 +1157,40 @@ abstract class WebViewClientFlutterApi { } { const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading', codec); + 'dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading', codec); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading was null.'); + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading was null, expected non-null int.'); + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null int.'); final int? arg_webViewInstanceId = args[1] as int?; - assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading was null, expected non-null int.'); + assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null int.'); final WebResourceRequestData? arg_request = args[2] as WebResourceRequestData?; - assert(arg_request != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideRequestLoading was null, expected non-null WebResourceRequestData.'); - api.shouldOverrideRequestLoading(arg_instanceId!, arg_webViewInstanceId!, arg_request!); + assert(arg_request != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null WebResourceRequestData.'); + api.requestLoading(arg_instanceId!, arg_webViewInstanceId!, arg_request!); return; }); } } { const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading', codec); + 'dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading', codec); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading was null.'); + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading was null, expected non-null int.'); + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null int.'); final int? arg_webViewInstanceId = args[1] as int?; - assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading was null, expected non-null int.'); + assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null int.'); final String? arg_url = args[2] as String?; - assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.shouldOverrideUrlLoading was null, expected non-null String.'); - api.shouldOverrideUrlLoading(arg_instanceId!, arg_webViewInstanceId!, arg_url!); + assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null String.'); + api.urlLoading(arg_instanceId!, arg_webViewInstanceId!, arg_url!); return; }); } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index 0fec31cf9d06..9582b79ab4b6 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -158,10 +158,10 @@ class WebViewHostApiImpl extends WebViewHostApi { } } -/// Host api implementation for [WebViewSettings]. -class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { - /// Constructs a [WebViewSettingsHostApiImpl]. - WebViewSettingsHostApiImpl({InstanceManager? instanceManager}) { +/// Host api implementation for [WebSettings]. +class WebSettingsHostApiImpl extends WebSettingsHostApi { + /// Constructs a [WebSettingsHostApiImpl]. + WebSettingsHostApiImpl({InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? InstanceManager.instance; } @@ -169,7 +169,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { late final InstanceManager instanceManager; /// Helper method to convert instances ids to objects. - Future createFromInstance(WebViewSettings instance) async { + Future createFromInstance(WebSettings instance) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { return create( @@ -180,7 +180,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { } /// Helper method to convert instances ids to objects. - Future disposeFromInstance(WebViewSettings instance) async { + Future disposeFromInstance(WebSettings instance) async { final int? instanceId = instanceManager.removeInstance(instance); if (instanceId != null) { return dispose(instanceId); @@ -189,7 +189,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { /// Helper method to convert instances ids to objects. Future setDomStorageEnabledFromInstance( - WebViewSettings instance, + WebSettings instance, bool flag, ) { return setDomStorageEnabled(instanceManager.getInstanceId(instance)!, flag); @@ -197,7 +197,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { /// Helper method to convert instances ids to objects. Future setJavaScriptCanOpenWindowsAutomaticallyFromInstance( - WebViewSettings instance, + WebSettings instance, bool flag, ) { return setJavaScriptCanOpenWindowsAutomatically( @@ -208,7 +208,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { /// Helper method to convert instances ids to objects. Future setSupportMultipleWindowsFromInstance( - WebViewSettings instance, + WebSettings instance, bool support, ) { return setSupportMultipleWindows( @@ -217,7 +217,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { /// Helper method to convert instances ids to objects. Future setJavaScriptEnabledFromInstance( - WebViewSettings instance, + WebSettings instance, bool flag, ) { return setJavaScriptCanOpenWindowsAutomatically( @@ -228,7 +228,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { /// Helper method to convert instances ids to objects. Future setUserAgentStringFromInstance( - WebViewSettings instance, + WebSettings instance, String userAgentString, ) { return setUserAgentString( @@ -239,7 +239,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { /// Helper method to convert instances ids to objects. Future setMediaPlaybackRequiresUserGestureFromInstance( - WebViewSettings instance, + WebSettings instance, bool require, ) { return setMediaPlaybackRequiresUserGesture( @@ -250,7 +250,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { /// Helper method to convert instances ids to objects. Future setSupportZoomFromInstance( - WebViewSettings instance, + WebSettings instance, bool support, ) { return setSupportZoom(instanceManager.getInstanceId(instance)!, support); @@ -258,7 +258,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { /// Helper method to convert instances ids to objects. Future setLoadWithOverviewModeFromInstance( - WebViewSettings instance, + WebSettings instance, bool overview, ) { return setLoadWithOverviewMode( @@ -269,7 +269,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { /// Helper method to convert instances ids to objects. Future setUseWideViewPortFromInstance( - WebViewSettings instance, + WebSettings instance, bool use, ) { return setUseWideViewPort(instanceManager.getInstanceId(instance)!, use); @@ -277,7 +277,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { /// Helper method to convert instances ids to objects. Future setDisplayZoomControlsFromInstance( - WebViewSettings instance, + WebSettings instance, bool enabled, ) { return setDisplayZoomControls( @@ -288,7 +288,7 @@ class WebViewSettingsHostApiImpl extends WebViewSettingsHostApi { /// Helper method to convert instances ids to objects. Future setBuiltInZoomControlsFromInstance( - WebViewSettings instance, + WebSettings instance, bool enabled, ) { return setBuiltInZoomControls( @@ -445,7 +445,7 @@ class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { } @override - void shouldOverrideRequestLoading( + void requestLoading( int instanceId, int webViewInstanceId, WebResourceRequestData request, @@ -466,7 +466,7 @@ class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { } @override - void shouldOverrideUrlLoading( + void urlLoading( int instanceId, int webViewInstanceId, String url, diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart index b9343dad9c48..7efbe17861bf 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -72,7 +72,7 @@ abstract class WebViewHostApi { } @HostApi() -abstract class WebViewSettingsHostApi { +abstract class WebSettingsHostApi { void create(int instanceId, int webViewInstanceId); void dispose(int instanceId); @@ -140,17 +140,13 @@ abstract class WebViewClientFlutterApi { String failingUrl, ); - void shouldOverrideRequestLoading( + void requestLoading( int instanceId, int webViewInstanceId, WebResourceRequestData request, ); - void shouldOverrideUrlLoading( - int instanceId, - int webViewInstanceId, - String url, - ); + void urlLoading(int instanceId, int webViewInstanceId, String url); } @HostApi() From 7d30dd47ad07beec6e0e1725aef6c05a54f68115 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 18 Oct 2021 10:24:53 -0700 Subject: [PATCH 08/54] test instance manager and formatting --- .../DownloadListenerHostApiImpl.java | 24 +- .../GeneratedAndroidWebView.java | 2080 ++++++++++------- .../JavaScriptChannelHostApiImpl.java | 23 +- .../WebViewClientHostApiImpl.java | 139 +- .../webviewflutter/WebViewHostApiImpl.java | 17 +- .../lib/src/android_webview.dart | 2 +- .../lib/src/android_webview.pigeon.dart | 577 +++-- .../lib/src/instance_manager.dart | 10 +- .../test/instance_manager_test.dart | 35 + 9 files changed, 1712 insertions(+), 1195 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/test/instance_manager_test.dart diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java index 2ec499c546d9..6638e218611d 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java @@ -2,24 +2,30 @@ import android.webkit.DownloadListener; -public class DownloadListenerHostApiImpl implements GeneratedAndroidWebView.DownloadListenerHostApi { +public class DownloadListenerHostApiImpl + implements GeneratedAndroidWebView.DownloadListenerHostApi { private final InstanceManager instanceManager; private final GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi; - DownloadListenerHostApiImpl(InstanceManager instanceManager, GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { + DownloadListenerHostApiImpl( + InstanceManager instanceManager, + GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { this.instanceManager = instanceManager; this.downloadListenerFlutterApi = downloadListenerFlutterApi; } @Override public void create(Long instanceId) { - final DownloadListener downloadListener = (url, userAgent, contentDisposition, mimetype, contentLength) -> downloadListenerFlutterApi.onDownloadStart(instanceId, - url, - userAgent, - contentDisposition, - mimetype, - contentLength, - reply -> {}); + final DownloadListener downloadListener = + (url, userAgent, contentDisposition, mimetype, contentLength) -> + downloadListenerFlutterApi.onDownloadStart( + instanceId, + url, + userAgent, + contentDisposition, + mimetype, + contentLength, + reply -> {}); instanceManager.addInstance(downloadListener, instanceId); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index a790e6f722b5..34e1e0b54f7e 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -9,11 +9,10 @@ import io.flutter.plugin.common.StandardMessageCodec; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; -import java.util.Arrays; import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.Arrays; import java.util.HashMap; +import java.util.Map; /** Generated class from Pigeon. */ @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"}) @@ -22,28 +21,64 @@ public class GeneratedAndroidWebView { /** Generated class from Pigeon that represents data sent in messages. */ public static class WebResourceRequestData { private String url; - public String getUrl() { return url; } - public void setUrl(String setterArg) { this.url = setterArg; } + + public String getUrl() { + return url; + } + + public void setUrl(String setterArg) { + this.url = setterArg; + } private Boolean isForMainFrame; - public Boolean getIsForMainFrame() { return isForMainFrame; } - public void setIsForMainFrame(Boolean setterArg) { this.isForMainFrame = setterArg; } + + public Boolean getIsForMainFrame() { + return isForMainFrame; + } + + public void setIsForMainFrame(Boolean setterArg) { + this.isForMainFrame = setterArg; + } private Boolean isRedirect; - public Boolean getIsRedirect() { return isRedirect; } - public void setIsRedirect(Boolean setterArg) { this.isRedirect = setterArg; } + + public Boolean getIsRedirect() { + return isRedirect; + } + + public void setIsRedirect(Boolean setterArg) { + this.isRedirect = setterArg; + } private Boolean hasGesture; - public Boolean getHasGesture() { return hasGesture; } - public void setHasGesture(Boolean setterArg) { this.hasGesture = setterArg; } + + public Boolean getHasGesture() { + return hasGesture; + } + + public void setHasGesture(Boolean setterArg) { + this.hasGesture = setterArg; + } private String method; - public String getMethod() { return method; } - public void setMethod(String setterArg) { this.method = setterArg; } + + public String getMethod() { + return method; + } + + public void setMethod(String setterArg) { + this.method = setterArg; + } private Map requestHeaders; - public Map getRequestHeaders() { return requestHeaders; } - public void setRequestHeaders(Map setterArg) { this.requestHeaders = setterArg; } + + public Map getRequestHeaders() { + return requestHeaders; + } + + public void setRequestHeaders(Map setterArg) { + this.requestHeaders = setterArg; + } Map toMap() { Map toMapResult = new HashMap<>(); @@ -55,20 +90,21 @@ Map toMap() { toMapResult.put("requestHeaders", requestHeaders); return toMapResult; } + static WebResourceRequestData fromMap(Map map) { WebResourceRequestData fromMapResult = new WebResourceRequestData(); Object url = map.get("url"); - fromMapResult.url = (String)url; + fromMapResult.url = (String) url; Object isForMainFrame = map.get("isForMainFrame"); - fromMapResult.isForMainFrame = (Boolean)isForMainFrame; + fromMapResult.isForMainFrame = (Boolean) isForMainFrame; Object isRedirect = map.get("isRedirect"); - fromMapResult.isRedirect = (Boolean)isRedirect; + fromMapResult.isRedirect = (Boolean) isRedirect; Object hasGesture = map.get("hasGesture"); - fromMapResult.hasGesture = (Boolean)hasGesture; + fromMapResult.hasGesture = (Boolean) hasGesture; Object method = map.get("method"); - fromMapResult.method = (String)method; + fromMapResult.method = (String) method; Object requestHeaders = map.get("requestHeaders"); - fromMapResult.requestHeaders = (Map)requestHeaders; + fromMapResult.requestHeaders = (Map) requestHeaders; return fromMapResult; } } @@ -76,12 +112,24 @@ static WebResourceRequestData fromMap(Map map) { /** Generated class from Pigeon that represents data sent in messages. */ public static class WebResourceErrorData { private Long errorCode; - public Long getErrorCode() { return errorCode; } - public void setErrorCode(Long setterArg) { this.errorCode = setterArg; } + + public Long getErrorCode() { + return errorCode; + } + + public void setErrorCode(Long setterArg) { + this.errorCode = setterArg; + } private String description; - public String getDescription() { return description; } - public void setDescription(String setterArg) { this.description = setterArg; } + + public String getDescription() { + return description; + } + + public void setDescription(String setterArg) { + this.description = setterArg; + } Map toMap() { Map toMapResult = new HashMap<>(); @@ -89,47 +137,74 @@ Map toMap() { toMapResult.put("description", description); return toMapResult; } + static WebResourceErrorData fromMap(Map map) { WebResourceErrorData fromMapResult = new WebResourceErrorData(); Object errorCode = map.get("errorCode"); - fromMapResult.errorCode = (errorCode == null) ? null : ((errorCode instanceof Integer) ? (Integer)errorCode : (Long)errorCode); + fromMapResult.errorCode = + (errorCode == null) + ? null + : ((errorCode instanceof Integer) ? (Integer) errorCode : (Long) errorCode); Object description = map.get("description"); - fromMapResult.description = (String)description; + fromMapResult.description = (String) description; return fromMapResult; } } public interface Result { void success(T result); + void error(Throwable error); } + private static class WebViewHostApiCodec extends StandardMessageCodec { public static final WebViewHostApiCodec INSTANCE = new WebViewHostApiCodec(); + private WebViewHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface WebViewHostApi { void create(Long instanceId, Boolean useHybridComposition); + void dispose(Long instanceId); + void loadUrl(Long instanceId, String url, Map headers); + String getUrl(Long instanceId); + Boolean canGoBack(Long instanceId); + Boolean canGoForward(Long instanceId); + void goBack(Long instanceId); + void goForward(Long instanceId); + void reload(Long instanceId); + void clearCache(Long instanceId, Boolean includeDiskFiles); + void evaluateJavascript(Long instanceId, String javascriptString, Result result); + String getTitle(Long instanceId); + void scrollTo(Long instanceId, Long x, Long y); + void scrollBy(Long instanceId, Long x, Long y); + Long getScrollX(Long instanceId); + Long getScrollY(Long instanceId); + void setWebContentsDebuggingEnabled(Boolean enabled); + void setWebViewClient(Long instanceId, Long webViewClientInstanceId); + void addJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); + void removeJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); + void setDownloadListener(Long instanceId, Long listenerInstanceId); /** The codec used by WebViewHostApi. */ @@ -141,591 +216,645 @@ static MessageCodec getCodec() { static void setup(BinaryMessenger binaryMessenger, WebViewHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.create", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean useHybridCompositionArg = (Boolean)args.get(1); - if (useHybridCompositionArg == null) { - throw new NullPointerException("useHybridCompositionArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), useHybridCompositionArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean useHybridCompositionArg = (Boolean) args.get(1); + if (useHybridCompositionArg == null) { + throw new NullPointerException("useHybridCompositionArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), useHybridCompositionArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.dispose", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.loadUrl", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.loadUrl", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String urlArg = (String)args.get(1); - if (urlArg == null) { - throw new NullPointerException("urlArg unexpectedly null."); - } - Map headersArg = (Map)args.get(2); - if (headersArg == null) { - throw new NullPointerException("headersArg unexpectedly null."); - } - api.loadUrl(instanceIdArg.longValue(), urlArg, headersArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String urlArg = (String) args.get(1); + if (urlArg == null) { + throw new NullPointerException("urlArg unexpectedly null."); + } + Map headersArg = (Map) args.get(2); + if (headersArg == null) { + throw new NullPointerException("headersArg unexpectedly null."); + } + api.loadUrl(instanceIdArg.longValue(), urlArg, headersArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getUrl", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getUrl", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String output = api.getUrl(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String output = api.getUrl(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoBack", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoBack", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean output = api.canGoBack(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean output = api.canGoBack(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoForward", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoForward", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean output = api.canGoForward(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean output = api.canGoForward(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goBack", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goBack", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.goBack(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.goBack(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goForward", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goForward", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.goForward(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.goForward(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.reload", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.reload", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.reload(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.reload(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.clearCache", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.clearCache", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean includeDiskFilesArg = (Boolean)args.get(1); - if (includeDiskFilesArg == null) { - throw new NullPointerException("includeDiskFilesArg unexpectedly null."); - } - api.clearCache(instanceIdArg.longValue(), includeDiskFilesArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean includeDiskFilesArg = (Boolean) args.get(1); + if (includeDiskFilesArg == null) { + throw new NullPointerException("includeDiskFilesArg unexpectedly null."); + } + api.clearCache(instanceIdArg.longValue(), includeDiskFilesArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.evaluateJavascript", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.evaluateJavascript", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String javascriptStringArg = (String)args.get(1); - if (javascriptStringArg == null) { - throw new NullPointerException("javascriptStringArg unexpectedly null."); - } - Result resultCallback = new Result() { - public void success(String result) { - wrapped.put("result", result); - reply.reply(wrapped); - } - public void error(Throwable error) { - wrapped.put("error", wrapError(error)); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String javascriptStringArg = (String) args.get(1); + if (javascriptStringArg == null) { + throw new NullPointerException("javascriptStringArg unexpectedly null."); + } + Result resultCallback = + new Result() { + public void success(String result) { + wrapped.put("result", result); + reply.reply(wrapped); + } + + public void error(Throwable error) { + wrapped.put("error", wrapError(error)); + reply.reply(wrapped); + } + }; + + api.evaluateJavascript( + instanceIdArg.longValue(), javascriptStringArg, resultCallback); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); reply.reply(wrapped); } - }; - - api.evaluateJavascript(instanceIdArg.longValue(), javascriptStringArg, resultCallback); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - reply.reply(wrapped); - } - }); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getTitle", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getTitle", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String output = api.getTitle(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String output = api.getTitle(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollTo", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollTo", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number xArg = (Number)args.get(1); - if (xArg == null) { - throw new NullPointerException("xArg unexpectedly null."); - } - Number yArg = (Number)args.get(2); - if (yArg == null) { - throw new NullPointerException("yArg unexpectedly null."); - } - api.scrollTo(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number xArg = (Number) args.get(1); + if (xArg == null) { + throw new NullPointerException("xArg unexpectedly null."); + } + Number yArg = (Number) args.get(2); + if (yArg == null) { + throw new NullPointerException("yArg unexpectedly null."); + } + api.scrollTo(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollBy", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollBy", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number xArg = (Number)args.get(1); - if (xArg == null) { - throw new NullPointerException("xArg unexpectedly null."); - } - Number yArg = (Number)args.get(2); - if (yArg == null) { - throw new NullPointerException("yArg unexpectedly null."); - } - api.scrollBy(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number xArg = (Number) args.get(1); + if (xArg == null) { + throw new NullPointerException("xArg unexpectedly null."); + } + Number yArg = (Number) args.get(2); + if (yArg == null) { + throw new NullPointerException("yArg unexpectedly null."); + } + api.scrollBy(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollX", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollX", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Long output = api.getScrollX(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Long output = api.getScrollX(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollY", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollY", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Long output = api.getScrollY(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Long output = api.getScrollY(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Boolean enabledArg = (Boolean)args.get(0); - if (enabledArg == null) { - throw new NullPointerException("enabledArg unexpectedly null."); - } - api.setWebContentsDebuggingEnabled(enabledArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Boolean enabledArg = (Boolean) args.get(0); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setWebContentsDebuggingEnabled(enabledArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebViewClient", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebViewClient", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number webViewClientInstanceIdArg = (Number)args.get(1); - if (webViewClientInstanceIdArg == null) { - throw new NullPointerException("webViewClientInstanceIdArg unexpectedly null."); - } - api.setWebViewClient(instanceIdArg.longValue(), webViewClientInstanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number webViewClientInstanceIdArg = (Number) args.get(1); + if (webViewClientInstanceIdArg == null) { + throw new NullPointerException("webViewClientInstanceIdArg unexpectedly null."); + } + api.setWebViewClient( + instanceIdArg.longValue(), webViewClientInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number javaScriptChannelInstanceIdArg = (Number)args.get(1); - if (javaScriptChannelInstanceIdArg == null) { - throw new NullPointerException("javaScriptChannelInstanceIdArg unexpectedly null."); - } - api.addJavaScriptChannel(instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number javaScriptChannelInstanceIdArg = (Number) args.get(1); + if (javaScriptChannelInstanceIdArg == null) { + throw new NullPointerException( + "javaScriptChannelInstanceIdArg unexpectedly null."); + } + api.addJavaScriptChannel( + instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number javaScriptChannelInstanceIdArg = (Number)args.get(1); - if (javaScriptChannelInstanceIdArg == null) { - throw new NullPointerException("javaScriptChannelInstanceIdArg unexpectedly null."); - } - api.removeJavaScriptChannel(instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number javaScriptChannelInstanceIdArg = (Number) args.get(1); + if (javaScriptChannelInstanceIdArg == null) { + throw new NullPointerException( + "javaScriptChannelInstanceIdArg unexpectedly null."); + } + api.removeJavaScriptChannel( + instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setDownloadListener", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.setDownloadListener", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number listenerInstanceIdArg = (Number)args.get(1); - if (listenerInstanceIdArg == null) { - throw new NullPointerException("listenerInstanceIdArg unexpectedly null."); - } - api.setDownloadListener(instanceIdArg.longValue(), listenerInstanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number listenerInstanceIdArg = (Number) args.get(1); + if (listenerInstanceIdArg == null) { + throw new NullPointerException("listenerInstanceIdArg unexpectedly null."); + } + api.setDownloadListener( + instanceIdArg.longValue(), listenerInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } + private static class WebSettingsHostApiCodec extends StandardMessageCodec { public static final WebSettingsHostApiCodec INSTANCE = new WebSettingsHostApiCodec(); + private WebSettingsHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface WebSettingsHostApi { void create(Long instanceId, Long webViewInstanceId); + void dispose(Long instanceId); + void setDomStorageEnabled(Long instanceId, Boolean flag); + void setJavaScriptCanOpenWindowsAutomatically(Long instanceId, Boolean flag); + void setSupportMultipleWindows(Long instanceId, Boolean support); + void setJavaScriptEnabled(Long instanceId, Boolean flag); + void setUserAgentString(Long instanceId, String userAgentString); + void setMediaPlaybackRequiresUserGesture(Long instanceId, Boolean require); + void setSupportZoom(Long instanceId, Boolean support); + void setLoadWithOverviewMode(Long instanceId, Boolean overview); + void setUseWideViewPort(Long instanceId, Boolean use); + void setDisplayZoomControls(Long instanceId, Boolean enabled); + void setBuiltInZoomControls(Long instanceId, Boolean enabled); /** The codec used by WebSettingsHostApi. */ @@ -733,378 +862,419 @@ static MessageCodec getCodec() { return WebSettingsHostApiCodec.INSTANCE; } - /** Sets up an instance of `WebSettingsHostApi` to handle messages through the `binaryMessenger`. */ + /** + * Sets up an instance of `WebSettingsHostApi` to handle messages through the `binaryMessenger`. + */ static void setup(BinaryMessenger binaryMessenger, WebSettingsHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.create", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number webViewInstanceIdArg = (Number)args.get(1); - if (webViewInstanceIdArg == null) { - throw new NullPointerException("webViewInstanceIdArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), webViewInstanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number webViewInstanceIdArg = (Number) args.get(1); + if (webViewInstanceIdArg == null) { + throw new NullPointerException("webViewInstanceIdArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), webViewInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.dispose", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean flagArg = (Boolean)args.get(1); - if (flagArg == null) { - throw new NullPointerException("flagArg unexpectedly null."); - } - api.setDomStorageEnabled(instanceIdArg.longValue(), flagArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean) args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setDomStorageEnabled(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean flagArg = (Boolean)args.get(1); - if (flagArg == null) { - throw new NullPointerException("flagArg unexpectedly null."); - } - api.setJavaScriptCanOpenWindowsAutomatically(instanceIdArg.longValue(), flagArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean) args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setJavaScriptCanOpenWindowsAutomatically(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean supportArg = (Boolean)args.get(1); - if (supportArg == null) { - throw new NullPointerException("supportArg unexpectedly null."); - } - api.setSupportMultipleWindows(instanceIdArg.longValue(), supportArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean supportArg = (Boolean) args.get(1); + if (supportArg == null) { + throw new NullPointerException("supportArg unexpectedly null."); + } + api.setSupportMultipleWindows(instanceIdArg.longValue(), supportArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean flagArg = (Boolean)args.get(1); - if (flagArg == null) { - throw new NullPointerException("flagArg unexpectedly null."); - } - api.setJavaScriptEnabled(instanceIdArg.longValue(), flagArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean) args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setJavaScriptEnabled(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String userAgentStringArg = (String)args.get(1); - if (userAgentStringArg == null) { - throw new NullPointerException("userAgentStringArg unexpectedly null."); - } - api.setUserAgentString(instanceIdArg.longValue(), userAgentStringArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String userAgentStringArg = (String) args.get(1); + if (userAgentStringArg == null) { + throw new NullPointerException("userAgentStringArg unexpectedly null."); + } + api.setUserAgentString(instanceIdArg.longValue(), userAgentStringArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean requireArg = (Boolean)args.get(1); - if (requireArg == null) { - throw new NullPointerException("requireArg unexpectedly null."); - } - api.setMediaPlaybackRequiresUserGesture(instanceIdArg.longValue(), requireArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean requireArg = (Boolean) args.get(1); + if (requireArg == null) { + throw new NullPointerException("requireArg unexpectedly null."); + } + api.setMediaPlaybackRequiresUserGesture(instanceIdArg.longValue(), requireArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean supportArg = (Boolean)args.get(1); - if (supportArg == null) { - throw new NullPointerException("supportArg unexpectedly null."); - } - api.setSupportZoom(instanceIdArg.longValue(), supportArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean supportArg = (Boolean) args.get(1); + if (supportArg == null) { + throw new NullPointerException("supportArg unexpectedly null."); + } + api.setSupportZoom(instanceIdArg.longValue(), supportArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean overviewArg = (Boolean)args.get(1); - if (overviewArg == null) { - throw new NullPointerException("overviewArg unexpectedly null."); - } - api.setLoadWithOverviewMode(instanceIdArg.longValue(), overviewArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean overviewArg = (Boolean) args.get(1); + if (overviewArg == null) { + throw new NullPointerException("overviewArg unexpectedly null."); + } + api.setLoadWithOverviewMode(instanceIdArg.longValue(), overviewArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean useArg = (Boolean)args.get(1); - if (useArg == null) { - throw new NullPointerException("useArg unexpectedly null."); - } - api.setUseWideViewPort(instanceIdArg.longValue(), useArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean useArg = (Boolean) args.get(1); + if (useArg == null) { + throw new NullPointerException("useArg unexpectedly null."); + } + api.setUseWideViewPort(instanceIdArg.longValue(), useArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean enabledArg = (Boolean)args.get(1); - if (enabledArg == null) { - throw new NullPointerException("enabledArg unexpectedly null."); - } - api.setDisplayZoomControls(instanceIdArg.longValue(), enabledArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean enabledArg = (Boolean) args.get(1); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setDisplayZoomControls(instanceIdArg.longValue(), enabledArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean enabledArg = (Boolean)args.get(1); - if (enabledArg == null) { - throw new NullPointerException("enabledArg unexpectedly null."); - } - api.setBuiltInZoomControls(instanceIdArg.longValue(), enabledArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean enabledArg = (Boolean) args.get(1); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setBuiltInZoomControls(instanceIdArg.longValue(), enabledArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } + private static class JavaScriptChannelHostApiCodec extends StandardMessageCodec { - public static final JavaScriptChannelHostApiCodec INSTANCE = new JavaScriptChannelHostApiCodec(); + public static final JavaScriptChannelHostApiCodec INSTANCE = + new JavaScriptChannelHostApiCodec(); + private JavaScriptChannelHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface JavaScriptChannelHostApi { void create(Long instanceId, String channelName); + void dispose(Long instanceId); /** The codec used by JavaScriptChannelHostApi. */ @@ -1112,96 +1282,115 @@ static MessageCodec getCodec() { return JavaScriptChannelHostApiCodec.INSTANCE; } - /** Sets up an instance of `JavaScriptChannelHostApi` to handle messages through the `binaryMessenger`. */ + /** + * Sets up an instance of `JavaScriptChannelHostApi` to handle messages through the + * `binaryMessenger`. + */ static void setup(BinaryMessenger binaryMessenger, JavaScriptChannelHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.create", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String channelNameArg = (String)args.get(1); - if (channelNameArg == null) { - throw new NullPointerException("channelNameArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), channelNameArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String channelNameArg = (String) args.get(1); + if (channelNameArg == null) { + throw new NullPointerException("channelNameArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), channelNameArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.dispose", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } + private static class JavaScriptChannelFlutterApiCodec extends StandardMessageCodec { - public static final JavaScriptChannelFlutterApiCodec INSTANCE = new JavaScriptChannelFlutterApiCodec(); + public static final JavaScriptChannelFlutterApiCodec INSTANCE = + new JavaScriptChannelFlutterApiCodec(); + private JavaScriptChannelFlutterApiCodec() {} } - /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ public static class JavaScriptChannelFlutterApi { private final BinaryMessenger binaryMessenger; - public JavaScriptChannelFlutterApi(BinaryMessenger argBinaryMessenger){ + + public JavaScriptChannelFlutterApi(BinaryMessenger argBinaryMessenger) { this.binaryMessenger = argBinaryMessenger; } + public interface Reply { void reply(T reply); } + static MessageCodec getCodec() { return JavaScriptChannelFlutterApiCodec.INSTANCE; } public void postMessage(Long instanceIdArg, String messageArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, messageArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, messageArg)), + channelReply -> { + callback.reply(null); + }); } } + private static class WebViewClientHostApiCodec extends StandardMessageCodec { public static final WebViewClientHostApiCodec INSTANCE = new WebViewClientHostApiCodec(); + private WebViewClientHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface WebViewClientHostApi { void create(Long instanceId, Boolean shouldOverrideUrlLoading); + void dispose(Long instanceId); /** The codec used by WebViewClientHostApi. */ @@ -1209,166 +1398,236 @@ static MessageCodec getCodec() { return WebViewClientHostApiCodec.INSTANCE; } - /** Sets up an instance of `WebViewClientHostApi` to handle messages through the `binaryMessenger`. */ + /** + * Sets up an instance of `WebViewClientHostApi` to handle messages through the + * `binaryMessenger`. + */ static void setup(BinaryMessenger binaryMessenger, WebViewClientHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.create", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean shouldOverrideUrlLoadingArg = (Boolean)args.get(1); - if (shouldOverrideUrlLoadingArg == null) { - throw new NullPointerException("shouldOverrideUrlLoadingArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), shouldOverrideUrlLoadingArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean shouldOverrideUrlLoadingArg = (Boolean) args.get(1); + if (shouldOverrideUrlLoadingArg == null) { + throw new NullPointerException( + "shouldOverrideUrlLoadingArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), shouldOverrideUrlLoadingArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.dispose", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } + private static class WebViewClientFlutterApiCodec extends StandardMessageCodec { public static final WebViewClientFlutterApiCodec INSTANCE = new WebViewClientFlutterApiCodec(); + private WebViewClientFlutterApiCodec() {} + @Override protected Object readValueOfType(byte type, ByteBuffer buffer) { switch (type) { - case (byte)128: + case (byte) 128: return WebResourceErrorData.fromMap((Map) readValue(buffer)); - - case (byte)129: + + case (byte) 129: return WebResourceRequestData.fromMap((Map) readValue(buffer)); - - case (byte)130: + + case (byte) 130: return WebResourceRequestData.fromMap((Map) readValue(buffer)); - - default: + + default: return super.readValueOfType(type, buffer); - } } + @Override - protected void writeValue(ByteArrayOutputStream stream, Object value) { + protected void writeValue(ByteArrayOutputStream stream, Object value) { if (value instanceof WebResourceErrorData) { stream.write(128); writeValue(stream, ((WebResourceErrorData) value).toMap()); - } else - if (value instanceof WebResourceRequestData) { + } else if (value instanceof WebResourceRequestData) { stream.write(129); writeValue(stream, ((WebResourceRequestData) value).toMap()); - } else - if (value instanceof WebResourceRequestData) { + } else if (value instanceof WebResourceRequestData) { stream.write(130); writeValue(stream, ((WebResourceRequestData) value).toMap()); - } else -{ + } else { super.writeValue(stream, value); } } } - /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ public static class WebViewClientFlutterApi { private final BinaryMessenger binaryMessenger; - public WebViewClientFlutterApi(BinaryMessenger argBinaryMessenger){ + + public WebViewClientFlutterApi(BinaryMessenger argBinaryMessenger) { this.binaryMessenger = argBinaryMessenger; } + public interface Reply { void reply(T reply); } + static MessageCodec getCodec() { return WebViewClientFlutterApiCodec.INSTANCE; } - public void onPageStarted(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + public void onPageStarted( + Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), + channelReply -> { + callback.reply(null); + }); } - public void onPageFinished(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + + public void onPageFinished( + Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), + channelReply -> { + callback.reply(null); + }); } - public void onReceivedRequestError(Long instanceIdArg, Long webViewInstanceIdArg, WebResourceRequestData requestArg, WebResourceErrorData errorArg, Reply callback) { + + public void onReceivedRequestError( + Long instanceIdArg, + Long webViewInstanceIdArg, + WebResourceRequestData requestArg, + WebResourceErrorData errorArg, + Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg, errorArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError", + getCodec()); + channel.send( + new ArrayList( + Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg, errorArg)), + channelReply -> { + callback.reply(null); + }); } - public void onReceivedError(Long instanceIdArg, Long webViewInstanceIdArg, Long errorCodeArg, String descriptionArg, String failingUrlArg, Reply callback) { + + public void onReceivedError( + Long instanceIdArg, + Long webViewInstanceIdArg, + Long errorCodeArg, + String descriptionArg, + String failingUrlArg, + Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, errorCodeArg, descriptionArg, failingUrlArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError", + getCodec()); + channel.send( + new ArrayList( + Arrays.asList( + instanceIdArg, + webViewInstanceIdArg, + errorCodeArg, + descriptionArg, + failingUrlArg)), + channelReply -> { + callback.reply(null); + }); } - public void requestLoading(Long instanceIdArg, Long webViewInstanceIdArg, WebResourceRequestData requestArg, Reply callback) { + + public void requestLoading( + Long instanceIdArg, + Long webViewInstanceIdArg, + WebResourceRequestData requestArg, + Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg)), + channelReply -> { + callback.reply(null); + }); } - public void urlLoading(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + + public void urlLoading( + Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading", getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), + channelReply -> { + callback.reply(null); + }); } } + private static class DownloadListenerHostApiCodec extends StandardMessageCodec { public static final DownloadListenerHostApiCodec INSTANCE = new DownloadListenerHostApiCodec(); + private DownloadListenerHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface DownloadListenerHostApi { void create(Long instanceId); + void dispose(Long instanceId); /** The codec used by DownloadListenerHostApi. */ @@ -1376,84 +1635,115 @@ static MessageCodec getCodec() { return DownloadListenerHostApiCodec.INSTANCE; } - /** Sets up an instance of `DownloadListenerHostApi` to handle messages through the `binaryMessenger`. */ + /** + * Sets up an instance of `DownloadListenerHostApi` to handle messages through the + * `binaryMessenger`. + */ static void setup(BinaryMessenger binaryMessenger, DownloadListenerHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.create", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.create(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.create(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.dispose", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } + private static class DownloadListenerFlutterApiCodec extends StandardMessageCodec { - public static final DownloadListenerFlutterApiCodec INSTANCE = new DownloadListenerFlutterApiCodec(); + public static final DownloadListenerFlutterApiCodec INSTANCE = + new DownloadListenerFlutterApiCodec(); + private DownloadListenerFlutterApiCodec() {} } - /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ public static class DownloadListenerFlutterApi { private final BinaryMessenger binaryMessenger; - public DownloadListenerFlutterApi(BinaryMessenger argBinaryMessenger){ + + public DownloadListenerFlutterApi(BinaryMessenger argBinaryMessenger) { this.binaryMessenger = argBinaryMessenger; } + public interface Reply { void reply(T reply); } + static MessageCodec getCodec() { return DownloadListenerFlutterApiCodec.INSTANCE; } - public void onDownloadStart(Long instanceIdArg, String urlArg, String userAgentArg, String contentDispositionArg, String mimetypeArg, Long contentLengthArg, Reply callback) { + public void onDownloadStart( + Long instanceIdArg, + String urlArg, + String userAgentArg, + String contentDispositionArg, + String mimetypeArg, + Long contentLengthArg, + Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, urlArg, userAgentArg, contentDispositionArg, mimetypeArg, contentLengthArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart", + getCodec()); + channel.send( + new ArrayList( + Arrays.asList( + instanceIdArg, + urlArg, + userAgentArg, + contentDispositionArg, + mimetypeArg, + contentLengthArg)), + channelReply -> { + callback.reply(null); + }); } } + private static Map wrapError(Throwable exception) { Map errorMap = new HashMap<>(); errorMap.put("message", exception.toString()); diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java index bc00ade10632..2feb2cb196ad 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -3,14 +3,16 @@ import android.os.Handler; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; -public class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.JavaScriptChannelHostApi { +public class JavaScriptChannelHostApiImpl + implements GeneratedAndroidWebView.JavaScriptChannelHostApi { private final InstanceManager instanceManager; private final JavaScriptChannelFlutterApi javaScriptChannelFlutterApi; private final Handler platformThreadHandler; - JavaScriptChannelHostApiImpl(InstanceManager instanceManager, - JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, - Handler platformThreadHandler) { + JavaScriptChannelHostApiImpl( + InstanceManager instanceManager, + JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, + Handler platformThreadHandler) { this.instanceManager = instanceManager; this.javaScriptChannelFlutterApi = javaScriptChannelFlutterApi; this.platformThreadHandler = platformThreadHandler; @@ -18,12 +20,13 @@ public class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.Jav @Override public void create(Long instanceId, String channelName) { - final JavaScriptChannel javaScriptChannel = new JavaScriptChannel(null, channelName, platformThreadHandler) { - @Override - public void postMessage(String message) { - javaScriptChannelFlutterApi.postMessage(instanceId, message, reply -> { }); - } - }; + final JavaScriptChannel javaScriptChannel = + new JavaScriptChannel(null, channelName, platformThreadHandler) { + @Override + public void postMessage(String message) { + javaScriptChannelFlutterApi.postMessage(instanceId, message, reply -> {}); + } + }; instanceManager.addInstance(javaScriptChannel, instanceId); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java index af21e5c43791..a45bf994627c 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java @@ -6,92 +6,101 @@ import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; - import androidx.annotation.RequiresApi; - import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientFlutterApi; public class WebViewClientHostApiImpl implements GeneratedAndroidWebView.WebViewClientHostApi { private final InstanceManager instanceManager; private final WebViewClientFlutterApi webViewClientFlutterApi; - WebViewClientHostApiImpl(InstanceManager instanceManager, WebViewClientFlutterApi webViewClientFlutterApi) { + WebViewClientHostApiImpl( + InstanceManager instanceManager, WebViewClientFlutterApi webViewClientFlutterApi) { this.instanceManager = instanceManager; this.webViewClientFlutterApi = webViewClientFlutterApi; } @Override public void create(Long instanceId, Boolean shouldOverrideUrlLoading) { - final WebViewClient webViewClient = new WebViewClient() { - @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - webViewClientFlutterApi.onPageStarted(instanceId, instanceManager.getInstanceId(view), url, reply -> { }); - } + final WebViewClient webViewClient = + new WebViewClient() { + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + webViewClientFlutterApi.onPageStarted( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } - @Override - public void onPageFinished(WebView view, String url) { - webViewClientFlutterApi.onPageFinished(instanceId, instanceManager.getInstanceId(view), url, reply -> { }); - } + @Override + public void onPageFinished(WebView view, String url) { + webViewClientFlutterApi.onPageFinished( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } - @RequiresApi(api = Build.VERSION_CODES.M) - @Override - public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { - final GeneratedAndroidWebView.WebResourceRequestData requestData = new GeneratedAndroidWebView.WebResourceRequestData(); - requestData.setUrl(request.getUrl().toString()); - requestData.setIsForMainFrame(request.isForMainFrame()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - requestData.setIsRedirect(request.isRedirect()); - } - requestData.setHasGesture(request.hasGesture()); - requestData.setMethod(request.getMethod()); - requestData.setRequestHeaders(request.getRequestHeaders()); + @RequiresApi(api = Build.VERSION_CODES.M) + @Override + public void onReceivedError( + WebView view, WebResourceRequest request, WebResourceError error) { + final GeneratedAndroidWebView.WebResourceRequestData requestData = + new GeneratedAndroidWebView.WebResourceRequestData(); + requestData.setUrl(request.getUrl().toString()); + requestData.setIsForMainFrame(request.isForMainFrame()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + requestData.setIsRedirect(request.isRedirect()); + } + requestData.setHasGesture(request.hasGesture()); + requestData.setMethod(request.getMethod()); + requestData.setRequestHeaders(request.getRequestHeaders()); - final GeneratedAndroidWebView.WebResourceErrorData errorData = new GeneratedAndroidWebView.WebResourceErrorData(); - errorData.setErrorCode((long) error.getErrorCode()); - errorData.setDescription(error.getDescription().toString()); + final GeneratedAndroidWebView.WebResourceErrorData errorData = + new GeneratedAndroidWebView.WebResourceErrorData(); + errorData.setErrorCode((long) error.getErrorCode()); + errorData.setDescription(error.getDescription().toString()); - webViewClientFlutterApi.onReceivedRequestError(instanceId, - instanceManager.getInstanceId(view), - requestData, - errorData, reply -> { }); - } + webViewClientFlutterApi.onReceivedRequestError( + instanceId, + instanceManager.getInstanceId(view), + requestData, + errorData, + reply -> {}); + } - @Override - public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { - webViewClientFlutterApi.onReceivedError(instanceId, - instanceManager.getInstanceId(view), - (long) errorCode, description, - failingUrl, reply -> { }); - } + @Override + public void onReceivedError( + WebView view, int errorCode, String description, String failingUrl) { + webViewClientFlutterApi.onReceivedError( + instanceId, + instanceManager.getInstanceId(view), + (long) errorCode, + description, + failingUrl, + reply -> {}); + } - @RequiresApi(api = Build.VERSION_CODES.M) - @Override - public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { - final GeneratedAndroidWebView.WebResourceRequestData requestData = new GeneratedAndroidWebView.WebResourceRequestData(); - requestData.setUrl(request.getUrl().toString()); - requestData.setIsForMainFrame(request.isForMainFrame()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - requestData.setIsRedirect(request.isRedirect()); - } - requestData.setHasGesture(request.hasGesture()); - requestData.setMethod(request.getMethod()); - requestData.setRequestHeaders(request.getRequestHeaders()); + @RequiresApi(api = Build.VERSION_CODES.M) + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + final GeneratedAndroidWebView.WebResourceRequestData requestData = + new GeneratedAndroidWebView.WebResourceRequestData(); + requestData.setUrl(request.getUrl().toString()); + requestData.setIsForMainFrame(request.isForMainFrame()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + requestData.setIsRedirect(request.isRedirect()); + } + requestData.setHasGesture(request.hasGesture()); + requestData.setMethod(request.getMethod()); + requestData.setRequestHeaders(request.getRequestHeaders()); - webViewClientFlutterApi.requestLoading(instanceId, - instanceManager.getInstanceId(view), - requestData, reply -> {}); - return shouldOverrideUrlLoading; - } + webViewClientFlutterApi.requestLoading( + instanceId, instanceManager.getInstanceId(view), requestData, reply -> {}); + return shouldOverrideUrlLoading; + } - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - webViewClientFlutterApi.urlLoading(instanceId, - instanceManager.getInstanceId(view), - url, - reply -> {}); - return shouldOverrideUrlLoading; - } - }; + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + webViewClientFlutterApi.urlLoading( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + return shouldOverrideUrlLoading; + } + }; instanceManager.addInstance(webViewClient, instanceId); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index 26ef3cfeb755..984bb216abe7 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -5,12 +5,9 @@ import android.webkit.DownloadListener; import android.webkit.WebView; import android.webkit.WebViewClient; - import androidx.annotation.NonNull; - -import java.util.Map; - import io.flutter.plugin.platform.PlatformView; +import java.util.Map; class WebViewHostApiImpl implements GeneratedAndroidWebView.WebViewHostApi { private final InstanceManager instanceManager; @@ -76,7 +73,8 @@ public void onInputConnectionUnlocked() { @Override public void create(Long instanceId, Boolean useHybridComposition) { - final WebView webView = useHybridComposition ? new WebViewImpl(context) : new InputAwareWebViewImpl(context, null); + final WebView webView = + useHybridComposition ? new WebViewImpl(context) : new InputAwareWebViewImpl(context, null); instanceManager.addInstance(webView, instanceId); } @@ -134,7 +132,8 @@ public void clearCache(Long instanceId, Boolean includeDiskFiles) { } @Override - public void evaluateJavascript(Long instanceId, String javascriptString, GeneratedAndroidWebView.Result result) { + public void evaluateJavascript( + Long instanceId, String javascriptString, GeneratedAndroidWebView.Result result) { final WebView webView = (WebView) instanceManager.getInstance(instanceId); webView.evaluateJavascript(javascriptString, result::success); } @@ -183,14 +182,16 @@ public void setWebViewClient(Long instanceId, Long webViewClientInstanceId) { @Override public void addJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId) { final WebView webView = (WebView) instanceManager.getInstance(instanceId); - final JavaScriptChannel javaScriptChannel = (JavaScriptChannel) instanceManager.getInstance(javaScriptChannelInstanceId); + final JavaScriptChannel javaScriptChannel = + (JavaScriptChannel) instanceManager.getInstance(javaScriptChannelInstanceId); webView.addJavascriptInterface(javaScriptChannel, javaScriptChannel.javaScriptChannelName); } @Override public void removeJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId) { final WebView webView = (WebView) instanceManager.getInstance(instanceId); - final JavaScriptChannel javaScriptChannel = (JavaScriptChannel) instanceManager.getInstance(javaScriptChannelInstanceId); + final JavaScriptChannel javaScriptChannel = + (JavaScriptChannel) instanceManager.getInstance(javaScriptChannelInstanceId); webView.removeJavascriptInterface(javaScriptChannel.javaScriptChannelName); } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index 3f7bd1866d1c..c4b0b445aa18 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -19,7 +19,7 @@ const String _nullStringIdentifier = ''; /// guide on invoking a browser with /// [url_launcher](https://pub.dev/packages/url_launcher). /// -/// WebView objects allow you to display web content as part of your wiget +/// WebView objects allow you to display web content as part of your widget /// layout, but lack some of the features of fully-developed browsers. A WebView /// is useful when you need increased control over the UI and advanced /// configuration options that will allow you to embed web pages in a diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart index 109f82e5a8a3..930563cb2ced 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -35,7 +35,8 @@ class WebResourceRequestData { ..isRedirect = pigeonMap['isRedirect'] as bool? ..hasGesture = pigeonMap['hasGesture'] as bool? ..method = pigeonMap['method'] as String? - ..requestHeaders = (pigeonMap['requestHeaders'] as Map?)?.cast(); + ..requestHeaders = (pigeonMap['requestHeaders'] as Map?) + ?.cast(); } } @@ -66,7 +67,8 @@ class WebViewHostApi { /// Constructor for [WebViewHostApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - WebViewHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + WebViewHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; final BinaryMessenger? _binaryMessenger; @@ -74,9 +76,11 @@ class WebViewHostApi { Future create(int arg_instanceId, bool arg_useHybridComposition) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.create', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.create', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = - await channel.send([arg_instanceId, arg_useHybridComposition]) as Map?; + await channel.send([arg_instanceId, arg_useHybridComposition]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -84,7 +88,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -97,7 +102,8 @@ class WebViewHostApi { Future dispose(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.dispose', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.dispose', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -107,7 +113,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -118,11 +125,14 @@ class WebViewHostApi { } } - Future loadUrl(int arg_instanceId, String arg_url, Map arg_headers) async { + Future loadUrl(int arg_instanceId, String arg_url, + Map arg_headers) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.loadUrl', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.loadUrl', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = - await channel.send([arg_instanceId, arg_url, arg_headers]) as Map?; + await channel.send([arg_instanceId, arg_url, arg_headers]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -130,7 +140,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -143,7 +154,8 @@ class WebViewHostApi { Future getUrl(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.getUrl', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.getUrl', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -153,7 +165,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -166,7 +179,8 @@ class WebViewHostApi { Future canGoBack(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.canGoBack', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.canGoBack', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -176,7 +190,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -189,7 +204,8 @@ class WebViewHostApi { Future canGoForward(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.canGoForward', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.canGoForward', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -199,7 +215,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -212,7 +229,8 @@ class WebViewHostApi { Future goBack(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.goBack', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.goBack', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -222,7 +240,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -235,7 +254,8 @@ class WebViewHostApi { Future goForward(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.goForward', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.goForward', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -245,7 +265,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -258,7 +279,8 @@ class WebViewHostApi { Future reload(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.reload', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.reload', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -268,7 +290,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -281,9 +304,11 @@ class WebViewHostApi { Future clearCache(int arg_instanceId, bool arg_includeDiskFiles) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.clearCache', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.clearCache', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = - await channel.send([arg_instanceId, arg_includeDiskFiles]) as Map?; + await channel.send([arg_instanceId, arg_includeDiskFiles]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -291,7 +316,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -302,11 +328,14 @@ class WebViewHostApi { } } - Future evaluateJavascript(int arg_instanceId, String arg_javascriptString) async { + Future evaluateJavascript( + int arg_instanceId, String arg_javascriptString) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.evaluateJavascript', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.evaluateJavascript', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = - await channel.send([arg_instanceId, arg_javascriptString]) as Map?; + await channel.send([arg_instanceId, arg_javascriptString]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -314,7 +343,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -327,7 +357,8 @@ class WebViewHostApi { Future getTitle(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.getTitle', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.getTitle', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -337,7 +368,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -350,9 +382,10 @@ class WebViewHostApi { Future scrollTo(int arg_instanceId, int arg_x, int arg_y) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.scrollTo', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_x, arg_y]) as Map?; + 'dev.flutter.pigeon.WebViewHostApi.scrollTo', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_x, arg_y]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -360,7 +393,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -373,9 +407,10 @@ class WebViewHostApi { Future scrollBy(int arg_instanceId, int arg_x, int arg_y) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.scrollBy', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_x, arg_y]) as Map?; + 'dev.flutter.pigeon.WebViewHostApi.scrollBy', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_x, arg_y]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -383,7 +418,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -396,7 +432,8 @@ class WebViewHostApi { Future getScrollX(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.getScrollX', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.getScrollX', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -406,7 +443,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -419,7 +457,8 @@ class WebViewHostApi { Future getScrollY(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.getScrollY', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.getScrollY', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -429,7 +468,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -442,7 +482,9 @@ class WebViewHostApi { Future setWebContentsDebuggingEnabled(bool arg_enabled) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled', + codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_enabled]) as Map?; if (replyMap == null) { @@ -452,7 +494,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -463,11 +506,14 @@ class WebViewHostApi { } } - Future setWebViewClient(int arg_instanceId, int arg_webViewClientInstanceId) async { + Future setWebViewClient( + int arg_instanceId, int arg_webViewClientInstanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.setWebViewClient', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_webViewClientInstanceId]) as Map?; + 'dev.flutter.pigeon.WebViewHostApi.setWebViewClient', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_webViewClientInstanceId]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -475,7 +521,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -486,11 +533,14 @@ class WebViewHostApi { } } - Future addJavaScriptChannel(int arg_instanceId, int arg_javaScriptChannelInstanceId) async { + Future addJavaScriptChannel( + int arg_instanceId, int arg_javaScriptChannelInstanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_javaScriptChannelInstanceId]) as Map?; + 'dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_javaScriptChannelInstanceId]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -498,7 +548,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -509,11 +560,14 @@ class WebViewHostApi { } } - Future removeJavaScriptChannel(int arg_instanceId, int arg_javaScriptChannelInstanceId) async { + Future removeJavaScriptChannel( + int arg_instanceId, int arg_javaScriptChannelInstanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_javaScriptChannelInstanceId]) as Map?; + 'dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_javaScriptChannelInstanceId]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -521,7 +575,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -532,11 +587,14 @@ class WebViewHostApi { } } - Future setDownloadListener(int arg_instanceId, int arg_listenerInstanceId) async { + Future setDownloadListener( + int arg_instanceId, int arg_listenerInstanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.setDownloadListener', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewHostApi.setDownloadListener', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = - await channel.send([arg_instanceId, arg_listenerInstanceId]) as Map?; + await channel.send([arg_instanceId, arg_listenerInstanceId]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -544,7 +602,8 @@ class WebViewHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -564,7 +623,8 @@ class WebSettingsHostApi { /// Constructor for [WebSettingsHostApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - WebSettingsHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + WebSettingsHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; final BinaryMessenger? _binaryMessenger; @@ -572,9 +632,11 @@ class WebSettingsHostApi { Future create(int arg_instanceId, int arg_webViewInstanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.create', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.create', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = - await channel.send([arg_instanceId, arg_webViewInstanceId]) as Map?; + await channel.send([arg_instanceId, arg_webViewInstanceId]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -582,7 +644,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -595,7 +658,8 @@ class WebSettingsHostApi { Future dispose(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.dispose', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.dispose', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -605,7 +669,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -618,9 +683,10 @@ class WebSettingsHostApi { Future setDomStorageEnabled(int arg_instanceId, bool arg_flag) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_flag]) as Map?; + 'dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_flag]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -628,7 +694,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -639,11 +706,14 @@ class WebSettingsHostApi { } } - Future setJavaScriptCanOpenWindowsAutomatically(int arg_instanceId, bool arg_flag) async { + Future setJavaScriptCanOpenWindowsAutomatically( + int arg_instanceId, bool arg_flag) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_flag]) as Map?; + 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically', + codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_flag]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -651,7 +721,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -662,11 +733,14 @@ class WebSettingsHostApi { } } - Future setSupportMultipleWindows(int arg_instanceId, bool arg_support) async { + Future setSupportMultipleWindows( + int arg_instanceId, bool arg_support) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_support]) as Map?; + 'dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows', + codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_support]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -674,7 +748,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -687,9 +762,10 @@ class WebSettingsHostApi { Future setJavaScriptEnabled(int arg_instanceId, bool arg_flag) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_flag]) as Map?; + 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_flag]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -697,7 +773,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -708,11 +785,14 @@ class WebSettingsHostApi { } } - Future setUserAgentString(int arg_instanceId, String arg_userAgentString) async { + Future setUserAgentString( + int arg_instanceId, String arg_userAgentString) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = - await channel.send([arg_instanceId, arg_userAgentString]) as Map?; + await channel.send([arg_instanceId, arg_userAgentString]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -720,7 +800,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -731,11 +812,14 @@ class WebSettingsHostApi { } } - Future setMediaPlaybackRequiresUserGesture(int arg_instanceId, bool arg_require) async { + Future setMediaPlaybackRequiresUserGesture( + int arg_instanceId, bool arg_require) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_require]) as Map?; + 'dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture', + codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_require]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -743,7 +827,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -756,9 +841,10 @@ class WebSettingsHostApi { Future setSupportZoom(int arg_instanceId, bool arg_support) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_support]) as Map?; + 'dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_support]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -766,7 +852,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -777,11 +864,13 @@ class WebSettingsHostApi { } } - Future setLoadWithOverviewMode(int arg_instanceId, bool arg_overview) async { + Future setLoadWithOverviewMode( + int arg_instanceId, bool arg_overview) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_overview]) as Map?; + 'dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_overview]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -789,7 +878,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -802,9 +892,10 @@ class WebSettingsHostApi { Future setUseWideViewPort(int arg_instanceId, bool arg_use) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_use]) as Map?; + 'dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_use]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -812,7 +903,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -823,11 +915,13 @@ class WebSettingsHostApi { } } - Future setDisplayZoomControls(int arg_instanceId, bool arg_enabled) async { + Future setDisplayZoomControls( + int arg_instanceId, bool arg_enabled) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_enabled]) as Map?; + 'dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_enabled]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -835,7 +929,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -846,11 +941,13 @@ class WebSettingsHostApi { } } - Future setBuiltInZoomControls(int arg_instanceId, bool arg_enabled) async { + Future setBuiltInZoomControls( + int arg_instanceId, bool arg_enabled) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_enabled]) as Map?; + 'dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_enabled]) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -858,7 +955,8 @@ class WebSettingsHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -878,7 +976,8 @@ class JavaScriptChannelHostApi { /// Constructor for [JavaScriptChannelHostApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - JavaScriptChannelHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + JavaScriptChannelHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; final BinaryMessenger? _binaryMessenger; @@ -886,9 +985,11 @@ class JavaScriptChannelHostApi { Future create(int arg_instanceId, String arg_channelName) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.JavaScriptChannelHostApi.create', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.JavaScriptChannelHostApi.create', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = - await channel.send([arg_instanceId, arg_channelName]) as Map?; + await channel.send([arg_instanceId, arg_channelName]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -896,7 +997,8 @@ class JavaScriptChannelHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -909,7 +1011,8 @@ class JavaScriptChannelHostApi { Future dispose(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.JavaScriptChannelHostApi.dispose', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.JavaScriptChannelHostApi.dispose', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -919,7 +1022,8 @@ class JavaScriptChannelHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -934,8 +1038,10 @@ class JavaScriptChannelHostApi { class _JavaScriptChannelFlutterApiCodec extends StandardMessageCodec { const _JavaScriptChannelFlutterApiCodec(); } + abstract class JavaScriptChannelFlutterApi { - static const MessageCodec codec = _JavaScriptChannelFlutterApiCodec(); + static const MessageCodec codec = + _JavaScriptChannelFlutterApiCodec(); void postMessage(int instanceId, String message); static void setup(JavaScriptChannelFlutterApi? api) { @@ -946,12 +1052,15 @@ abstract class JavaScriptChannelFlutterApi { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null, expected non-null int.'); final String? arg_message = args[1] as String?; - assert(arg_message != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null, expected non-null String.'); + assert(arg_message != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null, expected non-null String.'); api.postMessage(arg_instanceId!, arg_message!); return; }); @@ -968,17 +1077,21 @@ class WebViewClientHostApi { /// Constructor for [WebViewClientHostApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - WebViewClientHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + WebViewClientHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; final BinaryMessenger? _binaryMessenger; static const MessageCodec codec = _WebViewClientHostApiCodec(); - Future create(int arg_instanceId, bool arg_shouldOverrideUrlLoading) async { + Future create( + int arg_instanceId, bool arg_shouldOverrideUrlLoading) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientHostApi.create', codec, binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_shouldOverrideUrlLoading]) as Map?; + 'dev.flutter.pigeon.WebViewClientHostApi.create', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_shouldOverrideUrlLoading]) + as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -986,7 +1099,8 @@ class WebViewClientHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -999,7 +1113,8 @@ class WebViewClientHostApi { Future dispose(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientHostApi.dispose', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.WebViewClientHostApi.dispose', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -1009,7 +1124,8 @@ class WebViewClientHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -1028,45 +1144,46 @@ class _WebViewClientFlutterApiCodec extends StandardMessageCodec { if (value is WebResourceErrorData) { buffer.putUint8(128); writeValue(buffer, value.encode()); - } else - if (value is WebResourceRequestData) { + } else if (value is WebResourceRequestData) { buffer.putUint8(129); writeValue(buffer, value.encode()); - } else - if (value is WebResourceRequestData) { + } else if (value is WebResourceRequestData) { buffer.putUint8(130); writeValue(buffer, value.encode()); - } else -{ + } else { super.writeValue(buffer, value); } } + @override Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { - case 128: + case 128: return WebResourceErrorData.decode(readValue(buffer)!); - - case 129: + + case 129: return WebResourceRequestData.decode(readValue(buffer)!); - - case 130: + + case 130: return WebResourceRequestData.decode(readValue(buffer)!); - - default: + + default: return super.readValueOfType(type, buffer); - } } } + abstract class WebViewClientFlutterApi { static const MessageCodec codec = _WebViewClientFlutterApiCodec(); void onPageStarted(int instanceId, int webViewInstanceId, String url); void onPageFinished(int instanceId, int webViewInstanceId, String url); - void onReceivedRequestError(int instanceId, int webViewInstanceId, WebResourceRequestData request, WebResourceErrorData error); - void onReceivedError(int instanceId, int webViewInstanceId, int errorCode, String description, String failingUrl); - void requestLoading(int instanceId, int webViewInstanceId, WebResourceRequestData request); + void onReceivedRequestError(int instanceId, int webViewInstanceId, + WebResourceRequestData request, WebResourceErrorData error); + void onReceivedError(int instanceId, int webViewInstanceId, int errorCode, + String description, String failingUrl); + void requestLoading( + int instanceId, int webViewInstanceId, WebResourceRequestData request); void urlLoading(int instanceId, int webViewInstanceId, String url); static void setup(WebViewClientFlutterApi? api) { { @@ -1076,14 +1193,18 @@ abstract class WebViewClientFlutterApi { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null int.'); final int? arg_webViewInstanceId = args[1] as int?; - assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null int.'); + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null int.'); final String? arg_url = args[2] as String?; - assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null String.'); + assert(arg_url != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null String.'); api.onPageStarted(arg_instanceId!, arg_webViewInstanceId!, arg_url!); return; }); @@ -1096,14 +1217,18 @@ abstract class WebViewClientFlutterApi { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null int.'); final int? arg_webViewInstanceId = args[1] as int?; - assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null int.'); + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null int.'); final String? arg_url = args[2] as String?; - assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null String.'); + assert(arg_url != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null String.'); api.onPageFinished(arg_instanceId!, arg_webViewInstanceId!, arg_url!); return; }); @@ -1111,22 +1236,31 @@ abstract class WebViewClientFlutterApi { } { const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError', codec); + 'dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError', + codec); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null int.'); final int? arg_webViewInstanceId = args[1] as int?; - assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null int.'); - final WebResourceRequestData? arg_request = args[2] as WebResourceRequestData?; - assert(arg_request != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null WebResourceRequestData.'); - final WebResourceErrorData? arg_error = args[3] as WebResourceErrorData?; - assert(arg_error != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null WebResourceErrorData.'); - api.onReceivedRequestError(arg_instanceId!, arg_webViewInstanceId!, arg_request!, arg_error!); + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null int.'); + final WebResourceRequestData? arg_request = + args[2] as WebResourceRequestData?; + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null WebResourceRequestData.'); + final WebResourceErrorData? arg_error = + args[3] as WebResourceErrorData?; + assert(arg_error != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null WebResourceErrorData.'); + api.onReceivedRequestError(arg_instanceId!, arg_webViewInstanceId!, + arg_request!, arg_error!); return; }); } @@ -1138,19 +1272,26 @@ abstract class WebViewClientFlutterApi { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); final int? arg_webViewInstanceId = args[1] as int?; - assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); final int? arg_errorCode = args[2] as int?; - assert(arg_errorCode != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); + assert(arg_errorCode != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); final String? arg_description = args[3] as String?; - assert(arg_description != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null String.'); + assert(arg_description != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null String.'); final String? arg_failingUrl = args[4] as String?; - assert(arg_failingUrl != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null String.'); - api.onReceivedError(arg_instanceId!, arg_webViewInstanceId!, arg_errorCode!, arg_description!, arg_failingUrl!); + assert(arg_failingUrl != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null String.'); + api.onReceivedError(arg_instanceId!, arg_webViewInstanceId!, + arg_errorCode!, arg_description!, arg_failingUrl!); return; }); } @@ -1162,15 +1303,21 @@ abstract class WebViewClientFlutterApi { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null int.'); final int? arg_webViewInstanceId = args[1] as int?; - assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null int.'); - final WebResourceRequestData? arg_request = args[2] as WebResourceRequestData?; - assert(arg_request != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null WebResourceRequestData.'); - api.requestLoading(arg_instanceId!, arg_webViewInstanceId!, arg_request!); + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null int.'); + final WebResourceRequestData? arg_request = + args[2] as WebResourceRequestData?; + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null WebResourceRequestData.'); + api.requestLoading( + arg_instanceId!, arg_webViewInstanceId!, arg_request!); return; }); } @@ -1182,14 +1329,18 @@ abstract class WebViewClientFlutterApi { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null int.'); final int? arg_webViewInstanceId = args[1] as int?; - assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null int.'); + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null int.'); final String? arg_url = args[2] as String?; - assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null String.'); + assert(arg_url != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null String.'); api.urlLoading(arg_instanceId!, arg_webViewInstanceId!, arg_url!); return; }); @@ -1206,7 +1357,8 @@ class DownloadListenerHostApi { /// Constructor for [DownloadListenerHostApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - DownloadListenerHostApi({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; + DownloadListenerHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; final BinaryMessenger? _binaryMessenger; @@ -1214,7 +1366,8 @@ class DownloadListenerHostApi { Future create(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.DownloadListenerHostApi.create', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.DownloadListenerHostApi.create', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -1224,7 +1377,8 @@ class DownloadListenerHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -1237,7 +1391,8 @@ class DownloadListenerHostApi { Future dispose(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.DownloadListenerHostApi.dispose', codec, binaryMessenger: _binaryMessenger); + 'dev.flutter.pigeon.DownloadListenerHostApi.dispose', codec, + binaryMessenger: _binaryMessenger); final Map? replyMap = await channel.send([arg_instanceId]) as Map?; if (replyMap == null) { @@ -1247,7 +1402,8 @@ class DownloadListenerHostApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = (replyMap['error'] as Map?)!; + final Map error = + (replyMap['error'] as Map?)!; throw PlatformException( code: (error['code'] as String?)!, message: error['message'] as String?, @@ -1262,33 +1418,44 @@ class DownloadListenerHostApi { class _DownloadListenerFlutterApiCodec extends StandardMessageCodec { const _DownloadListenerFlutterApiCodec(); } + abstract class DownloadListenerFlutterApi { static const MessageCodec codec = _DownloadListenerFlutterApiCodec(); - void onDownloadStart(int instanceId, String url, String userAgent, String contentDisposition, String mimetype, int contentLength); + void onDownloadStart(int instanceId, String url, String userAgent, + String contentDisposition, String mimetype, int contentLength); static void setup(DownloadListenerFlutterApi? api) { { const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart', codec); + 'dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart', + codec); if (api == null) { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null int.'); final String? arg_url = args[1] as String?; - assert(arg_url != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + assert(arg_url != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); final String? arg_userAgent = args[2] as String?; - assert(arg_userAgent != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + assert(arg_userAgent != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); final String? arg_contentDisposition = args[3] as String?; - assert(arg_contentDisposition != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + assert(arg_contentDisposition != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); final String? arg_mimetype = args[4] as String?; - assert(arg_mimetype != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + assert(arg_mimetype != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); final int? arg_contentLength = args[5] as int?; - assert(arg_contentLength != null, 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null int.'); - api.onDownloadStart(arg_instanceId!, arg_url!, arg_userAgent!, arg_contentDisposition!, arg_mimetype!, arg_contentLength!); + assert(arg_contentLength != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null int.'); + api.onDownloadStart(arg_instanceId!, arg_url!, arg_userAgent!, + arg_contentDisposition!, arg_mimetype!, arg_contentLength!); return; }); } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart index bafe0ae00fdb..94d8bc3253eb 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart @@ -7,12 +7,15 @@ class InstanceManager { Map _instanceIdsToInstances = {}; Map _instancesToInstanceIds = {}; - static int _nextInstanceId = 0; + int _nextInstanceId = 0; /// Global instance of [InstanceManager]. static final InstanceManager instance = InstanceManager(); - /// Add a new instance with instanceId. + /// Attempt to add a new instance. + /// + /// Returns new if [instance] has already been added. Otherwise, it is added + /// with a new instance id. int? tryAddInstance(Object instance) { if (_instancesToInstanceIds.containsKey(instance)) { return null; @@ -25,6 +28,9 @@ class InstanceManager { } /// Remove the instance from the manager. + /// + /// Returns null if the instance is removed. Otherwise, return the instanceId + /// of the removed instance. int? removeInstance(Object instance) { final int? instanceId = _instancesToInstanceIds[instance]; if (instanceId != null) { diff --git a/packages/webview_flutter/webview_flutter_android/test/instance_manager_test.dart b/packages/webview_flutter/webview_flutter_android/test/instance_manager_test.dart new file mode 100644 index 000000000000..fd020fc362c8 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/test/instance_manager_test.dart @@ -0,0 +1,35 @@ +// 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. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:webview_flutter_android/src/instance_manager.dart'; + +void main() { + group('$InstanceManager', () { + late InstanceManager testInstanceManager; + + setUp(() { + testInstanceManager = InstanceManager(); + }); + + test('tryAddInstance', () { + final Object object = Object(); + + expect(testInstanceManager.tryAddInstance(object), 0); + expect(testInstanceManager.getInstanceId(object), 0); + expect(testInstanceManager.getInstance(0), object); + expect(testInstanceManager.tryAddInstance(object), null); + }); + + test('removeInstance', () { + final Object object = Object(); + testInstanceManager.tryAddInstance(object); + + expect(testInstanceManager.removeInstance(object), 0); + expect(testInstanceManager.getInstanceId(object), null); + expect(testInstanceManager.getInstance(0), null); + expect(testInstanceManager.removeInstance(object), null); + }); + }); +} From ff4b6cfc64284a4cc8c1be81e421029ea4317b15 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 18 Oct 2021 10:34:48 -0700 Subject: [PATCH 09/54] add dart files --- .../generatePigeons.sh | 5 + .../lib/src/android_webview.dart | 591 +++++++ .../lib/src/android_webview.pigeon.dart | 1464 +++++++++++++++++ .../lib/src/android_webview_api_impls.dart | 539 ++++++ .../lib/src/instance_manager.dart | 52 + .../pigeons/android_webview.dart | 168 ++ .../webview_flutter_android/pubspec.yaml | 1 + .../test/instance_manager_test.dart | 35 + 8 files changed, 2855 insertions(+) create mode 100755 packages/webview_flutter/webview_flutter_android/generatePigeons.sh create mode 100644 packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart create mode 100644 packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart create mode 100644 packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart create mode 100644 packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart create mode 100644 packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart create mode 100644 packages/webview_flutter/webview_flutter_android/test/instance_manager_test.dart diff --git a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh new file mode 100755 index 000000000000..d6598017cbda --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh @@ -0,0 +1,5 @@ +flutter pub run pigeon \ +--input pigeons/android_webview.dart \ +--dart_out lib/src/android_webview.pigeon.dart \ +--java_out ./android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java \ +--java_package io.flutter.plugins.webviewflutter diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart new file mode 100644 index 000000000000..c4b0b445aa18 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -0,0 +1,591 @@ +// 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. + +import 'package:flutter/widgets.dart' show AndroidViewSurface; + +import 'android_webview_api_impls.dart'; + +// TODO(bparrishMines): This can be removed once pigeon supports null values. +// Workaround to represent null Strings since pigeon doesn't support null +// values. +const String _nullStringIdentifier = ''; + +/// An Android View that displays web pages. +/// +/// **Basic usage** +/// In most cases, we recommend using a standard web browser, like Chrome, to +/// deliver content to the user. To learn more about web browsers, read the +/// guide on invoking a browser with +/// [url_launcher](https://pub.dev/packages/url_launcher). +/// +/// WebView objects allow you to display web content as part of your widget +/// layout, but lack some of the features of fully-developed browsers. A WebView +/// is useful when you need increased control over the UI and advanced +/// configuration options that will allow you to embed web pages in a +/// specially-designed environment for your app. +/// +/// To learn more about WebView and alternatives for serving web content, read +/// the documentation on +/// [Web-based content](https://developer.android.com/guide/webapps). +class WebView { + /// Constructs a new WebView. + WebView({this.useHybridComposition = false}) { + _api.createFromInstance(this); + } + + static final WebViewHostApiImpl _api = WebViewHostApiImpl(); + + WebViewClient? _currentWebViewClient; + DownloadListener? _currentDownloadListener; + Set _javaScriptChannels = {}; + + /// Whether the [WebView] will be rendered with an [AndroidViewSurface]. + /// + /// This implementation uses hybrid composition to render the WebView Widget. + /// This comes at the cost of some performance on Android versions below 10. + /// See + /// https://flutter.dev/docs/development/platform-integration/platform-views#performance + /// for more information. + /// + /// Defaults to false. + final bool useHybridComposition; + + /// The [WebSettings] object used to control the settings for this WebView. + late final WebSettings settings = WebSettings._(this); + + /// Enables debugging of web contents (HTML / CSS / JavaScript) loaded into any WebViews of this application. + /// + /// This flag can be enabled in order to facilitate debugging of web layouts + /// and JavaScript code running inside WebViews. Please refer to [WebView] + /// documentation for the debugging guide. The default is false. + static Future setWebContentsDebuggingEnabled(bool enabled) { + return _api.setWebContentsDebuggingEnabled(enabled); + } + + /// Loads the given URL with additional HTTP headers, specified as a map from name to value. + /// + /// Note that if this map contains any of the headers that are set by default + /// by this WebView, such as those controlling caching, accept types or the + /// User-Agent, their values may be overridden by this WebView's defaults. + /// + /// Also see compatibility note on [evaluateJavascript]. + Future loadUrl(String url, Map headers) { + return _api.loadUrlFromInstance(this, url, headers); + } + + /// Gets the URL for the current page. + /// + /// This is not always the same as the URL passed to + /// [WebViewClient.onPageStarted] because although the load for that URL has + /// begun, the current page may not have changed. + /// + /// Returns null if no page has been loaded. + Future getUrl() async { + final String result = await _api.getUrlFromInstance(this); + if (result == _nullStringIdentifier) return null; + return result; + } + + /// Whether this WebView has a back history item. + Future canGoBack() { + return _api.canGoBackFromInstance(this); + } + + /// Whether this WebView has a forward history item. + Future canGoForward() { + return _api.canGoForwardFromInstance(this); + } + + /// Goes back in the history of this WebView. + Future goBack() { + return _api.goBackFromInstance(this); + } + + /// Goes forward in the history of this WebView. + Future goForward() { + return _api.goForwardFromInstance(this); + } + + /// Reloads the current URL. + Future reload() { + return _api.reloadFromInstance(this); + } + + /// Clears the resource cache. + /// + /// Note that the cache is per-application, so this will clear the cache for + /// all WebViews used. + Future clearCache(bool includeDiskFiles) { + return _api.clearCacheFromInstance(this, includeDiskFiles); + } + + // TODO(bparrishMines): Update documentation once addJavascriptInterface is added. + /// Asynchronously evaluates JavaScript in the context of the currently displayed page. + /// + /// If non-null, the returned value will be any result returned from that + /// execution. + /// + /// Compatibility note. Applications targeting Android versions N or later, + /// JavaScript state from an empty WebView is no longer persisted across + /// navigations like [loadUrl]. For example, global variables and functions + /// defined before calling [loadUrl]) will not exist in the loaded page. + Future evaluateJavascript(String javascriptString) async { + final String result = await _api.evaluateJavascriptFromInstance( + this, + javascriptString, + ); + if (result == _nullStringIdentifier) return null; + return result; + } + + // TODO(bparrishMines): Update documentation when WebViewClient.onReceivedTitle is added. + /// Gets the title for the current page. + /// + /// Returns null if no page has been loaded. + Future getTitle() async { + final String result = await _api.getTitleFromInstance(this); + if (result == _nullStringIdentifier) return null; + return result; + } + + // TODO(bparrishMines): Update documentation when onScrollChanged is added. + /// Set the scrolled position of your view. + Future scrollTo(int x, int y) { + return _api.scrollToFromInstance(this, x, y); + } + + // TODO(bparrishMines): Update documentation when onScrollChanged is added. + /// Move the scrolled position of your view. + Future scrollBy(int x, int y) { + return _api.scrollByFromInstance(this, x, y); + } + + /// Return the scrolled left position of this view. + /// + /// This is the left edge of the displayed part of your view. You do not + /// need to draw any pixels farther left, since those are outside of the frame + /// of your view on screen. + Future getScrollX() { + return _api.getScrollXFromInstance(this); + } + + /// Return the scrolled top position of this view. + /// + /// This is the top edge of the displayed part of your view. You do not need + /// to draw any pixels above it, since those are outside of the frame of your + /// view on screen. + Future getScrollY() { + return _api.getScrollYFromInstance(this); + } + + /// Sets the [WebViewClient] that will receive various notifications and requests. + /// + /// This will replace the current handler. + Future setWebViewClient(WebViewClient webViewClient) async { + final WebViewClient? currentWebViewClient = _currentWebViewClient; + if (currentWebViewClient != null) { + // ignore: unawaited_futures + WebViewClient._api.disposeFromInstance(currentWebViewClient); + } + + // ignore: unawaited_futures + WebViewClient._api.createFromInstance(webViewClient); + _currentWebViewClient = webViewClient; + return _api.setWebViewClientFromInstance(this, webViewClient); + } + + /// Injects the supplied [JavascriptChannel] into this WebView. + /// + /// The object is injected into all frames of the web page, including all the + /// iframes, using the supplied name. This allows the object's methods to + /// be accessed from JavaScript. + /// + /// Note that injected objects will not appear in JavaScript until the page is + /// next (re)loaded. JavaScript should be enabled before injecting the object. + /// For example: + /// + /// ```dart + /// webview.settings.setJavaScriptEnabled(true); + /// webView.addJavascriptChannel(JavScriptChannel("injectedObject")); + /// webView.loadUrl("about:blank", {}); + /// webView.loadUrl("javascript:injectedObject.postMessage("Hello, World!")", {}); + /// ``` + /// + /// **Important** + /// * Because the object is exposed to all the frames, any frame could obtain + /// the object name and call methods on it. There is no way to tell the + /// calling frame's origin from the app side, so the app must not assume that + /// the caller is trustworthy unless the app can guarantee that no third party + /// content is ever loaded into the WebView even inside an iframe. + Future addJavaScriptChannel(JavaScriptChannel javaScriptChannel) async { + // ignore: unawaited_futures + JavaScriptChannel._api.createFromInstance(javaScriptChannel); + _javaScriptChannels.add(javaScriptChannel); + return _api.addJavaScriptChannelFromInstance(this, javaScriptChannel); + } + + /// Removes a previously injected [JavaScriptChannel] from this WebView. + /// + /// Note that the removal will not be reflected in JavaScript until the page + /// is next (re)loaded. See [addJavaScriptChannel]. + Future removeJavaScriptChannel(JavaScriptChannel javaScriptChannel) { + JavaScriptChannel._api.disposeFromInstance(javaScriptChannel); + _javaScriptChannels.remove(javaScriptChannel); + return _api.removeJavaScriptChannelFromInstance(this, javaScriptChannel); + } + + /// Registers the interface to be used when content can not be handled by the rendering engine, and should be downloaded instead. + /// + /// This will replace the current handler. + Future setDownloadListener(DownloadListener listener) { + final DownloadListener? currentDownloadListener = _currentDownloadListener; + if (currentDownloadListener != null) { + DownloadListener._api.disposeFromInstance(currentDownloadListener); + } + + DownloadListener._api.createFromInstance(listener); + _currentDownloadListener = listener; + return _api.setDownloadListenerFromInstance(this, listener); + } +} + +/// Manages settings state for a [WebView]. +/// +/// When a WebView is first created, it obtains a set of default settings. These +/// default settings will be returned from any getter call. A WebSettings object +/// obtained from [WebView.settings] is tied to the life of the WebView. If a +/// WebView has been destroyed, any method call on [WebSettings] will throw an +/// Exception. +class WebSettings { + WebSettings._(this.webView) { + _api.createFromInstance(this); + } + + /// The webView instance this is attached to. + final WebView webView; + + static final WebSettingsHostApiImpl _api = WebSettingsHostApiImpl(); + + /// Sets whether the DOM storage API is enabled. + /// + /// The default value is false. + Future setDomStorageEnabled(bool flag) { + return _api.setDomStorageEnabledFromInstance(this, flag); + } + + /// Tells JavaScript to open windows automatically. + /// + /// This applies to the JavaScript function `window.open()`. The default is + /// false. + Future setJavaScriptCanOpenWindowsAutomatically(bool flag) { + return _api.setJavaScriptCanOpenWindowsAutomaticallyFromInstance( + this, + flag, + ); + } + + // TODO(bparrishMines): Update documentation when WebChromeClient.onCreateWindow is added. + /// Sets whether the WebView should supports multiple windows. + /// + /// The default is false. + Future setSupportMultipleWindows(bool support) { + return _api.setSupportZoomFromInstance(this, support); + } + + /// Tells the WebView to enable JavaScript execution. + /// + /// The default is false. + Future setJavaScriptEnabled(bool flag) { + return _api.setJavaScriptEnabledFromInstance(this, flag); + } + + /// Sets the WebView's user-agent string. + /// + /// If the string is empty, the system default value will be used. Note that + /// starting from KITKAT Android version, changing the user-agent while + /// loading a web page causes WebView to initiate loading once again. + Future setUserAgentString(String userAgentString) { + return _api.setUserAgentStringFromInstance(this, userAgentString); + } + + /// Sets whether the WebView requires a user gesture to play media. + /// + /// The default is true. + Future setMediaPlaybackRequiresUserGesture(bool require) { + return _api.setMediaPlaybackRequiresUserGestureFromInstance(this, require); + } + + // TODO(bparrishMines): Update documentation when WebView.zoomIn and WebView.zoomOut are added. + /// Sets whether the WebView should support zooming using its on-screen zoom controls and gestures. + /// + /// The particular zoom mechanisms that should be used can be set with + /// [setBuiltInZoomControls]. + /// + /// The default is true. + Future setSupportZoom(bool support) { + return _api.setSupportZoomFromInstance(this, support); + } + + /// Sets whether the WebView loads pages in overview mode, that is, zooms out the content to fit on screen by width. + /// + /// This setting is taken into account when the content width is greater than + /// the width of the WebView control, for example, when [setUseWideViewPort] + /// is enabled. + /// + /// The default is false. + Future setLoadWithOverviewMode(bool overview) { + return _api.setLoadWithOverviewModeFromInstance(this, overview); + } + + /// Sets whether the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. + /// + /// When the value of the setting is false, the layout width is always set to + /// the width of the WebView control in device-independent (CSS) pixels. When + /// the value is true and the page contains the viewport meta tag, the value + /// of the width specified in the tag is used. If the page does not contain + /// the tag or does not provide a width, then a wide viewport will be used. + Future setUseWideViewPort(bool use) { + return _api.setUseWideViewPortFromInstance(this, use); + } + + // TODO(bparrishMines): Update documentation when ZoomButtonsController is added. + /// Sets whether the WebView should display on-screen zoom controls when using the built-in zoom mechanisms. + /// + /// See [setBuiltInZoomControls]. The default is true. However, on-screen zoom + /// controls are deprecated in Android so it's recommended to set this to + /// false. + Future setDisplayZoomControls(bool enabled) { + return _api.setDisplayZoomControlsFromInstance(this, enabled); + } + + // TODO(bparrishMines): Update documentation when ZoomButtonsController is added. + /// Sets whether the WebView should use its built-in zoom mechanisms. + /// + /// The built-in zoom mechanisms comprise on-screen zoom controls, which are + /// displayed over the WebView's content, and the use of a pinch gesture to + /// control zooming. Whether or not these on-screen controls are displayed can + /// be set with [setDisplayZoomControls]. The default is false. + /// + /// The built-in mechanisms are the only currently supported zoom mechanisms, + /// so it is recommended that this setting is always enabled. However, + /// on-screen zoom controls are deprecated in Android so it's recommended to + /// disable [setDisplayZoomControls]. + Future setBuiltInZoomControls(bool enabled) { + return _api.setBuiltInZoomControlsFromInstance(this, enabled); + } +} + +/// Exposes a channel to receive calls from javaScript. +/// +/// See [WebView.addJavaScriptChannel]. +abstract class JavaScriptChannel { + /// Constructs a [JavaScriptChannel]. + JavaScriptChannel(this.channelName); + + static final JavaScriptChannelHostApiImpl _api = + JavaScriptChannelHostApiImpl(); + + /// Used to identify this object to receive messages from javaScript. + final String channelName; + + /// Callback method when javaScript calls `postMessage` on the object instance passed. + void postMessage(String message); +} + +/// Receive various notifications and requests for [WebView]. +abstract class WebViewClient { + /// Constructs a [WebViewClient]. + WebViewClient({this.shouldOverrideUrlLoading = true}); + + /// User authentication failed on server. + static const int errorAuthentication = 0xfffffffc; + + /// Malformed URL. + static const int errorBadUrl = 0xfffffff4; + + /// Failed to connect to the server. + static const int errorConnect = 0xfffffffa; + + /// Failed to perform SSL handshake. + static const int errorFailedSslHandshake = 0xfffffff5; + + /// Generic file error. + static const int errorFile = 0xfffffff3; + + /// File not found. + static const int errorFileNotFound = 0xfffffff2; + + /// Server or proxy hostname lookup failed. + static const int errorHostLookup = 0xfffffffe; + + /// Failed to read or write to the server. + static const int errorIO = 0xfffffff9; + + /// User authentication failed on proxy. + static const int errorProxyAuthentication = 0xfffffffb; + + /// Too many redirects. + static const int errorRedirectLoop = 0xfffffff7; + + /// Connection timed out. + static const int errorTimeout = 0xfffffff8; + + /// Too many requests during this load. + static const int errorTooManyRequests = 0xfffffff1; + + /// Generic error. + static const int errorUnknown = 0xffffffff; + + /// Resource load was canceled by Safe Browsing. + static const int errorUnsafeResource = 0xfffffff0; + + /// Unsupported authentication scheme (not basic or digest). + static const int errorUnsupportedAuthScheme = 0xfffffffd; + + /// Unsupported URI scheme. + static const int errorUnsupportedScheme = 0xfffffff6; + + static final WebViewClientHostApiImpl _api = WebViewClientHostApiImpl(); + + /// Whether loading a url should be overridden. + /// + /// In Java, `shouldOverrideUrlLoading()` and `shouldOverrideRequestLoading()` + /// callbacks must synchronously return a boolean. This sets the default + /// return value. + /// + /// Setting [shouldOverrideUrlLoading] to true causes the current [WebView] to + /// abort loading the URL, while returning false causes the [WebView] to + /// continue loading the URL as usual. [requestLoading] or [urlLoading] will + /// still be called either way. + /// + /// Defaults to true. + final bool shouldOverrideUrlLoading; + + /// Notify the host application that a page has started loading. + /// + /// This method is called once for each main frame load so a page with iframes + /// or framesets will call onPageStarted one time for the main frame. This + /// also means that [onPageStarted] will not be called when the contents of an + /// embedded frame changes, i.e. clicking a link whose target is an iframe, it + /// will also not be called for fragment navigations (navigations to + /// #fragment_id). + void onPageStarted(WebView webView, String url); + + // TODO(bparrishMines): Update documentation when WebView.postVisualStateCallback is added. + /// Notify the host application that a page has finished loading. + /// + /// This method is called only for main frame. Receiving an [onPageFinished] + /// callback does not guarantee that the next frame drawn by WebView will + /// reflect the state of the DOM at this point. + void onPageFinished(WebView webView, String url); + + /// Report web resource loading error to the host application. + /// + /// These errors usually indicate inability to connect to the server. Note + /// that unlike the deprecated version of the callback, the new version will + /// be called for any resource (iframe, image, etc.), not just for the main + /// page. Thus, it is recommended to perform minimum required work in this + /// callback. + void onReceivedRequestError( + WebView webView, + WebResourceRequest request, + WebResourceError error, + ); + + /// Report an error to the host application. + /// + /// These errors are unrecoverable (i.e. the main resource is unavailable). + /// The errorCode parameter corresponds to one of the error* constants. + @Deprecated('Only called on Android version < 23.') + void onReceivedError( + WebView webView, + int errorCode, + String description, + String failingUrl, + ); + + // TODO(bparrishMines): Update documentation once synchronous url handling is supported. + /// When a URL is about to be loaded in the current [WebView]. + /// + /// If a [WebViewClient] is not provided, by default [WebView] will ask + /// Activity Manager to choose the proper handler for the URL. If a + /// [WebViewClient] is provided, setting [shouldOverrideUrlLoading] to true + /// causes the current [WebView] to abort loading the URL, while returning + /// false causes the [WebView] to continue loading the URL as usual. + void requestLoading(WebView webView, WebResourceRequest request); + + // TODO(bparrishMines): Update documentation once synchronous url handling is supported. + /// When a URL is about to be loaded in the current [WebView]. + /// + /// If a [WebViewClient] is not provided, by default [WebView] will ask + /// Activity Manager to choose the proper handler for the URL. If a + /// [WebViewClient] is provided, setting [shouldOverrideUrlLoading] to true + /// causes the current [WebView] to abort loading the URL, while returning + /// false causes the [WebView] to continue loading the URL as usual. + void urlLoading(WebView webView, String url); +} + +/// The interface to be used when content can not be handled by the rendering engine for [WebView], and should be downloaded instead. +abstract class DownloadListener { + static final DownloadListenerHostApiImpl _api = DownloadListenerHostApiImpl(); + + /// Notify the host application that a file should be downloaded. + void onDownloadStart( + String url, + String userAgent, + String contentDisposition, + String mimetype, + int contentLength, + ); +} + +/// Encompasses parameters to the [WebViewClient.requestLoading] method. +class WebResourceRequest { + /// Constructs a [WebResourceRequest]. + WebResourceRequest({ + required this.url, + required this.isForMainFrame, + required this.isRedirect, + required this.hasGesture, + required this.method, + required this.requestHeaders, + }); + + /// Gets the URL for which the resource request was made. + final String url; + + /// Gets whether the request was made in order to fetch the main frame's document. + final isForMainFrame; + + /// Gets whether the request was a result of a server-side redirect. + /// + /// Only supported on Android version >= 24. + final bool? isRedirect; + + /// Gets whether a gesture (such as a click) was associated with the request. + final bool hasGesture; + + /// Gets the method associated with the request, for example "GET". + final String method; + + /// Gets the headers associated with the request. + final Map requestHeaders; +} + +/// Encapsulates information about errors occurred during loading of web resources. +/// +/// See [WebViewClient.onReceivedRequestError]. +class WebResourceError { + /// Constructs a [WebResourceError]. + WebResourceError({ + required this.errorCode, + required this.description, + }); + + /// The integer code of the error (e.g. [WebViewClient.errorAuthentication]. + final int errorCode; + + /// Describes the error. + final String description; +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart new file mode 100644 index 000000000000..930563cb2ced --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -0,0 +1,1464 @@ +// Autogenerated from Pigeon (v1.0.7), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name +// @dart = 2.12 +import 'dart:async'; +import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; + +import 'package:flutter/foundation.dart' show WriteBuffer, ReadBuffer; +import 'package:flutter/services.dart'; + +class WebResourceRequestData { + String? url; + bool? isForMainFrame; + bool? isRedirect; + bool? hasGesture; + String? method; + Map? requestHeaders; + + Object encode() { + final Map pigeonMap = {}; + pigeonMap['url'] = url; + pigeonMap['isForMainFrame'] = isForMainFrame; + pigeonMap['isRedirect'] = isRedirect; + pigeonMap['hasGesture'] = hasGesture; + pigeonMap['method'] = method; + pigeonMap['requestHeaders'] = requestHeaders; + return pigeonMap; + } + + static WebResourceRequestData decode(Object message) { + final Map pigeonMap = message as Map; + return WebResourceRequestData() + ..url = pigeonMap['url'] as String? + ..isForMainFrame = pigeonMap['isForMainFrame'] as bool? + ..isRedirect = pigeonMap['isRedirect'] as bool? + ..hasGesture = pigeonMap['hasGesture'] as bool? + ..method = pigeonMap['method'] as String? + ..requestHeaders = (pigeonMap['requestHeaders'] as Map?) + ?.cast(); + } +} + +class WebResourceErrorData { + int? errorCode; + String? description; + + Object encode() { + final Map pigeonMap = {}; + pigeonMap['errorCode'] = errorCode; + pigeonMap['description'] = description; + return pigeonMap; + } + + static WebResourceErrorData decode(Object message) { + final Map pigeonMap = message as Map; + return WebResourceErrorData() + ..errorCode = pigeonMap['errorCode'] as int? + ..description = pigeonMap['description'] as String?; + } +} + +class _WebViewHostApiCodec extends StandardMessageCodec { + const _WebViewHostApiCodec(); +} + +class WebViewHostApi { + /// Constructor for [WebViewHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + WebViewHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _WebViewHostApiCodec(); + + Future create(int arg_instanceId, bool arg_useHybridComposition) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.create', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_useHybridComposition]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future dispose(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.dispose', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future loadUrl(int arg_instanceId, String arg_url, + Map arg_headers) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.loadUrl', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_url, arg_headers]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future getUrl(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getUrl', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as String?)!; + } + } + + Future canGoBack(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.canGoBack', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as bool?)!; + } + } + + Future canGoForward(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.canGoForward', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as bool?)!; + } + } + + Future goBack(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.goBack', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future goForward(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.goForward', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future reload(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.reload', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future clearCache(int arg_instanceId, bool arg_includeDiskFiles) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.clearCache', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_includeDiskFiles]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future evaluateJavascript( + int arg_instanceId, String arg_javascriptString) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.evaluateJavascript', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_javascriptString]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as String?)!; + } + } + + Future getTitle(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getTitle', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as String?)!; + } + } + + Future scrollTo(int arg_instanceId, int arg_x, int arg_y) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.scrollTo', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_x, arg_y]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future scrollBy(int arg_instanceId, int arg_x, int arg_y) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.scrollBy', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_x, arg_y]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future getScrollX(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getScrollX', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as int?)!; + } + } + + Future getScrollY(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getScrollY', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as int?)!; + } + } + + Future setWebContentsDebuggingEnabled(bool arg_enabled) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled', + codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_enabled]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setWebViewClient( + int arg_instanceId, int arg_webViewClientInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.setWebViewClient', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_webViewClientInstanceId]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future addJavaScriptChannel( + int arg_instanceId, int arg_javaScriptChannelInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_javaScriptChannelInstanceId]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future removeJavaScriptChannel( + int arg_instanceId, int arg_javaScriptChannelInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_javaScriptChannelInstanceId]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setDownloadListener( + int arg_instanceId, int arg_listenerInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.setDownloadListener', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_listenerInstanceId]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + +class _WebSettingsHostApiCodec extends StandardMessageCodec { + const _WebSettingsHostApiCodec(); +} + +class WebSettingsHostApi { + /// Constructor for [WebSettingsHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + WebSettingsHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _WebSettingsHostApiCodec(); + + Future create(int arg_instanceId, int arg_webViewInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.create', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_webViewInstanceId]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future dispose(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.dispose', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setDomStorageEnabled(int arg_instanceId, bool arg_flag) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_flag]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setJavaScriptCanOpenWindowsAutomatically( + int arg_instanceId, bool arg_flag) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically', + codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_flag]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setSupportMultipleWindows( + int arg_instanceId, bool arg_support) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows', + codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_support]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setJavaScriptEnabled(int arg_instanceId, bool arg_flag) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_flag]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setUserAgentString( + int arg_instanceId, String arg_userAgentString) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_userAgentString]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setMediaPlaybackRequiresUserGesture( + int arg_instanceId, bool arg_require) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture', + codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_require]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setSupportZoom(int arg_instanceId, bool arg_support) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_support]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setLoadWithOverviewMode( + int arg_instanceId, bool arg_overview) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_overview]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setUseWideViewPort(int arg_instanceId, bool arg_use) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_use]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setDisplayZoomControls( + int arg_instanceId, bool arg_enabled) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_enabled]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future setBuiltInZoomControls( + int arg_instanceId, bool arg_enabled) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_enabled]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + +class _JavaScriptChannelHostApiCodec extends StandardMessageCodec { + const _JavaScriptChannelHostApiCodec(); +} + +class JavaScriptChannelHostApi { + /// Constructor for [JavaScriptChannelHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + JavaScriptChannelHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _JavaScriptChannelHostApiCodec(); + + Future create(int arg_instanceId, String arg_channelName) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.JavaScriptChannelHostApi.create', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_channelName]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future dispose(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.JavaScriptChannelHostApi.dispose', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + +class _JavaScriptChannelFlutterApiCodec extends StandardMessageCodec { + const _JavaScriptChannelFlutterApiCodec(); +} + +abstract class JavaScriptChannelFlutterApi { + static const MessageCodec codec = + _JavaScriptChannelFlutterApiCodec(); + + void postMessage(int instanceId, String message); + static void setup(JavaScriptChannelFlutterApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null, expected non-null int.'); + final String? arg_message = args[1] as String?; + assert(arg_message != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage was null, expected non-null String.'); + api.postMessage(arg_instanceId!, arg_message!); + return; + }); + } + } + } +} + +class _WebViewClientHostApiCodec extends StandardMessageCodec { + const _WebViewClientHostApiCodec(); +} + +class WebViewClientHostApi { + /// Constructor for [WebViewClientHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + WebViewClientHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _WebViewClientHostApiCodec(); + + Future create( + int arg_instanceId, bool arg_shouldOverrideUrlLoading) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientHostApi.create', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_shouldOverrideUrlLoading]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future dispose(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientHostApi.dispose', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + +class _WebViewClientFlutterApiCodec extends StandardMessageCodec { + const _WebViewClientFlutterApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is WebResourceErrorData) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is WebResourceRequestData) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is WebResourceRequestData) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return WebResourceErrorData.decode(readValue(buffer)!); + + case 129: + return WebResourceRequestData.decode(readValue(buffer)!); + + case 130: + return WebResourceRequestData.decode(readValue(buffer)!); + + default: + return super.readValueOfType(type, buffer); + } + } +} + +abstract class WebViewClientFlutterApi { + static const MessageCodec codec = _WebViewClientFlutterApiCodec(); + + void onPageStarted(int instanceId, int webViewInstanceId, String url); + void onPageFinished(int instanceId, int webViewInstanceId, String url); + void onReceivedRequestError(int instanceId, int webViewInstanceId, + WebResourceRequestData request, WebResourceErrorData error); + void onReceivedError(int instanceId, int webViewInstanceId, int errorCode, + String description, String failingUrl); + void requestLoading( + int instanceId, int webViewInstanceId, WebResourceRequestData request); + void urlLoading(int instanceId, int webViewInstanceId, String url); + static void setup(WebViewClientFlutterApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null int.'); + final String? arg_url = args[2] as String?; + assert(arg_url != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted was null, expected non-null String.'); + api.onPageStarted(arg_instanceId!, arg_webViewInstanceId!, arg_url!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null int.'); + final String? arg_url = args[2] as String?; + assert(arg_url != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished was null, expected non-null String.'); + api.onPageFinished(arg_instanceId!, arg_webViewInstanceId!, arg_url!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError', + codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null int.'); + final WebResourceRequestData? arg_request = + args[2] as WebResourceRequestData?; + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null WebResourceRequestData.'); + final WebResourceErrorData? arg_error = + args[3] as WebResourceErrorData?; + assert(arg_error != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError was null, expected non-null WebResourceErrorData.'); + api.onReceivedRequestError(arg_instanceId!, arg_webViewInstanceId!, + arg_request!, arg_error!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); + final int? arg_errorCode = args[2] as int?; + assert(arg_errorCode != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null int.'); + final String? arg_description = args[3] as String?; + assert(arg_description != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null String.'); + final String? arg_failingUrl = args[4] as String?; + assert(arg_failingUrl != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError was null, expected non-null String.'); + api.onReceivedError(arg_instanceId!, arg_webViewInstanceId!, + arg_errorCode!, arg_description!, arg_failingUrl!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null int.'); + final WebResourceRequestData? arg_request = + args[2] as WebResourceRequestData?; + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading was null, expected non-null WebResourceRequestData.'); + api.requestLoading( + arg_instanceId!, arg_webViewInstanceId!, arg_request!); + return; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null int.'); + final String? arg_url = args[2] as String?; + assert(arg_url != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading was null, expected non-null String.'); + api.urlLoading(arg_instanceId!, arg_webViewInstanceId!, arg_url!); + return; + }); + } + } + } +} + +class _DownloadListenerHostApiCodec extends StandardMessageCodec { + const _DownloadListenerHostApiCodec(); +} + +class DownloadListenerHostApi { + /// Constructor for [DownloadListenerHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + DownloadListenerHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _DownloadListenerHostApiCodec(); + + Future create(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.DownloadListenerHostApi.create', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future dispose(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.DownloadListenerHostApi.dispose', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + +class _DownloadListenerFlutterApiCodec extends StandardMessageCodec { + const _DownloadListenerFlutterApiCodec(); +} + +abstract class DownloadListenerFlutterApi { + static const MessageCodec codec = _DownloadListenerFlutterApiCodec(); + + void onDownloadStart(int instanceId, String url, String userAgent, + String contentDisposition, String mimetype, int contentLength); + static void setup(DownloadListenerFlutterApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart', + codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null int.'); + final String? arg_url = args[1] as String?; + assert(arg_url != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + final String? arg_userAgent = args[2] as String?; + assert(arg_userAgent != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + final String? arg_contentDisposition = args[3] as String?; + assert(arg_contentDisposition != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + final String? arg_mimetype = args[4] as String?; + assert(arg_mimetype != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null String.'); + final int? arg_contentLength = args[5] as int?; + assert(arg_contentLength != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart was null, expected non-null int.'); + api.onDownloadStart(arg_instanceId!, arg_url!, arg_userAgent!, + arg_contentDisposition!, arg_mimetype!, arg_contentLength!); + return; + }); + } + } + } +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart new file mode 100644 index 000000000000..9582b79ab4b6 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -0,0 +1,539 @@ +// 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. + +import 'android_webview.dart'; +import 'android_webview.pigeon.dart'; +import 'instance_manager.dart'; + +/// Host api implementation for [WebView]. +class WebViewHostApiImpl extends WebViewHostApi { + /// Constructs a [WebViewHostApiImpl]. + WebViewHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + /// Maintains instances stored to communicate with java objects. + late final InstanceManager instanceManager; + + /// Helper method to convert instances ids to objects. + Future createFromInstance(WebView instance) async { + final int? instanceId = instanceManager.tryAddInstance(instance); + if (instanceId != null) { + return create(instanceId, instance.useHybridComposition); + } + } + + /// Helper method to convert instances ids to objects. + Future disposeFromInstance(WebView instance) async { + final int? instanceId = instanceManager.removeInstance(instance); + if (instanceId != null) { + return dispose(instanceId); + } + } + + /// Helper method to convert instances ids to objects. + Future loadUrlFromInstance( + WebView instance, + String url, + Map headers, + ) { + return loadUrl(instanceManager.getInstanceId(instance)!, url, headers); + } + + /// Helper method to convert instances ids to objects. + Future getUrlFromInstance(WebView instance) { + return getUrl(instanceManager.getInstanceId(instance)!); + } + + /// Helper method to convert instances ids to objects. + Future canGoBackFromInstance(WebView instance) { + return canGoBack(instanceManager.getInstanceId(instance)!); + } + + /// Helper method to convert instances ids to objects. + Future canGoForwardFromInstance(WebView instance) { + return canGoForward(instanceManager.getInstanceId(instance)!); + } + + /// Helper method to convert instances ids to objects. + Future goBackFromInstance(WebView instance) { + return goBack(instanceManager.getInstanceId(instance)!); + } + + /// Helper method to convert instances ids to objects. + Future goForwardFromInstance(WebView instance) { + return goForward(instanceManager.getInstanceId(instance)!); + } + + /// Helper method to convert instances ids to objects. + Future reloadFromInstance(WebView instance) { + return reload(instanceManager.getInstanceId(instance)!); + } + + /// Helper method to convert instances ids to objects. + Future clearCacheFromInstance(WebView instance, bool includeDiskFiles) { + return clearCache( + instanceManager.getInstanceId(instance)!, + includeDiskFiles, + ); + } + + /// Helper method to convert instances ids to objects. + Future evaluateJavascriptFromInstance( + WebView instance, + String javascriptString, + ) { + return evaluateJavascript( + instanceManager.getInstanceId(instance)!, javascriptString); + } + + /// Helper method to convert instances ids to objects. + Future getTitleFromInstance(WebView instance) { + return getTitle(instanceManager.getInstanceId(instance)!); + } + + /// Helper method to convert instances ids to objects. + Future scrollToFromInstance(WebView instance, int x, int y) { + return scrollTo(instanceManager.getInstanceId(instance)!, x, y); + } + + /// Helper method to convert instances ids to objects. + Future scrollByFromInstance(WebView instance, int x, int y) { + return scrollBy(instanceManager.getInstanceId(instance)!, x, y); + } + + /// Helper method to convert instances ids to objects. + Future getScrollXFromInstance(WebView instance) { + return getScrollX(instanceManager.getInstanceId(instance)!); + } + + /// Helper method to convert instances ids to objects. + Future getScrollYFromInstance(WebView instance) { + return getScrollY(instanceManager.getInstanceId(instance)!); + } + + /// Helper method to convert instances ids to objects. + Future setWebViewClientFromInstance( + WebView instance, + WebViewClient webViewClient, + ) { + return setWebViewClient( + instanceManager.getInstanceId(instance)!, + instanceManager.getInstanceId(webViewClient)!, + ); + } + + /// Helper method to convert instances ids to objects. + Future addJavaScriptChannelFromInstance( + WebView instance, + JavaScriptChannel javaScriptChannel, + ) { + return addJavaScriptChannel( + instanceManager.getInstanceId(instance)!, + instanceManager.getInstanceId(javaScriptChannel)!, + ); + } + + /// Helper method to convert instances ids to objects. + Future removeJavaScriptChannelFromInstance( + WebView instance, + JavaScriptChannel javaScriptChannel, + ) { + return removeJavaScriptChannel( + instanceManager.getInstanceId(instance)!, + instanceManager.getInstanceId(javaScriptChannel)!, + ); + } + + /// Helper method to convert instances ids to objects. + Future setDownloadListenerFromInstance( + WebView instance, + DownloadListener listener, + ) { + return setDownloadListener( + instanceManager.getInstanceId(instance)!, + instanceManager.getInstanceId(listener)!, + ); + } +} + +/// Host api implementation for [WebSettings]. +class WebSettingsHostApiImpl extends WebSettingsHostApi { + /// Constructs a [WebSettingsHostApiImpl]. + WebSettingsHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + /// Maintains instances stored to communicate with java objects. + late final InstanceManager instanceManager; + + /// Helper method to convert instances ids to objects. + Future createFromInstance(WebSettings instance) async { + final int? instanceId = instanceManager.tryAddInstance(instance); + if (instanceId != null) { + return create( + instanceId, + instanceManager.getInstanceId(instance.webView)!, + ); + } + } + + /// Helper method to convert instances ids to objects. + Future disposeFromInstance(WebSettings instance) async { + final int? instanceId = instanceManager.removeInstance(instance); + if (instanceId != null) { + return dispose(instanceId); + } + } + + /// Helper method to convert instances ids to objects. + Future setDomStorageEnabledFromInstance( + WebSettings instance, + bool flag, + ) { + return setDomStorageEnabled(instanceManager.getInstanceId(instance)!, flag); + } + + /// Helper method to convert instances ids to objects. + Future setJavaScriptCanOpenWindowsAutomaticallyFromInstance( + WebSettings instance, + bool flag, + ) { + return setJavaScriptCanOpenWindowsAutomatically( + instanceManager.getInstanceId(instance)!, + flag, + ); + } + + /// Helper method to convert instances ids to objects. + Future setSupportMultipleWindowsFromInstance( + WebSettings instance, + bool support, + ) { + return setSupportMultipleWindows( + instanceManager.getInstanceId(instance)!, support); + } + + /// Helper method to convert instances ids to objects. + Future setJavaScriptEnabledFromInstance( + WebSettings instance, + bool flag, + ) { + return setJavaScriptCanOpenWindowsAutomatically( + instanceManager.getInstanceId(instance)!, + flag, + ); + } + + /// Helper method to convert instances ids to objects. + Future setUserAgentStringFromInstance( + WebSettings instance, + String userAgentString, + ) { + return setUserAgentString( + instanceManager.getInstanceId(instance)!, + userAgentString, + ); + } + + /// Helper method to convert instances ids to objects. + Future setMediaPlaybackRequiresUserGestureFromInstance( + WebSettings instance, + bool require, + ) { + return setMediaPlaybackRequiresUserGesture( + instanceManager.getInstanceId(instance)!, + require, + ); + } + + /// Helper method to convert instances ids to objects. + Future setSupportZoomFromInstance( + WebSettings instance, + bool support, + ) { + return setSupportZoom(instanceManager.getInstanceId(instance)!, support); + } + + /// Helper method to convert instances ids to objects. + Future setLoadWithOverviewModeFromInstance( + WebSettings instance, + bool overview, + ) { + return setLoadWithOverviewMode( + instanceManager.getInstanceId(instance)!, + overview, + ); + } + + /// Helper method to convert instances ids to objects. + Future setUseWideViewPortFromInstance( + WebSettings instance, + bool use, + ) { + return setUseWideViewPort(instanceManager.getInstanceId(instance)!, use); + } + + /// Helper method to convert instances ids to objects. + Future setDisplayZoomControlsFromInstance( + WebSettings instance, + bool enabled, + ) { + return setDisplayZoomControls( + instanceManager.getInstanceId(instance)!, + enabled, + ); + } + + /// Helper method to convert instances ids to objects. + Future setBuiltInZoomControlsFromInstance( + WebSettings instance, + bool enabled, + ) { + return setBuiltInZoomControls( + instanceManager.getInstanceId(instance)!, + enabled, + ); + } +} + +/// Host api implementation for [JavaScriptChannel]. +class JavaScriptChannelHostApiImpl extends JavaScriptChannelHostApi { + /// Constructs a [JavaScriptChannelHostApiImpl]. + JavaScriptChannelHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + /// Maintains instances stored to communicate with java objects. + late final InstanceManager instanceManager; + + /// Helper method to convert instances ids to objects. + Future createFromInstance(JavaScriptChannel instance) async { + final int? instanceId = instanceManager.tryAddInstance(instance); + if (instanceId != null) { + return create(instanceId, instance.channelName); + } + } + + /// Helper method to convert instances ids to objects. + Future disposeFromInstance(JavaScriptChannel instance) async { + final int? instanceId = instanceManager.removeInstance(instance); + if (instanceId != null) { + return dispose(instanceId); + } + } +} + +/// Flutter api implementation for [JavaScriptChannel]. +class JavaScriptChannelFlutterApiImpl extends JavaScriptChannelFlutterApi { + /// Constructs a [JavaScriptChannelFlutterApiImpl]. + JavaScriptChannelHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + /// Maintains instances stored to communicate with java objects. + late final InstanceManager instanceManager; + + @override + void postMessage(int instanceId, String message) { + final JavaScriptChannel instance = + instanceManager.getInstance(instanceId) as JavaScriptChannel; + instance.postMessage(message); + } +} + +/// Host api implementation for [WebViewClient]. +class WebViewClientHostApiImpl extends WebViewClientHostApi { + /// Constructs a [WebViewClientHostApiImpl]. + WebViewClientHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + /// Maintains instances stored to communicate with java objects. + late final InstanceManager instanceManager; + + /// Helper method to convert instances ids to objects. + Future createFromInstance(WebViewClient instance) async { + final int? instanceId = instanceManager.tryAddInstance(instance); + if (instanceId != null) { + return create(instanceId, instance.shouldOverrideUrlLoading); + } + } + + /// Helper method to convert instances ids to objects. + Future disposeFromInstance(WebViewClient instance) async { + final int? instanceId = instanceManager.removeInstance(instance); + if (instanceId != null) { + return dispose(instanceId); + } + } +} + +/// Flutter api implementation for [WebViewClient]. +class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { + /// Constructs a [WebViewClientFlutterApiImpl]. + WebViewClientFlutterApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + /// Maintains instances stored to communicate with java objects. + late final InstanceManager instanceManager; + + @override + void onPageFinished(int instanceId, int webViewInstanceId, String url) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.onPageFinished( + instanceManager.getInstance(webViewInstanceId) as WebView, + url, + ); + } + + @override + void onPageStarted(int instanceId, int webViewInstanceId, String url) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.onPageStarted( + instanceManager.getInstance(webViewInstanceId) as WebView, + url, + ); + } + + @override + void onReceivedError( + int instanceId, + int webViewInstanceId, + int errorCode, + String description, + String failingUrl, + ) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.onReceivedError( + instanceManager.getInstance(webViewInstanceId) as WebView, + errorCode, + description, + failingUrl, + ); + } + + @override + void onReceivedRequestError( + int instanceId, + int webViewInstanceId, + WebResourceRequestData request, + WebResourceErrorData error, + ) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.onReceivedRequestError( + instanceManager.getInstance(webViewInstanceId) as WebView, + WebResourceRequest( + url: request.url!, + isForMainFrame: request.isForMainFrame!, + isRedirect: request.isRedirect, + hasGesture: request.hasGesture!, + method: request.method!, + requestHeaders: request.requestHeaders!.cast(), + ), + WebResourceError( + errorCode: error.errorCode!, + description: error.description!, + ), + ); + } + + @override + void requestLoading( + int instanceId, + int webViewInstanceId, + WebResourceRequestData request, + ) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.requestLoading( + instanceManager.getInstance(webViewInstanceId) as WebView, + WebResourceRequest( + url: request.url!, + isForMainFrame: request.isForMainFrame!, + isRedirect: request.isRedirect, + hasGesture: request.hasGesture!, + method: request.method!, + requestHeaders: request.requestHeaders!.cast(), + ), + ); + } + + @override + void urlLoading( + int instanceId, + int webViewInstanceId, + String url, + ) { + final WebViewClient instance = + instanceManager.getInstance(instanceId) as WebViewClient; + instance.urlLoading( + instanceManager.getInstance(webViewInstanceId) as WebView, + url, + ); + } +} + +/// Host api implementation for [DownloadListener]. +class DownloadListenerHostApiImpl extends DownloadListenerHostApi { + /// Constructs a [DownloadListenerHostApiImpl]. + DownloadListenerHostApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + /// Maintains instances stored to communicate with java objects. + late final InstanceManager instanceManager; + + /// Helper method to convert instances ids to objects. + Future createFromInstance(DownloadListener instance) async { + final int? instanceId = instanceManager.tryAddInstance(instance); + if (instanceId != null) { + return create(instanceId); + } + } + + /// Helper method to convert instances ids to objects. + Future disposeFromInstance(DownloadListener instance) async { + final int? instanceId = instanceManager.removeInstance(instance); + if (instanceId != null) { + return dispose(instanceId); + } + } +} + +/// Flutter api implementation for [DownloadListener]. +class DownloadListenerFlutterApiImpl extends DownloadListenerFlutterApi { + /// Constructs a [DownloadListenerFlutterApiImpl]. + DownloadListenerFlutterApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + /// Maintains instances stored to communicate with java objects. + late final InstanceManager instanceManager; + + @override + void onDownloadStart( + int instanceId, + String url, + String userAgent, + String contentDisposition, + String mimetype, + int contentLength, + ) { + final DownloadListener instance = + instanceManager.getInstance(instanceId) as DownloadListener; + instance.onDownloadStart( + url, + userAgent, + contentDisposition, + mimetype, + contentLength, + ); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart new file mode 100644 index 000000000000..94d8bc3253eb --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/lib/src/instance_manager.dart @@ -0,0 +1,52 @@ +// 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. + +/// Maintains instances stored to communicate with java objects. +class InstanceManager { + Map _instanceIdsToInstances = {}; + Map _instancesToInstanceIds = {}; + + int _nextInstanceId = 0; + + /// Global instance of [InstanceManager]. + static final InstanceManager instance = InstanceManager(); + + /// Attempt to add a new instance. + /// + /// Returns new if [instance] has already been added. Otherwise, it is added + /// with a new instance id. + int? tryAddInstance(Object instance) { + if (_instancesToInstanceIds.containsKey(instance)) { + return null; + } + + final int instanceId = _nextInstanceId++; + _instancesToInstanceIds[instance] = instanceId; + _instanceIdsToInstances[instanceId] = instance; + return instanceId; + } + + /// Remove the instance from the manager. + /// + /// Returns null if the instance is removed. Otherwise, return the instanceId + /// of the removed instance. + int? removeInstance(Object instance) { + final int? instanceId = _instancesToInstanceIds[instance]; + if (instanceId != null) { + _instancesToInstanceIds.remove(instance); + _instanceIdsToInstances.remove(instanceId); + } + return instanceId; + } + + /// Retrieve the Object paired with instanceId. + Object? getInstance(int instanceId) { + return _instanceIdsToInstances[instanceId]; + } + + /// Retrieve the instanceId paired with instance. + int? getInstanceId(Object instance) { + return _instancesToInstanceIds[instance]; + } +} diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart new file mode 100644 index 000000000000..7efbe17861bf --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -0,0 +1,168 @@ +// 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. + +import 'package:pigeon/pigeon.dart'; + +class WebResourceRequestData { + String? url; + bool? isForMainFrame; + bool? isRedirect; + bool? hasGesture; + String? method; + Map? requestHeaders; +} + +class WebResourceErrorData { + int? errorCode; + String? description; +} + +@HostApi() +abstract class WebViewHostApi { + void create(int instanceId, bool useHybridComposition); + + void dispose(int instanceId); + + void loadUrl( + int instanceId, + String url, + Map headers, + ); + + String getUrl(int instanceId); + + bool canGoBack(int instanceId); + + bool canGoForward(int instanceId); + + void goBack(int instanceId); + + void goForward(int instanceId); + + void reload(int instanceId); + + void clearCache(int instanceId, bool includeDiskFiles); + + @async + String evaluateJavascript( + int instanceId, + String javascriptString, + ); + + String getTitle(int instanceId); + + void scrollTo(int instanceId, int x, int y); + + void scrollBy(int instanceId, int x, int y); + + int getScrollX(int instanceId); + + int getScrollY(int instanceId); + + void setWebContentsDebuggingEnabled(bool enabled); + + void setWebViewClient(int instanceId, int webViewClientInstanceId); + + void addJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId); + + void removeJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId); + + void setDownloadListener(int instanceId, int listenerInstanceId); +} + +@HostApi() +abstract class WebSettingsHostApi { + void create(int instanceId, int webViewInstanceId); + + void dispose(int instanceId); + + void setDomStorageEnabled(int instanceId, bool flag); + + void setJavaScriptCanOpenWindowsAutomatically(int instanceId, bool flag); + + void setSupportMultipleWindows(int instanceId, bool support); + + void setJavaScriptEnabled(int instanceId, bool flag); + + void setUserAgentString(int instanceId, String userAgentString); + + void setMediaPlaybackRequiresUserGesture(int instanceId, bool require); + + void setSupportZoom(int instanceId, bool support); + + void setLoadWithOverviewMode(int instanceId, bool overview); + + void setUseWideViewPort(int instanceId, bool use); + + void setDisplayZoomControls(int instanceId, bool enabled); + + void setBuiltInZoomControls(int instanceId, bool enabled); +} + +@HostApi() +abstract class JavaScriptChannelHostApi { + void create(int instanceId, String channelName); + + void dispose(int instanceId); +} + +@FlutterApi() +abstract class JavaScriptChannelFlutterApi { + void postMessage(int instanceId, String message); +} + +@HostApi() +abstract class WebViewClientHostApi { + void create(int instanceId, bool shouldOverrideUrlLoading); + + void dispose(int instanceId); +} + +@FlutterApi() +abstract class WebViewClientFlutterApi { + void onPageStarted(int instanceId, int webViewInstanceId, String url); + + void onPageFinished(int instanceId, int webViewInstanceId, String url); + + void onReceivedRequestError( + int instanceId, + int webViewInstanceId, + WebResourceRequestData request, + WebResourceErrorData error, + ); + + void onReceivedError( + int instanceId, + int webViewInstanceId, + int errorCode, + String description, + String failingUrl, + ); + + void requestLoading( + int instanceId, + int webViewInstanceId, + WebResourceRequestData request, + ); + + void urlLoading(int instanceId, int webViewInstanceId, String url); +} + +@HostApi() +abstract class DownloadListenerHostApi { + void create(int instanceId); + void dispose(int instanceId); +} + +@FlutterApi() +abstract class DownloadListenerFlutterApi { + void onDownloadStart( + int instanceId, + String url, + String userAgent, + String contentDisposition, + String mimetype, + int contentLength, + ); +} diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 36f186087c08..04511e670d4c 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -27,5 +27,6 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter + pigeon: 1.0.7 pedantic: ^1.10.0 diff --git a/packages/webview_flutter/webview_flutter_android/test/instance_manager_test.dart b/packages/webview_flutter/webview_flutter_android/test/instance_manager_test.dart new file mode 100644 index 000000000000..fd020fc362c8 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/test/instance_manager_test.dart @@ -0,0 +1,35 @@ +// 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. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:webview_flutter_android/src/instance_manager.dart'; + +void main() { + group('$InstanceManager', () { + late InstanceManager testInstanceManager; + + setUp(() { + testInstanceManager = InstanceManager(); + }); + + test('tryAddInstance', () { + final Object object = Object(); + + expect(testInstanceManager.tryAddInstance(object), 0); + expect(testInstanceManager.getInstanceId(object), 0); + expect(testInstanceManager.getInstance(0), object); + expect(testInstanceManager.tryAddInstance(object), null); + }); + + test('removeInstance', () { + final Object object = Object(); + testInstanceManager.tryAddInstance(object); + + expect(testInstanceManager.removeInstance(object), 0); + expect(testInstanceManager.getInstanceId(object), null); + expect(testInstanceManager.getInstance(0), null); + expect(testInstanceManager.removeInstance(object), null); + }); + }); +} From 4659d4d5d47888ddc8848ec1eaf795d9e0d3df23 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 18 Oct 2021 11:09:21 -0700 Subject: [PATCH 10/54] ingore deprecated and add license --- .../webview_flutter_android/generatePigeons.sh | 4 ++++ .../lib/src/android_webview.pigeon.dart | 4 ++++ .../lib/src/android_webview_api_impls.dart | 1 + 3 files changed, 9 insertions(+) diff --git a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh index d6598017cbda..9ddb854b21ed 100755 --- a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh +++ b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh @@ -1,3 +1,7 @@ +# 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. + flutter pub run pigeon \ --input pigeons/android_webview.dart \ --dart_out lib/src/android_webview.pigeon.dart \ diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart index 930563cb2ced..206b045e900a 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -1,3 +1,7 @@ +// 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. + // Autogenerated from Pigeon (v1.0.7), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index 9582b79ab4b6..af9d055216ba 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -410,6 +410,7 @@ class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { ) { final WebViewClient instance = instanceManager.getInstance(instanceId) as WebViewClient; + // ignore: deprecated_member_use_from_same_package instance.onReceivedError( instanceManager.getInstance(webViewInstanceId) as WebView, errorCode, From df0034a563e3c0249a1ed8ea7f1033759df0be95 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 18 Oct 2021 15:53:17 -0700 Subject: [PATCH 11/54] add tests --- .../generatePigeons.sh | 3 +- .../lib/src/android_webview.dart | 131 +++++++------ .../lib/src/android_webview.pigeon.dart | 4 - .../lib/src/android_webview_api_impls.dart | 27 ++- .../pigeons/android_webview.dart | 2 +- .../test/android_webview_test.dart | 178 ++++++++++++++++++ .../test/test_binary_messenger.dart | 24 +++ 7 files changed, 300 insertions(+), 69 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart create mode 100644 packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart diff --git a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh index 9ddb854b21ed..6dab4481b600 100755 --- a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh +++ b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh @@ -5,5 +5,4 @@ flutter pub run pigeon \ --input pigeons/android_webview.dart \ --dart_out lib/src/android_webview.pigeon.dart \ ---java_out ./android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java \ ---java_package io.flutter.plugins.webviewflutter +--dart_test_out test/android_webview_test.pigeon.dart diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index c4b0b445aa18..a1ef8968c86f 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart' show AndroidViewSurface; import 'android_webview_api_impls.dart'; -// TODO(bparrishMines): This can be removed once pigeon supports null values. +// TODO(bparrishMines): This can be removed once pigeon supports null values: https://github.com/flutter/flutter/issues/59118 // Workaround to represent null Strings since pigeon doesn't support null // values. const String _nullStringIdentifier = ''; @@ -31,10 +32,12 @@ const String _nullStringIdentifier = ''; class WebView { /// Constructs a new WebView. WebView({this.useHybridComposition = false}) { - _api.createFromInstance(this); + api.createFromInstance(this); } - static final WebViewHostApiImpl _api = WebViewHostApiImpl(); + /// Pigeon Host Api implementation for [WebView]. + @visibleForTesting + static WebViewHostApiImpl api = WebViewHostApiImpl(); WebViewClient? _currentWebViewClient; DownloadListener? _currentDownloadListener; @@ -60,7 +63,7 @@ class WebView { /// and JavaScript code running inside WebViews. Please refer to [WebView] /// documentation for the debugging guide. The default is false. static Future setWebContentsDebuggingEnabled(bool enabled) { - return _api.setWebContentsDebuggingEnabled(enabled); + return api.setWebContentsDebuggingEnabled(enabled); } /// Loads the given URL with additional HTTP headers, specified as a map from name to value. @@ -71,7 +74,7 @@ class WebView { /// /// Also see compatibility note on [evaluateJavascript]. Future loadUrl(String url, Map headers) { - return _api.loadUrlFromInstance(this, url, headers); + return api.loadUrlFromInstance(this, url, headers); } /// Gets the URL for the current page. @@ -82,34 +85,34 @@ class WebView { /// /// Returns null if no page has been loaded. Future getUrl() async { - final String result = await _api.getUrlFromInstance(this); + final String result = await api.getUrlFromInstance(this); if (result == _nullStringIdentifier) return null; return result; } /// Whether this WebView has a back history item. Future canGoBack() { - return _api.canGoBackFromInstance(this); + return api.canGoBackFromInstance(this); } /// Whether this WebView has a forward history item. Future canGoForward() { - return _api.canGoForwardFromInstance(this); + return api.canGoForwardFromInstance(this); } /// Goes back in the history of this WebView. Future goBack() { - return _api.goBackFromInstance(this); + return api.goBackFromInstance(this); } /// Goes forward in the history of this WebView. Future goForward() { - return _api.goForwardFromInstance(this); + return api.goForwardFromInstance(this); } /// Reloads the current URL. Future reload() { - return _api.reloadFromInstance(this); + return api.reloadFromInstance(this); } /// Clears the resource cache. @@ -117,7 +120,7 @@ class WebView { /// Note that the cache is per-application, so this will clear the cache for /// all WebViews used. Future clearCache(bool includeDiskFiles) { - return _api.clearCacheFromInstance(this, includeDiskFiles); + return api.clearCacheFromInstance(this, includeDiskFiles); } // TODO(bparrishMines): Update documentation once addJavascriptInterface is added. @@ -131,7 +134,7 @@ class WebView { /// navigations like [loadUrl]. For example, global variables and functions /// defined before calling [loadUrl]) will not exist in the loaded page. Future evaluateJavascript(String javascriptString) async { - final String result = await _api.evaluateJavascriptFromInstance( + final String result = await api.evaluateJavascriptFromInstance( this, javascriptString, ); @@ -144,7 +147,7 @@ class WebView { /// /// Returns null if no page has been loaded. Future getTitle() async { - final String result = await _api.getTitleFromInstance(this); + final String result = await api.getTitleFromInstance(this); if (result == _nullStringIdentifier) return null; return result; } @@ -152,13 +155,13 @@ class WebView { // TODO(bparrishMines): Update documentation when onScrollChanged is added. /// Set the scrolled position of your view. Future scrollTo(int x, int y) { - return _api.scrollToFromInstance(this, x, y); + return api.scrollToFromInstance(this, x, y); } // TODO(bparrishMines): Update documentation when onScrollChanged is added. /// Move the scrolled position of your view. Future scrollBy(int x, int y) { - return _api.scrollByFromInstance(this, x, y); + return api.scrollByFromInstance(this, x, y); } /// Return the scrolled left position of this view. @@ -167,7 +170,7 @@ class WebView { /// need to draw any pixels farther left, since those are outside of the frame /// of your view on screen. Future getScrollX() { - return _api.getScrollXFromInstance(this); + return api.getScrollXFromInstance(this); } /// Return the scrolled top position of this view. @@ -176,23 +179,26 @@ class WebView { /// to draw any pixels above it, since those are outside of the frame of your /// view on screen. Future getScrollY() { - return _api.getScrollYFromInstance(this); + return api.getScrollYFromInstance(this); } /// Sets the [WebViewClient] that will receive various notifications and requests. /// /// This will replace the current handler. - Future setWebViewClient(WebViewClient webViewClient) async { + Future setWebViewClient(WebViewClient webViewClient) { final WebViewClient? currentWebViewClient = _currentWebViewClient; + + if (webViewClient == currentWebViewClient) { + return Future.value(); + } + if (currentWebViewClient != null) { - // ignore: unawaited_futures - WebViewClient._api.disposeFromInstance(currentWebViewClient); + WebViewClient.api.disposeFromInstance(currentWebViewClient); } - // ignore: unawaited_futures - WebViewClient._api.createFromInstance(webViewClient); + WebViewClient.api.createFromInstance(webViewClient); _currentWebViewClient = webViewClient; - return _api.setWebViewClientFromInstance(this, webViewClient); + return api.setWebViewClientFromInstance(this, webViewClient); } /// Injects the supplied [JavascriptChannel] into this WebView. @@ -218,11 +224,10 @@ class WebView { /// calling frame's origin from the app side, so the app must not assume that /// the caller is trustworthy unless the app can guarantee that no third party /// content is ever loaded into the WebView even inside an iframe. - Future addJavaScriptChannel(JavaScriptChannel javaScriptChannel) async { - // ignore: unawaited_futures - JavaScriptChannel._api.createFromInstance(javaScriptChannel); + Future addJavaScriptChannel(JavaScriptChannel javaScriptChannel) { + JavaScriptChannel.api.createFromInstance(javaScriptChannel); _javaScriptChannels.add(javaScriptChannel); - return _api.addJavaScriptChannelFromInstance(this, javaScriptChannel); + return api.addJavaScriptChannelFromInstance(this, javaScriptChannel); } /// Removes a previously injected [JavaScriptChannel] from this WebView. @@ -230,9 +235,9 @@ class WebView { /// Note that the removal will not be reflected in JavaScript until the page /// is next (re)loaded. See [addJavaScriptChannel]. Future removeJavaScriptChannel(JavaScriptChannel javaScriptChannel) { - JavaScriptChannel._api.disposeFromInstance(javaScriptChannel); _javaScriptChannels.remove(javaScriptChannel); - return _api.removeJavaScriptChannelFromInstance(this, javaScriptChannel); + api.removeJavaScriptChannelFromInstance(this, javaScriptChannel); + return JavaScriptChannel.api.disposeFromInstance(javaScriptChannel); } /// Registers the interface to be used when content can not be handled by the rendering engine, and should be downloaded instead. @@ -240,13 +245,18 @@ class WebView { /// This will replace the current handler. Future setDownloadListener(DownloadListener listener) { final DownloadListener? currentDownloadListener = _currentDownloadListener; + + if (listener == currentDownloadListener) { + return Future.value(); + } + if (currentDownloadListener != null) { - DownloadListener._api.disposeFromInstance(currentDownloadListener); + DownloadListener.api.disposeFromInstance(currentDownloadListener); } - DownloadListener._api.createFromInstance(listener); + DownloadListener.api.createFromInstance(listener); _currentDownloadListener = listener; - return _api.setDownloadListenerFromInstance(this, listener); + return api.setDownloadListenerFromInstance(this, listener); } } @@ -259,19 +269,21 @@ class WebView { /// Exception. class WebSettings { WebSettings._(this.webView) { - _api.createFromInstance(this); + api.createFromInstance(this); } /// The webView instance this is attached to. final WebView webView; - static final WebSettingsHostApiImpl _api = WebSettingsHostApiImpl(); + /// Pigeon Host Api implementation for [WebSettings]. + @visibleForTesting + static WebSettingsHostApiImpl api = WebSettingsHostApiImpl(); /// Sets whether the DOM storage API is enabled. /// /// The default value is false. Future setDomStorageEnabled(bool flag) { - return _api.setDomStorageEnabledFromInstance(this, flag); + return api.setDomStorageEnabledFromInstance(this, flag); } /// Tells JavaScript to open windows automatically. @@ -279,7 +291,7 @@ class WebSettings { /// This applies to the JavaScript function `window.open()`. The default is /// false. Future setJavaScriptCanOpenWindowsAutomatically(bool flag) { - return _api.setJavaScriptCanOpenWindowsAutomaticallyFromInstance( + return api.setJavaScriptCanOpenWindowsAutomaticallyFromInstance( this, flag, ); @@ -290,14 +302,14 @@ class WebSettings { /// /// The default is false. Future setSupportMultipleWindows(bool support) { - return _api.setSupportZoomFromInstance(this, support); + return api.setSupportZoomFromInstance(this, support); } /// Tells the WebView to enable JavaScript execution. /// /// The default is false. Future setJavaScriptEnabled(bool flag) { - return _api.setJavaScriptEnabledFromInstance(this, flag); + return api.setJavaScriptEnabledFromInstance(this, flag); } /// Sets the WebView's user-agent string. @@ -306,14 +318,14 @@ class WebSettings { /// starting from KITKAT Android version, changing the user-agent while /// loading a web page causes WebView to initiate loading once again. Future setUserAgentString(String userAgentString) { - return _api.setUserAgentStringFromInstance(this, userAgentString); + return api.setUserAgentStringFromInstance(this, userAgentString); } /// Sets whether the WebView requires a user gesture to play media. /// /// The default is true. Future setMediaPlaybackRequiresUserGesture(bool require) { - return _api.setMediaPlaybackRequiresUserGestureFromInstance(this, require); + return api.setMediaPlaybackRequiresUserGestureFromInstance(this, require); } // TODO(bparrishMines): Update documentation when WebView.zoomIn and WebView.zoomOut are added. @@ -324,7 +336,7 @@ class WebSettings { /// /// The default is true. Future setSupportZoom(bool support) { - return _api.setSupportZoomFromInstance(this, support); + return api.setSupportZoomFromInstance(this, support); } /// Sets whether the WebView loads pages in overview mode, that is, zooms out the content to fit on screen by width. @@ -335,7 +347,7 @@ class WebSettings { /// /// The default is false. Future setLoadWithOverviewMode(bool overview) { - return _api.setLoadWithOverviewModeFromInstance(this, overview); + return api.setLoadWithOverviewModeFromInstance(this, overview); } /// Sets whether the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. @@ -346,7 +358,7 @@ class WebSettings { /// of the width specified in the tag is used. If the page does not contain /// the tag or does not provide a width, then a wide viewport will be used. Future setUseWideViewPort(bool use) { - return _api.setUseWideViewPortFromInstance(this, use); + return api.setUseWideViewPortFromInstance(this, use); } // TODO(bparrishMines): Update documentation when ZoomButtonsController is added. @@ -356,7 +368,7 @@ class WebSettings { /// controls are deprecated in Android so it's recommended to set this to /// false. Future setDisplayZoomControls(bool enabled) { - return _api.setDisplayZoomControlsFromInstance(this, enabled); + return api.setDisplayZoomControlsFromInstance(this, enabled); } // TODO(bparrishMines): Update documentation when ZoomButtonsController is added. @@ -372,7 +384,7 @@ class WebSettings { /// on-screen zoom controls are deprecated in Android so it's recommended to /// disable [setDisplayZoomControls]. Future setBuiltInZoomControls(bool enabled) { - return _api.setBuiltInZoomControlsFromInstance(this, enabled); + return api.setBuiltInZoomControlsFromInstance(this, enabled); } } @@ -383,14 +395,15 @@ abstract class JavaScriptChannel { /// Constructs a [JavaScriptChannel]. JavaScriptChannel(this.channelName); - static final JavaScriptChannelHostApiImpl _api = - JavaScriptChannelHostApiImpl(); + /// Pigeon Host Api implementation for [JavaScriptChannel]. + @visibleForTesting + static JavaScriptChannelHostApiImpl api = JavaScriptChannelHostApiImpl(); /// Used to identify this object to receive messages from javaScript. final String channelName; /// Callback method when javaScript calls `postMessage` on the object instance passed. - void postMessage(String message); + void postMessage(String message) {} } /// Receive various notifications and requests for [WebView]. @@ -446,7 +459,9 @@ abstract class WebViewClient { /// Unsupported URI scheme. static const int errorUnsupportedScheme = 0xfffffff6; - static final WebViewClientHostApiImpl _api = WebViewClientHostApiImpl(); + /// Pigeon Host Api implementation for [WebViewClient]. + @visibleForTesting + static WebViewClientHostApiImpl api = WebViewClientHostApiImpl(); /// Whether loading a url should be overridden. /// @@ -470,7 +485,7 @@ abstract class WebViewClient { /// embedded frame changes, i.e. clicking a link whose target is an iframe, it /// will also not be called for fragment navigations (navigations to /// #fragment_id). - void onPageStarted(WebView webView, String url); + void onPageStarted(WebView webView, String url) {} // TODO(bparrishMines): Update documentation when WebView.postVisualStateCallback is added. /// Notify the host application that a page has finished loading. @@ -478,7 +493,7 @@ abstract class WebViewClient { /// This method is called only for main frame. Receiving an [onPageFinished] /// callback does not guarantee that the next frame drawn by WebView will /// reflect the state of the DOM at this point. - void onPageFinished(WebView webView, String url); + void onPageFinished(WebView webView, String url) {} /// Report web resource loading error to the host application. /// @@ -491,7 +506,7 @@ abstract class WebViewClient { WebView webView, WebResourceRequest request, WebResourceError error, - ); + ) {} /// Report an error to the host application. /// @@ -503,7 +518,7 @@ abstract class WebViewClient { int errorCode, String description, String failingUrl, - ); + ) {} // TODO(bparrishMines): Update documentation once synchronous url handling is supported. /// When a URL is about to be loaded in the current [WebView]. @@ -513,7 +528,7 @@ abstract class WebViewClient { /// [WebViewClient] is provided, setting [shouldOverrideUrlLoading] to true /// causes the current [WebView] to abort loading the URL, while returning /// false causes the [WebView] to continue loading the URL as usual. - void requestLoading(WebView webView, WebResourceRequest request); + void requestLoading(WebView webView, WebResourceRequest request) {} // TODO(bparrishMines): Update documentation once synchronous url handling is supported. /// When a URL is about to be loaded in the current [WebView]. @@ -523,12 +538,14 @@ abstract class WebViewClient { /// [WebViewClient] is provided, setting [shouldOverrideUrlLoading] to true /// causes the current [WebView] to abort loading the URL, while returning /// false causes the [WebView] to continue loading the URL as usual. - void urlLoading(WebView webView, String url); + void urlLoading(WebView webView, String url) {} } /// The interface to be used when content can not be handled by the rendering engine for [WebView], and should be downloaded instead. abstract class DownloadListener { - static final DownloadListenerHostApiImpl _api = DownloadListenerHostApiImpl(); + /// Pigeon Host Api implementation for [DownloadListener]. + @visibleForTesting + static DownloadListenerHostApiImpl api = DownloadListenerHostApiImpl(); /// Notify the host application that a file should be downloaded. void onDownloadStart( diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart index 206b045e900a..930563cb2ced 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -1,7 +1,3 @@ -// 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. - // Autogenerated from Pigeon (v1.0.7), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index af9d055216ba..121f24b827d9 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/services.dart'; + import 'android_webview.dart'; import 'android_webview.pigeon.dart'; import 'instance_manager.dart'; @@ -9,7 +11,10 @@ import 'instance_manager.dart'; /// Host api implementation for [WebView]. class WebViewHostApiImpl extends WebViewHostApi { /// Constructs a [WebViewHostApiImpl]. - WebViewHostApiImpl({InstanceManager? instanceManager}) { + WebViewHostApiImpl({ + BinaryMessenger? binaryMessenger, + InstanceManager? instanceManager, + }) : super(binaryMessenger: binaryMessenger) { this.instanceManager = instanceManager ?? InstanceManager.instance; } @@ -161,7 +166,10 @@ class WebViewHostApiImpl extends WebViewHostApi { /// Host api implementation for [WebSettings]. class WebSettingsHostApiImpl extends WebSettingsHostApi { /// Constructs a [WebSettingsHostApiImpl]. - WebSettingsHostApiImpl({InstanceManager? instanceManager}) { + WebSettingsHostApiImpl({ + BinaryMessenger? binaryMessenger, + InstanceManager? instanceManager, + }) : super(binaryMessenger: binaryMessenger) { this.instanceManager = instanceManager ?? InstanceManager.instance; } @@ -301,7 +309,10 @@ class WebSettingsHostApiImpl extends WebSettingsHostApi { /// Host api implementation for [JavaScriptChannel]. class JavaScriptChannelHostApiImpl extends JavaScriptChannelHostApi { /// Constructs a [JavaScriptChannelHostApiImpl]. - JavaScriptChannelHostApiImpl({InstanceManager? instanceManager}) { + JavaScriptChannelHostApiImpl({ + BinaryMessenger? binaryMessenger, + InstanceManager? instanceManager, + }) : super(binaryMessenger: binaryMessenger) { this.instanceManager = instanceManager ?? InstanceManager.instance; } @@ -346,7 +357,10 @@ class JavaScriptChannelFlutterApiImpl extends JavaScriptChannelFlutterApi { /// Host api implementation for [WebViewClient]. class WebViewClientHostApiImpl extends WebViewClientHostApi { /// Constructs a [WebViewClientHostApiImpl]. - WebViewClientHostApiImpl({InstanceManager? instanceManager}) { + WebViewClientHostApiImpl({ + BinaryMessenger? binaryMessenger, + InstanceManager? instanceManager, + }) : super(binaryMessenger: binaryMessenger) { this.instanceManager = instanceManager ?? InstanceManager.instance; } @@ -484,7 +498,10 @@ class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { /// Host api implementation for [DownloadListener]. class DownloadListenerHostApiImpl extends DownloadListenerHostApi { /// Constructs a [DownloadListenerHostApiImpl]. - DownloadListenerHostApiImpl({InstanceManager? instanceManager}) { + DownloadListenerHostApiImpl({ + BinaryMessenger? binaryMessenger, + InstanceManager? instanceManager, + }) : super(binaryMessenger: binaryMessenger) { this.instanceManager = instanceManager ?? InstanceManager.instance; } diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart index 7efbe17861bf..7aae9da25968 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -18,7 +18,7 @@ class WebResourceErrorData { String? description; } -@HostApi() +@HostApi(dartHostTestHandler: 'TestWebViewHostApi') abstract class WebViewHostApi { void create(int instanceId, bool useHybridComposition); diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart new file mode 100644 index 000000000000..eaea437f679b --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart @@ -0,0 +1,178 @@ +// 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. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:webview_flutter_android/src/android_webview.dart'; +import 'package:webview_flutter_android/src/android_webview_api_impls.dart'; +import 'package:webview_flutter_android/src/instance_manager.dart'; + +import 'test_binary_messenger.dart'; + +void main() { + group('Android WebView', () { + group('$WebView', () { + setUp(() { + WebView.api = WebViewHostApiImpl( + instanceManager: InstanceManager(), + binaryMessenger: TestBinaryMessenger(), + ); + }); + + tearDownAll(() { + WebView.api = WebViewHostApiImpl(); + }); + + test('create', () { + final WebView webView = WebView(); + expect(WebView.api.instanceManager.getInstanceId(webView), isNotNull); + }); + }); + + group('$WebSettings', () { + setUp(() { + final InstanceManager instanceManager = InstanceManager(); + final TestBinaryMessenger binaryMessenger = TestBinaryMessenger(); + WebView.api = WebViewHostApiImpl( + instanceManager: instanceManager, + binaryMessenger: binaryMessenger, + ); + WebSettings.api = WebSettingsHostApiImpl( + instanceManager: instanceManager, + binaryMessenger: binaryMessenger, + ); + }); + + test('create', () { + final WebView webView = WebView(); + final WebSettings webSettings = webView.settings; + expect( + WebSettings.api.instanceManager.getInstanceId(webSettings), + isNotNull, + ); + }); + }); + + group('$JavaScriptChannel', () { + setUp(() { + final InstanceManager instanceManager = InstanceManager(); + final TestBinaryMessenger binaryMessenger = TestBinaryMessenger(); + WebView.api = WebViewHostApiImpl( + instanceManager: instanceManager, + binaryMessenger: binaryMessenger, + ); + JavaScriptChannel.api = JavaScriptChannelHostApiImpl( + instanceManager: instanceManager, + binaryMessenger: binaryMessenger, + ); + }); + + test('create', () { + final WebView webView = WebView(); + final JavaScriptChannel channel = TestJavaScriptChannel('myChannel'); + + webView.addJavaScriptChannel(channel); + expect( + JavaScriptChannel.api.instanceManager.getInstanceId(channel), + isNotNull, + ); + + webView.removeJavaScriptChannel(channel); + expect( + JavaScriptChannel.api.instanceManager.getInstanceId(channel), + isNull, + ); + }); + }); + + group('$WebViewClient', () { + setUp(() { + final InstanceManager instanceManager = InstanceManager(); + final TestBinaryMessenger binaryMessenger = TestBinaryMessenger(); + WebView.api = WebViewHostApiImpl( + instanceManager: instanceManager, + binaryMessenger: binaryMessenger, + ); + WebViewClient.api = WebViewClientHostApiImpl( + instanceManager: instanceManager, + binaryMessenger: binaryMessenger, + ); + }); + + test('create', () { + final WebView webView = WebView(); + final WebViewClient webViewClient1 = TestWebViewClient(); + final WebViewClient webViewClient2 = TestWebViewClient(); + + webView.setWebViewClient(webViewClient1); + expect( + WebViewClient.api.instanceManager.getInstanceId(webViewClient1), + isNotNull, + ); + + webView.setWebViewClient(webViewClient2); + expect( + WebViewClient.api.instanceManager.getInstanceId(webViewClient1), + isNull, + ); + }); + }); + + group('$DownloadListener', () { + setUp(() { + final InstanceManager instanceManager = InstanceManager(); + final TestBinaryMessenger binaryMessenger = TestBinaryMessenger(); + WebView.api = WebViewHostApiImpl( + instanceManager: instanceManager, + binaryMessenger: binaryMessenger, + ); + DownloadListener.api = DownloadListenerHostApiImpl( + instanceManager: instanceManager, + binaryMessenger: binaryMessenger, + ); + }); + + test('create', () { + final WebView webView = WebView(); + final DownloadListener downloadListener1 = TestDownloadListener(); + final DownloadListener downloadListener2 = TestDownloadListener(); + + webView.setDownloadListener(downloadListener1); + expect( + DownloadListener.api.instanceManager.getInstanceId(downloadListener1), + isNotNull, + ); + + webView.setDownloadListener(downloadListener2); + expect( + DownloadListener.api.instanceManager.getInstanceId(downloadListener1), + isNull, + ); + }); + }); + }); +} + +class TestJavaScriptChannel extends JavaScriptChannel { + TestJavaScriptChannel(String channelName) : super(channelName); + + @override + void postMessage(String message) { + // Do nothing. + } +} + +class TestWebViewClient extends WebViewClient {} + +class TestDownloadListener extends DownloadListener { + @override + void onDownloadStart( + String url, + String userAgent, + String contentDisposition, + String mimetype, + int contentLength, + ) { + // Do nothing. + } +} diff --git a/packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart b/packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart new file mode 100644 index 000000000000..c6e983ccd066 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart @@ -0,0 +1,24 @@ +import 'dart:ui'; + +import 'package:flutter/services.dart'; + +class TestBinaryMessenger implements BinaryMessenger { + @override + Future handlePlatformMessage( + String channel, + ByteData? data, + PlatformMessageResponseCallback? callback, + ) async { + // Do nothing. + } + + @override + Future? send(String channel, ByteData? message) async { + return StandardMessageCodec().encodeMessage({}); + } + + @override + void setMessageHandler(String channel, MessageHandler? handler) { + // Do nothing. + } +} From cf1529c8bbb9d07c71ad71df4fcd55ff80ec1e76 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 18 Oct 2021 15:55:39 -0700 Subject: [PATCH 12/54] add license --- .../webview_flutter_android/test/test_binary_messenger.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart b/packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart index c6e983ccd066..1aac4d25d251 100644 --- a/packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart +++ b/packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart @@ -1,3 +1,7 @@ +// 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. + import 'dart:ui'; import 'package:flutter/services.dart'; From e5ecf8b775e9614a0878877cbc981a30fbe0f236 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 18 Oct 2021 16:29:53 -0700 Subject: [PATCH 13/54] license again --- .../lib/src/android_webview.pigeon.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart index 930563cb2ced..206b045e900a 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -1,3 +1,7 @@ +// 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. + // Autogenerated from Pigeon (v1.0.7), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name From ef3e70230f4db0b2339fa03889936166495304a7 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 18 Oct 2021 17:10:25 -0700 Subject: [PATCH 14/54] remove test file --- .../webview_flutter/webview_flutter_android/generatePigeons.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh index 6dab4481b600..5a009c780505 100755 --- a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh +++ b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh @@ -4,5 +4,4 @@ flutter pub run pigeon \ --input pigeons/android_webview.dart \ ---dart_out lib/src/android_webview.pigeon.dart \ ---dart_test_out test/android_webview_test.pigeon.dart +--dart_out lib/src/android_webview.pigeon.dart From 5010487f53e3b8cdfc39a453ad75f83eae81a8e8 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Tue, 19 Oct 2021 14:10:36 -0700 Subject: [PATCH 15/54] use generated flutter api for testing --- .../generatePigeons.sh | 3 +- .../pigeons/android_webview.dart | 8 +- .../test/android_webview.pigeon.dart | 799 ++++++++++++++++++ .../test/android_webview_test.dart | 214 ++++- 4 files changed, 982 insertions(+), 42 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart diff --git a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh index 5a009c780505..d866473636cc 100755 --- a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh +++ b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh @@ -4,4 +4,5 @@ flutter pub run pigeon \ --input pigeons/android_webview.dart \ ---dart_out lib/src/android_webview.pigeon.dart +--dart_out lib/src/android_webview.pigeon.dart \ +--dart_test_out test/android_webview.pigeon.dart diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart index 7aae9da25968..3c9202bddcdf 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -71,7 +71,7 @@ abstract class WebViewHostApi { void setDownloadListener(int instanceId, int listenerInstanceId); } -@HostApi() +@HostApi(dartHostTestHandler: 'TestWebSettingsHostApi') abstract class WebSettingsHostApi { void create(int instanceId, int webViewInstanceId); @@ -100,7 +100,7 @@ abstract class WebSettingsHostApi { void setBuiltInZoomControls(int instanceId, bool enabled); } -@HostApi() +@HostApi(dartHostTestHandler:'TestJavaScriptChannelHostApi') abstract class JavaScriptChannelHostApi { void create(int instanceId, String channelName); @@ -112,7 +112,7 @@ abstract class JavaScriptChannelFlutterApi { void postMessage(int instanceId, String message); } -@HostApi() +@HostApi(dartHostTestHandler: 'TestWebViewClientHostApi') abstract class WebViewClientHostApi { void create(int instanceId, bool shouldOverrideUrlLoading); @@ -149,7 +149,7 @@ abstract class WebViewClientFlutterApi { void urlLoading(int instanceId, int webViewInstanceId, String url); } -@HostApi() +@HostApi(dartHostTestHandler: 'TestDownloadListenerHostApi') abstract class DownloadListenerHostApi { void create(int instanceId); void dispose(int instanceId); diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart new file mode 100644 index 000000000000..e4fa4b8eb86c --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart @@ -0,0 +1,799 @@ +// 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. + +// Autogenerated from Pigeon (v1.0.7), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import +// @dart = 2.12 +import 'dart:async'; +import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; +import 'package:flutter/foundation.dart' show WriteBuffer, ReadBuffer; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../lib/src/android_webview.pigeon.dart'; + +class _TestWebViewHostApiCodec extends StandardMessageCodec { + const _TestWebViewHostApiCodec(); +} +abstract class TestWebViewHostApi { + static const MessageCodec codec = _TestWebViewHostApiCodec(); + + void create(int instanceId, bool useHybridComposition); + void dispose(int instanceId); + void loadUrl(int instanceId, String url, Map headers); + String getUrl(int instanceId); + bool canGoBack(int instanceId); + bool canGoForward(int instanceId); + void goBack(int instanceId); + void goForward(int instanceId); + void reload(int instanceId); + void clearCache(int instanceId, bool includeDiskFiles); + Future evaluateJavascript(int instanceId, String javascriptString); + String getTitle(int instanceId); + void scrollTo(int instanceId, int x, int y); + void scrollBy(int instanceId, int x, int y); + int getScrollX(int instanceId); + int getScrollY(int instanceId); + void setWebContentsDebuggingEnabled(bool enabled); + void setWebViewClient(int instanceId, int webViewClientInstanceId); + void addJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId); + void removeJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId); + void setDownloadListener(int instanceId, int listenerInstanceId); + static void setup(TestWebViewHostApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.create', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null, expected non-null int.'); + final bool? arg_useHybridComposition = args[1] as bool?; + assert(arg_useHybridComposition != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null, expected non-null bool.'); + api.create(arg_instanceId!, arg_useHybridComposition!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.dispose', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.dispose was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.dispose was null, expected non-null int.'); + api.dispose(arg_instanceId!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.loadUrl', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null int.'); + final String? arg_url = args[1] as String?; + assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null String.'); + final Map? arg_headers = args[2] as Map?; + assert(arg_headers != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null Map.'); + api.loadUrl(arg_instanceId!, arg_url!, arg_headers!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getUrl', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getUrl was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getUrl was null, expected non-null int.'); + final String output = api.getUrl(arg_instanceId!); + return {'result': output}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.canGoBack', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoBack was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoBack was null, expected non-null int.'); + final bool output = api.canGoBack(arg_instanceId!); + return {'result': output}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.canGoForward', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoForward was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoForward was null, expected non-null int.'); + final bool output = api.canGoForward(arg_instanceId!); + return {'result': output}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.goBack', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goBack was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goBack was null, expected non-null int.'); + api.goBack(arg_instanceId!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.goForward', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goForward was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goForward was null, expected non-null int.'); + api.goForward(arg_instanceId!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.reload', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.reload was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.reload was null, expected non-null int.'); + api.reload(arg_instanceId!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.clearCache', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null, expected non-null int.'); + final bool? arg_includeDiskFiles = args[1] as bool?; + assert(arg_includeDiskFiles != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null, expected non-null bool.'); + api.clearCache(arg_instanceId!, arg_includeDiskFiles!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.evaluateJavascript', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null, expected non-null int.'); + final String? arg_javascriptString = args[1] as String?; + assert(arg_javascriptString != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null, expected non-null String.'); + final String output = await api.evaluateJavascript(arg_instanceId!, arg_javascriptString!); + return {'result': output}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getTitle', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getTitle was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getTitle was null, expected non-null int.'); + final String output = api.getTitle(arg_instanceId!); + return {'result': output}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.scrollTo', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); + final int? arg_x = args[1] as int?; + assert(arg_x != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); + final int? arg_y = args[2] as int?; + assert(arg_y != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); + api.scrollTo(arg_instanceId!, arg_x!, arg_y!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.scrollBy', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); + final int? arg_x = args[1] as int?; + assert(arg_x != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); + final int? arg_y = args[2] as int?; + assert(arg_y != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); + api.scrollBy(arg_instanceId!, arg_x!, arg_y!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getScrollX', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollX was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollX was null, expected non-null int.'); + final int output = api.getScrollX(arg_instanceId!); + return {'result': output}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.getScrollY', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollY was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollY was null, expected non-null int.'); + final int output = api.getScrollY(arg_instanceId!); + return {'result': output}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled was null.'); + final List args = (message as List?)!; + final bool? arg_enabled = args[0] as bool?; + assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled was null, expected non-null bool.'); + api.setWebContentsDebuggingEnabled(arg_enabled!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.setWebViewClient', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null, expected non-null int.'); + final int? arg_webViewClientInstanceId = args[1] as int?; + assert(arg_webViewClientInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null, expected non-null int.'); + api.setWebViewClient(arg_instanceId!, arg_webViewClientInstanceId!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null, expected non-null int.'); + final int? arg_javaScriptChannelInstanceId = args[1] as int?; + assert(arg_javaScriptChannelInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null, expected non-null int.'); + api.addJavaScriptChannel(arg_instanceId!, arg_javaScriptChannelInstanceId!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null, expected non-null int.'); + final int? arg_javaScriptChannelInstanceId = args[1] as int?; + assert(arg_javaScriptChannelInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null, expected non-null int.'); + api.removeJavaScriptChannel(arg_instanceId!, arg_javaScriptChannelInstanceId!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.setDownloadListener', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null, expected non-null int.'); + final int? arg_listenerInstanceId = args[1] as int?; + assert(arg_listenerInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null, expected non-null int.'); + api.setDownloadListener(arg_instanceId!, arg_listenerInstanceId!); + return {}; + }); + } + } + } +} + +class _TestWebSettingsHostApiCodec extends StandardMessageCodec { + const _TestWebSettingsHostApiCodec(); +} +abstract class TestWebSettingsHostApi { + static const MessageCodec codec = _TestWebSettingsHostApiCodec(); + + void create(int instanceId, int webViewInstanceId); + void dispose(int instanceId); + void setDomStorageEnabled(int instanceId, bool flag); + void setJavaScriptCanOpenWindowsAutomatically(int instanceId, bool flag); + void setSupportMultipleWindows(int instanceId, bool support); + void setJavaScriptEnabled(int instanceId, bool flag); + void setUserAgentString(int instanceId, String userAgentString); + void setMediaPlaybackRequiresUserGesture(int instanceId, bool require); + void setSupportZoom(int instanceId, bool support); + void setLoadWithOverviewMode(int instanceId, bool overview); + void setUseWideViewPort(int instanceId, bool use); + void setDisplayZoomControls(int instanceId, bool enabled); + void setBuiltInZoomControls(int instanceId, bool enabled); + static void setup(TestWebSettingsHostApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.create', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null, expected non-null int.'); + api.create(arg_instanceId!, arg_webViewInstanceId!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.dispose', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.dispose was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.dispose was null, expected non-null int.'); + api.dispose(arg_instanceId!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null, expected non-null int.'); + final bool? arg_flag = args[1] as bool?; + assert(arg_flag != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null, expected non-null bool.'); + api.setDomStorageEnabled(arg_instanceId!, arg_flag!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null, expected non-null int.'); + final bool? arg_flag = args[1] as bool?; + assert(arg_flag != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null, expected non-null bool.'); + api.setJavaScriptCanOpenWindowsAutomatically(arg_instanceId!, arg_flag!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null, expected non-null int.'); + final bool? arg_support = args[1] as bool?; + assert(arg_support != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null, expected non-null bool.'); + api.setSupportMultipleWindows(arg_instanceId!, arg_support!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null, expected non-null int.'); + final bool? arg_flag = args[1] as bool?; + assert(arg_flag != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null, expected non-null bool.'); + api.setJavaScriptEnabled(arg_instanceId!, arg_flag!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null, expected non-null int.'); + final String? arg_userAgentString = args[1] as String?; + assert(arg_userAgentString != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null, expected non-null String.'); + api.setUserAgentString(arg_instanceId!, arg_userAgentString!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null, expected non-null int.'); + final bool? arg_require = args[1] as bool?; + assert(arg_require != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null, expected non-null bool.'); + api.setMediaPlaybackRequiresUserGesture(arg_instanceId!, arg_require!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null, expected non-null int.'); + final bool? arg_support = args[1] as bool?; + assert(arg_support != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null, expected non-null bool.'); + api.setSupportZoom(arg_instanceId!, arg_support!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null, expected non-null int.'); + final bool? arg_overview = args[1] as bool?; + assert(arg_overview != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null, expected non-null bool.'); + api.setLoadWithOverviewMode(arg_instanceId!, arg_overview!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null, expected non-null int.'); + final bool? arg_use = args[1] as bool?; + assert(arg_use != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null, expected non-null bool.'); + api.setUseWideViewPort(arg_instanceId!, arg_use!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null, expected non-null int.'); + final bool? arg_enabled = args[1] as bool?; + assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null, expected non-null bool.'); + api.setDisplayZoomControls(arg_instanceId!, arg_enabled!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null, expected non-null int.'); + final bool? arg_enabled = args[1] as bool?; + assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null, expected non-null bool.'); + api.setBuiltInZoomControls(arg_instanceId!, arg_enabled!); + return {}; + }); + } + } + } +} + +class _TestJavaScriptChannelHostApiCodec extends StandardMessageCodec { + const _TestJavaScriptChannelHostApiCodec(); +} +abstract class TestJavaScriptChannelHostApi { + static const MessageCodec codec = _TestJavaScriptChannelHostApiCodec(); + + void create(int instanceId, String channelName); + void dispose(int instanceId); + static void setup(TestJavaScriptChannelHostApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.JavaScriptChannelHostApi.create', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null, expected non-null int.'); + final String? arg_channelName = args[1] as String?; + assert(arg_channelName != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null, expected non-null String.'); + api.create(arg_instanceId!, arg_channelName!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.JavaScriptChannelHostApi.dispose', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.dispose was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.dispose was null, expected non-null int.'); + api.dispose(arg_instanceId!); + return {}; + }); + } + } + } +} + +class _TestWebViewClientHostApiCodec extends StandardMessageCodec { + const _TestWebViewClientHostApiCodec(); +} +abstract class TestWebViewClientHostApi { + static const MessageCodec codec = _TestWebViewClientHostApiCodec(); + + void create(int instanceId, bool shouldOverrideUrlLoading); + void dispose(int instanceId); + static void setup(TestWebViewClientHostApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientHostApi.create', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null, expected non-null int.'); + final bool? arg_shouldOverrideUrlLoading = args[1] as bool?; + assert(arg_shouldOverrideUrlLoading != null, 'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null, expected non-null bool.'); + api.create(arg_instanceId!, arg_shouldOverrideUrlLoading!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientHostApi.dispose', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientHostApi.dispose was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientHostApi.dispose was null, expected non-null int.'); + api.dispose(arg_instanceId!); + return {}; + }); + } + } + } +} + +class _TestDownloadListenerHostApiCodec extends StandardMessageCodec { + const _TestDownloadListenerHostApiCodec(); +} +abstract class TestDownloadListenerHostApi { + static const MessageCodec codec = _TestDownloadListenerHostApiCodec(); + + void create(int instanceId); + void dispose(int instanceId); + static void setup(TestDownloadListenerHostApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.DownloadListenerHostApi.create', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.create was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.create was null, expected non-null int.'); + api.create(arg_instanceId!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.DownloadListenerHostApi.dispose', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.dispose was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.dispose was null, expected non-null int.'); + api.dispose(arg_instanceId!); + return {}; + }); + } + } + } +} diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart index eaea437f679b..b3d0e998ce84 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart @@ -7,20 +7,19 @@ import 'package:webview_flutter_android/src/android_webview.dart'; import 'package:webview_flutter_android/src/android_webview_api_impls.dart'; import 'package:webview_flutter_android/src/instance_manager.dart'; -import 'test_binary_messenger.dart'; +import 'android_webview.pigeon.dart'; void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + group('Android WebView', () { group('$WebView', () { - setUp(() { - WebView.api = WebViewHostApiImpl( - instanceManager: InstanceManager(), - binaryMessenger: TestBinaryMessenger(), - ); + setUpAll(() { + TestWebViewHostApi.setup(TestWebViewHostApiImpl()); }); - tearDownAll(() { - WebView.api = WebViewHostApiImpl(); + setUp(() { + WebView.api = WebViewHostApiImpl(instanceManager: InstanceManager()); }); test('create', () { @@ -30,16 +29,16 @@ void main() { }); group('$WebSettings', () { + setUpAll(() { + TestWebViewHostApi.setup(TestWebViewHostApiImpl()); + TestWebSettingsHostApi.setup(TestWebSettingsHostApiImpl()); + }); + setUp(() { final InstanceManager instanceManager = InstanceManager(); - final TestBinaryMessenger binaryMessenger = TestBinaryMessenger(); - WebView.api = WebViewHostApiImpl( - instanceManager: instanceManager, - binaryMessenger: binaryMessenger, - ); + WebView.api = WebViewHostApiImpl(instanceManager: instanceManager); WebSettings.api = WebSettingsHostApiImpl( instanceManager: instanceManager, - binaryMessenger: binaryMessenger, ); }); @@ -54,16 +53,16 @@ void main() { }); group('$JavaScriptChannel', () { + setUpAll(() { + TestWebViewHostApi.setup(TestWebViewHostApiImpl()); + TestJavaScriptChannelHostApi.setup(TestJavaScriptChannelHostApiImpl()); + }); + setUp(() { final InstanceManager instanceManager = InstanceManager(); - final TestBinaryMessenger binaryMessenger = TestBinaryMessenger(); - WebView.api = WebViewHostApiImpl( - instanceManager: instanceManager, - binaryMessenger: binaryMessenger, - ); + WebView.api = WebViewHostApiImpl(instanceManager: instanceManager); JavaScriptChannel.api = JavaScriptChannelHostApiImpl( instanceManager: instanceManager, - binaryMessenger: binaryMessenger, ); }); @@ -86,16 +85,16 @@ void main() { }); group('$WebViewClient', () { + setUpAll(() { + TestWebViewHostApi.setup(TestWebViewHostApiImpl()); + TestWebViewClientHostApi.setup(TestWebViewClientHostApiImpl()); + }); + setUp(() { final InstanceManager instanceManager = InstanceManager(); - final TestBinaryMessenger binaryMessenger = TestBinaryMessenger(); - WebView.api = WebViewHostApiImpl( - instanceManager: instanceManager, - binaryMessenger: binaryMessenger, - ); + WebView.api = WebViewHostApiImpl(instanceManager: instanceManager); WebViewClient.api = WebViewClientHostApiImpl( instanceManager: instanceManager, - binaryMessenger: binaryMessenger, ); }); @@ -119,16 +118,16 @@ void main() { }); group('$DownloadListener', () { + setUpAll(() { + TestWebViewHostApi.setup(TestWebViewHostApiImpl()); + TestDownloadListenerHostApi.setup(TestDownloadListenerHostApiImpl()); + }); + setUp(() { final InstanceManager instanceManager = InstanceManager(); - final TestBinaryMessenger binaryMessenger = TestBinaryMessenger(); - WebView.api = WebViewHostApiImpl( - instanceManager: instanceManager, - binaryMessenger: binaryMessenger, - ); + WebView.api = WebViewHostApiImpl(instanceManager: instanceManager); DownloadListener.api = DownloadListenerHostApiImpl( instanceManager: instanceManager, - binaryMessenger: binaryMessenger, ); }); @@ -157,9 +156,7 @@ class TestJavaScriptChannel extends JavaScriptChannel { TestJavaScriptChannel(String channelName) : super(channelName); @override - void postMessage(String message) { - // Do nothing. - } + void postMessage(String message) {} } class TestWebViewClient extends WebViewClient {} @@ -172,7 +169,150 @@ class TestDownloadListener extends DownloadListener { String contentDisposition, String mimetype, int contentLength, - ) { - // Do nothing. + ) {} +} + +class TestWebViewHostApiImpl extends TestWebViewHostApi { + @override + void addJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId) {} + + @override + bool canGoBack(int instanceId) { + throw UnimplementedError(); + } + + @override + bool canGoForward(int instanceId) { + throw UnimplementedError(); + } + + @override + void clearCache(int instanceId, bool includeDiskFiles) {} + + @override + void create(int instanceId, bool useHybridComposition) {} + + @override + void dispose(int instanceId) {} + + @override + Future evaluateJavascript(int instanceId, String javascriptString) { + throw UnimplementedError(); + } + + @override + int getScrollX(int instanceId) { + throw UnimplementedError(); + } + + @override + int getScrollY(int instanceId) { + throw UnimplementedError(); + } + + @override + String getTitle(int instanceId) { + throw UnimplementedError(); + } + + @override + String getUrl(int instanceId) { + throw UnimplementedError(); } + + @override + void goBack(int instanceId) {} + + @override + void goForward(int instanceId) {} + + @override + void loadUrl(int instanceId, String url, Map headers) {} + + @override + void reload(int instanceId) {} + + @override + void removeJavaScriptChannel( + int instanceId, int javaScriptChannelInstanceId) {} + + @override + void scrollBy(int instanceId, int x, int y) {} + + @override + void scrollTo(int instanceId, int x, int y) {} + + @override + void setDownloadListener(int instanceId, int listenerInstanceId) {} + + @override + void setWebContentsDebuggingEnabled(bool enabled) {} + + @override + void setWebViewClient(int instanceId, int webViewClientInstanceId) {} +} + +class TestWebSettingsHostApiImpl extends TestWebSettingsHostApi { + @override + void create(int instanceId, int webViewInstanceId) {} + + @override + void dispose(int instanceId) {} + + @override + void setBuiltInZoomControls(int instanceId, bool enabled) {} + + @override + void setDisplayZoomControls(int instanceId, bool enabled) {} + + @override + void setDomStorageEnabled(int instanceId, bool flag) {} + + @override + void setJavaScriptCanOpenWindowsAutomatically(int instanceId, bool flag) {} + + @override + void setJavaScriptEnabled(int instanceId, bool flag) {} + + @override + void setLoadWithOverviewMode(int instanceId, bool overview) {} + + @override + void setMediaPlaybackRequiresUserGesture(int instanceId, bool require) {} + + @override + void setSupportMultipleWindows(int instanceId, bool support) {} + + @override + void setSupportZoom(int instanceId, bool support) {} + + @override + void setUseWideViewPort(int instanceId, bool use) {} + + @override + void setUserAgentString(int instanceId, String userAgentString) {} +} + +class TestJavaScriptChannelHostApiImpl extends TestJavaScriptChannelHostApi { + @override + void create(int instanceId, String channelName) {} + + @override + void dispose(int instanceId) {} +} + +class TestWebViewClientHostApiImpl extends TestWebViewClientHostApi { + @override + void create(int instanceId, bool shouldOverrideUrlLoading) {} + + @override + void dispose(int instanceId) {} +} + +class TestDownloadListenerHostApiImpl extends TestDownloadListenerHostApi { + @override + void create(int instanceId) {} + + @override + void dispose(int instanceId) {} } From 2e1b590f02c1aa41e04018d7a50403e5225f14c9 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Tue, 19 Oct 2021 14:52:19 -0700 Subject: [PATCH 16/54] formatting and remove circle reference --- .../lib/src/android_webview.dart | 14 +- .../lib/src/android_webview_api_impls.dart | 4 +- .../pigeons/android_webview.dart | 2 +- .../test/android_webview.pigeon.dart | 371 ++++++++++++------ .../test/android_webview_test.dart | 2 +- 5 files changed, 261 insertions(+), 132 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index a1ef8968c86f..a7984054fe06 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -55,7 +55,7 @@ class WebView { final bool useHybridComposition; /// The [WebSettings] object used to control the settings for this WebView. - late final WebSettings settings = WebSettings._(this); + late final WebSettings settings = WebSettings(this); /// Enables debugging of web contents (HTML / CSS / JavaScript) loaded into any WebViews of this application. /// @@ -268,13 +268,15 @@ class WebView { /// WebView has been destroyed, any method call on [WebSettings] will throw an /// Exception. class WebSettings { - WebSettings._(this.webView) { - api.createFromInstance(this); + /// Constructs a [WebSettings]. + /// + /// This constructor is only used for testing. An instance should be obtained + /// with [WebView.settings]. + @visibleForTesting + WebSettings(WebView webView) { + api.createFromInstance(this, webView); } - /// The webView instance this is attached to. - final WebView webView; - /// Pigeon Host Api implementation for [WebSettings]. @visibleForTesting static WebSettingsHostApiImpl api = WebSettingsHostApiImpl(); diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index 121f24b827d9..83621e02cb16 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -177,12 +177,12 @@ class WebSettingsHostApiImpl extends WebSettingsHostApi { late final InstanceManager instanceManager; /// Helper method to convert instances ids to objects. - Future createFromInstance(WebSettings instance) async { + Future createFromInstance(WebSettings instance, WebView webView) async { final int? instanceId = instanceManager.tryAddInstance(instance); if (instanceId != null) { return create( instanceId, - instanceManager.getInstanceId(instance.webView)!, + instanceManager.getInstanceId(webView)!, ); } } diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart index 3c9202bddcdf..375f3ced67f2 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -100,7 +100,7 @@ abstract class WebSettingsHostApi { void setBuiltInZoomControls(int instanceId, bool enabled); } -@HostApi(dartHostTestHandler:'TestJavaScriptChannelHostApi') +@HostApi(dartHostTestHandler: 'TestJavaScriptChannelHostApi') abstract class JavaScriptChannelHostApi { void create(int instanceId, String channelName); diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart index e4fa4b8eb86c..9f6996950b3f 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart @@ -17,6 +17,7 @@ import '../lib/src/android_webview.pigeon.dart'; class _TestWebViewHostApiCodec extends StandardMessageCodec { const _TestWebViewHostApiCodec(); } + abstract class TestWebViewHostApi { static const MessageCodec codec = _TestWebViewHostApiCodec(); @@ -49,12 +50,15 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null, expected non-null int.'); final bool? arg_useHybridComposition = args[1] as bool?; - assert(arg_useHybridComposition != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null, expected non-null bool.'); + assert(arg_useHybridComposition != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null, expected non-null bool.'); api.create(arg_instanceId!, arg_useHybridComposition!); return {}; }); @@ -67,10 +71,12 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.dispose was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.dispose was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.dispose was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.dispose was null, expected non-null int.'); api.dispose(arg_instanceId!); return {}; }); @@ -83,14 +89,19 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null int.'); final String? arg_url = args[1] as String?; - assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null String.'); - final Map? arg_headers = args[2] as Map?; - assert(arg_headers != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null Map.'); + assert(arg_url != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null String.'); + final Map? arg_headers = + args[2] as Map?; + assert(arg_headers != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null Map.'); api.loadUrl(arg_instanceId!, arg_url!, arg_headers!); return {}; }); @@ -103,10 +114,12 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getUrl was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.getUrl was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getUrl was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.getUrl was null, expected non-null int.'); final String output = api.getUrl(arg_instanceId!); return {'result': output}; }); @@ -119,10 +132,12 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoBack was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoBack was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoBack was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoBack was null, expected non-null int.'); final bool output = api.canGoBack(arg_instanceId!); return {'result': output}; }); @@ -135,10 +150,12 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoForward was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoForward was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoForward was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoForward was null, expected non-null int.'); final bool output = api.canGoForward(arg_instanceId!); return {'result': output}; }); @@ -151,10 +168,12 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goBack was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.goBack was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goBack was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.goBack was null, expected non-null int.'); api.goBack(arg_instanceId!); return {}; }); @@ -167,10 +186,12 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goForward was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.goForward was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goForward was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.goForward was null, expected non-null int.'); api.goForward(arg_instanceId!); return {}; }); @@ -183,10 +204,12 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.reload was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.reload was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.reload was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.reload was null, expected non-null int.'); api.reload(arg_instanceId!); return {}; }); @@ -199,12 +222,15 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null, expected non-null int.'); final bool? arg_includeDiskFiles = args[1] as bool?; - assert(arg_includeDiskFiles != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null, expected non-null bool.'); + assert(arg_includeDiskFiles != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null, expected non-null bool.'); api.clearCache(arg_instanceId!, arg_includeDiskFiles!); return {}; }); @@ -217,13 +243,17 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null, expected non-null int.'); final String? arg_javascriptString = args[1] as String?; - assert(arg_javascriptString != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null, expected non-null String.'); - final String output = await api.evaluateJavascript(arg_instanceId!, arg_javascriptString!); + assert(arg_javascriptString != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null, expected non-null String.'); + final String output = await api.evaluateJavascript( + arg_instanceId!, arg_javascriptString!); return {'result': output}; }); } @@ -235,10 +265,12 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getTitle was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.getTitle was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getTitle was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.getTitle was null, expected non-null int.'); final String output = api.getTitle(arg_instanceId!); return {'result': output}; }); @@ -251,14 +283,18 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); final int? arg_x = args[1] as int?; - assert(arg_x != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); + assert(arg_x != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); final int? arg_y = args[2] as int?; - assert(arg_y != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); + assert(arg_y != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); api.scrollTo(arg_instanceId!, arg_x!, arg_y!); return {}; }); @@ -271,14 +307,18 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); final int? arg_x = args[1] as int?; - assert(arg_x != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); + assert(arg_x != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); final int? arg_y = args[2] as int?; - assert(arg_y != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); + assert(arg_y != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); api.scrollBy(arg_instanceId!, arg_x!, arg_y!); return {}; }); @@ -291,10 +331,12 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollX was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollX was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollX was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollX was null, expected non-null int.'); final int output = api.getScrollX(arg_instanceId!); return {'result': output}; }); @@ -307,10 +349,12 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollY was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollY was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollY was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollY was null, expected non-null int.'); final int output = api.getScrollY(arg_instanceId!); return {'result': output}; }); @@ -318,15 +362,18 @@ abstract class TestWebViewHostApi { } { const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled', codec); + 'dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled', + codec); if (api == null) { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled was null.'); final List args = (message as List?)!; final bool? arg_enabled = args[0] as bool?; - assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled was null, expected non-null bool.'); + assert(arg_enabled != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled was null, expected non-null bool.'); api.setWebContentsDebuggingEnabled(arg_enabled!); return {}; }); @@ -339,12 +386,15 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null, expected non-null int.'); final int? arg_webViewClientInstanceId = args[1] as int?; - assert(arg_webViewClientInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null, expected non-null int.'); + assert(arg_webViewClientInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null, expected non-null int.'); api.setWebViewClient(arg_instanceId!, arg_webViewClientInstanceId!); return {}; }); @@ -357,13 +407,17 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null, expected non-null int.'); final int? arg_javaScriptChannelInstanceId = args[1] as int?; - assert(arg_javaScriptChannelInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null, expected non-null int.'); - api.addJavaScriptChannel(arg_instanceId!, arg_javaScriptChannelInstanceId!); + assert(arg_javaScriptChannelInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null, expected non-null int.'); + api.addJavaScriptChannel( + arg_instanceId!, arg_javaScriptChannelInstanceId!); return {}; }); } @@ -375,13 +429,17 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null, expected non-null int.'); final int? arg_javaScriptChannelInstanceId = args[1] as int?; - assert(arg_javaScriptChannelInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null, expected non-null int.'); - api.removeJavaScriptChannel(arg_instanceId!, arg_javaScriptChannelInstanceId!); + assert(arg_javaScriptChannelInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null, expected non-null int.'); + api.removeJavaScriptChannel( + arg_instanceId!, arg_javaScriptChannelInstanceId!); return {}; }); } @@ -393,12 +451,15 @@ abstract class TestWebViewHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null, expected non-null int.'); final int? arg_listenerInstanceId = args[1] as int?; - assert(arg_listenerInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null, expected non-null int.'); + assert(arg_listenerInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null, expected non-null int.'); api.setDownloadListener(arg_instanceId!, arg_listenerInstanceId!); return {}; }); @@ -410,6 +471,7 @@ abstract class TestWebViewHostApi { class _TestWebSettingsHostApiCodec extends StandardMessageCodec { const _TestWebSettingsHostApiCodec(); } + abstract class TestWebSettingsHostApi { static const MessageCodec codec = _TestWebSettingsHostApiCodec(); @@ -434,12 +496,15 @@ abstract class TestWebSettingsHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null, expected non-null int.'); final int? arg_webViewInstanceId = args[1] as int?; - assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null, expected non-null int.'); + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null, expected non-null int.'); api.create(arg_instanceId!, arg_webViewInstanceId!); return {}; }); @@ -452,10 +517,12 @@ abstract class TestWebSettingsHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.dispose was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.dispose was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.dispose was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.dispose was null, expected non-null int.'); api.dispose(arg_instanceId!); return {}; }); @@ -468,12 +535,15 @@ abstract class TestWebSettingsHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null, expected non-null int.'); final bool? arg_flag = args[1] as bool?; - assert(arg_flag != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null, expected non-null bool.'); + assert(arg_flag != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null, expected non-null bool.'); api.setDomStorageEnabled(arg_instanceId!, arg_flag!); return {}; }); @@ -481,35 +551,44 @@ abstract class TestWebSettingsHostApi { } { const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically', codec); + 'dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically', + codec); if (api == null) { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null, expected non-null int.'); final bool? arg_flag = args[1] as bool?; - assert(arg_flag != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null, expected non-null bool.'); - api.setJavaScriptCanOpenWindowsAutomatically(arg_instanceId!, arg_flag!); + assert(arg_flag != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null, expected non-null bool.'); + api.setJavaScriptCanOpenWindowsAutomatically( + arg_instanceId!, arg_flag!); return {}; }); } } { const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows', codec); + 'dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows', + codec); if (api == null) { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null, expected non-null int.'); final bool? arg_support = args[1] as bool?; - assert(arg_support != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null, expected non-null bool.'); + assert(arg_support != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null, expected non-null bool.'); api.setSupportMultipleWindows(arg_instanceId!, arg_support!); return {}; }); @@ -522,12 +601,15 @@ abstract class TestWebSettingsHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null, expected non-null int.'); final bool? arg_flag = args[1] as bool?; - assert(arg_flag != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null, expected non-null bool.'); + assert(arg_flag != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null, expected non-null bool.'); api.setJavaScriptEnabled(arg_instanceId!, arg_flag!); return {}; }); @@ -540,12 +622,15 @@ abstract class TestWebSettingsHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null, expected non-null int.'); final String? arg_userAgentString = args[1] as String?; - assert(arg_userAgentString != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null, expected non-null String.'); + assert(arg_userAgentString != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null, expected non-null String.'); api.setUserAgentString(arg_instanceId!, arg_userAgentString!); return {}; }); @@ -553,18 +638,23 @@ abstract class TestWebSettingsHostApi { } { const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture', codec); + 'dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture', + codec); if (api == null) { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null, expected non-null int.'); final bool? arg_require = args[1] as bool?; - assert(arg_require != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null, expected non-null bool.'); - api.setMediaPlaybackRequiresUserGesture(arg_instanceId!, arg_require!); + assert(arg_require != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null, expected non-null bool.'); + api.setMediaPlaybackRequiresUserGesture( + arg_instanceId!, arg_require!); return {}; }); } @@ -576,12 +666,15 @@ abstract class TestWebSettingsHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null, expected non-null int.'); final bool? arg_support = args[1] as bool?; - assert(arg_support != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null, expected non-null bool.'); + assert(arg_support != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null, expected non-null bool.'); api.setSupportZoom(arg_instanceId!, arg_support!); return {}; }); @@ -589,17 +682,21 @@ abstract class TestWebSettingsHostApi { } { const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode', codec); + 'dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode', + codec); if (api == null) { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null, expected non-null int.'); final bool? arg_overview = args[1] as bool?; - assert(arg_overview != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null, expected non-null bool.'); + assert(arg_overview != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null, expected non-null bool.'); api.setLoadWithOverviewMode(arg_instanceId!, arg_overview!); return {}; }); @@ -612,12 +709,15 @@ abstract class TestWebSettingsHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null, expected non-null int.'); final bool? arg_use = args[1] as bool?; - assert(arg_use != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null, expected non-null bool.'); + assert(arg_use != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null, expected non-null bool.'); api.setUseWideViewPort(arg_instanceId!, arg_use!); return {}; }); @@ -625,17 +725,21 @@ abstract class TestWebSettingsHostApi { } { const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls', codec); + 'dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls', + codec); if (api == null) { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null, expected non-null int.'); final bool? arg_enabled = args[1] as bool?; - assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null, expected non-null bool.'); + assert(arg_enabled != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null, expected non-null bool.'); api.setDisplayZoomControls(arg_instanceId!, arg_enabled!); return {}; }); @@ -643,17 +747,21 @@ abstract class TestWebSettingsHostApi { } { const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls', codec); + 'dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls', + codec); if (api == null) { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null, expected non-null int.'); final bool? arg_enabled = args[1] as bool?; - assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null, expected non-null bool.'); + assert(arg_enabled != null, + 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null, expected non-null bool.'); api.setBuiltInZoomControls(arg_instanceId!, arg_enabled!); return {}; }); @@ -665,8 +773,10 @@ abstract class TestWebSettingsHostApi { class _TestJavaScriptChannelHostApiCodec extends StandardMessageCodec { const _TestJavaScriptChannelHostApiCodec(); } + abstract class TestJavaScriptChannelHostApi { - static const MessageCodec codec = _TestJavaScriptChannelHostApiCodec(); + static const MessageCodec codec = + _TestJavaScriptChannelHostApiCodec(); void create(int instanceId, String channelName); void dispose(int instanceId); @@ -678,12 +788,15 @@ abstract class TestJavaScriptChannelHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null, expected non-null int.'); final String? arg_channelName = args[1] as String?; - assert(arg_channelName != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null, expected non-null String.'); + assert(arg_channelName != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null, expected non-null String.'); api.create(arg_instanceId!, arg_channelName!); return {}; }); @@ -696,10 +809,12 @@ abstract class TestJavaScriptChannelHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.dispose was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.dispose was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.dispose was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.dispose was null, expected non-null int.'); api.dispose(arg_instanceId!); return {}; }); @@ -711,6 +826,7 @@ abstract class TestJavaScriptChannelHostApi { class _TestWebViewClientHostApiCodec extends StandardMessageCodec { const _TestWebViewClientHostApiCodec(); } + abstract class TestWebViewClientHostApi { static const MessageCodec codec = _TestWebViewClientHostApiCodec(); @@ -724,12 +840,15 @@ abstract class TestWebViewClientHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null, expected non-null int.'); final bool? arg_shouldOverrideUrlLoading = args[1] as bool?; - assert(arg_shouldOverrideUrlLoading != null, 'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null, expected non-null bool.'); + assert(arg_shouldOverrideUrlLoading != null, + 'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null, expected non-null bool.'); api.create(arg_instanceId!, arg_shouldOverrideUrlLoading!); return {}; }); @@ -742,10 +861,12 @@ abstract class TestWebViewClientHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientHostApi.dispose was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientHostApi.dispose was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewClientHostApi.dispose was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientHostApi.dispose was null, expected non-null int.'); api.dispose(arg_instanceId!); return {}; }); @@ -757,8 +878,10 @@ abstract class TestWebViewClientHostApi { class _TestDownloadListenerHostApiCodec extends StandardMessageCodec { const _TestDownloadListenerHostApiCodec(); } + abstract class TestDownloadListenerHostApi { - static const MessageCodec codec = _TestDownloadListenerHostApiCodec(); + static const MessageCodec codec = + _TestDownloadListenerHostApiCodec(); void create(int instanceId); void dispose(int instanceId); @@ -770,10 +893,12 @@ abstract class TestDownloadListenerHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.create was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.create was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.create was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.create was null, expected non-null int.'); api.create(arg_instanceId!); return {}; }); @@ -786,10 +911,12 @@ abstract class TestDownloadListenerHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - assert(message != null, 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.dispose was null.'); + assert(message != null, + 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.dispose was null.'); final List args = (message as List?)!; final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.dispose was null, expected non-null int.'); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.dispose was null, expected non-null int.'); api.dispose(arg_instanceId!); return {}; }); diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart index b3d0e998ce84..2373ec0d1bfc 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart @@ -44,7 +44,7 @@ void main() { test('create', () { final WebView webView = WebView(); - final WebSettings webSettings = webView.settings; + final WebSettings webSettings = WebSettings(webView); expect( WebSettings.api.instanceManager.getInstanceId(webSettings), isNotNull, From 916ca2a7c6fc0800752c3e635969e4591fafc482 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Tue, 19 Oct 2021 14:59:53 -0700 Subject: [PATCH 17/54] add avoid_relative_lib_imports to generated test file --- .../webview_flutter_android/test/android_webview.pigeon.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart index 9f6996950b3f..821dacebd2ed 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart @@ -4,7 +4,7 @@ // Autogenerated from Pigeon (v1.0.7), do not edit directly. // See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, avoid_relative_lib_imports // @dart = 2.12 import 'dart:async'; import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; From 484cce06740919353118186b8beade5f86c84b58 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Tue, 19 Oct 2021 15:17:27 -0700 Subject: [PATCH 18/54] remove unused file --- .../test/test_binary_messenger.dart | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart diff --git a/packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart b/packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart deleted file mode 100644 index 1aac4d25d251..000000000000 --- a/packages/webview_flutter/webview_flutter_android/test/test_binary_messenger.dart +++ /dev/null @@ -1,28 +0,0 @@ -// 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. - -import 'dart:ui'; - -import 'package:flutter/services.dart'; - -class TestBinaryMessenger implements BinaryMessenger { - @override - Future handlePlatformMessage( - String channel, - ByteData? data, - PlatformMessageResponseCallback? callback, - ) async { - // Do nothing. - } - - @override - Future? send(String channel, ByteData? message) async { - return StandardMessageCodec().encodeMessage({}); - } - - @override - void setMessageHandler(String channel, MessageHandler? handler) { - // Do nothing. - } -} From a6ffb48e4b1cef6d0cdbbda91f7e5425eb2735d5 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 20 Oct 2021 12:12:28 -0700 Subject: [PATCH 19/54] webview and websettings api tests --- .../DownloadListenerHostApiImpl.java | 2 +- .../GeneratedAndroidWebView.java | 2080 +++++++---------- .../JavaScriptChannelHostApiImpl.java | 2 +- ...iImpl.java => WebSettingsHostApiImpl.java} | 14 +- .../WebViewClientHostApiImpl.java | 2 +- .../webviewflutter/WebViewHostApiImpl.java | 30 +- .../webviewflutter/WebSettingsTest.java | 102 + .../plugins/webviewflutter/WebViewTest.java | 178 ++ .../generatePigeons.sh | 4 +- 9 files changed, 1215 insertions(+), 1199 deletions(-) rename packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/{WebViewSettingsHostApiImpl.java => WebSettingsHostApiImpl.java} (85%) create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java index 6638e218611d..05f753033530 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java @@ -2,7 +2,7 @@ import android.webkit.DownloadListener; -public class DownloadListenerHostApiImpl +class DownloadListenerHostApiImpl implements GeneratedAndroidWebView.DownloadListenerHostApi { private final InstanceManager instanceManager; private final GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi; diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index 34e1e0b54f7e..a790e6f722b5 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -9,10 +9,11 @@ import io.flutter.plugin.common.StandardMessageCodec; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; -import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.HashMap; /** Generated class from Pigeon. */ @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"}) @@ -21,64 +22,28 @@ public class GeneratedAndroidWebView { /** Generated class from Pigeon that represents data sent in messages. */ public static class WebResourceRequestData { private String url; - - public String getUrl() { - return url; - } - - public void setUrl(String setterArg) { - this.url = setterArg; - } + public String getUrl() { return url; } + public void setUrl(String setterArg) { this.url = setterArg; } private Boolean isForMainFrame; - - public Boolean getIsForMainFrame() { - return isForMainFrame; - } - - public void setIsForMainFrame(Boolean setterArg) { - this.isForMainFrame = setterArg; - } + public Boolean getIsForMainFrame() { return isForMainFrame; } + public void setIsForMainFrame(Boolean setterArg) { this.isForMainFrame = setterArg; } private Boolean isRedirect; - - public Boolean getIsRedirect() { - return isRedirect; - } - - public void setIsRedirect(Boolean setterArg) { - this.isRedirect = setterArg; - } + public Boolean getIsRedirect() { return isRedirect; } + public void setIsRedirect(Boolean setterArg) { this.isRedirect = setterArg; } private Boolean hasGesture; - - public Boolean getHasGesture() { - return hasGesture; - } - - public void setHasGesture(Boolean setterArg) { - this.hasGesture = setterArg; - } + public Boolean getHasGesture() { return hasGesture; } + public void setHasGesture(Boolean setterArg) { this.hasGesture = setterArg; } private String method; - - public String getMethod() { - return method; - } - - public void setMethod(String setterArg) { - this.method = setterArg; - } + public String getMethod() { return method; } + public void setMethod(String setterArg) { this.method = setterArg; } private Map requestHeaders; - - public Map getRequestHeaders() { - return requestHeaders; - } - - public void setRequestHeaders(Map setterArg) { - this.requestHeaders = setterArg; - } + public Map getRequestHeaders() { return requestHeaders; } + public void setRequestHeaders(Map setterArg) { this.requestHeaders = setterArg; } Map toMap() { Map toMapResult = new HashMap<>(); @@ -90,21 +55,20 @@ Map toMap() { toMapResult.put("requestHeaders", requestHeaders); return toMapResult; } - static WebResourceRequestData fromMap(Map map) { WebResourceRequestData fromMapResult = new WebResourceRequestData(); Object url = map.get("url"); - fromMapResult.url = (String) url; + fromMapResult.url = (String)url; Object isForMainFrame = map.get("isForMainFrame"); - fromMapResult.isForMainFrame = (Boolean) isForMainFrame; + fromMapResult.isForMainFrame = (Boolean)isForMainFrame; Object isRedirect = map.get("isRedirect"); - fromMapResult.isRedirect = (Boolean) isRedirect; + fromMapResult.isRedirect = (Boolean)isRedirect; Object hasGesture = map.get("hasGesture"); - fromMapResult.hasGesture = (Boolean) hasGesture; + fromMapResult.hasGesture = (Boolean)hasGesture; Object method = map.get("method"); - fromMapResult.method = (String) method; + fromMapResult.method = (String)method; Object requestHeaders = map.get("requestHeaders"); - fromMapResult.requestHeaders = (Map) requestHeaders; + fromMapResult.requestHeaders = (Map)requestHeaders; return fromMapResult; } } @@ -112,24 +76,12 @@ static WebResourceRequestData fromMap(Map map) { /** Generated class from Pigeon that represents data sent in messages. */ public static class WebResourceErrorData { private Long errorCode; - - public Long getErrorCode() { - return errorCode; - } - - public void setErrorCode(Long setterArg) { - this.errorCode = setterArg; - } + public Long getErrorCode() { return errorCode; } + public void setErrorCode(Long setterArg) { this.errorCode = setterArg; } private String description; - - public String getDescription() { - return description; - } - - public void setDescription(String setterArg) { - this.description = setterArg; - } + public String getDescription() { return description; } + public void setDescription(String setterArg) { this.description = setterArg; } Map toMap() { Map toMapResult = new HashMap<>(); @@ -137,74 +89,47 @@ Map toMap() { toMapResult.put("description", description); return toMapResult; } - static WebResourceErrorData fromMap(Map map) { WebResourceErrorData fromMapResult = new WebResourceErrorData(); Object errorCode = map.get("errorCode"); - fromMapResult.errorCode = - (errorCode == null) - ? null - : ((errorCode instanceof Integer) ? (Integer) errorCode : (Long) errorCode); + fromMapResult.errorCode = (errorCode == null) ? null : ((errorCode instanceof Integer) ? (Integer)errorCode : (Long)errorCode); Object description = map.get("description"); - fromMapResult.description = (String) description; + fromMapResult.description = (String)description; return fromMapResult; } } public interface Result { void success(T result); - void error(Throwable error); } - private static class WebViewHostApiCodec extends StandardMessageCodec { public static final WebViewHostApiCodec INSTANCE = new WebViewHostApiCodec(); - private WebViewHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ public interface WebViewHostApi { void create(Long instanceId, Boolean useHybridComposition); - void dispose(Long instanceId); - void loadUrl(Long instanceId, String url, Map headers); - String getUrl(Long instanceId); - Boolean canGoBack(Long instanceId); - Boolean canGoForward(Long instanceId); - void goBack(Long instanceId); - void goForward(Long instanceId); - void reload(Long instanceId); - void clearCache(Long instanceId, Boolean includeDiskFiles); - void evaluateJavascript(Long instanceId, String javascriptString, Result result); - String getTitle(Long instanceId); - void scrollTo(Long instanceId, Long x, Long y); - void scrollBy(Long instanceId, Long x, Long y); - Long getScrollX(Long instanceId); - Long getScrollY(Long instanceId); - void setWebContentsDebuggingEnabled(Boolean enabled); - void setWebViewClient(Long instanceId, Long webViewClientInstanceId); - void addJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); - void removeJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); - void setDownloadListener(Long instanceId, Long listenerInstanceId); /** The codec used by WebViewHostApi. */ @@ -216,645 +141,591 @@ static MessageCodec getCodec() { static void setup(BinaryMessenger binaryMessenger, WebViewHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.create", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean useHybridCompositionArg = (Boolean) args.get(1); - if (useHybridCompositionArg == null) { - throw new NullPointerException("useHybridCompositionArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), useHybridCompositionArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean useHybridCompositionArg = (Boolean)args.get(1); + if (useHybridCompositionArg == null) { + throw new NullPointerException("useHybridCompositionArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), useHybridCompositionArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.dispose", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.loadUrl", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.loadUrl", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String urlArg = (String) args.get(1); - if (urlArg == null) { - throw new NullPointerException("urlArg unexpectedly null."); - } - Map headersArg = (Map) args.get(2); - if (headersArg == null) { - throw new NullPointerException("headersArg unexpectedly null."); - } - api.loadUrl(instanceIdArg.longValue(), urlArg, headersArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String urlArg = (String)args.get(1); + if (urlArg == null) { + throw new NullPointerException("urlArg unexpectedly null."); + } + Map headersArg = (Map)args.get(2); + if (headersArg == null) { + throw new NullPointerException("headersArg unexpectedly null."); + } + api.loadUrl(instanceIdArg.longValue(), urlArg, headersArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getUrl", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getUrl", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String output = api.getUrl(instanceIdArg.longValue()); - wrapped.put("result", output); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String output = api.getUrl(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoBack", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoBack", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean output = api.canGoBack(instanceIdArg.longValue()); - wrapped.put("result", output); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean output = api.canGoBack(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoForward", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoForward", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean output = api.canGoForward(instanceIdArg.longValue()); - wrapped.put("result", output); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean output = api.canGoForward(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goBack", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goBack", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.goBack(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.goBack(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goForward", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goForward", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.goForward(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.goForward(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.reload", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.reload", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.reload(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.reload(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.clearCache", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.clearCache", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean includeDiskFilesArg = (Boolean) args.get(1); - if (includeDiskFilesArg == null) { - throw new NullPointerException("includeDiskFilesArg unexpectedly null."); - } - api.clearCache(instanceIdArg.longValue(), includeDiskFilesArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean includeDiskFilesArg = (Boolean)args.get(1); + if (includeDiskFilesArg == null) { + throw new NullPointerException("includeDiskFilesArg unexpectedly null."); + } + api.clearCache(instanceIdArg.longValue(), includeDiskFilesArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebViewHostApi.evaluateJavascript", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.evaluateJavascript", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String javascriptStringArg = (String) args.get(1); - if (javascriptStringArg == null) { - throw new NullPointerException("javascriptStringArg unexpectedly null."); - } - Result resultCallback = - new Result() { - public void success(String result) { - wrapped.put("result", result); - reply.reply(wrapped); - } - - public void error(Throwable error) { - wrapped.put("error", wrapError(error)); - reply.reply(wrapped); - } - }; - - api.evaluateJavascript( - instanceIdArg.longValue(), javascriptStringArg, resultCallback); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String javascriptStringArg = (String)args.get(1); + if (javascriptStringArg == null) { + throw new NullPointerException("javascriptStringArg unexpectedly null."); + } + Result resultCallback = new Result() { + public void success(String result) { + wrapped.put("result", result); reply.reply(wrapped); } - }); + public void error(Throwable error) { + wrapped.put("error", wrapError(error)); + reply.reply(wrapped); + } + }; + + api.evaluateJavascript(instanceIdArg.longValue(), javascriptStringArg, resultCallback); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + reply.reply(wrapped); + } + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getTitle", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getTitle", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String output = api.getTitle(instanceIdArg.longValue()); - wrapped.put("result", output); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String output = api.getTitle(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollTo", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollTo", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number xArg = (Number) args.get(1); - if (xArg == null) { - throw new NullPointerException("xArg unexpectedly null."); - } - Number yArg = (Number) args.get(2); - if (yArg == null) { - throw new NullPointerException("yArg unexpectedly null."); - } - api.scrollTo(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number xArg = (Number)args.get(1); + if (xArg == null) { + throw new NullPointerException("xArg unexpectedly null."); + } + Number yArg = (Number)args.get(2); + if (yArg == null) { + throw new NullPointerException("yArg unexpectedly null."); + } + api.scrollTo(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollBy", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollBy", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number xArg = (Number) args.get(1); - if (xArg == null) { - throw new NullPointerException("xArg unexpectedly null."); - } - Number yArg = (Number) args.get(2); - if (yArg == null) { - throw new NullPointerException("yArg unexpectedly null."); - } - api.scrollBy(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number xArg = (Number)args.get(1); + if (xArg == null) { + throw new NullPointerException("xArg unexpectedly null."); + } + Number yArg = (Number)args.get(2); + if (yArg == null) { + throw new NullPointerException("yArg unexpectedly null."); + } + api.scrollBy(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollX", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollX", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Long output = api.getScrollX(instanceIdArg.longValue()); - wrapped.put("result", output); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Long output = api.getScrollX(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollY", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollY", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Long output = api.getScrollY(instanceIdArg.longValue()); - wrapped.put("result", output); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Long output = api.getScrollY(instanceIdArg.longValue()); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Boolean enabledArg = (Boolean) args.get(0); - if (enabledArg == null) { - throw new NullPointerException("enabledArg unexpectedly null."); - } - api.setWebContentsDebuggingEnabled(enabledArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Boolean enabledArg = (Boolean)args.get(0); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setWebContentsDebuggingEnabled(enabledArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebViewClient", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebViewClient", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number webViewClientInstanceIdArg = (Number) args.get(1); - if (webViewClientInstanceIdArg == null) { - throw new NullPointerException("webViewClientInstanceIdArg unexpectedly null."); - } - api.setWebViewClient( - instanceIdArg.longValue(), webViewClientInstanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number webViewClientInstanceIdArg = (Number)args.get(1); + if (webViewClientInstanceIdArg == null) { + throw new NullPointerException("webViewClientInstanceIdArg unexpectedly null."); + } + api.setWebViewClient(instanceIdArg.longValue(), webViewClientInstanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number javaScriptChannelInstanceIdArg = (Number) args.get(1); - if (javaScriptChannelInstanceIdArg == null) { - throw new NullPointerException( - "javaScriptChannelInstanceIdArg unexpectedly null."); - } - api.addJavaScriptChannel( - instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number javaScriptChannelInstanceIdArg = (Number)args.get(1); + if (javaScriptChannelInstanceIdArg == null) { + throw new NullPointerException("javaScriptChannelInstanceIdArg unexpectedly null."); + } + api.addJavaScriptChannel(instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number javaScriptChannelInstanceIdArg = (Number) args.get(1); - if (javaScriptChannelInstanceIdArg == null) { - throw new NullPointerException( - "javaScriptChannelInstanceIdArg unexpectedly null."); - } - api.removeJavaScriptChannel( - instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number javaScriptChannelInstanceIdArg = (Number)args.get(1); + if (javaScriptChannelInstanceIdArg == null) { + throw new NullPointerException("javaScriptChannelInstanceIdArg unexpectedly null."); + } + api.removeJavaScriptChannel(instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebViewHostApi.setDownloadListener", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setDownloadListener", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number listenerInstanceIdArg = (Number) args.get(1); - if (listenerInstanceIdArg == null) { - throw new NullPointerException("listenerInstanceIdArg unexpectedly null."); - } - api.setDownloadListener( - instanceIdArg.longValue(), listenerInstanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number listenerInstanceIdArg = (Number)args.get(1); + if (listenerInstanceIdArg == null) { + throw new NullPointerException("listenerInstanceIdArg unexpectedly null."); + } + api.setDownloadListener(instanceIdArg.longValue(), listenerInstanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } - private static class WebSettingsHostApiCodec extends StandardMessageCodec { public static final WebSettingsHostApiCodec INSTANCE = new WebSettingsHostApiCodec(); - private WebSettingsHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ public interface WebSettingsHostApi { void create(Long instanceId, Long webViewInstanceId); - void dispose(Long instanceId); - void setDomStorageEnabled(Long instanceId, Boolean flag); - void setJavaScriptCanOpenWindowsAutomatically(Long instanceId, Boolean flag); - void setSupportMultipleWindows(Long instanceId, Boolean support); - void setJavaScriptEnabled(Long instanceId, Boolean flag); - void setUserAgentString(Long instanceId, String userAgentString); - void setMediaPlaybackRequiresUserGesture(Long instanceId, Boolean require); - void setSupportZoom(Long instanceId, Boolean support); - void setLoadWithOverviewMode(Long instanceId, Boolean overview); - void setUseWideViewPort(Long instanceId, Boolean use); - void setDisplayZoomControls(Long instanceId, Boolean enabled); - void setBuiltInZoomControls(Long instanceId, Boolean enabled); /** The codec used by WebSettingsHostApi. */ @@ -862,419 +733,378 @@ static MessageCodec getCodec() { return WebSettingsHostApiCodec.INSTANCE; } - /** - * Sets up an instance of `WebSettingsHostApi` to handle messages through the `binaryMessenger`. - */ + /** Sets up an instance of `WebSettingsHostApi` to handle messages through the `binaryMessenger`. */ static void setup(BinaryMessenger binaryMessenger, WebSettingsHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.create", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number webViewInstanceIdArg = (Number) args.get(1); - if (webViewInstanceIdArg == null) { - throw new NullPointerException("webViewInstanceIdArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), webViewInstanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number webViewInstanceIdArg = (Number)args.get(1); + if (webViewInstanceIdArg == null) { + throw new NullPointerException("webViewInstanceIdArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), webViewInstanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.dispose", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean flagArg = (Boolean) args.get(1); - if (flagArg == null) { - throw new NullPointerException("flagArg unexpectedly null."); - } - api.setDomStorageEnabled(instanceIdArg.longValue(), flagArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean)args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setDomStorageEnabled(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean flagArg = (Boolean) args.get(1); - if (flagArg == null) { - throw new NullPointerException("flagArg unexpectedly null."); - } - api.setJavaScriptCanOpenWindowsAutomatically(instanceIdArg.longValue(), flagArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean)args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setJavaScriptCanOpenWindowsAutomatically(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean supportArg = (Boolean) args.get(1); - if (supportArg == null) { - throw new NullPointerException("supportArg unexpectedly null."); - } - api.setSupportMultipleWindows(instanceIdArg.longValue(), supportArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean supportArg = (Boolean)args.get(1); + if (supportArg == null) { + throw new NullPointerException("supportArg unexpectedly null."); + } + api.setSupportMultipleWindows(instanceIdArg.longValue(), supportArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean flagArg = (Boolean) args.get(1); - if (flagArg == null) { - throw new NullPointerException("flagArg unexpectedly null."); - } - api.setJavaScriptEnabled(instanceIdArg.longValue(), flagArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean)args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setJavaScriptEnabled(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String userAgentStringArg = (String) args.get(1); - if (userAgentStringArg == null) { - throw new NullPointerException("userAgentStringArg unexpectedly null."); - } - api.setUserAgentString(instanceIdArg.longValue(), userAgentStringArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String userAgentStringArg = (String)args.get(1); + if (userAgentStringArg == null) { + throw new NullPointerException("userAgentStringArg unexpectedly null."); + } + api.setUserAgentString(instanceIdArg.longValue(), userAgentStringArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean requireArg = (Boolean) args.get(1); - if (requireArg == null) { - throw new NullPointerException("requireArg unexpectedly null."); - } - api.setMediaPlaybackRequiresUserGesture(instanceIdArg.longValue(), requireArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean requireArg = (Boolean)args.get(1); + if (requireArg == null) { + throw new NullPointerException("requireArg unexpectedly null."); + } + api.setMediaPlaybackRequiresUserGesture(instanceIdArg.longValue(), requireArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean supportArg = (Boolean) args.get(1); - if (supportArg == null) { - throw new NullPointerException("supportArg unexpectedly null."); - } - api.setSupportZoom(instanceIdArg.longValue(), supportArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean supportArg = (Boolean)args.get(1); + if (supportArg == null) { + throw new NullPointerException("supportArg unexpectedly null."); + } + api.setSupportZoom(instanceIdArg.longValue(), supportArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean overviewArg = (Boolean) args.get(1); - if (overviewArg == null) { - throw new NullPointerException("overviewArg unexpectedly null."); - } - api.setLoadWithOverviewMode(instanceIdArg.longValue(), overviewArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean overviewArg = (Boolean)args.get(1); + if (overviewArg == null) { + throw new NullPointerException("overviewArg unexpectedly null."); + } + api.setLoadWithOverviewMode(instanceIdArg.longValue(), overviewArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean useArg = (Boolean) args.get(1); - if (useArg == null) { - throw new NullPointerException("useArg unexpectedly null."); - } - api.setUseWideViewPort(instanceIdArg.longValue(), useArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean useArg = (Boolean)args.get(1); + if (useArg == null) { + throw new NullPointerException("useArg unexpectedly null."); + } + api.setUseWideViewPort(instanceIdArg.longValue(), useArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean enabledArg = (Boolean) args.get(1); - if (enabledArg == null) { - throw new NullPointerException("enabledArg unexpectedly null."); - } - api.setDisplayZoomControls(instanceIdArg.longValue(), enabledArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean enabledArg = (Boolean)args.get(1); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setDisplayZoomControls(instanceIdArg.longValue(), enabledArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls", - getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean enabledArg = (Boolean) args.get(1); - if (enabledArg == null) { - throw new NullPointerException("enabledArg unexpectedly null."); - } - api.setBuiltInZoomControls(instanceIdArg.longValue(), enabledArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean enabledArg = (Boolean)args.get(1); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setBuiltInZoomControls(instanceIdArg.longValue(), enabledArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } - private static class JavaScriptChannelHostApiCodec extends StandardMessageCodec { - public static final JavaScriptChannelHostApiCodec INSTANCE = - new JavaScriptChannelHostApiCodec(); - + public static final JavaScriptChannelHostApiCodec INSTANCE = new JavaScriptChannelHostApiCodec(); private JavaScriptChannelHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ public interface JavaScriptChannelHostApi { void create(Long instanceId, String channelName); - void dispose(Long instanceId); /** The codec used by JavaScriptChannelHostApi. */ @@ -1282,115 +1112,96 @@ static MessageCodec getCodec() { return JavaScriptChannelHostApiCodec.INSTANCE; } - /** - * Sets up an instance of `JavaScriptChannelHostApi` to handle messages through the - * `binaryMessenger`. - */ + /** Sets up an instance of `JavaScriptChannelHostApi` to handle messages through the `binaryMessenger`. */ static void setup(BinaryMessenger binaryMessenger, JavaScriptChannelHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.create", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String channelNameArg = (String) args.get(1); - if (channelNameArg == null) { - throw new NullPointerException("channelNameArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), channelNameArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String channelNameArg = (String)args.get(1); + if (channelNameArg == null) { + throw new NullPointerException("channelNameArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), channelNameArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.dispose", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } - private static class JavaScriptChannelFlutterApiCodec extends StandardMessageCodec { - public static final JavaScriptChannelFlutterApiCodec INSTANCE = - new JavaScriptChannelFlutterApiCodec(); - + public static final JavaScriptChannelFlutterApiCodec INSTANCE = new JavaScriptChannelFlutterApiCodec(); private JavaScriptChannelFlutterApiCodec() {} } - /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ public static class JavaScriptChannelFlutterApi { private final BinaryMessenger binaryMessenger; - - public JavaScriptChannelFlutterApi(BinaryMessenger argBinaryMessenger) { + public JavaScriptChannelFlutterApi(BinaryMessenger argBinaryMessenger){ this.binaryMessenger = argBinaryMessenger; } - public interface Reply { void reply(T reply); } - static MessageCodec getCodec() { return JavaScriptChannelFlutterApiCodec.INSTANCE; } public void postMessage(Long instanceIdArg, String messageArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage", - getCodec()); - channel.send( - new ArrayList(Arrays.asList(instanceIdArg, messageArg)), - channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, messageArg)), channelReply -> { + callback.reply(null); + }); } } - private static class WebViewClientHostApiCodec extends StandardMessageCodec { public static final WebViewClientHostApiCodec INSTANCE = new WebViewClientHostApiCodec(); - private WebViewClientHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ public interface WebViewClientHostApi { void create(Long instanceId, Boolean shouldOverrideUrlLoading); - void dispose(Long instanceId); /** The codec used by WebViewClientHostApi. */ @@ -1398,236 +1209,166 @@ static MessageCodec getCodec() { return WebViewClientHostApiCodec.INSTANCE; } - /** - * Sets up an instance of `WebViewClientHostApi` to handle messages through the - * `binaryMessenger`. - */ + /** Sets up an instance of `WebViewClientHostApi` to handle messages through the `binaryMessenger`. */ static void setup(BinaryMessenger binaryMessenger, WebViewClientHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.create", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean shouldOverrideUrlLoadingArg = (Boolean) args.get(1); - if (shouldOverrideUrlLoadingArg == null) { - throw new NullPointerException( - "shouldOverrideUrlLoadingArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), shouldOverrideUrlLoadingArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean shouldOverrideUrlLoadingArg = (Boolean)args.get(1); + if (shouldOverrideUrlLoadingArg == null) { + throw new NullPointerException("shouldOverrideUrlLoadingArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), shouldOverrideUrlLoadingArg); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.dispose", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } - private static class WebViewClientFlutterApiCodec extends StandardMessageCodec { public static final WebViewClientFlutterApiCodec INSTANCE = new WebViewClientFlutterApiCodec(); - private WebViewClientFlutterApiCodec() {} - @Override protected Object readValueOfType(byte type, ByteBuffer buffer) { switch (type) { - case (byte) 128: + case (byte)128: return WebResourceErrorData.fromMap((Map) readValue(buffer)); - - case (byte) 129: + + case (byte)129: return WebResourceRequestData.fromMap((Map) readValue(buffer)); - - case (byte) 130: + + case (byte)130: return WebResourceRequestData.fromMap((Map) readValue(buffer)); - - default: + + default: return super.readValueOfType(type, buffer); + } } - @Override - protected void writeValue(ByteArrayOutputStream stream, Object value) { + protected void writeValue(ByteArrayOutputStream stream, Object value) { if (value instanceof WebResourceErrorData) { stream.write(128); writeValue(stream, ((WebResourceErrorData) value).toMap()); - } else if (value instanceof WebResourceRequestData) { + } else + if (value instanceof WebResourceRequestData) { stream.write(129); writeValue(stream, ((WebResourceRequestData) value).toMap()); - } else if (value instanceof WebResourceRequestData) { + } else + if (value instanceof WebResourceRequestData) { stream.write(130); writeValue(stream, ((WebResourceRequestData) value).toMap()); - } else { + } else +{ super.writeValue(stream, value); } } } - /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ public static class WebViewClientFlutterApi { private final BinaryMessenger binaryMessenger; - - public WebViewClientFlutterApi(BinaryMessenger argBinaryMessenger) { + public WebViewClientFlutterApi(BinaryMessenger argBinaryMessenger){ this.binaryMessenger = argBinaryMessenger; } - public interface Reply { void reply(T reply); } - static MessageCodec getCodec() { return WebViewClientFlutterApiCodec.INSTANCE; } - public void onPageStarted( - Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + public void onPageStarted(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted", - getCodec()); - channel.send( - new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), - channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { + callback.reply(null); + }); } - - public void onPageFinished( - Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + public void onPageFinished(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished", - getCodec()); - channel.send( - new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), - channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { + callback.reply(null); + }); } - - public void onReceivedRequestError( - Long instanceIdArg, - Long webViewInstanceIdArg, - WebResourceRequestData requestArg, - WebResourceErrorData errorArg, - Reply callback) { + public void onReceivedRequestError(Long instanceIdArg, Long webViewInstanceIdArg, WebResourceRequestData requestArg, WebResourceErrorData errorArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError", - getCodec()); - channel.send( - new ArrayList( - Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg, errorArg)), - channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg, errorArg)), channelReply -> { + callback.reply(null); + }); } - - public void onReceivedError( - Long instanceIdArg, - Long webViewInstanceIdArg, - Long errorCodeArg, - String descriptionArg, - String failingUrlArg, - Reply callback) { + public void onReceivedError(Long instanceIdArg, Long webViewInstanceIdArg, Long errorCodeArg, String descriptionArg, String failingUrlArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError", - getCodec()); - channel.send( - new ArrayList( - Arrays.asList( - instanceIdArg, - webViewInstanceIdArg, - errorCodeArg, - descriptionArg, - failingUrlArg)), - channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, errorCodeArg, descriptionArg, failingUrlArg)), channelReply -> { + callback.reply(null); + }); } - - public void requestLoading( - Long instanceIdArg, - Long webViewInstanceIdArg, - WebResourceRequestData requestArg, - Reply callback) { + public void requestLoading(Long instanceIdArg, Long webViewInstanceIdArg, WebResourceRequestData requestArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading", - getCodec()); - channel.send( - new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg)), - channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg)), channelReply -> { + callback.reply(null); + }); } - - public void urlLoading( - Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + public void urlLoading(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading", getCodec()); - channel.send( - new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), - channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { + callback.reply(null); + }); } } - private static class DownloadListenerHostApiCodec extends StandardMessageCodec { public static final DownloadListenerHostApiCodec INSTANCE = new DownloadListenerHostApiCodec(); - private DownloadListenerHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ public interface DownloadListenerHostApi { void create(Long instanceId); - void dispose(Long instanceId); /** The codec used by DownloadListenerHostApi. */ @@ -1635,115 +1376,84 @@ static MessageCodec getCodec() { return DownloadListenerHostApiCodec.INSTANCE; } - /** - * Sets up an instance of `DownloadListenerHostApi` to handle messages through the - * `binaryMessenger`. - */ + /** Sets up an instance of `DownloadListenerHostApi` to handle messages through the `binaryMessenger`. */ static void setup(BinaryMessenger binaryMessenger, DownloadListenerHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.create", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.create(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.create(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.dispose", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList)message; + Number instanceIdArg = (Number)args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } - private static class DownloadListenerFlutterApiCodec extends StandardMessageCodec { - public static final DownloadListenerFlutterApiCodec INSTANCE = - new DownloadListenerFlutterApiCodec(); - + public static final DownloadListenerFlutterApiCodec INSTANCE = new DownloadListenerFlutterApiCodec(); private DownloadListenerFlutterApiCodec() {} } - /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ public static class DownloadListenerFlutterApi { private final BinaryMessenger binaryMessenger; - - public DownloadListenerFlutterApi(BinaryMessenger argBinaryMessenger) { + public DownloadListenerFlutterApi(BinaryMessenger argBinaryMessenger){ this.binaryMessenger = argBinaryMessenger; } - public interface Reply { void reply(T reply); } - static MessageCodec getCodec() { return DownloadListenerFlutterApiCodec.INSTANCE; } - public void onDownloadStart( - Long instanceIdArg, - String urlArg, - String userAgentArg, - String contentDispositionArg, - String mimetypeArg, - Long contentLengthArg, - Reply callback) { + public void onDownloadStart(Long instanceIdArg, String urlArg, String userAgentArg, String contentDispositionArg, String mimetypeArg, Long contentLengthArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, - "dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart", - getCodec()); - channel.send( - new ArrayList( - Arrays.asList( - instanceIdArg, - urlArg, - userAgentArg, - contentDispositionArg, - mimetypeArg, - contentLengthArg)), - channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart", getCodec()); + channel.send(new ArrayList(Arrays.asList(instanceIdArg, urlArg, userAgentArg, contentDispositionArg, mimetypeArg, contentLengthArg)), channelReply -> { + callback.reply(null); + }); } } - private static Map wrapError(Throwable exception) { Map errorMap = new HashMap<>(); errorMap.put("message", exception.toString()); diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java index 2feb2cb196ad..2874e4c8b529 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -3,7 +3,7 @@ import android.os.Handler; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; -public class JavaScriptChannelHostApiImpl +class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.JavaScriptChannelHostApi { private final InstanceManager instanceManager; private final JavaScriptChannelFlutterApi javaScriptChannelFlutterApi; diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewSettingsHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java similarity index 85% rename from packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewSettingsHostApiImpl.java rename to packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java index 24b0586c8aeb..943531920c1f 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewSettingsHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java @@ -3,17 +3,25 @@ import android.webkit.WebSettings; import android.webkit.WebView; -class WebViewSettingsHostApiImpl implements GeneratedAndroidWebView.WebSettingsHostApi { +class WebSettingsHostApiImpl implements GeneratedAndroidWebView.WebSettingsHostApi { private final InstanceManager instanceManager; + private final WebSettingsProxy webSettingsProxy; - WebViewSettingsHostApiImpl(InstanceManager instanceManager) { + static class WebSettingsProxy { + WebSettings createWebSettings(WebView webView) { + return webView.getSettings(); + } + } + + WebSettingsHostApiImpl(InstanceManager instanceManager, WebSettingsProxy webSettingsProxy) { this.instanceManager = instanceManager; + this.webSettingsProxy = webSettingsProxy; } @Override public void create(Long instanceId, Long webViewInstanceId) { final WebView webView = (WebView) instanceManager.getInstance(webViewInstanceId); - instanceManager.addInstance(webView.getSettings(), instanceId); + instanceManager.addInstance(webSettingsProxy.createWebSettings(webView), instanceId); } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java index a45bf994627c..310c37c22189 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java @@ -9,7 +9,7 @@ import androidx.annotation.RequiresApi; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientFlutterApi; -public class WebViewClientHostApiImpl implements GeneratedAndroidWebView.WebViewClientHostApi { +class WebViewClientHostApiImpl implements GeneratedAndroidWebView.WebViewClientHostApi { private final InstanceManager instanceManager; private final WebViewClientFlutterApi webViewClientFlutterApi; diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index 984bb216abe7..4399454aed1b 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -11,10 +11,25 @@ class WebViewHostApiImpl implements GeneratedAndroidWebView.WebViewHostApi { private final InstanceManager instanceManager; + private final WebViewProxy webViewProxy; private final Context context; - private static class WebViewImpl extends WebView implements PlatformView { - public WebViewImpl(Context context) { + static class WebViewProxy { + WebView createWebView(Context context) { + return new WebViewPlatformView(context); + } + + WebView createInputAwareWebView(Context context) { + return new InputAwareWebViewPlatformView(context, null); + } + + void setWebContentsDebuggingEnabled(boolean enabled) { + WebView.setWebContentsDebuggingEnabled(enabled); + } + } + + private static class WebViewPlatformView extends WebView implements PlatformView { + public WebViewPlatformView(Context context) { super(context); } @@ -29,8 +44,8 @@ public void dispose() { } } - private static class InputAwareWebViewImpl extends InputAwareWebView implements PlatformView { - InputAwareWebViewImpl(Context context, View containerView) { + private static class InputAwareWebViewPlatformView extends InputAwareWebView implements PlatformView { + InputAwareWebViewPlatformView(Context context, View containerView) { super(context, containerView); } @@ -66,15 +81,16 @@ public void onInputConnectionUnlocked() { } } - WebViewHostApiImpl(InstanceManager instanceManager, Context context) { + WebViewHostApiImpl(InstanceManager instanceManager, WebViewProxy webViewProxy, Context context) { this.instanceManager = instanceManager; + this.webViewProxy = webViewProxy; this.context = context; } @Override public void create(Long instanceId, Boolean useHybridComposition) { final WebView webView = - useHybridComposition ? new WebViewImpl(context) : new InputAwareWebViewImpl(context, null); + useHybridComposition ? webViewProxy.createWebView(context) : webViewProxy.createInputAwareWebView(context); instanceManager.addInstance(webView, instanceId); } @@ -170,7 +186,7 @@ public Long getScrollY(Long instanceId) { @Override public void setWebContentsDebuggingEnabled(Boolean enabled) { - WebView.setWebContentsDebuggingEnabled(enabled); + webViewProxy.setWebContentsDebuggingEnabled(enabled); } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java new file mode 100644 index 000000000000..9d3411bb362d --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java @@ -0,0 +1,102 @@ +package io.flutter.plugins.webviewflutter; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.webkit.WebSettings; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class WebSettingsTest { + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + public WebSettings mockWebSettings; + + @Mock + WebSettingsHostApiImpl.WebSettingsProxy mockWebSettingsProxy; + + InstanceManager testInstanceManager; + WebSettingsHostApiImpl testHostApiImpl; + + @Before + public void setUp() { + testInstanceManager = new InstanceManager(); + when(mockWebSettingsProxy.createWebSettings(any())).thenReturn(mockWebSettings); + testHostApiImpl = new WebSettingsHostApiImpl(testInstanceManager, mockWebSettingsProxy); + testHostApiImpl.create(0L, 0L); + } + + @Test + public void setDomStorageEnabled() { + testHostApiImpl.setDomStorageEnabled(0L, true); + verify(mockWebSettings).setDomStorageEnabled(true); + } + + @Test + public void setJavaScriptCanOpenWindowsAutomatically() { + testHostApiImpl.setJavaScriptCanOpenWindowsAutomatically(0L, false); + verify(mockWebSettings).setJavaScriptCanOpenWindowsAutomatically(false); + } + + @Test + public void setSupportMultipleWindows() { + testHostApiImpl.setSupportMultipleWindows(0L, true); + verify(mockWebSettings).setSupportMultipleWindows(true); + } + + @Test + public void setJavaScriptEnabled() { + testHostApiImpl.setJavaScriptEnabled(0L, false); + verify(mockWebSettings).setJavaScriptEnabled(false); + } + + @Test + public void setUserAgentString() { + testHostApiImpl.setUserAgentString(0L, "hello"); + verify(mockWebSettings).setUserAgentString("hello"); + } + + @Test + public void setMediaPlaybackRequiresUserGesture() { + testHostApiImpl.setMediaPlaybackRequiresUserGesture(0L, false); + verify(mockWebSettings).setMediaPlaybackRequiresUserGesture(false); + } + + @Test + public void setSupportZoom() { + testHostApiImpl.setSupportZoom(0L, true); + verify(mockWebSettings).setSupportZoom(true); + } + + @Test + public void setLoadWithOverviewMode() { + testHostApiImpl.setLoadWithOverviewMode(0L, false); + verify(mockWebSettings).setLoadWithOverviewMode(false); + } + + @Test + public void setUseWideViewPort() { + testHostApiImpl.setUseWideViewPort(0L, true); + verify(mockWebSettings).setUseWideViewPort(true); + } + + @Test + public void setDisplayZoomControls() { + testHostApiImpl.setDisplayZoomControls(0L, false); + verify(mockWebSettings).setDisplayZoomControls(false); + } + + @Test + public void setBuiltInZoomControls() { + testHostApiImpl.setBuiltInZoomControls(0L, true); + verify(mockWebSettings).setBuiltInZoomControls(true); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java index 131a5a3eb53a..2a1d1bc03944 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java @@ -5,11 +5,51 @@ package io.flutter.plugins.webviewflutter; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.content.Context; +import android.webkit.DownloadListener; +import android.webkit.ValueCallback; +import android.webkit.WebView; import android.webkit.WebViewClient; + +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.HashMap; public class WebViewTest { + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + public WebView mockWebView; + + @Mock + WebViewHostApiImpl.WebViewProxy mockWebViewProxy; + + @Mock + Context mockContext; + + InstanceManager testInstanceManager; + WebViewHostApiImpl testHostApiImpl; + + @Before + public void setUp() { + testInstanceManager = new InstanceManager(); + when(mockWebViewProxy.createWebView(mockContext)).thenReturn(mockWebView); + testHostApiImpl = new WebViewHostApiImpl(testInstanceManager, mockWebViewProxy, mockContext); + testHostApiImpl.create(0L, true); + } + @Test public void errorCodes() { assertEquals( @@ -46,4 +86,142 @@ public void errorCodes() { FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_UNSUPPORTED_SCHEME), "unsupportedScheme"); } + + @Test + public void loadUrl() { + testHostApiImpl.loadUrl(0L, "https://www.google.com", new HashMap<>()); + verify(mockWebView).loadUrl("https://www.google.com", new HashMap<>()); + } + + @Test + public void getUrl() { + when(mockWebView.getUrl()).thenReturn("https://www.google.com"); + assertEquals(testHostApiImpl.getUrl(0L), "https://www.google.com"); + } + + @Test + public void canGoBack() { + when(mockWebView.canGoBack()).thenReturn(true); + assertEquals(testHostApiImpl.canGoBack(0L), true); + } + + @Test + public void canGoForward() { + when(mockWebView.canGoForward()).thenReturn(false); + assertEquals(testHostApiImpl.canGoForward(0L), false); + } + + @Test + public void goBack() { + testHostApiImpl.goBack(0L); + verify(mockWebView).goBack(); + } + + @Test + public void goForward() { + testHostApiImpl.goForward(0L); + verify(mockWebView).goForward(); + } + + @Test + public void reload() { + testHostApiImpl.reload(0L); + verify(mockWebView).reload(); + } + + @Test + public void clearCache() { + testHostApiImpl.clearCache(0L, false); + verify(mockWebView).clearCache(false); + } + + @Test + public void evaluateJavaScript() { + final String[] successValue = new String[1]; + testHostApiImpl.evaluateJavascript(0L, "2 + 2", new GeneratedAndroidWebView.Result() { + @Override + public void success(String result) { + successValue[0] = result; + } + + @Override + public void error(Throwable error) { + + } + }); + + @SuppressWarnings("unchecked") + final ArgumentCaptor> callbackCaptor = + ArgumentCaptor.forClass(ValueCallback.class); + verify(mockWebView).evaluateJavascript(eq("2 + 2"), callbackCaptor.capture()); + + callbackCaptor.getValue().onReceiveValue("da result"); + assertEquals(successValue[0], "da result"); + } + + @Test + public void getTitle() { + when(mockWebView.getTitle()).thenReturn("My title"); + assertEquals(testHostApiImpl.getTitle(0L), "My title"); + } + + @Test + public void scrollTo() { + testHostApiImpl.scrollTo(0L, 12L, 13L); + verify(mockWebView).scrollTo(12, 13); + } + + @Test + public void scrollBy() { + testHostApiImpl.scrollBy(0L, 15L, 23L); + verify(mockWebView).scrollBy(15, 23); + } + + @Test + public void getScrollX() { + when(mockWebView.getScrollX()).thenReturn(55); + assertEquals((long) testHostApiImpl.getScrollX(0L), 55); + } + + @Test + public void getScrollY() { + when(mockWebView.getScrollY()).thenReturn(23); + assertEquals((long) testHostApiImpl.getScrollY(0L), 23); + } + + @Test + public void setWebViewClient() { + final WebViewClient mockWebViewClient = mock(WebViewClient.class); + testInstanceManager.addInstance(mockWebViewClient, 1L); + + testHostApiImpl.setWebViewClient(0L, 1L); + verify(mockWebView).setWebViewClient(mockWebViewClient); + } + + @Test + public void addJavaScriptChannel() { + final JavaScriptChannel javaScriptChannel = new JavaScriptChannel(null, "aName", null); + testInstanceManager.addInstance(javaScriptChannel, 1L); + + testHostApiImpl.addJavaScriptChannel(0L, 1L); + verify(mockWebView).addJavascriptInterface(javaScriptChannel, "aName"); + } + + @Test + public void removeJavaScriptChannel() { + final JavaScriptChannel javaScriptChannel = new JavaScriptChannel(null, "aName", null); + testInstanceManager.addInstance(javaScriptChannel, 1L); + + testHostApiImpl.removeJavaScriptChannel(0L, 1L); + verify(mockWebView).removeJavascriptInterface("aName"); + } + + @Test + public void setDownloadListener() { + final DownloadListener mockDownloadListener = mock(DownloadListener.class); + testInstanceManager.addInstance(mockDownloadListener, 1L); + + testHostApiImpl.setDownloadListener(0L, 1L); + verify(mockWebView).setDownloadListener(mockDownloadListener); + } } diff --git a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh index d866473636cc..30a6918fc922 100755 --- a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh +++ b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh @@ -5,4 +5,6 @@ flutter pub run pigeon \ --input pigeons/android_webview.dart \ --dart_out lib/src/android_webview.pigeon.dart \ ---dart_test_out test/android_webview.pigeon.dart +--dart_test_out test/android_webview.pigeon.dart \ +--java_out android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.Java \ +--java_package io.flutter.plugins.webviewflutter From 31cf7af11e40ada4e9cda6b85c0435693668dfd1 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 20 Oct 2021 20:09:13 -0700 Subject: [PATCH 20/54] finish tests --- .../DownloadListenerHostApiImpl.java | 29 ++-- .../GeneratedAndroidWebView.java | 4 + .../JavaScriptChannelHostApiImpl.java | 30 +++- .../WebViewClientHostApiImpl.java | 163 +++++++++++++----- .../webviewflutter/DownloadListenerTest.java | 52 ++++++ .../webviewflutter/JavaScriptChannelTest.java | 48 ++++++ .../webviewflutter/TestBinaryMessenger.java | 25 +++ .../webviewflutter/WebViewClientTest.java | 70 ++++++++ 8 files changed, 363 insertions(+), 58 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java index 05f753033530..a89817e3b45b 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java @@ -5,28 +5,35 @@ class DownloadListenerHostApiImpl implements GeneratedAndroidWebView.DownloadListenerHostApi { private final InstanceManager instanceManager; + private final DownloadListenerProxy downloadListenerProxy; private final GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi; + static class DownloadListenerProxy { + DownloadListener createDownloadListener(Long instanceId, GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { + return (url, userAgent, contentDisposition, mimetype, contentLength) -> + downloadListenerFlutterApi.onDownloadStart( + instanceId, + url, + userAgent, + contentDisposition, + mimetype, + contentLength, + reply -> {}); + } + } + DownloadListenerHostApiImpl( InstanceManager instanceManager, + DownloadListenerProxy downloadListenerProxy, GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { this.instanceManager = instanceManager; + this.downloadListenerProxy = downloadListenerProxy; this.downloadListenerFlutterApi = downloadListenerFlutterApi; } @Override public void create(Long instanceId) { - final DownloadListener downloadListener = - (url, userAgent, contentDisposition, mimetype, contentLength) -> - downloadListenerFlutterApi.onDownloadStart( - instanceId, - url, - userAgent, - contentDisposition, - mimetype, - contentLength, - reply -> {}); - instanceManager.addInstance(downloadListener, instanceId); + instanceManager.addInstance(downloadListenerProxy.createDownloadListener(instanceId, downloadListenerFlutterApi), instanceId); } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index a790e6f722b5..0c4158e63502 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -1,3 +1,7 @@ +// 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. + // Autogenerated from Pigeon (v1.0.7), do not edit directly. // See also: https://pub.dev/packages/pigeon diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java index 2874e4c8b529..a4ab11898920 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -1,32 +1,48 @@ package io.flutter.plugins.webviewflutter; import android.os.Handler; +import android.os.Looper; + import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.JavaScriptChannelHostApi { private final InstanceManager instanceManager; + private final JavaScriptChannelProxy javaScriptChannelProxy; private final JavaScriptChannelFlutterApi javaScriptChannelFlutterApi; private final Handler platformThreadHandler; + + static class JavaScriptChannelProxy { + JavaScriptChannel createJavaScriptChannel(Long instanceId, JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, String channelName, Handler platformThreadHandler) { + return new JavaScriptChannel(null, channelName, platformThreadHandler) { + @Override + public void postMessage(String message) { + Runnable postMessageRunnable = + () -> javaScriptChannelFlutterApi.postMessage(instanceId, message, reply -> {}); + if (platformThreadHandler.getLooper() == Looper.myLooper()) { + postMessageRunnable.run(); + } else { + platformThreadHandler.post(postMessageRunnable); + } + } + }; + } + } JavaScriptChannelHostApiImpl( InstanceManager instanceManager, + JavaScriptChannelProxy javaScriptChannelProxy, JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, Handler platformThreadHandler) { this.instanceManager = instanceManager; + this.javaScriptChannelProxy = javaScriptChannelProxy; this.javaScriptChannelFlutterApi = javaScriptChannelFlutterApi; this.platformThreadHandler = platformThreadHandler; } @Override public void create(Long instanceId, String channelName) { - final JavaScriptChannel javaScriptChannel = - new JavaScriptChannel(null, channelName, platformThreadHandler) { - @Override - public void postMessage(String message) { - javaScriptChannelFlutterApi.postMessage(instanceId, message, reply -> {}); - } - }; + final JavaScriptChannel javaScriptChannel = javaScriptChannelProxy.createJavaScriptChannel(instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); instanceManager.addInstance(javaScriptChannel, instanceId); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java index 310c37c22189..109a71c2ef73 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java @@ -1,28 +1,66 @@ package io.flutter.plugins.webviewflutter; +import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.graphics.Bitmap; import android.os.Build; import android.webkit.WebResourceError; import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; + +import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; +import androidx.webkit.WebResourceErrorCompat; +import androidx.webkit.WebViewClientCompat; + import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientFlutterApi; class WebViewClientHostApiImpl implements GeneratedAndroidWebView.WebViewClientHostApi { private final InstanceManager instanceManager; + private final WebViewClientProxy webViewClientProxy; private final WebViewClientFlutterApi webViewClientFlutterApi; + + @RequiresApi(api = Build.VERSION_CODES.M) + static GeneratedAndroidWebView.WebResourceErrorData createWebResourceErrorData(WebResourceError error) { + final GeneratedAndroidWebView.WebResourceErrorData errorData = + new GeneratedAndroidWebView.WebResourceErrorData(); + errorData.setErrorCode((long) error.getErrorCode()); + errorData.setDescription(error.getDescription().toString()); + + return errorData; + } + + @SuppressLint("RequiresFeature") + static GeneratedAndroidWebView.WebResourceErrorData createWebResourceErrorData(WebResourceErrorCompat error) { + final GeneratedAndroidWebView.WebResourceErrorData errorData = + new GeneratedAndroidWebView.WebResourceErrorData(); + errorData.setErrorCode((long) error.getErrorCode()); + errorData.setDescription(error.getDescription().toString()); - WebViewClientHostApiImpl( - InstanceManager instanceManager, WebViewClientFlutterApi webViewClientFlutterApi) { - this.instanceManager = instanceManager; - this.webViewClientFlutterApi = webViewClientFlutterApi; + return errorData; + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + static GeneratedAndroidWebView.WebResourceRequestData createWebResourceRequestData(WebResourceRequest request) { + final GeneratedAndroidWebView.WebResourceRequestData requestData = + new GeneratedAndroidWebView.WebResourceRequestData(); + requestData.setUrl(request.getUrl().toString()); + requestData.setIsForMainFrame(request.isForMainFrame()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + requestData.setIsRedirect(request.isRedirect()); + } + requestData.setHasGesture(request.hasGesture()); + requestData.setMethod(request.getMethod()); + requestData.setRequestHeaders(request.getRequestHeaders()); + + return requestData; } - @Override - public void create(Long instanceId, Boolean shouldOverrideUrlLoading) { - final WebViewClient webViewClient = - new WebViewClient() { + static class WebViewClientProxy { + WebViewClient createWebViewClient(Long instanceId, InstanceManager instanceManager, Boolean shouldOverrideUrlLoading, WebViewClientFlutterApi webViewClientFlutterApi) { + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + return new WebViewClient() { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { webViewClientFlutterApi.onPageStarted( @@ -35,31 +73,14 @@ public void onPageFinished(WebView view, String url) { instanceId, instanceManager.getInstanceId(view), url, reply -> {}); } - @RequiresApi(api = Build.VERSION_CODES.M) @Override public void onReceivedError( WebView view, WebResourceRequest request, WebResourceError error) { - final GeneratedAndroidWebView.WebResourceRequestData requestData = - new GeneratedAndroidWebView.WebResourceRequestData(); - requestData.setUrl(request.getUrl().toString()); - requestData.setIsForMainFrame(request.isForMainFrame()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - requestData.setIsRedirect(request.isRedirect()); - } - requestData.setHasGesture(request.hasGesture()); - requestData.setMethod(request.getMethod()); - requestData.setRequestHeaders(request.getRequestHeaders()); - - final GeneratedAndroidWebView.WebResourceErrorData errorData = - new GeneratedAndroidWebView.WebResourceErrorData(); - errorData.setErrorCode((long) error.getErrorCode()); - errorData.setDescription(error.getDescription().toString()); - webViewClientFlutterApi.onReceivedRequestError( instanceId, instanceManager.getInstanceId(view), - requestData, - errorData, + createWebResourceRequestData(request), + createWebResourceErrorData(error), reply -> {}); } @@ -75,22 +96,68 @@ public void onReceivedError( reply -> {}); } - @RequiresApi(api = Build.VERSION_CODES.M) @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { - final GeneratedAndroidWebView.WebResourceRequestData requestData = - new GeneratedAndroidWebView.WebResourceRequestData(); - requestData.setUrl(request.getUrl().toString()); - requestData.setIsForMainFrame(request.isForMainFrame()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - requestData.setIsRedirect(request.isRedirect()); - } - requestData.setHasGesture(request.hasGesture()); - requestData.setMethod(request.getMethod()); - requestData.setRequestHeaders(request.getRequestHeaders()); + webViewClientFlutterApi.requestLoading( + instanceId, + instanceManager.getInstanceId(view), + createWebResourceRequestData(request), + reply -> {}); + return shouldOverrideUrlLoading; + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + webViewClientFlutterApi.urlLoading( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + return shouldOverrideUrlLoading; + } + }; + } else { + return new WebViewClientCompat() { + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + webViewClientFlutterApi.onPageStarted( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + + @Override + public void onPageFinished(WebView view, String url) { + webViewClientFlutterApi.onPageFinished( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + + // This method is only called when the WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR feature is + // enabled. The deprecated method is called when a device doesn't support this. + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @SuppressLint("RequiresFeature") + @Override + public void onReceivedError(@NonNull WebView view, @NonNull WebResourceRequest request, @NonNull WebResourceErrorCompat error) { + webViewClientFlutterApi.onReceivedRequestError( + instanceId, + instanceManager.getInstanceId(view), + createWebResourceRequestData(request), + createWebResourceErrorData(error), + reply -> {}); + } + + @Override + public void onReceivedError( + WebView view, int errorCode, String description, String failingUrl) { + webViewClientFlutterApi.onReceivedError( + instanceId, + instanceManager.getInstanceId(view), + (long) errorCode, + description, + failingUrl, + reply -> {}); + } + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @Override + public boolean shouldOverrideUrlLoading(@NonNull WebView view, @NonNull WebResourceRequest request) { webViewClientFlutterApi.requestLoading( - instanceId, instanceManager.getInstanceId(view), requestData, reply -> {}); + instanceId, instanceManager.getInstanceId(view), createWebResourceRequestData(request), reply -> {}); return shouldOverrideUrlLoading; } @@ -101,7 +168,23 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { return shouldOverrideUrlLoading; } }; - instanceManager.addInstance(webViewClient, instanceId); + } + } + } + + WebViewClientHostApiImpl( + InstanceManager instanceManager, WebViewClientProxy webViewClientProxy, WebViewClientFlutterApi webViewClientFlutterApi) { + this.instanceManager = instanceManager; + this.webViewClientProxy = webViewClientProxy; + this.webViewClientFlutterApi = webViewClientFlutterApi; + } + + @Override + public void create(Long instanceId, Boolean shouldOverrideUrlLoading) { + instanceManager.addInstance( + webViewClientProxy.createWebViewClient(instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi), + instanceId + ); } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java new file mode 100644 index 000000000000..e698eb647be0 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java @@ -0,0 +1,52 @@ +package io.flutter.plugins.webviewflutter; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import android.webkit.DownloadListener; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class DownloadListenerTest { + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + public GeneratedAndroidWebView.DownloadListenerFlutterApi mockFlutterApi; + + InstanceManager testInstanceManager; + DownloadListenerHostApiImpl testHostApiImpl; + DownloadListener testDownloadListener; + + @Before + public void setUp() { + testInstanceManager = new InstanceManager(); + + final DownloadListenerHostApiImpl.DownloadListenerProxy downloadListenerProxy = new DownloadListenerHostApiImpl.DownloadListenerProxy() { + @Override + DownloadListener createDownloadListener(Long instanceId, GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { + testDownloadListener = super.createDownloadListener(instanceId, downloadListenerFlutterApi); + return testDownloadListener; + } + }; + + testHostApiImpl = new DownloadListenerHostApiImpl(testInstanceManager, downloadListenerProxy, mockFlutterApi); + testHostApiImpl.create(0L); + } + + @Test + public void postMessage() { + testDownloadListener.onDownloadStart("https://www.google.com", + "userAgent", + "contentDisposition", + "mimetype", + 54); + verify(mockFlutterApi).onDownloadStart(eq(0L), eq("https://www.google.com"), eq("userAgent"), eq("contentDisposition"), eq("mimetype"), eq(54L), any()); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java new file mode 100644 index 000000000000..4f5ee84fdda5 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java @@ -0,0 +1,48 @@ +package io.flutter.plugins.webviewflutter; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import android.os.Handler; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class JavaScriptChannelTest { + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + public GeneratedAndroidWebView.JavaScriptChannelFlutterApi mockFlutterApi; + + InstanceManager testInstanceManager; + JavaScriptChannelHostApiImpl testHostApiImpl; + JavaScriptChannel testJavaScriptChannel; + + @Before + public void setUp() { + testInstanceManager = new InstanceManager(); + + final JavaScriptChannelHostApiImpl.JavaScriptChannelProxy javaScriptChannelProxy = new JavaScriptChannelHostApiImpl.JavaScriptChannelProxy() { + @Override + JavaScriptChannel createJavaScriptChannel(Long instanceId, GeneratedAndroidWebView.JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, String channelName, Handler platformThreadHandler) { + testJavaScriptChannel = super.createJavaScriptChannel(instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); + return testJavaScriptChannel; + } + }; + + testHostApiImpl = new JavaScriptChannelHostApiImpl(testInstanceManager, javaScriptChannelProxy, mockFlutterApi, new Handler()); + testHostApiImpl.create(0L, "aChannelName"); + } + + @Test + public void postMessage() { + testJavaScriptChannel.postMessage("A message post."); + verify(mockFlutterApi).postMessage(eq(0L), eq("A message post."), any()); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java new file mode 100644 index 000000000000..8e4bb78d488c --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java @@ -0,0 +1,25 @@ +package io.flutter.plugins.webviewflutter; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.nio.ByteBuffer; + +import io.flutter.plugin.common.BinaryMessenger; + +public class TestBinaryMessenger implements BinaryMessenger { + @Override + public void send(@NonNull String s, @Nullable ByteBuffer byteBuffer) { + + } + + @Override + public void send(@NonNull String s, @Nullable ByteBuffer byteBuffer, @Nullable BinaryReply binaryReply) { + + } + + @Override + public void setMessageHandler(@NonNull String s, @Nullable BinaryMessageHandler binaryMessageHandler) { + + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java new file mode 100644 index 000000000000..b941063047fd --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java @@ -0,0 +1,70 @@ +package io.flutter.plugins.webviewflutter; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.net.Uri; +import android.webkit.WebResourceRequest; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import java.util.Map; + +public class WebViewClientTest { + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + public GeneratedAndroidWebView.WebViewClientFlutterApi mockFlutterApi; + + @Mock + public WebView mockWebView; + + InstanceManager testInstanceManager; + WebViewClientHostApiImpl testHostApiImpl; + WebViewClient testWebViewClient; + + @Before + public void setUp() { + testInstanceManager = new InstanceManager(); + testInstanceManager.addInstance(mockWebView, 0L); + + final WebViewClientHostApiImpl.WebViewClientProxy webViewClientProxy = new WebViewClientHostApiImpl.WebViewClientProxy() { + @Override + WebViewClient createWebViewClient(Long instanceId, InstanceManager instanceManager, Boolean shouldOverrideUrlLoading, GeneratedAndroidWebView.WebViewClientFlutterApi webViewClientFlutterApi) { + testWebViewClient = super.createWebViewClient(instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi); + return testWebViewClient; + } + }; + + testHostApiImpl = new WebViewClientHostApiImpl(testInstanceManager, webViewClientProxy, mockFlutterApi); + testHostApiImpl.create(1L, true); + } + + @Test + public void onPageStarted() { + testWebViewClient.onPageStarted(mockWebView, "https://www.google.com", null); + verify(mockFlutterApi).onPageStarted(eq(1L), eq(0L), eq("https://www.google.com"), any()); + } + + @Test + public void onReceivedError() { + testWebViewClient.onReceivedError(mockWebView, 32, "description", "https://www.google.com"); + verify(mockFlutterApi).onReceivedError(eq(1L), eq(0L), eq(32L), eq("description"), eq("https://www.google.com"), any()); + } + + @Test + public void urlLoading() { + testWebViewClient.shouldOverrideUrlLoading(mockWebView, "https://www.google.com"); + verify(mockFlutterApi).urlLoading(eq(1L), eq(0L), eq("https://www.google.com"), any()); + } +} From 470ce8b9f12922953bd1529ddb7183decf40cf93 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 20 Oct 2021 20:09:48 -0700 Subject: [PATCH 21/54] formatting --- .../DownloadListenerHostApiImpl.java | 21 +- .../GeneratedAndroidWebView.java | 2080 ++++++++++------- .../JavaScriptChannelHostApiImpl.java | 16 +- .../WebViewClientHostApiImpl.java | 50 +- .../webviewflutter/WebViewHostApiImpl.java | 11 +- .../webviewflutter/DownloadListenerTest.java | 47 +- .../webviewflutter/JavaScriptChannelTest.java | 34 +- .../webviewflutter/TestBinaryMessenger.java | 18 +- .../webviewflutter/WebSettingsTest.java | 10 +- .../webviewflutter/WebViewClientTest.java | 43 +- .../plugins/webviewflutter/WebViewTest.java | 39 +- 11 files changed, 1338 insertions(+), 1031 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java index a89817e3b45b..5bf60ef3171c 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java @@ -2,26 +2,21 @@ import android.webkit.DownloadListener; -class DownloadListenerHostApiImpl - implements GeneratedAndroidWebView.DownloadListenerHostApi { +class DownloadListenerHostApiImpl implements GeneratedAndroidWebView.DownloadListenerHostApi { private final InstanceManager instanceManager; private final DownloadListenerProxy downloadListenerProxy; private final GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi; static class DownloadListenerProxy { - DownloadListener createDownloadListener(Long instanceId, GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { + DownloadListener createDownloadListener( + Long instanceId, + GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { return (url, userAgent, contentDisposition, mimetype, contentLength) -> downloadListenerFlutterApi.onDownloadStart( - instanceId, - url, - userAgent, - contentDisposition, - mimetype, - contentLength, - reply -> {}); + instanceId, url, userAgent, contentDisposition, mimetype, contentLength, reply -> {}); } } - + DownloadListenerHostApiImpl( InstanceManager instanceManager, DownloadListenerProxy downloadListenerProxy, @@ -33,7 +28,9 @@ DownloadListener createDownloadListener(Long instanceId, GeneratedAndroidWebView @Override public void create(Long instanceId) { - instanceManager.addInstance(downloadListenerProxy.createDownloadListener(instanceId, downloadListenerFlutterApi), instanceId); + instanceManager.addInstance( + downloadListenerProxy.createDownloadListener(instanceId, downloadListenerFlutterApi), + instanceId); } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index 0c4158e63502..f1725e1b7c7b 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -13,11 +13,10 @@ import io.flutter.plugin.common.StandardMessageCodec; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; -import java.util.Arrays; import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.Arrays; import java.util.HashMap; +import java.util.Map; /** Generated class from Pigeon. */ @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"}) @@ -26,28 +25,64 @@ public class GeneratedAndroidWebView { /** Generated class from Pigeon that represents data sent in messages. */ public static class WebResourceRequestData { private String url; - public String getUrl() { return url; } - public void setUrl(String setterArg) { this.url = setterArg; } + + public String getUrl() { + return url; + } + + public void setUrl(String setterArg) { + this.url = setterArg; + } private Boolean isForMainFrame; - public Boolean getIsForMainFrame() { return isForMainFrame; } - public void setIsForMainFrame(Boolean setterArg) { this.isForMainFrame = setterArg; } + + public Boolean getIsForMainFrame() { + return isForMainFrame; + } + + public void setIsForMainFrame(Boolean setterArg) { + this.isForMainFrame = setterArg; + } private Boolean isRedirect; - public Boolean getIsRedirect() { return isRedirect; } - public void setIsRedirect(Boolean setterArg) { this.isRedirect = setterArg; } + + public Boolean getIsRedirect() { + return isRedirect; + } + + public void setIsRedirect(Boolean setterArg) { + this.isRedirect = setterArg; + } private Boolean hasGesture; - public Boolean getHasGesture() { return hasGesture; } - public void setHasGesture(Boolean setterArg) { this.hasGesture = setterArg; } + + public Boolean getHasGesture() { + return hasGesture; + } + + public void setHasGesture(Boolean setterArg) { + this.hasGesture = setterArg; + } private String method; - public String getMethod() { return method; } - public void setMethod(String setterArg) { this.method = setterArg; } + + public String getMethod() { + return method; + } + + public void setMethod(String setterArg) { + this.method = setterArg; + } private Map requestHeaders; - public Map getRequestHeaders() { return requestHeaders; } - public void setRequestHeaders(Map setterArg) { this.requestHeaders = setterArg; } + + public Map getRequestHeaders() { + return requestHeaders; + } + + public void setRequestHeaders(Map setterArg) { + this.requestHeaders = setterArg; + } Map toMap() { Map toMapResult = new HashMap<>(); @@ -59,20 +94,21 @@ Map toMap() { toMapResult.put("requestHeaders", requestHeaders); return toMapResult; } + static WebResourceRequestData fromMap(Map map) { WebResourceRequestData fromMapResult = new WebResourceRequestData(); Object url = map.get("url"); - fromMapResult.url = (String)url; + fromMapResult.url = (String) url; Object isForMainFrame = map.get("isForMainFrame"); - fromMapResult.isForMainFrame = (Boolean)isForMainFrame; + fromMapResult.isForMainFrame = (Boolean) isForMainFrame; Object isRedirect = map.get("isRedirect"); - fromMapResult.isRedirect = (Boolean)isRedirect; + fromMapResult.isRedirect = (Boolean) isRedirect; Object hasGesture = map.get("hasGesture"); - fromMapResult.hasGesture = (Boolean)hasGesture; + fromMapResult.hasGesture = (Boolean) hasGesture; Object method = map.get("method"); - fromMapResult.method = (String)method; + fromMapResult.method = (String) method; Object requestHeaders = map.get("requestHeaders"); - fromMapResult.requestHeaders = (Map)requestHeaders; + fromMapResult.requestHeaders = (Map) requestHeaders; return fromMapResult; } } @@ -80,12 +116,24 @@ static WebResourceRequestData fromMap(Map map) { /** Generated class from Pigeon that represents data sent in messages. */ public static class WebResourceErrorData { private Long errorCode; - public Long getErrorCode() { return errorCode; } - public void setErrorCode(Long setterArg) { this.errorCode = setterArg; } + + public Long getErrorCode() { + return errorCode; + } + + public void setErrorCode(Long setterArg) { + this.errorCode = setterArg; + } private String description; - public String getDescription() { return description; } - public void setDescription(String setterArg) { this.description = setterArg; } + + public String getDescription() { + return description; + } + + public void setDescription(String setterArg) { + this.description = setterArg; + } Map toMap() { Map toMapResult = new HashMap<>(); @@ -93,47 +141,74 @@ Map toMap() { toMapResult.put("description", description); return toMapResult; } + static WebResourceErrorData fromMap(Map map) { WebResourceErrorData fromMapResult = new WebResourceErrorData(); Object errorCode = map.get("errorCode"); - fromMapResult.errorCode = (errorCode == null) ? null : ((errorCode instanceof Integer) ? (Integer)errorCode : (Long)errorCode); + fromMapResult.errorCode = + (errorCode == null) + ? null + : ((errorCode instanceof Integer) ? (Integer) errorCode : (Long) errorCode); Object description = map.get("description"); - fromMapResult.description = (String)description; + fromMapResult.description = (String) description; return fromMapResult; } } public interface Result { void success(T result); + void error(Throwable error); } + private static class WebViewHostApiCodec extends StandardMessageCodec { public static final WebViewHostApiCodec INSTANCE = new WebViewHostApiCodec(); + private WebViewHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface WebViewHostApi { void create(Long instanceId, Boolean useHybridComposition); + void dispose(Long instanceId); + void loadUrl(Long instanceId, String url, Map headers); + String getUrl(Long instanceId); + Boolean canGoBack(Long instanceId); + Boolean canGoForward(Long instanceId); + void goBack(Long instanceId); + void goForward(Long instanceId); + void reload(Long instanceId); + void clearCache(Long instanceId, Boolean includeDiskFiles); + void evaluateJavascript(Long instanceId, String javascriptString, Result result); + String getTitle(Long instanceId); + void scrollTo(Long instanceId, Long x, Long y); + void scrollBy(Long instanceId, Long x, Long y); + Long getScrollX(Long instanceId); + Long getScrollY(Long instanceId); + void setWebContentsDebuggingEnabled(Boolean enabled); + void setWebViewClient(Long instanceId, Long webViewClientInstanceId); + void addJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); + void removeJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); + void setDownloadListener(Long instanceId, Long listenerInstanceId); /** The codec used by WebViewHostApi. */ @@ -145,591 +220,645 @@ static MessageCodec getCodec() { static void setup(BinaryMessenger binaryMessenger, WebViewHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.create", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean useHybridCompositionArg = (Boolean)args.get(1); - if (useHybridCompositionArg == null) { - throw new NullPointerException("useHybridCompositionArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), useHybridCompositionArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean useHybridCompositionArg = (Boolean) args.get(1); + if (useHybridCompositionArg == null) { + throw new NullPointerException("useHybridCompositionArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), useHybridCompositionArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.dispose", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.loadUrl", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.loadUrl", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String urlArg = (String)args.get(1); - if (urlArg == null) { - throw new NullPointerException("urlArg unexpectedly null."); - } - Map headersArg = (Map)args.get(2); - if (headersArg == null) { - throw new NullPointerException("headersArg unexpectedly null."); - } - api.loadUrl(instanceIdArg.longValue(), urlArg, headersArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String urlArg = (String) args.get(1); + if (urlArg == null) { + throw new NullPointerException("urlArg unexpectedly null."); + } + Map headersArg = (Map) args.get(2); + if (headersArg == null) { + throw new NullPointerException("headersArg unexpectedly null."); + } + api.loadUrl(instanceIdArg.longValue(), urlArg, headersArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getUrl", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getUrl", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String output = api.getUrl(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String output = api.getUrl(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoBack", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoBack", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean output = api.canGoBack(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean output = api.canGoBack(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoForward", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoForward", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean output = api.canGoForward(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean output = api.canGoForward(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goBack", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goBack", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.goBack(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.goBack(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goForward", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goForward", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.goForward(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.goForward(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.reload", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.reload", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.reload(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.reload(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.clearCache", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.clearCache", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean includeDiskFilesArg = (Boolean)args.get(1); - if (includeDiskFilesArg == null) { - throw new NullPointerException("includeDiskFilesArg unexpectedly null."); - } - api.clearCache(instanceIdArg.longValue(), includeDiskFilesArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean includeDiskFilesArg = (Boolean) args.get(1); + if (includeDiskFilesArg == null) { + throw new NullPointerException("includeDiskFilesArg unexpectedly null."); + } + api.clearCache(instanceIdArg.longValue(), includeDiskFilesArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.evaluateJavascript", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.evaluateJavascript", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String javascriptStringArg = (String)args.get(1); - if (javascriptStringArg == null) { - throw new NullPointerException("javascriptStringArg unexpectedly null."); - } - Result resultCallback = new Result() { - public void success(String result) { - wrapped.put("result", result); - reply.reply(wrapped); - } - public void error(Throwable error) { - wrapped.put("error", wrapError(error)); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String javascriptStringArg = (String) args.get(1); + if (javascriptStringArg == null) { + throw new NullPointerException("javascriptStringArg unexpectedly null."); + } + Result resultCallback = + new Result() { + public void success(String result) { + wrapped.put("result", result); + reply.reply(wrapped); + } + + public void error(Throwable error) { + wrapped.put("error", wrapError(error)); + reply.reply(wrapped); + } + }; + + api.evaluateJavascript( + instanceIdArg.longValue(), javascriptStringArg, resultCallback); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); reply.reply(wrapped); } - }; - - api.evaluateJavascript(instanceIdArg.longValue(), javascriptStringArg, resultCallback); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - reply.reply(wrapped); - } - }); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getTitle", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getTitle", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String output = api.getTitle(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String output = api.getTitle(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollTo", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollTo", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number xArg = (Number)args.get(1); - if (xArg == null) { - throw new NullPointerException("xArg unexpectedly null."); - } - Number yArg = (Number)args.get(2); - if (yArg == null) { - throw new NullPointerException("yArg unexpectedly null."); - } - api.scrollTo(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number xArg = (Number) args.get(1); + if (xArg == null) { + throw new NullPointerException("xArg unexpectedly null."); + } + Number yArg = (Number) args.get(2); + if (yArg == null) { + throw new NullPointerException("yArg unexpectedly null."); + } + api.scrollTo(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollBy", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollBy", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number xArg = (Number)args.get(1); - if (xArg == null) { - throw new NullPointerException("xArg unexpectedly null."); - } - Number yArg = (Number)args.get(2); - if (yArg == null) { - throw new NullPointerException("yArg unexpectedly null."); - } - api.scrollBy(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number xArg = (Number) args.get(1); + if (xArg == null) { + throw new NullPointerException("xArg unexpectedly null."); + } + Number yArg = (Number) args.get(2); + if (yArg == null) { + throw new NullPointerException("yArg unexpectedly null."); + } + api.scrollBy(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollX", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollX", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Long output = api.getScrollX(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Long output = api.getScrollX(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollY", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollY", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Long output = api.getScrollY(instanceIdArg.longValue()); - wrapped.put("result", output); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Long output = api.getScrollY(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Boolean enabledArg = (Boolean)args.get(0); - if (enabledArg == null) { - throw new NullPointerException("enabledArg unexpectedly null."); - } - api.setWebContentsDebuggingEnabled(enabledArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Boolean enabledArg = (Boolean) args.get(0); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setWebContentsDebuggingEnabled(enabledArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebViewClient", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebViewClient", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number webViewClientInstanceIdArg = (Number)args.get(1); - if (webViewClientInstanceIdArg == null) { - throw new NullPointerException("webViewClientInstanceIdArg unexpectedly null."); - } - api.setWebViewClient(instanceIdArg.longValue(), webViewClientInstanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number webViewClientInstanceIdArg = (Number) args.get(1); + if (webViewClientInstanceIdArg == null) { + throw new NullPointerException("webViewClientInstanceIdArg unexpectedly null."); + } + api.setWebViewClient( + instanceIdArg.longValue(), webViewClientInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number javaScriptChannelInstanceIdArg = (Number)args.get(1); - if (javaScriptChannelInstanceIdArg == null) { - throw new NullPointerException("javaScriptChannelInstanceIdArg unexpectedly null."); - } - api.addJavaScriptChannel(instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number javaScriptChannelInstanceIdArg = (Number) args.get(1); + if (javaScriptChannelInstanceIdArg == null) { + throw new NullPointerException( + "javaScriptChannelInstanceIdArg unexpectedly null."); + } + api.addJavaScriptChannel( + instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number javaScriptChannelInstanceIdArg = (Number)args.get(1); - if (javaScriptChannelInstanceIdArg == null) { - throw new NullPointerException("javaScriptChannelInstanceIdArg unexpectedly null."); - } - api.removeJavaScriptChannel(instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number javaScriptChannelInstanceIdArg = (Number) args.get(1); + if (javaScriptChannelInstanceIdArg == null) { + throw new NullPointerException( + "javaScriptChannelInstanceIdArg unexpectedly null."); + } + api.removeJavaScriptChannel( + instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setDownloadListener", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.setDownloadListener", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number listenerInstanceIdArg = (Number)args.get(1); - if (listenerInstanceIdArg == null) { - throw new NullPointerException("listenerInstanceIdArg unexpectedly null."); - } - api.setDownloadListener(instanceIdArg.longValue(), listenerInstanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number listenerInstanceIdArg = (Number) args.get(1); + if (listenerInstanceIdArg == null) { + throw new NullPointerException("listenerInstanceIdArg unexpectedly null."); + } + api.setDownloadListener( + instanceIdArg.longValue(), listenerInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } + private static class WebSettingsHostApiCodec extends StandardMessageCodec { public static final WebSettingsHostApiCodec INSTANCE = new WebSettingsHostApiCodec(); + private WebSettingsHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface WebSettingsHostApi { void create(Long instanceId, Long webViewInstanceId); + void dispose(Long instanceId); + void setDomStorageEnabled(Long instanceId, Boolean flag); + void setJavaScriptCanOpenWindowsAutomatically(Long instanceId, Boolean flag); + void setSupportMultipleWindows(Long instanceId, Boolean support); + void setJavaScriptEnabled(Long instanceId, Boolean flag); + void setUserAgentString(Long instanceId, String userAgentString); + void setMediaPlaybackRequiresUserGesture(Long instanceId, Boolean require); + void setSupportZoom(Long instanceId, Boolean support); + void setLoadWithOverviewMode(Long instanceId, Boolean overview); + void setUseWideViewPort(Long instanceId, Boolean use); + void setDisplayZoomControls(Long instanceId, Boolean enabled); + void setBuiltInZoomControls(Long instanceId, Boolean enabled); /** The codec used by WebSettingsHostApi. */ @@ -737,378 +866,419 @@ static MessageCodec getCodec() { return WebSettingsHostApiCodec.INSTANCE; } - /** Sets up an instance of `WebSettingsHostApi` to handle messages through the `binaryMessenger`. */ + /** + * Sets up an instance of `WebSettingsHostApi` to handle messages through the `binaryMessenger`. + */ static void setup(BinaryMessenger binaryMessenger, WebSettingsHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.create", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Number webViewInstanceIdArg = (Number)args.get(1); - if (webViewInstanceIdArg == null) { - throw new NullPointerException("webViewInstanceIdArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), webViewInstanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number webViewInstanceIdArg = (Number) args.get(1); + if (webViewInstanceIdArg == null) { + throw new NullPointerException("webViewInstanceIdArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), webViewInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.dispose", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean flagArg = (Boolean)args.get(1); - if (flagArg == null) { - throw new NullPointerException("flagArg unexpectedly null."); - } - api.setDomStorageEnabled(instanceIdArg.longValue(), flagArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean) args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setDomStorageEnabled(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean flagArg = (Boolean)args.get(1); - if (flagArg == null) { - throw new NullPointerException("flagArg unexpectedly null."); - } - api.setJavaScriptCanOpenWindowsAutomatically(instanceIdArg.longValue(), flagArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean) args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setJavaScriptCanOpenWindowsAutomatically(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean supportArg = (Boolean)args.get(1); - if (supportArg == null) { - throw new NullPointerException("supportArg unexpectedly null."); - } - api.setSupportMultipleWindows(instanceIdArg.longValue(), supportArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean supportArg = (Boolean) args.get(1); + if (supportArg == null) { + throw new NullPointerException("supportArg unexpectedly null."); + } + api.setSupportMultipleWindows(instanceIdArg.longValue(), supportArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean flagArg = (Boolean)args.get(1); - if (flagArg == null) { - throw new NullPointerException("flagArg unexpectedly null."); - } - api.setJavaScriptEnabled(instanceIdArg.longValue(), flagArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean) args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setJavaScriptEnabled(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String userAgentStringArg = (String)args.get(1); - if (userAgentStringArg == null) { - throw new NullPointerException("userAgentStringArg unexpectedly null."); - } - api.setUserAgentString(instanceIdArg.longValue(), userAgentStringArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String userAgentStringArg = (String) args.get(1); + if (userAgentStringArg == null) { + throw new NullPointerException("userAgentStringArg unexpectedly null."); + } + api.setUserAgentString(instanceIdArg.longValue(), userAgentStringArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean requireArg = (Boolean)args.get(1); - if (requireArg == null) { - throw new NullPointerException("requireArg unexpectedly null."); - } - api.setMediaPlaybackRequiresUserGesture(instanceIdArg.longValue(), requireArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean requireArg = (Boolean) args.get(1); + if (requireArg == null) { + throw new NullPointerException("requireArg unexpectedly null."); + } + api.setMediaPlaybackRequiresUserGesture(instanceIdArg.longValue(), requireArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean supportArg = (Boolean)args.get(1); - if (supportArg == null) { - throw new NullPointerException("supportArg unexpectedly null."); - } - api.setSupportZoom(instanceIdArg.longValue(), supportArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean supportArg = (Boolean) args.get(1); + if (supportArg == null) { + throw new NullPointerException("supportArg unexpectedly null."); + } + api.setSupportZoom(instanceIdArg.longValue(), supportArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean overviewArg = (Boolean)args.get(1); - if (overviewArg == null) { - throw new NullPointerException("overviewArg unexpectedly null."); - } - api.setLoadWithOverviewMode(instanceIdArg.longValue(), overviewArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean overviewArg = (Boolean) args.get(1); + if (overviewArg == null) { + throw new NullPointerException("overviewArg unexpectedly null."); + } + api.setLoadWithOverviewMode(instanceIdArg.longValue(), overviewArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean useArg = (Boolean)args.get(1); - if (useArg == null) { - throw new NullPointerException("useArg unexpectedly null."); - } - api.setUseWideViewPort(instanceIdArg.longValue(), useArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean useArg = (Boolean) args.get(1); + if (useArg == null) { + throw new NullPointerException("useArg unexpectedly null."); + } + api.setUseWideViewPort(instanceIdArg.longValue(), useArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean enabledArg = (Boolean)args.get(1); - if (enabledArg == null) { - throw new NullPointerException("enabledArg unexpectedly null."); - } - api.setDisplayZoomControls(instanceIdArg.longValue(), enabledArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean enabledArg = (Boolean) args.get(1); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setDisplayZoomControls(instanceIdArg.longValue(), enabledArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls", + getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean enabledArg = (Boolean)args.get(1); - if (enabledArg == null) { - throw new NullPointerException("enabledArg unexpectedly null."); - } - api.setBuiltInZoomControls(instanceIdArg.longValue(), enabledArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean enabledArg = (Boolean) args.get(1); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setBuiltInZoomControls(instanceIdArg.longValue(), enabledArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } + private static class JavaScriptChannelHostApiCodec extends StandardMessageCodec { - public static final JavaScriptChannelHostApiCodec INSTANCE = new JavaScriptChannelHostApiCodec(); + public static final JavaScriptChannelHostApiCodec INSTANCE = + new JavaScriptChannelHostApiCodec(); + private JavaScriptChannelHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface JavaScriptChannelHostApi { void create(Long instanceId, String channelName); + void dispose(Long instanceId); /** The codec used by JavaScriptChannelHostApi. */ @@ -1116,96 +1286,115 @@ static MessageCodec getCodec() { return JavaScriptChannelHostApiCodec.INSTANCE; } - /** Sets up an instance of `JavaScriptChannelHostApi` to handle messages through the `binaryMessenger`. */ + /** + * Sets up an instance of `JavaScriptChannelHostApi` to handle messages through the + * `binaryMessenger`. + */ static void setup(BinaryMessenger binaryMessenger, JavaScriptChannelHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.create", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String channelNameArg = (String)args.get(1); - if (channelNameArg == null) { - throw new NullPointerException("channelNameArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), channelNameArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String channelNameArg = (String) args.get(1); + if (channelNameArg == null) { + throw new NullPointerException("channelNameArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), channelNameArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.dispose", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } + private static class JavaScriptChannelFlutterApiCodec extends StandardMessageCodec { - public static final JavaScriptChannelFlutterApiCodec INSTANCE = new JavaScriptChannelFlutterApiCodec(); + public static final JavaScriptChannelFlutterApiCodec INSTANCE = + new JavaScriptChannelFlutterApiCodec(); + private JavaScriptChannelFlutterApiCodec() {} } - /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ public static class JavaScriptChannelFlutterApi { private final BinaryMessenger binaryMessenger; - public JavaScriptChannelFlutterApi(BinaryMessenger argBinaryMessenger){ + + public JavaScriptChannelFlutterApi(BinaryMessenger argBinaryMessenger) { this.binaryMessenger = argBinaryMessenger; } + public interface Reply { void reply(T reply); } + static MessageCodec getCodec() { return JavaScriptChannelFlutterApiCodec.INSTANCE; } public void postMessage(Long instanceIdArg, String messageArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, messageArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, messageArg)), + channelReply -> { + callback.reply(null); + }); } } + private static class WebViewClientHostApiCodec extends StandardMessageCodec { public static final WebViewClientHostApiCodec INSTANCE = new WebViewClientHostApiCodec(); + private WebViewClientHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface WebViewClientHostApi { void create(Long instanceId, Boolean shouldOverrideUrlLoading); + void dispose(Long instanceId); /** The codec used by WebViewClientHostApi. */ @@ -1213,166 +1402,236 @@ static MessageCodec getCodec() { return WebViewClientHostApiCodec.INSTANCE; } - /** Sets up an instance of `WebViewClientHostApi` to handle messages through the `binaryMessenger`. */ + /** + * Sets up an instance of `WebViewClientHostApi` to handle messages through the + * `binaryMessenger`. + */ static void setup(BinaryMessenger binaryMessenger, WebViewClientHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.create", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - Boolean shouldOverrideUrlLoadingArg = (Boolean)args.get(1); - if (shouldOverrideUrlLoadingArg == null) { - throw new NullPointerException("shouldOverrideUrlLoadingArg unexpectedly null."); - } - api.create(instanceIdArg.longValue(), shouldOverrideUrlLoadingArg); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean shouldOverrideUrlLoadingArg = (Boolean) args.get(1); + if (shouldOverrideUrlLoadingArg == null) { + throw new NullPointerException( + "shouldOverrideUrlLoadingArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), shouldOverrideUrlLoadingArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.dispose", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } + private static class WebViewClientFlutterApiCodec extends StandardMessageCodec { public static final WebViewClientFlutterApiCodec INSTANCE = new WebViewClientFlutterApiCodec(); + private WebViewClientFlutterApiCodec() {} + @Override protected Object readValueOfType(byte type, ByteBuffer buffer) { switch (type) { - case (byte)128: + case (byte) 128: return WebResourceErrorData.fromMap((Map) readValue(buffer)); - - case (byte)129: + + case (byte) 129: return WebResourceRequestData.fromMap((Map) readValue(buffer)); - - case (byte)130: + + case (byte) 130: return WebResourceRequestData.fromMap((Map) readValue(buffer)); - - default: + + default: return super.readValueOfType(type, buffer); - } } + @Override - protected void writeValue(ByteArrayOutputStream stream, Object value) { + protected void writeValue(ByteArrayOutputStream stream, Object value) { if (value instanceof WebResourceErrorData) { stream.write(128); writeValue(stream, ((WebResourceErrorData) value).toMap()); - } else - if (value instanceof WebResourceRequestData) { + } else if (value instanceof WebResourceRequestData) { stream.write(129); writeValue(stream, ((WebResourceRequestData) value).toMap()); - } else - if (value instanceof WebResourceRequestData) { + } else if (value instanceof WebResourceRequestData) { stream.write(130); writeValue(stream, ((WebResourceRequestData) value).toMap()); - } else -{ + } else { super.writeValue(stream, value); } } } - /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ public static class WebViewClientFlutterApi { private final BinaryMessenger binaryMessenger; - public WebViewClientFlutterApi(BinaryMessenger argBinaryMessenger){ + + public WebViewClientFlutterApi(BinaryMessenger argBinaryMessenger) { this.binaryMessenger = argBinaryMessenger; } + public interface Reply { void reply(T reply); } + static MessageCodec getCodec() { return WebViewClientFlutterApiCodec.INSTANCE; } - public void onPageStarted(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + public void onPageStarted( + Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), + channelReply -> { + callback.reply(null); + }); } - public void onPageFinished(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + + public void onPageFinished( + Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), + channelReply -> { + callback.reply(null); + }); } - public void onReceivedRequestError(Long instanceIdArg, Long webViewInstanceIdArg, WebResourceRequestData requestArg, WebResourceErrorData errorArg, Reply callback) { + + public void onReceivedRequestError( + Long instanceIdArg, + Long webViewInstanceIdArg, + WebResourceRequestData requestArg, + WebResourceErrorData errorArg, + Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg, errorArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError", + getCodec()); + channel.send( + new ArrayList( + Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg, errorArg)), + channelReply -> { + callback.reply(null); + }); } - public void onReceivedError(Long instanceIdArg, Long webViewInstanceIdArg, Long errorCodeArg, String descriptionArg, String failingUrlArg, Reply callback) { + + public void onReceivedError( + Long instanceIdArg, + Long webViewInstanceIdArg, + Long errorCodeArg, + String descriptionArg, + String failingUrlArg, + Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, errorCodeArg, descriptionArg, failingUrlArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError", + getCodec()); + channel.send( + new ArrayList( + Arrays.asList( + instanceIdArg, + webViewInstanceIdArg, + errorCodeArg, + descriptionArg, + failingUrlArg)), + channelReply -> { + callback.reply(null); + }); } - public void requestLoading(Long instanceIdArg, Long webViewInstanceIdArg, WebResourceRequestData requestArg, Reply callback) { + + public void requestLoading( + Long instanceIdArg, + Long webViewInstanceIdArg, + WebResourceRequestData requestArg, + Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg)), + channelReply -> { + callback.reply(null); + }); } - public void urlLoading(Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + + public void urlLoading( + Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading", getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), + channelReply -> { + callback.reply(null); + }); } } + private static class DownloadListenerHostApiCodec extends StandardMessageCodec { public static final DownloadListenerHostApiCodec INSTANCE = new DownloadListenerHostApiCodec(); + private DownloadListenerHostApiCodec() {} } - /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface DownloadListenerHostApi { void create(Long instanceId); + void dispose(Long instanceId); /** The codec used by DownloadListenerHostApi. */ @@ -1380,84 +1639,115 @@ static MessageCodec getCodec() { return DownloadListenerHostApiCodec.INSTANCE; } - /** Sets up an instance of `DownloadListenerHostApi` to handle messages through the `binaryMessenger`. */ + /** + * Sets up an instance of `DownloadListenerHostApi` to handle messages through the + * `binaryMessenger`. + */ static void setup(BinaryMessenger binaryMessenger, DownloadListenerHostApi api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.create", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.create", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.create(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.create(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.dispose", getCodec()); + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.dispose", getCodec()); if (api != null) { - channel.setMessageHandler((message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList)message; - Number instanceIdArg = (Number)args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } - catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); } else { channel.setMessageHandler(null); } } } } + private static class DownloadListenerFlutterApiCodec extends StandardMessageCodec { - public static final DownloadListenerFlutterApiCodec INSTANCE = new DownloadListenerFlutterApiCodec(); + public static final DownloadListenerFlutterApiCodec INSTANCE = + new DownloadListenerFlutterApiCodec(); + private DownloadListenerFlutterApiCodec() {} } - /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ public static class DownloadListenerFlutterApi { private final BinaryMessenger binaryMessenger; - public DownloadListenerFlutterApi(BinaryMessenger argBinaryMessenger){ + + public DownloadListenerFlutterApi(BinaryMessenger argBinaryMessenger) { this.binaryMessenger = argBinaryMessenger; } + public interface Reply { void reply(T reply); } + static MessageCodec getCodec() { return DownloadListenerFlutterApiCodec.INSTANCE; } - public void onDownloadStart(Long instanceIdArg, String urlArg, String userAgentArg, String contentDispositionArg, String mimetypeArg, Long contentLengthArg, Reply callback) { + public void onDownloadStart( + Long instanceIdArg, + String urlArg, + String userAgentArg, + String contentDispositionArg, + String mimetypeArg, + Long contentLengthArg, + Reply callback) { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart", getCodec()); - channel.send(new ArrayList(Arrays.asList(instanceIdArg, urlArg, userAgentArg, contentDispositionArg, mimetypeArg, contentLengthArg)), channelReply -> { - callback.reply(null); - }); + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart", + getCodec()); + channel.send( + new ArrayList( + Arrays.asList( + instanceIdArg, + urlArg, + userAgentArg, + contentDispositionArg, + mimetypeArg, + contentLengthArg)), + channelReply -> { + callback.reply(null); + }); } } + private static Map wrapError(Throwable exception) { Map errorMap = new HashMap<>(); errorMap.put("message", exception.toString()); diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java index a4ab11898920..b088eca52229 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -2,18 +2,20 @@ import android.os.Handler; import android.os.Looper; - import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; -class JavaScriptChannelHostApiImpl - implements GeneratedAndroidWebView.JavaScriptChannelHostApi { +class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.JavaScriptChannelHostApi { private final InstanceManager instanceManager; private final JavaScriptChannelProxy javaScriptChannelProxy; private final JavaScriptChannelFlutterApi javaScriptChannelFlutterApi; private final Handler platformThreadHandler; - + static class JavaScriptChannelProxy { - JavaScriptChannel createJavaScriptChannel(Long instanceId, JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, String channelName, Handler platformThreadHandler) { + JavaScriptChannel createJavaScriptChannel( + Long instanceId, + JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, + String channelName, + Handler platformThreadHandler) { return new JavaScriptChannel(null, channelName, platformThreadHandler) { @Override public void postMessage(String message) { @@ -42,7 +44,9 @@ public void postMessage(String message) { @Override public void create(Long instanceId, String channelName) { - final JavaScriptChannel javaScriptChannel = javaScriptChannelProxy.createJavaScriptChannel(instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); + final JavaScriptChannel javaScriptChannel = + javaScriptChannelProxy.createJavaScriptChannel( + instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); instanceManager.addInstance(javaScriptChannel, instanceId); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java index 109a71c2ef73..a3736fd17989 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java @@ -8,31 +8,31 @@ import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; - import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.webkit.WebResourceErrorCompat; import androidx.webkit.WebViewClientCompat; - import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientFlutterApi; class WebViewClientHostApiImpl implements GeneratedAndroidWebView.WebViewClientHostApi { private final InstanceManager instanceManager; private final WebViewClientProxy webViewClientProxy; private final WebViewClientFlutterApi webViewClientFlutterApi; - + @RequiresApi(api = Build.VERSION_CODES.M) - static GeneratedAndroidWebView.WebResourceErrorData createWebResourceErrorData(WebResourceError error) { + static GeneratedAndroidWebView.WebResourceErrorData createWebResourceErrorData( + WebResourceError error) { final GeneratedAndroidWebView.WebResourceErrorData errorData = new GeneratedAndroidWebView.WebResourceErrorData(); errorData.setErrorCode((long) error.getErrorCode()); errorData.setDescription(error.getDescription().toString()); - + return errorData; } - + @SuppressLint("RequiresFeature") - static GeneratedAndroidWebView.WebResourceErrorData createWebResourceErrorData(WebResourceErrorCompat error) { + static GeneratedAndroidWebView.WebResourceErrorData createWebResourceErrorData( + WebResourceErrorCompat error) { final GeneratedAndroidWebView.WebResourceErrorData errorData = new GeneratedAndroidWebView.WebResourceErrorData(); errorData.setErrorCode((long) error.getErrorCode()); @@ -40,9 +40,10 @@ static GeneratedAndroidWebView.WebResourceErrorData createWebResourceErrorData(W return errorData; } - + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - static GeneratedAndroidWebView.WebResourceRequestData createWebResourceRequestData(WebResourceRequest request) { + static GeneratedAndroidWebView.WebResourceRequestData createWebResourceRequestData( + WebResourceRequest request) { final GeneratedAndroidWebView.WebResourceRequestData requestData = new GeneratedAndroidWebView.WebResourceRequestData(); requestData.setUrl(request.getUrl().toString()); @@ -53,12 +54,16 @@ static GeneratedAndroidWebView.WebResourceRequestData createWebResourceRequestDa requestData.setHasGesture(request.hasGesture()); requestData.setMethod(request.getMethod()); requestData.setRequestHeaders(request.getRequestHeaders()); - + return requestData; } static class WebViewClientProxy { - WebViewClient createWebViewClient(Long instanceId, InstanceManager instanceManager, Boolean shouldOverrideUrlLoading, WebViewClientFlutterApi webViewClientFlutterApi) { + WebViewClient createWebViewClient( + Long instanceId, + InstanceManager instanceManager, + Boolean shouldOverrideUrlLoading, + WebViewClientFlutterApi webViewClientFlutterApi) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return new WebViewClient() { @Override @@ -132,7 +137,10 @@ public void onPageFinished(WebView view, String url) { @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @SuppressLint("RequiresFeature") @Override - public void onReceivedError(@NonNull WebView view, @NonNull WebResourceRequest request, @NonNull WebResourceErrorCompat error) { + public void onReceivedError( + @NonNull WebView view, + @NonNull WebResourceRequest request, + @NonNull WebResourceErrorCompat error) { webViewClientFlutterApi.onReceivedRequestError( instanceId, instanceManager.getInstanceId(view), @@ -155,9 +163,13 @@ public void onReceivedError( @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override - public boolean shouldOverrideUrlLoading(@NonNull WebView view, @NonNull WebResourceRequest request) { + public boolean shouldOverrideUrlLoading( + @NonNull WebView view, @NonNull WebResourceRequest request) { webViewClientFlutterApi.requestLoading( - instanceId, instanceManager.getInstanceId(view), createWebResourceRequestData(request), reply -> {}); + instanceId, + instanceManager.getInstanceId(view), + createWebResourceRequestData(request), + reply -> {}); return shouldOverrideUrlLoading; } @@ -173,7 +185,9 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { } WebViewClientHostApiImpl( - InstanceManager instanceManager, WebViewClientProxy webViewClientProxy, WebViewClientFlutterApi webViewClientFlutterApi) { + InstanceManager instanceManager, + WebViewClientProxy webViewClientProxy, + WebViewClientFlutterApi webViewClientFlutterApi) { this.instanceManager = instanceManager; this.webViewClientProxy = webViewClientProxy; this.webViewClientFlutterApi = webViewClientFlutterApi; @@ -182,9 +196,9 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { @Override public void create(Long instanceId, Boolean shouldOverrideUrlLoading) { instanceManager.addInstance( - webViewClientProxy.createWebViewClient(instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi), - instanceId - ); + webViewClientProxy.createWebViewClient( + instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi), + instanceId); } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index 4399454aed1b..53c74cb186c6 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -18,11 +18,11 @@ static class WebViewProxy { WebView createWebView(Context context) { return new WebViewPlatformView(context); } - + WebView createInputAwareWebView(Context context) { return new InputAwareWebViewPlatformView(context, null); } - + void setWebContentsDebuggingEnabled(boolean enabled) { WebView.setWebContentsDebuggingEnabled(enabled); } @@ -44,7 +44,8 @@ public void dispose() { } } - private static class InputAwareWebViewPlatformView extends InputAwareWebView implements PlatformView { + private static class InputAwareWebViewPlatformView extends InputAwareWebView + implements PlatformView { InputAwareWebViewPlatformView(Context context, View containerView) { super(context, containerView); } @@ -90,7 +91,9 @@ public void onInputConnectionUnlocked() { @Override public void create(Long instanceId, Boolean useHybridComposition) { final WebView webView = - useHybridComposition ? webViewProxy.createWebView(context) : webViewProxy.createInputAwareWebView(context); + useHybridComposition + ? webViewProxy.createWebView(context) + : webViewProxy.createInputAwareWebView(context); instanceManager.addInstance(webView, instanceId); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java index e698eb647be0..c4d4e48c22d2 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java @@ -5,7 +5,6 @@ import static org.mockito.Mockito.verify; import android.webkit.DownloadListener; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -14,11 +13,9 @@ import org.mockito.junit.MockitoRule; public class DownloadListenerTest { - @Rule - public MockitoRule mockitoRule = MockitoJUnit.rule(); + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock - public GeneratedAndroidWebView.DownloadListenerFlutterApi mockFlutterApi; + @Mock public GeneratedAndroidWebView.DownloadListenerFlutterApi mockFlutterApi; InstanceManager testInstanceManager; DownloadListenerHostApiImpl testHostApiImpl; @@ -28,25 +25,35 @@ public class DownloadListenerTest { public void setUp() { testInstanceManager = new InstanceManager(); - final DownloadListenerHostApiImpl.DownloadListenerProxy downloadListenerProxy = new DownloadListenerHostApiImpl.DownloadListenerProxy() { - @Override - DownloadListener createDownloadListener(Long instanceId, GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { - testDownloadListener = super.createDownloadListener(instanceId, downloadListenerFlutterApi); - return testDownloadListener; - } - }; - - testHostApiImpl = new DownloadListenerHostApiImpl(testInstanceManager, downloadListenerProxy, mockFlutterApi); + final DownloadListenerHostApiImpl.DownloadListenerProxy downloadListenerProxy = + new DownloadListenerHostApiImpl.DownloadListenerProxy() { + @Override + DownloadListener createDownloadListener( + Long instanceId, + GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { + testDownloadListener = + super.createDownloadListener(instanceId, downloadListenerFlutterApi); + return testDownloadListener; + } + }; + + testHostApiImpl = + new DownloadListenerHostApiImpl(testInstanceManager, downloadListenerProxy, mockFlutterApi); testHostApiImpl.create(0L); } @Test public void postMessage() { - testDownloadListener.onDownloadStart("https://www.google.com", - "userAgent", - "contentDisposition", - "mimetype", - 54); - verify(mockFlutterApi).onDownloadStart(eq(0L), eq("https://www.google.com"), eq("userAgent"), eq("contentDisposition"), eq("mimetype"), eq(54L), any()); + testDownloadListener.onDownloadStart( + "https://www.google.com", "userAgent", "contentDisposition", "mimetype", 54); + verify(mockFlutterApi) + .onDownloadStart( + eq(0L), + eq("https://www.google.com"), + eq("userAgent"), + eq("contentDisposition"), + eq("mimetype"), + eq(54L), + any()); } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java index 4f5ee84fdda5..dc9a6a98e14d 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java @@ -5,7 +5,6 @@ import static org.mockito.Mockito.verify; import android.os.Handler; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -14,11 +13,9 @@ import org.mockito.junit.MockitoRule; public class JavaScriptChannelTest { - @Rule - public MockitoRule mockitoRule = MockitoJUnit.rule(); + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock - public GeneratedAndroidWebView.JavaScriptChannelFlutterApi mockFlutterApi; + @Mock public GeneratedAndroidWebView.JavaScriptChannelFlutterApi mockFlutterApi; InstanceManager testInstanceManager; JavaScriptChannelHostApiImpl testHostApiImpl; @@ -28,15 +25,24 @@ public class JavaScriptChannelTest { public void setUp() { testInstanceManager = new InstanceManager(); - final JavaScriptChannelHostApiImpl.JavaScriptChannelProxy javaScriptChannelProxy = new JavaScriptChannelHostApiImpl.JavaScriptChannelProxy() { - @Override - JavaScriptChannel createJavaScriptChannel(Long instanceId, GeneratedAndroidWebView.JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, String channelName, Handler platformThreadHandler) { - testJavaScriptChannel = super.createJavaScriptChannel(instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); - return testJavaScriptChannel; - } - }; - - testHostApiImpl = new JavaScriptChannelHostApiImpl(testInstanceManager, javaScriptChannelProxy, mockFlutterApi, new Handler()); + final JavaScriptChannelHostApiImpl.JavaScriptChannelProxy javaScriptChannelProxy = + new JavaScriptChannelHostApiImpl.JavaScriptChannelProxy() { + @Override + JavaScriptChannel createJavaScriptChannel( + Long instanceId, + GeneratedAndroidWebView.JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, + String channelName, + Handler platformThreadHandler) { + testJavaScriptChannel = + super.createJavaScriptChannel( + instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); + return testJavaScriptChannel; + } + }; + + testHostApiImpl = + new JavaScriptChannelHostApiImpl( + testInstanceManager, javaScriptChannelProxy, mockFlutterApi, new Handler()); testHostApiImpl.create(0L, "aChannelName"); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java index 8e4bb78d488c..d20c55c97f67 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java @@ -2,24 +2,18 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; - -import java.nio.ByteBuffer; - import io.flutter.plugin.common.BinaryMessenger; +import java.nio.ByteBuffer; public class TestBinaryMessenger implements BinaryMessenger { @Override - public void send(@NonNull String s, @Nullable ByteBuffer byteBuffer) { - - } + public void send(@NonNull String s, @Nullable ByteBuffer byteBuffer) {} @Override - public void send(@NonNull String s, @Nullable ByteBuffer byteBuffer, @Nullable BinaryReply binaryReply) { - - } + public void send( + @NonNull String s, @Nullable ByteBuffer byteBuffer, @Nullable BinaryReply binaryReply) {} @Override - public void setMessageHandler(@NonNull String s, @Nullable BinaryMessageHandler binaryMessageHandler) { - - } + public void setMessageHandler( + @NonNull String s, @Nullable BinaryMessageHandler binaryMessageHandler) {} } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java index 9d3411bb362d..da20277fab96 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java @@ -5,7 +5,6 @@ import static org.mockito.Mockito.when; import android.webkit.WebSettings; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -14,14 +13,11 @@ import org.mockito.junit.MockitoRule; public class WebSettingsTest { - @Rule - public MockitoRule mockitoRule = MockitoJUnit.rule(); + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock - public WebSettings mockWebSettings; + @Mock public WebSettings mockWebSettings; - @Mock - WebSettingsHostApiImpl.WebSettingsProxy mockWebSettingsProxy; + @Mock WebSettingsHostApiImpl.WebSettingsProxy mockWebSettingsProxy; InstanceManager testInstanceManager; WebSettingsHostApiImpl testHostApiImpl; diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java index b941063047fd..084e1bfe467d 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java @@ -2,32 +2,23 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import android.net.Uri; -import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import java.util.Map; public class WebViewClientTest { - @Rule - public MockitoRule mockitoRule = MockitoJUnit.rule(); + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock - public GeneratedAndroidWebView.WebViewClientFlutterApi mockFlutterApi; + @Mock public GeneratedAndroidWebView.WebViewClientFlutterApi mockFlutterApi; - @Mock - public WebView mockWebView; + @Mock public WebView mockWebView; InstanceManager testInstanceManager; WebViewClientHostApiImpl testHostApiImpl; @@ -38,15 +29,23 @@ public void setUp() { testInstanceManager = new InstanceManager(); testInstanceManager.addInstance(mockWebView, 0L); - final WebViewClientHostApiImpl.WebViewClientProxy webViewClientProxy = new WebViewClientHostApiImpl.WebViewClientProxy() { - @Override - WebViewClient createWebViewClient(Long instanceId, InstanceManager instanceManager, Boolean shouldOverrideUrlLoading, GeneratedAndroidWebView.WebViewClientFlutterApi webViewClientFlutterApi) { - testWebViewClient = super.createWebViewClient(instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi); - return testWebViewClient; - } - }; + final WebViewClientHostApiImpl.WebViewClientProxy webViewClientProxy = + new WebViewClientHostApiImpl.WebViewClientProxy() { + @Override + WebViewClient createWebViewClient( + Long instanceId, + InstanceManager instanceManager, + Boolean shouldOverrideUrlLoading, + GeneratedAndroidWebView.WebViewClientFlutterApi webViewClientFlutterApi) { + testWebViewClient = + super.createWebViewClient( + instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi); + return testWebViewClient; + } + }; - testHostApiImpl = new WebViewClientHostApiImpl(testInstanceManager, webViewClientProxy, mockFlutterApi); + testHostApiImpl = + new WebViewClientHostApiImpl(testInstanceManager, webViewClientProxy, mockFlutterApi); testHostApiImpl.create(1L, true); } @@ -59,7 +58,9 @@ public void onPageStarted() { @Test public void onReceivedError() { testWebViewClient.onReceivedError(mockWebView, 32, "description", "https://www.google.com"); - verify(mockFlutterApi).onReceivedError(eq(1L), eq(0L), eq(32L), eq("description"), eq("https://www.google.com"), any()); + verify(mockFlutterApi) + .onReceivedError( + eq(1L), eq(0L), eq(32L), eq("description"), eq("https://www.google.com"), any()); } @Test diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java index 2a1d1bc03944..b914ce913e76 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java @@ -15,7 +15,7 @@ import android.webkit.ValueCallback; import android.webkit.WebView; import android.webkit.WebViewClient; - +import java.util.HashMap; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -24,20 +24,14 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import java.util.HashMap; - public class WebViewTest { - @Rule - public MockitoRule mockitoRule = MockitoJUnit.rule(); + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock - public WebView mockWebView; + @Mock public WebView mockWebView; - @Mock - WebViewHostApiImpl.WebViewProxy mockWebViewProxy; + @Mock WebViewHostApiImpl.WebViewProxy mockWebViewProxy; - @Mock - Context mockContext; + @Mock Context mockContext; InstanceManager testInstanceManager; WebViewHostApiImpl testHostApiImpl; @@ -138,17 +132,18 @@ public void clearCache() { @Test public void evaluateJavaScript() { final String[] successValue = new String[1]; - testHostApiImpl.evaluateJavascript(0L, "2 + 2", new GeneratedAndroidWebView.Result() { - @Override - public void success(String result) { - successValue[0] = result; - } - - @Override - public void error(Throwable error) { - - } - }); + testHostApiImpl.evaluateJavascript( + 0L, + "2 + 2", + new GeneratedAndroidWebView.Result() { + @Override + public void success(String result) { + successValue[0] = result; + } + + @Override + public void error(Throwable error) {} + }); @SuppressWarnings("unchecked") final ArgumentCaptor> callbackCaptor = From be2770d6368a6523de49dfde40c73730f3379dbd Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 20 Oct 2021 23:34:52 -0700 Subject: [PATCH 22/54] licensing and style --- .../DownloadListenerHostApiImpl.java | 24 ++++++----- .../webviewflutter/FlutterWebViewClient.java | 2 +- .../JavaScriptChannelHostApiImpl.java | 16 ++++--- .../WebSettingsHostApiImpl.java | 14 +++--- .../WebViewClientHostApiImpl.java | 43 +++++++++++++++---- .../webviewflutter/WebViewHostApiImpl.java | 4 ++ .../webviewflutter/DownloadListenerTest.java | 18 +++++--- .../webviewflutter/JavaScriptChannelTest.java | 14 ++++-- .../webviewflutter/WebSettingsTest.java | 11 +++-- .../webviewflutter/WebViewClientTest.java | 16 ++++--- 10 files changed, 114 insertions(+), 48 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java index 5bf60ef3171c..cfda4c77bceb 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java @@ -1,16 +1,20 @@ +// 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.DownloadListener; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerFlutterApi; class DownloadListenerHostApiImpl implements GeneratedAndroidWebView.DownloadListenerHostApi { private final InstanceManager instanceManager; - private final DownloadListenerProxy downloadListenerProxy; + private final DownloadListenerCreator downloadListenerCreator; private final GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi; - static class DownloadListenerProxy { + static class DownloadListenerCreator { DownloadListener createDownloadListener( - Long instanceId, - GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { + Long instanceId, DownloadListenerFlutterApi downloadListenerFlutterApi) { return (url, userAgent, contentDisposition, mimetype, contentLength) -> downloadListenerFlutterApi.onDownloadStart( instanceId, url, userAgent, contentDisposition, mimetype, contentLength, reply -> {}); @@ -19,18 +23,18 @@ DownloadListener createDownloadListener( DownloadListenerHostApiImpl( InstanceManager instanceManager, - DownloadListenerProxy downloadListenerProxy, - GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { + DownloadListenerCreator downloadListenerCreator, + DownloadListenerFlutterApi downloadListenerFlutterApi) { this.instanceManager = instanceManager; - this.downloadListenerProxy = downloadListenerProxy; + this.downloadListenerCreator = downloadListenerCreator; this.downloadListenerFlutterApi = downloadListenerFlutterApi; } @Override public void create(Long instanceId) { - instanceManager.addInstance( - downloadListenerProxy.createDownloadListener(instanceId, downloadListenerFlutterApi), - instanceId); + final DownloadListener downloadListener = + downloadListenerCreator.createDownloadListener(instanceId, downloadListenerFlutterApi); + instanceManager.addInstance(downloadListener, instanceId); } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java index 260ef8e8b15d..a86d3e8a4b63 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java @@ -104,7 +104,7 @@ boolean shouldOverrideUrlLoading(WebView view, String url) { return false; } // This version of shouldOverrideUrlLoading is only invoked by the webview on devices with - // webview versions earlier than 67(it is also invoked when hasNavigationDelegate is false). + // webview versions earlier than 67(it is also invoked when hasNavigationDelegate is false). // On these devices we cannot tell whether the navigation is targeted to the main frame or not. // We proceed assuming that the navigation is targeted to the main frame. If the page had any // frames they will be loaded in the main frame instead. diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java index b088eca52229..c17537abac50 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -1,3 +1,7 @@ +// 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.Handler; @@ -6,11 +10,11 @@ class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.JavaScriptChannelHostApi { private final InstanceManager instanceManager; - private final JavaScriptChannelProxy javaScriptChannelProxy; + private final JavaScriptChannelCreator javaScriptChannelCreator; private final JavaScriptChannelFlutterApi javaScriptChannelFlutterApi; private final Handler platformThreadHandler; - static class JavaScriptChannelProxy { + static class JavaScriptChannelCreator { JavaScriptChannel createJavaScriptChannel( Long instanceId, JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, @@ -19,7 +23,7 @@ JavaScriptChannel createJavaScriptChannel( return new JavaScriptChannel(null, channelName, platformThreadHandler) { @Override public void postMessage(String message) { - Runnable postMessageRunnable = + final Runnable postMessageRunnable = () -> javaScriptChannelFlutterApi.postMessage(instanceId, message, reply -> {}); if (platformThreadHandler.getLooper() == Looper.myLooper()) { postMessageRunnable.run(); @@ -33,11 +37,11 @@ public void postMessage(String message) { JavaScriptChannelHostApiImpl( InstanceManager instanceManager, - JavaScriptChannelProxy javaScriptChannelProxy, + JavaScriptChannelCreator javaScriptChannelCreator, JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, Handler platformThreadHandler) { this.instanceManager = instanceManager; - this.javaScriptChannelProxy = javaScriptChannelProxy; + this.javaScriptChannelCreator = javaScriptChannelCreator; this.javaScriptChannelFlutterApi = javaScriptChannelFlutterApi; this.platformThreadHandler = platformThreadHandler; } @@ -45,7 +49,7 @@ public void postMessage(String message) { @Override public void create(Long instanceId, String channelName) { final JavaScriptChannel javaScriptChannel = - javaScriptChannelProxy.createJavaScriptChannel( + javaScriptChannelCreator.createJavaScriptChannel( instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); instanceManager.addInstance(javaScriptChannel, instanceId); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java index 943531920c1f..5c3d00413971 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java @@ -1,3 +1,7 @@ +// 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.WebSettings; @@ -5,23 +9,23 @@ class WebSettingsHostApiImpl implements GeneratedAndroidWebView.WebSettingsHostApi { private final InstanceManager instanceManager; - private final WebSettingsProxy webSettingsProxy; + private final WebSettingsCreator webSettingsCreator; - static class WebSettingsProxy { + static class WebSettingsCreator { WebSettings createWebSettings(WebView webView) { return webView.getSettings(); } } - WebSettingsHostApiImpl(InstanceManager instanceManager, WebSettingsProxy webSettingsProxy) { + WebSettingsHostApiImpl(InstanceManager instanceManager, WebSettingsCreator webSettingsCreator) { this.instanceManager = instanceManager; - this.webSettingsProxy = webSettingsProxy; + this.webSettingsCreator = webSettingsCreator; } @Override public void create(Long instanceId, Long webViewInstanceId) { final WebView webView = (WebView) instanceManager.getInstance(webViewInstanceId); - instanceManager.addInstance(webSettingsProxy.createWebSettings(webView), instanceId); + instanceManager.addInstance(webSettingsCreator.createWebSettings(webView), instanceId); } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java index a3736fd17989..10b753570285 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java @@ -1,9 +1,14 @@ +// 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.annotation.SuppressLint; import android.annotation.TargetApi; import android.graphics.Bitmap; import android.os.Build; +import android.view.KeyEvent; import android.webkit.WebResourceError; import android.webkit.WebResourceRequest; import android.webkit.WebView; @@ -16,7 +21,7 @@ class WebViewClientHostApiImpl implements GeneratedAndroidWebView.WebViewClientHostApi { private final InstanceManager instanceManager; - private final WebViewClientProxy webViewClientProxy; + private final WebViewClientCreator webViewClientCreator; private final WebViewClientFlutterApi webViewClientFlutterApi; @RequiresApi(api = Build.VERSION_CODES.M) @@ -58,12 +63,20 @@ static GeneratedAndroidWebView.WebResourceRequestData createWebResourceRequestDa return requestData; } - static class WebViewClientProxy { + static class WebViewClientCreator { WebViewClient createWebViewClient( Long instanceId, InstanceManager instanceManager, Boolean shouldOverrideUrlLoading, WebViewClientFlutterApi webViewClientFlutterApi) { + // WebViewClientCompat is used to get + // shouldOverrideUrlLoading(WebView view, WebResourceRequest request) + // invoked by the webview on older Android devices, without it pages that use iframes will + // be broken when a navigationDelegate is set on Android version earlier than N. + // + // However, this if statement attempts to avoid using WebViewClientCompat on versions >= N due + // to bug https://bugs.chromium.org/p/chromium/issues/detail?id=925887. Also, see + // https://github.com/flutter/flutter/issues/29446. if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { return new WebViewClient() { @Override @@ -117,6 +130,13 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { instanceId, instanceManager.getInstanceId(view), url, reply -> {}); return shouldOverrideUrlLoading; } + + @Override + public void onUnhandledKeyEvent(WebView view, KeyEvent event) { + // Deliberately empty. Occasionally the webview will mark events as having failed to be + // handled even though they were handled. We don't want to propagate those as they're not + // truly lost. + } }; } else { return new WebViewClientCompat() { @@ -179,6 +199,13 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { instanceId, instanceManager.getInstanceId(view), url, reply -> {}); return shouldOverrideUrlLoading; } + + @Override + public void onUnhandledKeyEvent(WebView view, KeyEvent event) { + // Deliberately empty. Occasionally the webview will mark events as having failed to be + // handled even though they were handled. We don't want to propagate those as they're not + // truly lost. + } }; } } @@ -186,19 +213,19 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { WebViewClientHostApiImpl( InstanceManager instanceManager, - WebViewClientProxy webViewClientProxy, + WebViewClientCreator webViewClientCreator, WebViewClientFlutterApi webViewClientFlutterApi) { this.instanceManager = instanceManager; - this.webViewClientProxy = webViewClientProxy; + this.webViewClientCreator = webViewClientCreator; this.webViewClientFlutterApi = webViewClientFlutterApi; } @Override public void create(Long instanceId, Boolean shouldOverrideUrlLoading) { - instanceManager.addInstance( - webViewClientProxy.createWebViewClient( - instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi), - instanceId); + final WebViewClient webViewClient = + webViewClientCreator.createWebViewClient( + instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi); + instanceManager.addInstance(webViewClient, instanceId); } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index 53c74cb186c6..10b76def969a 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -1,3 +1,7 @@ +// 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.content.Context; diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java index c4d4e48c22d2..5ba073c7f418 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java @@ -1,3 +1,7 @@ +// 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 static org.mockito.ArgumentMatchers.any; @@ -5,6 +9,8 @@ import static org.mockito.Mockito.verify; import android.webkit.DownloadListener; +import io.flutter.plugins.webviewflutter.DownloadListenerHostApiImpl.DownloadListenerCreator; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerFlutterApi; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -15,7 +21,7 @@ public class DownloadListenerTest { @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock public GeneratedAndroidWebView.DownloadListenerFlutterApi mockFlutterApi; + @Mock public DownloadListenerFlutterApi mockFlutterApi; InstanceManager testInstanceManager; DownloadListenerHostApiImpl testHostApiImpl; @@ -25,12 +31,11 @@ public class DownloadListenerTest { public void setUp() { testInstanceManager = new InstanceManager(); - final DownloadListenerHostApiImpl.DownloadListenerProxy downloadListenerProxy = - new DownloadListenerHostApiImpl.DownloadListenerProxy() { + final DownloadListenerCreator downloadListenerCreator = + new DownloadListenerCreator() { @Override DownloadListener createDownloadListener( - Long instanceId, - GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi) { + Long instanceId, DownloadListenerFlutterApi downloadListenerFlutterApi) { testDownloadListener = super.createDownloadListener(instanceId, downloadListenerFlutterApi); return testDownloadListener; @@ -38,7 +43,8 @@ DownloadListener createDownloadListener( }; testHostApiImpl = - new DownloadListenerHostApiImpl(testInstanceManager, downloadListenerProxy, mockFlutterApi); + new DownloadListenerHostApiImpl( + testInstanceManager, downloadListenerCreator, mockFlutterApi); testHostApiImpl.create(0L); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java index dc9a6a98e14d..697ea0b70b90 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java @@ -1,3 +1,7 @@ +// 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 static org.mockito.ArgumentMatchers.any; @@ -5,6 +9,8 @@ import static org.mockito.Mockito.verify; import android.os.Handler; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; +import io.flutter.plugins.webviewflutter.JavaScriptChannelHostApiImpl.JavaScriptChannelCreator; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -25,12 +31,12 @@ public class JavaScriptChannelTest { public void setUp() { testInstanceManager = new InstanceManager(); - final JavaScriptChannelHostApiImpl.JavaScriptChannelProxy javaScriptChannelProxy = - new JavaScriptChannelHostApiImpl.JavaScriptChannelProxy() { + final JavaScriptChannelCreator javaScriptChannelCreator = + new JavaScriptChannelCreator() { @Override JavaScriptChannel createJavaScriptChannel( Long instanceId, - GeneratedAndroidWebView.JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, + JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, String channelName, Handler platformThreadHandler) { testJavaScriptChannel = @@ -42,7 +48,7 @@ JavaScriptChannel createJavaScriptChannel( testHostApiImpl = new JavaScriptChannelHostApiImpl( - testInstanceManager, javaScriptChannelProxy, mockFlutterApi, new Handler()); + testInstanceManager, javaScriptChannelCreator, mockFlutterApi, new Handler()); testHostApiImpl.create(0L, "aChannelName"); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java index da20277fab96..8ef32ddcb4ca 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java @@ -1,3 +1,7 @@ +// 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 static org.mockito.ArgumentMatchers.any; @@ -5,6 +9,7 @@ import static org.mockito.Mockito.when; import android.webkit.WebSettings; +import io.flutter.plugins.webviewflutter.WebSettingsHostApiImpl.WebSettingsCreator; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -17,7 +22,7 @@ public class WebSettingsTest { @Mock public WebSettings mockWebSettings; - @Mock WebSettingsHostApiImpl.WebSettingsProxy mockWebSettingsProxy; + @Mock WebSettingsCreator mockWebSettingsCreator; InstanceManager testInstanceManager; WebSettingsHostApiImpl testHostApiImpl; @@ -25,8 +30,8 @@ public class WebSettingsTest { @Before public void setUp() { testInstanceManager = new InstanceManager(); - when(mockWebSettingsProxy.createWebSettings(any())).thenReturn(mockWebSettings); - testHostApiImpl = new WebSettingsHostApiImpl(testInstanceManager, mockWebSettingsProxy); + when(mockWebSettingsCreator.createWebSettings(any())).thenReturn(mockWebSettings); + testHostApiImpl = new WebSettingsHostApiImpl(testInstanceManager, mockWebSettingsCreator); testHostApiImpl.create(0L, 0L); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java index 084e1bfe467d..f6d2054564e2 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java @@ -1,3 +1,7 @@ +// 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 static org.mockito.ArgumentMatchers.any; @@ -6,6 +10,8 @@ import android.webkit.WebView; import android.webkit.WebViewClient; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientFlutterApi; +import io.flutter.plugins.webviewflutter.WebViewClientHostApiImpl.WebViewClientCreator; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -16,7 +22,7 @@ public class WebViewClientTest { @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock public GeneratedAndroidWebView.WebViewClientFlutterApi mockFlutterApi; + @Mock public WebViewClientFlutterApi mockFlutterApi; @Mock public WebView mockWebView; @@ -29,14 +35,14 @@ public void setUp() { testInstanceManager = new InstanceManager(); testInstanceManager.addInstance(mockWebView, 0L); - final WebViewClientHostApiImpl.WebViewClientProxy webViewClientProxy = - new WebViewClientHostApiImpl.WebViewClientProxy() { + final WebViewClientCreator webViewClientCreator = + new WebViewClientCreator() { @Override WebViewClient createWebViewClient( Long instanceId, InstanceManager instanceManager, Boolean shouldOverrideUrlLoading, - GeneratedAndroidWebView.WebViewClientFlutterApi webViewClientFlutterApi) { + WebViewClientFlutterApi webViewClientFlutterApi) { testWebViewClient = super.createWebViewClient( instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi); @@ -45,7 +51,7 @@ WebViewClient createWebViewClient( }; testHostApiImpl = - new WebViewClientHostApiImpl(testInstanceManager, webViewClientProxy, mockFlutterApi); + new WebViewClientHostApiImpl(testInstanceManager, webViewClientCreator, mockFlutterApi); testHostApiImpl.create(1L, true); } From a9b6fa2db8ca3fff8c547c29d2c07077ed921dfd Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 20 Oct 2021 23:43:06 -0700 Subject: [PATCH 23/54] java portion --- .../android/build.gradle | 4 + .../DownloadListenerHostApiImpl.java | 44 + .../webviewflutter/FlutterWebViewClient.java | 2 +- .../GeneratedAndroidWebView.java | 1758 +++++++++++++++++ .../webviewflutter/InputAwareWebView.java | 2 +- .../webviewflutter/JavaScriptChannel.java | 2 +- .../JavaScriptChannelHostApiImpl.java | 61 + .../WebSettingsHostApiImpl.java | 101 + .../WebViewClientHostApiImpl.java | 235 +++ .../webviewflutter/WebViewHostApiImpl.java | 226 +++ .../webviewflutter/DownloadListenerTest.java | 65 + .../webviewflutter/JavaScriptChannelTest.java | 60 + .../webviewflutter/WebSettingsTest.java | 103 + .../webviewflutter/WebViewClientTest.java | 77 + .../plugins/webviewflutter/WebViewTest.java | 173 ++ .../generatePigeons.sh | 10 + 16 files changed, 2920 insertions(+), 3 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java create mode 100755 packages/webview_flutter/webview_flutter_android/generatePigeons.sh diff --git a/packages/webview_flutter/webview_flutter_android/android/build.gradle b/packages/webview_flutter/webview_flutter_android/android/build.gradle index 4a164317c60f..ef1485a765d0 100644 --- a/packages/webview_flutter/webview_flutter_android/android/build.gradle +++ b/packages/webview_flutter/webview_flutter_android/android/build.gradle @@ -42,6 +42,10 @@ android { testImplementation 'androidx.test:core:1.3.0' } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } testOptions { unitTests.includeAndroidResources = true diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java new file mode 100644 index 000000000000..cfda4c77bceb --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java @@ -0,0 +1,44 @@ +// 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.DownloadListener; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerFlutterApi; + +class DownloadListenerHostApiImpl implements GeneratedAndroidWebView.DownloadListenerHostApi { + private final InstanceManager instanceManager; + private final DownloadListenerCreator downloadListenerCreator; + private final GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi; + + static class DownloadListenerCreator { + DownloadListener createDownloadListener( + Long instanceId, DownloadListenerFlutterApi downloadListenerFlutterApi) { + return (url, userAgent, contentDisposition, mimetype, contentLength) -> + downloadListenerFlutterApi.onDownloadStart( + instanceId, url, userAgent, contentDisposition, mimetype, contentLength, reply -> {}); + } + } + + DownloadListenerHostApiImpl( + InstanceManager instanceManager, + DownloadListenerCreator downloadListenerCreator, + DownloadListenerFlutterApi downloadListenerFlutterApi) { + this.instanceManager = instanceManager; + this.downloadListenerCreator = downloadListenerCreator; + this.downloadListenerFlutterApi = downloadListenerFlutterApi; + } + + @Override + public void create(Long instanceId) { + final DownloadListener downloadListener = + downloadListenerCreator.createDownloadListener(instanceId, downloadListenerFlutterApi); + instanceManager.addInstance(downloadListener, instanceId); + } + + @Override + public void dispose(Long instanceId) { + instanceManager.removeInstanceId(instanceId); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java index 260ef8e8b15d..a86d3e8a4b63 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java @@ -104,7 +104,7 @@ boolean shouldOverrideUrlLoading(WebView view, String url) { return false; } // This version of shouldOverrideUrlLoading is only invoked by the webview on devices with - // webview versions earlier than 67(it is also invoked when hasNavigationDelegate is false). + // webview versions earlier than 67(it is also invoked when hasNavigationDelegate is false). // On these devices we cannot tell whether the navigation is targeted to the main frame or not. // We proceed assuming that the navigation is targeted to the main frame. If the page had any // frames they will be loaded in the main frame instead. diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java new file mode 100644 index 000000000000..f1725e1b7c7b --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -0,0 +1,1758 @@ +// 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. + +// Autogenerated from Pigeon (v1.0.7), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +package io.flutter.plugins.webviewflutter; + +import io.flutter.plugin.common.BasicMessageChannel; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.MessageCodec; +import io.flutter.plugin.common.StandardMessageCodec; +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** Generated class from Pigeon. */ +@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"}) +public class GeneratedAndroidWebView { + + /** Generated class from Pigeon that represents data sent in messages. */ + public static class WebResourceRequestData { + private String url; + + public String getUrl() { + return url; + } + + public void setUrl(String setterArg) { + this.url = setterArg; + } + + private Boolean isForMainFrame; + + public Boolean getIsForMainFrame() { + return isForMainFrame; + } + + public void setIsForMainFrame(Boolean setterArg) { + this.isForMainFrame = setterArg; + } + + private Boolean isRedirect; + + public Boolean getIsRedirect() { + return isRedirect; + } + + public void setIsRedirect(Boolean setterArg) { + this.isRedirect = setterArg; + } + + private Boolean hasGesture; + + public Boolean getHasGesture() { + return hasGesture; + } + + public void setHasGesture(Boolean setterArg) { + this.hasGesture = setterArg; + } + + private String method; + + public String getMethod() { + return method; + } + + public void setMethod(String setterArg) { + this.method = setterArg; + } + + private Map requestHeaders; + + public Map getRequestHeaders() { + return requestHeaders; + } + + public void setRequestHeaders(Map setterArg) { + this.requestHeaders = setterArg; + } + + Map toMap() { + Map toMapResult = new HashMap<>(); + toMapResult.put("url", url); + toMapResult.put("isForMainFrame", isForMainFrame); + toMapResult.put("isRedirect", isRedirect); + toMapResult.put("hasGesture", hasGesture); + toMapResult.put("method", method); + toMapResult.put("requestHeaders", requestHeaders); + return toMapResult; + } + + static WebResourceRequestData fromMap(Map map) { + WebResourceRequestData fromMapResult = new WebResourceRequestData(); + Object url = map.get("url"); + fromMapResult.url = (String) url; + Object isForMainFrame = map.get("isForMainFrame"); + fromMapResult.isForMainFrame = (Boolean) isForMainFrame; + Object isRedirect = map.get("isRedirect"); + fromMapResult.isRedirect = (Boolean) isRedirect; + Object hasGesture = map.get("hasGesture"); + fromMapResult.hasGesture = (Boolean) hasGesture; + Object method = map.get("method"); + fromMapResult.method = (String) method; + Object requestHeaders = map.get("requestHeaders"); + fromMapResult.requestHeaders = (Map) requestHeaders; + return fromMapResult; + } + } + + /** Generated class from Pigeon that represents data sent in messages. */ + public static class WebResourceErrorData { + private Long errorCode; + + public Long getErrorCode() { + return errorCode; + } + + public void setErrorCode(Long setterArg) { + this.errorCode = setterArg; + } + + private String description; + + public String getDescription() { + return description; + } + + public void setDescription(String setterArg) { + this.description = setterArg; + } + + Map toMap() { + Map toMapResult = new HashMap<>(); + toMapResult.put("errorCode", errorCode); + toMapResult.put("description", description); + return toMapResult; + } + + static WebResourceErrorData fromMap(Map map) { + WebResourceErrorData fromMapResult = new WebResourceErrorData(); + Object errorCode = map.get("errorCode"); + fromMapResult.errorCode = + (errorCode == null) + ? null + : ((errorCode instanceof Integer) ? (Integer) errorCode : (Long) errorCode); + Object description = map.get("description"); + fromMapResult.description = (String) description; + return fromMapResult; + } + } + + public interface Result { + void success(T result); + + void error(Throwable error); + } + + private static class WebViewHostApiCodec extends StandardMessageCodec { + public static final WebViewHostApiCodec INSTANCE = new WebViewHostApiCodec(); + + private WebViewHostApiCodec() {} + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + public interface WebViewHostApi { + void create(Long instanceId, Boolean useHybridComposition); + + void dispose(Long instanceId); + + void loadUrl(Long instanceId, String url, Map headers); + + String getUrl(Long instanceId); + + Boolean canGoBack(Long instanceId); + + Boolean canGoForward(Long instanceId); + + void goBack(Long instanceId); + + void goForward(Long instanceId); + + void reload(Long instanceId); + + void clearCache(Long instanceId, Boolean includeDiskFiles); + + void evaluateJavascript(Long instanceId, String javascriptString, Result result); + + String getTitle(Long instanceId); + + void scrollTo(Long instanceId, Long x, Long y); + + void scrollBy(Long instanceId, Long x, Long y); + + Long getScrollX(Long instanceId); + + Long getScrollY(Long instanceId); + + void setWebContentsDebuggingEnabled(Boolean enabled); + + void setWebViewClient(Long instanceId, Long webViewClientInstanceId); + + void addJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); + + void removeJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId); + + void setDownloadListener(Long instanceId, Long listenerInstanceId); + + /** The codec used by WebViewHostApi. */ + static MessageCodec getCodec() { + return WebViewHostApiCodec.INSTANCE; + } + + /** Sets up an instance of `WebViewHostApi` to handle messages through the `binaryMessenger`. */ + static void setup(BinaryMessenger binaryMessenger, WebViewHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean useHybridCompositionArg = (Boolean) args.get(1); + if (useHybridCompositionArg == null) { + throw new NullPointerException("useHybridCompositionArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), useHybridCompositionArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.dispose", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.loadUrl", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String urlArg = (String) args.get(1); + if (urlArg == null) { + throw new NullPointerException("urlArg unexpectedly null."); + } + Map headersArg = (Map) args.get(2); + if (headersArg == null) { + throw new NullPointerException("headersArg unexpectedly null."); + } + api.loadUrl(instanceIdArg.longValue(), urlArg, headersArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getUrl", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String output = api.getUrl(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoBack", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean output = api.canGoBack(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.canGoForward", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean output = api.canGoForward(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goBack", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.goBack(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.goForward", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.goForward(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.reload", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.reload(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.clearCache", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean includeDiskFilesArg = (Boolean) args.get(1); + if (includeDiskFilesArg == null) { + throw new NullPointerException("includeDiskFilesArg unexpectedly null."); + } + api.clearCache(instanceIdArg.longValue(), includeDiskFilesArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.evaluateJavascript", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String javascriptStringArg = (String) args.get(1); + if (javascriptStringArg == null) { + throw new NullPointerException("javascriptStringArg unexpectedly null."); + } + Result resultCallback = + new Result() { + public void success(String result) { + wrapped.put("result", result); + reply.reply(wrapped); + } + + public void error(Throwable error) { + wrapped.put("error", wrapError(error)); + reply.reply(wrapped); + } + }; + + api.evaluateJavascript( + instanceIdArg.longValue(), javascriptStringArg, resultCallback); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + reply.reply(wrapped); + } + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getTitle", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String output = api.getTitle(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollTo", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number xArg = (Number) args.get(1); + if (xArg == null) { + throw new NullPointerException("xArg unexpectedly null."); + } + Number yArg = (Number) args.get(2); + if (yArg == null) { + throw new NullPointerException("yArg unexpectedly null."); + } + api.scrollTo(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.scrollBy", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number xArg = (Number) args.get(1); + if (xArg == null) { + throw new NullPointerException("xArg unexpectedly null."); + } + Number yArg = (Number) args.get(2); + if (yArg == null) { + throw new NullPointerException("yArg unexpectedly null."); + } + api.scrollBy(instanceIdArg.longValue(), xArg.longValue(), yArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollX", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Long output = api.getScrollX(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.getScrollY", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Long output = api.getScrollY(instanceIdArg.longValue()); + wrapped.put("result", output); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Boolean enabledArg = (Boolean) args.get(0); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setWebContentsDebuggingEnabled(enabledArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.setWebViewClient", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number webViewClientInstanceIdArg = (Number) args.get(1); + if (webViewClientInstanceIdArg == null) { + throw new NullPointerException("webViewClientInstanceIdArg unexpectedly null."); + } + api.setWebViewClient( + instanceIdArg.longValue(), webViewClientInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number javaScriptChannelInstanceIdArg = (Number) args.get(1); + if (javaScriptChannelInstanceIdArg == null) { + throw new NullPointerException( + "javaScriptChannelInstanceIdArg unexpectedly null."); + } + api.addJavaScriptChannel( + instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number javaScriptChannelInstanceIdArg = (Number) args.get(1); + if (javaScriptChannelInstanceIdArg == null) { + throw new NullPointerException( + "javaScriptChannelInstanceIdArg unexpectedly null."); + } + api.removeJavaScriptChannel( + instanceIdArg.longValue(), javaScriptChannelInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.setDownloadListener", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number listenerInstanceIdArg = (Number) args.get(1); + if (listenerInstanceIdArg == null) { + throw new NullPointerException("listenerInstanceIdArg unexpectedly null."); + } + api.setDownloadListener( + instanceIdArg.longValue(), listenerInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + + private static class WebSettingsHostApiCodec extends StandardMessageCodec { + public static final WebSettingsHostApiCodec INSTANCE = new WebSettingsHostApiCodec(); + + private WebSettingsHostApiCodec() {} + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + public interface WebSettingsHostApi { + void create(Long instanceId, Long webViewInstanceId); + + void dispose(Long instanceId); + + void setDomStorageEnabled(Long instanceId, Boolean flag); + + void setJavaScriptCanOpenWindowsAutomatically(Long instanceId, Boolean flag); + + void setSupportMultipleWindows(Long instanceId, Boolean support); + + void setJavaScriptEnabled(Long instanceId, Boolean flag); + + void setUserAgentString(Long instanceId, String userAgentString); + + void setMediaPlaybackRequiresUserGesture(Long instanceId, Boolean require); + + void setSupportZoom(Long instanceId, Boolean support); + + void setLoadWithOverviewMode(Long instanceId, Boolean overview); + + void setUseWideViewPort(Long instanceId, Boolean use); + + void setDisplayZoomControls(Long instanceId, Boolean enabled); + + void setBuiltInZoomControls(Long instanceId, Boolean enabled); + + /** The codec used by WebSettingsHostApi. */ + static MessageCodec getCodec() { + return WebSettingsHostApiCodec.INSTANCE; + } + + /** + * Sets up an instance of `WebSettingsHostApi` to handle messages through the `binaryMessenger`. + */ + static void setup(BinaryMessenger binaryMessenger, WebSettingsHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number webViewInstanceIdArg = (Number) args.get(1); + if (webViewInstanceIdArg == null) { + throw new NullPointerException("webViewInstanceIdArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), webViewInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.dispose", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean) args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setDomStorageEnabled(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean) args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setJavaScriptCanOpenWindowsAutomatically(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean supportArg = (Boolean) args.get(1); + if (supportArg == null) { + throw new NullPointerException("supportArg unexpectedly null."); + } + api.setSupportMultipleWindows(instanceIdArg.longValue(), supportArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean flagArg = (Boolean) args.get(1); + if (flagArg == null) { + throw new NullPointerException("flagArg unexpectedly null."); + } + api.setJavaScriptEnabled(instanceIdArg.longValue(), flagArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String userAgentStringArg = (String) args.get(1); + if (userAgentStringArg == null) { + throw new NullPointerException("userAgentStringArg unexpectedly null."); + } + api.setUserAgentString(instanceIdArg.longValue(), userAgentStringArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean requireArg = (Boolean) args.get(1); + if (requireArg == null) { + throw new NullPointerException("requireArg unexpectedly null."); + } + api.setMediaPlaybackRequiresUserGesture(instanceIdArg.longValue(), requireArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean supportArg = (Boolean) args.get(1); + if (supportArg == null) { + throw new NullPointerException("supportArg unexpectedly null."); + } + api.setSupportZoom(instanceIdArg.longValue(), supportArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean overviewArg = (Boolean) args.get(1); + if (overviewArg == null) { + throw new NullPointerException("overviewArg unexpectedly null."); + } + api.setLoadWithOverviewMode(instanceIdArg.longValue(), overviewArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean useArg = (Boolean) args.get(1); + if (useArg == null) { + throw new NullPointerException("useArg unexpectedly null."); + } + api.setUseWideViewPort(instanceIdArg.longValue(), useArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean enabledArg = (Boolean) args.get(1); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setDisplayZoomControls(instanceIdArg.longValue(), enabledArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean enabledArg = (Boolean) args.get(1); + if (enabledArg == null) { + throw new NullPointerException("enabledArg unexpectedly null."); + } + api.setBuiltInZoomControls(instanceIdArg.longValue(), enabledArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + + private static class JavaScriptChannelHostApiCodec extends StandardMessageCodec { + public static final JavaScriptChannelHostApiCodec INSTANCE = + new JavaScriptChannelHostApiCodec(); + + private JavaScriptChannelHostApiCodec() {} + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + public interface JavaScriptChannelHostApi { + void create(Long instanceId, String channelName); + + void dispose(Long instanceId); + + /** The codec used by JavaScriptChannelHostApi. */ + static MessageCodec getCodec() { + return JavaScriptChannelHostApiCodec.INSTANCE; + } + + /** + * Sets up an instance of `JavaScriptChannelHostApi` to handle messages through the + * `binaryMessenger`. + */ + static void setup(BinaryMessenger binaryMessenger, JavaScriptChannelHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String channelNameArg = (String) args.get(1); + if (channelNameArg == null) { + throw new NullPointerException("channelNameArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), channelNameArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.dispose", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + + private static class JavaScriptChannelFlutterApiCodec extends StandardMessageCodec { + public static final JavaScriptChannelFlutterApiCodec INSTANCE = + new JavaScriptChannelFlutterApiCodec(); + + private JavaScriptChannelFlutterApiCodec() {} + } + + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + public static class JavaScriptChannelFlutterApi { + private final BinaryMessenger binaryMessenger; + + public JavaScriptChannelFlutterApi(BinaryMessenger argBinaryMessenger) { + this.binaryMessenger = argBinaryMessenger; + } + + public interface Reply { + void reply(T reply); + } + + static MessageCodec getCodec() { + return JavaScriptChannelFlutterApiCodec.INSTANCE; + } + + public void postMessage(Long instanceIdArg, String messageArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, messageArg)), + channelReply -> { + callback.reply(null); + }); + } + } + + private static class WebViewClientHostApiCodec extends StandardMessageCodec { + public static final WebViewClientHostApiCodec INSTANCE = new WebViewClientHostApiCodec(); + + private WebViewClientHostApiCodec() {} + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + public interface WebViewClientHostApi { + void create(Long instanceId, Boolean shouldOverrideUrlLoading); + + void dispose(Long instanceId); + + /** The codec used by WebViewClientHostApi. */ + static MessageCodec getCodec() { + return WebViewClientHostApiCodec.INSTANCE; + } + + /** + * Sets up an instance of `WebViewClientHostApi` to handle messages through the + * `binaryMessenger`. + */ + static void setup(BinaryMessenger binaryMessenger, WebViewClientHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Boolean shouldOverrideUrlLoadingArg = (Boolean) args.get(1); + if (shouldOverrideUrlLoadingArg == null) { + throw new NullPointerException( + "shouldOverrideUrlLoadingArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), shouldOverrideUrlLoadingArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.dispose", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + + private static class WebViewClientFlutterApiCodec extends StandardMessageCodec { + public static final WebViewClientFlutterApiCodec INSTANCE = new WebViewClientFlutterApiCodec(); + + private WebViewClientFlutterApiCodec() {} + + @Override + protected Object readValueOfType(byte type, ByteBuffer buffer) { + switch (type) { + case (byte) 128: + return WebResourceErrorData.fromMap((Map) readValue(buffer)); + + case (byte) 129: + return WebResourceRequestData.fromMap((Map) readValue(buffer)); + + case (byte) 130: + return WebResourceRequestData.fromMap((Map) readValue(buffer)); + + default: + return super.readValueOfType(type, buffer); + } + } + + @Override + protected void writeValue(ByteArrayOutputStream stream, Object value) { + if (value instanceof WebResourceErrorData) { + stream.write(128); + writeValue(stream, ((WebResourceErrorData) value).toMap()); + } else if (value instanceof WebResourceRequestData) { + stream.write(129); + writeValue(stream, ((WebResourceRequestData) value).toMap()); + } else if (value instanceof WebResourceRequestData) { + stream.write(130); + writeValue(stream, ((WebResourceRequestData) value).toMap()); + } else { + super.writeValue(stream, value); + } + } + } + + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + public static class WebViewClientFlutterApi { + private final BinaryMessenger binaryMessenger; + + public WebViewClientFlutterApi(BinaryMessenger argBinaryMessenger) { + this.binaryMessenger = argBinaryMessenger; + } + + public interface Reply { + void reply(T reply); + } + + static MessageCodec getCodec() { + return WebViewClientFlutterApiCodec.INSTANCE; + } + + public void onPageStarted( + Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), + channelReply -> { + callback.reply(null); + }); + } + + public void onPageFinished( + Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onPageFinished", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), + channelReply -> { + callback.reply(null); + }); + } + + public void onReceivedRequestError( + Long instanceIdArg, + Long webViewInstanceIdArg, + WebResourceRequestData requestArg, + WebResourceErrorData errorArg, + Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedRequestError", + getCodec()); + channel.send( + new ArrayList( + Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg, errorArg)), + channelReply -> { + callback.reply(null); + }); + } + + public void onReceivedError( + Long instanceIdArg, + Long webViewInstanceIdArg, + Long errorCodeArg, + String descriptionArg, + String failingUrlArg, + Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.onReceivedError", + getCodec()); + channel.send( + new ArrayList( + Arrays.asList( + instanceIdArg, + webViewInstanceIdArg, + errorCodeArg, + descriptionArg, + failingUrlArg)), + channelReply -> { + callback.reply(null); + }); + } + + public void requestLoading( + Long instanceIdArg, + Long webViewInstanceIdArg, + WebResourceRequestData requestArg, + Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewClientFlutterApi.requestLoading", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, requestArg)), + channelReply -> { + callback.reply(null); + }); + } + + public void urlLoading( + Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.urlLoading", getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)), + channelReply -> { + callback.reply(null); + }); + } + } + + private static class DownloadListenerHostApiCodec extends StandardMessageCodec { + public static final DownloadListenerHostApiCodec INSTANCE = new DownloadListenerHostApiCodec(); + + private DownloadListenerHostApiCodec() {} + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + public interface DownloadListenerHostApi { + void create(Long instanceId); + + void dispose(Long instanceId); + + /** The codec used by DownloadListenerHostApi. */ + static MessageCodec getCodec() { + return DownloadListenerHostApiCodec.INSTANCE; + } + + /** + * Sets up an instance of `DownloadListenerHostApi` to handle messages through the + * `binaryMessenger`. + */ + static void setup(BinaryMessenger binaryMessenger, DownloadListenerHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.create(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.dispose", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + + private static class DownloadListenerFlutterApiCodec extends StandardMessageCodec { + public static final DownloadListenerFlutterApiCodec INSTANCE = + new DownloadListenerFlutterApiCodec(); + + private DownloadListenerFlutterApiCodec() {} + } + + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + public static class DownloadListenerFlutterApi { + private final BinaryMessenger binaryMessenger; + + public DownloadListenerFlutterApi(BinaryMessenger argBinaryMessenger) { + this.binaryMessenger = argBinaryMessenger; + } + + public interface Reply { + void reply(T reply); + } + + static MessageCodec getCodec() { + return DownloadListenerFlutterApiCodec.INSTANCE; + } + + public void onDownloadStart( + Long instanceIdArg, + String urlArg, + String userAgentArg, + String contentDispositionArg, + String mimetypeArg, + Long contentLengthArg, + Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart", + getCodec()); + channel.send( + new ArrayList( + Arrays.asList( + instanceIdArg, + urlArg, + userAgentArg, + contentDispositionArg, + mimetypeArg, + contentLengthArg)), + channelReply -> { + callback.reply(null); + }); + } + } + + private static Map wrapError(Throwable exception) { + Map errorMap = new HashMap<>(); + errorMap.put("message", exception.toString()); + errorMap.put("code", exception.getClass().getSimpleName()); + errorMap.put("details", null); + return errorMap; + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java index 51b2a3809fff..0a4cb3effd29 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java @@ -25,7 +25,7 @@ * *

See also {@link ThreadedInputConnectionProxyAdapterView}. */ -final class InputAwareWebView extends WebView { +class InputAwareWebView extends WebView { private static final String TAG = "InputAwareWebView"; private View threadedInputConnectionProxyView; private ThreadedInputConnectionProxyAdapterView proxyAdapterView; diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java index 4d596351b3d0..2f987c0f86b3 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java @@ -19,7 +19,7 @@ */ class JavaScriptChannel { private final MethodChannel methodChannel; - private final String javaScriptChannelName; + final String javaScriptChannelName; private final Handler platformThreadHandler; /** diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java new file mode 100644 index 000000000000..c17537abac50 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -0,0 +1,61 @@ +// 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.Handler; +import android.os.Looper; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; + +class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.JavaScriptChannelHostApi { + private final InstanceManager instanceManager; + private final JavaScriptChannelCreator javaScriptChannelCreator; + private final JavaScriptChannelFlutterApi javaScriptChannelFlutterApi; + private final Handler platformThreadHandler; + + static class JavaScriptChannelCreator { + JavaScriptChannel createJavaScriptChannel( + Long instanceId, + JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, + String channelName, + Handler platformThreadHandler) { + return new JavaScriptChannel(null, channelName, platformThreadHandler) { + @Override + public void postMessage(String message) { + final Runnable postMessageRunnable = + () -> javaScriptChannelFlutterApi.postMessage(instanceId, message, reply -> {}); + if (platformThreadHandler.getLooper() == Looper.myLooper()) { + postMessageRunnable.run(); + } else { + platformThreadHandler.post(postMessageRunnable); + } + } + }; + } + } + + JavaScriptChannelHostApiImpl( + InstanceManager instanceManager, + JavaScriptChannelCreator javaScriptChannelCreator, + JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, + Handler platformThreadHandler) { + this.instanceManager = instanceManager; + this.javaScriptChannelCreator = javaScriptChannelCreator; + this.javaScriptChannelFlutterApi = javaScriptChannelFlutterApi; + this.platformThreadHandler = platformThreadHandler; + } + + @Override + public void create(Long instanceId, String channelName) { + final JavaScriptChannel javaScriptChannel = + javaScriptChannelCreator.createJavaScriptChannel( + instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); + instanceManager.addInstance(javaScriptChannel, instanceId); + } + + @Override + public void dispose(Long instanceId) { + instanceManager.removeInstanceId(instanceId); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java new file mode 100644 index 000000000000..5c3d00413971 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java @@ -0,0 +1,101 @@ +// 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.WebSettings; +import android.webkit.WebView; + +class WebSettingsHostApiImpl implements GeneratedAndroidWebView.WebSettingsHostApi { + private final InstanceManager instanceManager; + private final WebSettingsCreator webSettingsCreator; + + static class WebSettingsCreator { + WebSettings createWebSettings(WebView webView) { + return webView.getSettings(); + } + } + + WebSettingsHostApiImpl(InstanceManager instanceManager, WebSettingsCreator webSettingsCreator) { + this.instanceManager = instanceManager; + this.webSettingsCreator = webSettingsCreator; + } + + @Override + public void create(Long instanceId, Long webViewInstanceId) { + final WebView webView = (WebView) instanceManager.getInstance(webViewInstanceId); + instanceManager.addInstance(webSettingsCreator.createWebSettings(webView), instanceId); + } + + @Override + public void dispose(Long instanceId) { + instanceManager.removeInstanceId(instanceId); + } + + @Override + public void setDomStorageEnabled(Long instanceId, Boolean flag) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setDomStorageEnabled(flag); + } + + @Override + public void setJavaScriptCanOpenWindowsAutomatically(Long instanceId, Boolean flag) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setJavaScriptCanOpenWindowsAutomatically(flag); + } + + @Override + public void setSupportMultipleWindows(Long instanceId, Boolean support) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setSupportMultipleWindows(support); + } + + @Override + public void setJavaScriptEnabled(Long instanceId, Boolean flag) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setJavaScriptEnabled(flag); + } + + @Override + public void setUserAgentString(Long instanceId, String userAgentString) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setUserAgentString(userAgentString); + } + + @Override + public void setMediaPlaybackRequiresUserGesture(Long instanceId, Boolean require) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setMediaPlaybackRequiresUserGesture(require); + } + + @Override + public void setSupportZoom(Long instanceId, Boolean support) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setSupportZoom(support); + } + + @Override + public void setLoadWithOverviewMode(Long instanceId, Boolean overview) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setLoadWithOverviewMode(overview); + } + + @Override + public void setUseWideViewPort(Long instanceId, Boolean use) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setUseWideViewPort(use); + } + + @Override + public void setDisplayZoomControls(Long instanceId, Boolean enabled) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setDisplayZoomControls(enabled); + } + + @Override + public void setBuiltInZoomControls(Long instanceId, Boolean enabled) { + final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId); + webSettings.setBuiltInZoomControls(enabled); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java new file mode 100644 index 000000000000..10b753570285 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java @@ -0,0 +1,235 @@ +// 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.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.graphics.Bitmap; +import android.os.Build; +import android.view.KeyEvent; +import android.webkit.WebResourceError; +import android.webkit.WebResourceRequest; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.webkit.WebResourceErrorCompat; +import androidx.webkit.WebViewClientCompat; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientFlutterApi; + +class WebViewClientHostApiImpl implements GeneratedAndroidWebView.WebViewClientHostApi { + private final InstanceManager instanceManager; + private final WebViewClientCreator webViewClientCreator; + private final WebViewClientFlutterApi webViewClientFlutterApi; + + @RequiresApi(api = Build.VERSION_CODES.M) + static GeneratedAndroidWebView.WebResourceErrorData createWebResourceErrorData( + WebResourceError error) { + final GeneratedAndroidWebView.WebResourceErrorData errorData = + new GeneratedAndroidWebView.WebResourceErrorData(); + errorData.setErrorCode((long) error.getErrorCode()); + errorData.setDescription(error.getDescription().toString()); + + return errorData; + } + + @SuppressLint("RequiresFeature") + static GeneratedAndroidWebView.WebResourceErrorData createWebResourceErrorData( + WebResourceErrorCompat error) { + final GeneratedAndroidWebView.WebResourceErrorData errorData = + new GeneratedAndroidWebView.WebResourceErrorData(); + errorData.setErrorCode((long) error.getErrorCode()); + errorData.setDescription(error.getDescription().toString()); + + return errorData; + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + static GeneratedAndroidWebView.WebResourceRequestData createWebResourceRequestData( + WebResourceRequest request) { + final GeneratedAndroidWebView.WebResourceRequestData requestData = + new GeneratedAndroidWebView.WebResourceRequestData(); + requestData.setUrl(request.getUrl().toString()); + requestData.setIsForMainFrame(request.isForMainFrame()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + requestData.setIsRedirect(request.isRedirect()); + } + requestData.setHasGesture(request.hasGesture()); + requestData.setMethod(request.getMethod()); + requestData.setRequestHeaders(request.getRequestHeaders()); + + return requestData; + } + + static class WebViewClientCreator { + WebViewClient createWebViewClient( + Long instanceId, + InstanceManager instanceManager, + Boolean shouldOverrideUrlLoading, + WebViewClientFlutterApi webViewClientFlutterApi) { + // WebViewClientCompat is used to get + // shouldOverrideUrlLoading(WebView view, WebResourceRequest request) + // invoked by the webview on older Android devices, without it pages that use iframes will + // be broken when a navigationDelegate is set on Android version earlier than N. + // + // However, this if statement attempts to avoid using WebViewClientCompat on versions >= N due + // to bug https://bugs.chromium.org/p/chromium/issues/detail?id=925887. Also, see + // https://github.com/flutter/flutter/issues/29446. + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + return new WebViewClient() { + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + webViewClientFlutterApi.onPageStarted( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + + @Override + public void onPageFinished(WebView view, String url) { + webViewClientFlutterApi.onPageFinished( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + + @Override + public void onReceivedError( + WebView view, WebResourceRequest request, WebResourceError error) { + webViewClientFlutterApi.onReceivedRequestError( + instanceId, + instanceManager.getInstanceId(view), + createWebResourceRequestData(request), + createWebResourceErrorData(error), + reply -> {}); + } + + @Override + public void onReceivedError( + WebView view, int errorCode, String description, String failingUrl) { + webViewClientFlutterApi.onReceivedError( + instanceId, + instanceManager.getInstanceId(view), + (long) errorCode, + description, + failingUrl, + reply -> {}); + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + webViewClientFlutterApi.requestLoading( + instanceId, + instanceManager.getInstanceId(view), + createWebResourceRequestData(request), + reply -> {}); + return shouldOverrideUrlLoading; + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + webViewClientFlutterApi.urlLoading( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + return shouldOverrideUrlLoading; + } + + @Override + public void onUnhandledKeyEvent(WebView view, KeyEvent event) { + // Deliberately empty. Occasionally the webview will mark events as having failed to be + // handled even though they were handled. We don't want to propagate those as they're not + // truly lost. + } + }; + } else { + return new WebViewClientCompat() { + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + webViewClientFlutterApi.onPageStarted( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + + @Override + public void onPageFinished(WebView view, String url) { + webViewClientFlutterApi.onPageFinished( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + + // This method is only called when the WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR feature is + // enabled. The deprecated method is called when a device doesn't support this. + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @SuppressLint("RequiresFeature") + @Override + public void onReceivedError( + @NonNull WebView view, + @NonNull WebResourceRequest request, + @NonNull WebResourceErrorCompat error) { + webViewClientFlutterApi.onReceivedRequestError( + instanceId, + instanceManager.getInstanceId(view), + createWebResourceRequestData(request), + createWebResourceErrorData(error), + reply -> {}); + } + + @Override + public void onReceivedError( + WebView view, int errorCode, String description, String failingUrl) { + webViewClientFlutterApi.onReceivedError( + instanceId, + instanceManager.getInstanceId(view), + (long) errorCode, + description, + failingUrl, + reply -> {}); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @Override + public boolean shouldOverrideUrlLoading( + @NonNull WebView view, @NonNull WebResourceRequest request) { + webViewClientFlutterApi.requestLoading( + instanceId, + instanceManager.getInstanceId(view), + createWebResourceRequestData(request), + reply -> {}); + return shouldOverrideUrlLoading; + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + webViewClientFlutterApi.urlLoading( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + return shouldOverrideUrlLoading; + } + + @Override + public void onUnhandledKeyEvent(WebView view, KeyEvent event) { + // Deliberately empty. Occasionally the webview will mark events as having failed to be + // handled even though they were handled. We don't want to propagate those as they're not + // truly lost. + } + }; + } + } + } + + WebViewClientHostApiImpl( + InstanceManager instanceManager, + WebViewClientCreator webViewClientCreator, + WebViewClientFlutterApi webViewClientFlutterApi) { + this.instanceManager = instanceManager; + this.webViewClientCreator = webViewClientCreator; + this.webViewClientFlutterApi = webViewClientFlutterApi; + } + + @Override + public void create(Long instanceId, Boolean shouldOverrideUrlLoading) { + final WebViewClient webViewClient = + webViewClientCreator.createWebViewClient( + instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi); + instanceManager.addInstance(webViewClient, instanceId); + } + + @Override + public void dispose(Long instanceId) { + instanceManager.removeInstanceId(instanceId); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java new file mode 100644 index 000000000000..10b76def969a --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -0,0 +1,226 @@ +// 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.content.Context; +import android.view.View; +import android.webkit.DownloadListener; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import androidx.annotation.NonNull; +import io.flutter.plugin.platform.PlatformView; +import java.util.Map; + +class WebViewHostApiImpl implements GeneratedAndroidWebView.WebViewHostApi { + private final InstanceManager instanceManager; + private final WebViewProxy webViewProxy; + private final Context context; + + static class WebViewProxy { + WebView createWebView(Context context) { + return new WebViewPlatformView(context); + } + + WebView createInputAwareWebView(Context context) { + return new InputAwareWebViewPlatformView(context, null); + } + + void setWebContentsDebuggingEnabled(boolean enabled) { + WebView.setWebContentsDebuggingEnabled(enabled); + } + } + + private static class WebViewPlatformView extends WebView implements PlatformView { + public WebViewPlatformView(Context context) { + super(context); + } + + @Override + public View getView() { + return this; + } + + @Override + public void dispose() { + destroy(); + } + } + + private static class InputAwareWebViewPlatformView extends InputAwareWebView + implements PlatformView { + InputAwareWebViewPlatformView(Context context, View containerView) { + super(context, containerView); + } + + @Override + public View getView() { + return this; + } + + @Override + public void onFlutterViewAttached(@NonNull View flutterView) { + setContainerView(flutterView); + } + + @Override + public void onFlutterViewDetached() { + setContainerView(null); + } + + @Override + public void dispose() { + dispose(); + destroy(); + } + + @Override + public void onInputConnectionLocked() { + lockInputConnection(); + } + + @Override + public void onInputConnectionUnlocked() { + unlockInputConnection(); + } + } + + WebViewHostApiImpl(InstanceManager instanceManager, WebViewProxy webViewProxy, Context context) { + this.instanceManager = instanceManager; + this.webViewProxy = webViewProxy; + this.context = context; + } + + @Override + public void create(Long instanceId, Boolean useHybridComposition) { + final WebView webView = + useHybridComposition + ? webViewProxy.createWebView(context) + : webViewProxy.createInputAwareWebView(context); + instanceManager.addInstance(webView, instanceId); + } + + @Override + public void dispose(Long instanceId) { + instanceManager.removeInstanceId(instanceId); + } + + @Override + public void loadUrl(Long instanceId, String url, Map headers) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.loadUrl(url, headers); + } + + @Override + public String getUrl(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return webView.getUrl(); + } + + @Override + public Boolean canGoBack(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return webView.canGoBack(); + } + + @Override + public Boolean canGoForward(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return webView.canGoForward(); + } + + @Override + public void goBack(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.goBack(); + } + + @Override + public void goForward(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.goForward(); + } + + @Override + public void reload(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.reload(); + } + + @Override + public void clearCache(Long instanceId, Boolean includeDiskFiles) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.clearCache(includeDiskFiles); + } + + @Override + public void evaluateJavascript( + Long instanceId, String javascriptString, GeneratedAndroidWebView.Result result) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.evaluateJavascript(javascriptString, result::success); + } + + @Override + public String getTitle(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return webView.getTitle(); + } + + @Override + public void scrollTo(Long instanceId, Long x, Long y) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.scrollTo(x.intValue(), y.intValue()); + } + + @Override + public void scrollBy(Long instanceId, Long x, Long y) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.scrollBy(x.intValue(), y.intValue()); + } + + @Override + public Long getScrollX(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return (long) webView.getScrollX(); + } + + @Override + public Long getScrollY(Long instanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + return (long) webView.getScrollY(); + } + + @Override + public void setWebContentsDebuggingEnabled(Boolean enabled) { + webViewProxy.setWebContentsDebuggingEnabled(enabled); + } + + @Override + public void setWebViewClient(Long instanceId, Long webViewClientInstanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.setWebViewClient((WebViewClient) instanceManager.getInstance(webViewClientInstanceId)); + } + + @Override + public void addJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + final JavaScriptChannel javaScriptChannel = + (JavaScriptChannel) instanceManager.getInstance(javaScriptChannelInstanceId); + webView.addJavascriptInterface(javaScriptChannel, javaScriptChannel.javaScriptChannelName); + } + + @Override + public void removeJavaScriptChannel(Long instanceId, Long javaScriptChannelInstanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + final JavaScriptChannel javaScriptChannel = + (JavaScriptChannel) instanceManager.getInstance(javaScriptChannelInstanceId); + webView.removeJavascriptInterface(javaScriptChannel.javaScriptChannelName); + } + + @Override + public void setDownloadListener(Long instanceId, Long listenerInstanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.setDownloadListener((DownloadListener) instanceManager.getInstance(listenerInstanceId)); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java new file mode 100644 index 000000000000..5ba073c7f418 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java @@ -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 static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import android.webkit.DownloadListener; +import io.flutter.plugins.webviewflutter.DownloadListenerHostApiImpl.DownloadListenerCreator; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerFlutterApi; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class DownloadListenerTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock public DownloadListenerFlutterApi mockFlutterApi; + + InstanceManager testInstanceManager; + DownloadListenerHostApiImpl testHostApiImpl; + DownloadListener testDownloadListener; + + @Before + public void setUp() { + testInstanceManager = new InstanceManager(); + + final DownloadListenerCreator downloadListenerCreator = + new DownloadListenerCreator() { + @Override + DownloadListener createDownloadListener( + Long instanceId, DownloadListenerFlutterApi downloadListenerFlutterApi) { + testDownloadListener = + super.createDownloadListener(instanceId, downloadListenerFlutterApi); + return testDownloadListener; + } + }; + + testHostApiImpl = + new DownloadListenerHostApiImpl( + testInstanceManager, downloadListenerCreator, mockFlutterApi); + testHostApiImpl.create(0L); + } + + @Test + public void postMessage() { + testDownloadListener.onDownloadStart( + "https://www.google.com", "userAgent", "contentDisposition", "mimetype", 54); + verify(mockFlutterApi) + .onDownloadStart( + eq(0L), + eq("https://www.google.com"), + eq("userAgent"), + eq("contentDisposition"), + eq("mimetype"), + eq(54L), + any()); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java new file mode 100644 index 000000000000..697ea0b70b90 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java @@ -0,0 +1,60 @@ +// 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 static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import android.os.Handler; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; +import io.flutter.plugins.webviewflutter.JavaScriptChannelHostApiImpl.JavaScriptChannelCreator; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class JavaScriptChannelTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock public GeneratedAndroidWebView.JavaScriptChannelFlutterApi mockFlutterApi; + + InstanceManager testInstanceManager; + JavaScriptChannelHostApiImpl testHostApiImpl; + JavaScriptChannel testJavaScriptChannel; + + @Before + public void setUp() { + testInstanceManager = new InstanceManager(); + + final JavaScriptChannelCreator javaScriptChannelCreator = + new JavaScriptChannelCreator() { + @Override + JavaScriptChannel createJavaScriptChannel( + Long instanceId, + JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, + String channelName, + Handler platformThreadHandler) { + testJavaScriptChannel = + super.createJavaScriptChannel( + instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); + return testJavaScriptChannel; + } + }; + + testHostApiImpl = + new JavaScriptChannelHostApiImpl( + testInstanceManager, javaScriptChannelCreator, mockFlutterApi, new Handler()); + testHostApiImpl.create(0L, "aChannelName"); + } + + @Test + public void postMessage() { + testJavaScriptChannel.postMessage("A message post."); + verify(mockFlutterApi).postMessage(eq(0L), eq("A message post."), any()); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java new file mode 100644 index 000000000000..8ef32ddcb4ca --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebSettingsTest.java @@ -0,0 +1,103 @@ +// 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 static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.webkit.WebSettings; +import io.flutter.plugins.webviewflutter.WebSettingsHostApiImpl.WebSettingsCreator; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class WebSettingsTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock public WebSettings mockWebSettings; + + @Mock WebSettingsCreator mockWebSettingsCreator; + + InstanceManager testInstanceManager; + WebSettingsHostApiImpl testHostApiImpl; + + @Before + public void setUp() { + testInstanceManager = new InstanceManager(); + when(mockWebSettingsCreator.createWebSettings(any())).thenReturn(mockWebSettings); + testHostApiImpl = new WebSettingsHostApiImpl(testInstanceManager, mockWebSettingsCreator); + testHostApiImpl.create(0L, 0L); + } + + @Test + public void setDomStorageEnabled() { + testHostApiImpl.setDomStorageEnabled(0L, true); + verify(mockWebSettings).setDomStorageEnabled(true); + } + + @Test + public void setJavaScriptCanOpenWindowsAutomatically() { + testHostApiImpl.setJavaScriptCanOpenWindowsAutomatically(0L, false); + verify(mockWebSettings).setJavaScriptCanOpenWindowsAutomatically(false); + } + + @Test + public void setSupportMultipleWindows() { + testHostApiImpl.setSupportMultipleWindows(0L, true); + verify(mockWebSettings).setSupportMultipleWindows(true); + } + + @Test + public void setJavaScriptEnabled() { + testHostApiImpl.setJavaScriptEnabled(0L, false); + verify(mockWebSettings).setJavaScriptEnabled(false); + } + + @Test + public void setUserAgentString() { + testHostApiImpl.setUserAgentString(0L, "hello"); + verify(mockWebSettings).setUserAgentString("hello"); + } + + @Test + public void setMediaPlaybackRequiresUserGesture() { + testHostApiImpl.setMediaPlaybackRequiresUserGesture(0L, false); + verify(mockWebSettings).setMediaPlaybackRequiresUserGesture(false); + } + + @Test + public void setSupportZoom() { + testHostApiImpl.setSupportZoom(0L, true); + verify(mockWebSettings).setSupportZoom(true); + } + + @Test + public void setLoadWithOverviewMode() { + testHostApiImpl.setLoadWithOverviewMode(0L, false); + verify(mockWebSettings).setLoadWithOverviewMode(false); + } + + @Test + public void setUseWideViewPort() { + testHostApiImpl.setUseWideViewPort(0L, true); + verify(mockWebSettings).setUseWideViewPort(true); + } + + @Test + public void setDisplayZoomControls() { + testHostApiImpl.setDisplayZoomControls(0L, false); + verify(mockWebSettings).setDisplayZoomControls(false); + } + + @Test + public void setBuiltInZoomControls() { + testHostApiImpl.setBuiltInZoomControls(0L, true); + verify(mockWebSettings).setBuiltInZoomControls(true); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java new file mode 100644 index 000000000000..f6d2054564e2 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java @@ -0,0 +1,77 @@ +// 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 static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import android.webkit.WebView; +import android.webkit.WebViewClient; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientFlutterApi; +import io.flutter.plugins.webviewflutter.WebViewClientHostApiImpl.WebViewClientCreator; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class WebViewClientTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock public WebViewClientFlutterApi mockFlutterApi; + + @Mock public WebView mockWebView; + + InstanceManager testInstanceManager; + WebViewClientHostApiImpl testHostApiImpl; + WebViewClient testWebViewClient; + + @Before + public void setUp() { + testInstanceManager = new InstanceManager(); + testInstanceManager.addInstance(mockWebView, 0L); + + final WebViewClientCreator webViewClientCreator = + new WebViewClientCreator() { + @Override + WebViewClient createWebViewClient( + Long instanceId, + InstanceManager instanceManager, + Boolean shouldOverrideUrlLoading, + WebViewClientFlutterApi webViewClientFlutterApi) { + testWebViewClient = + super.createWebViewClient( + instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi); + return testWebViewClient; + } + }; + + testHostApiImpl = + new WebViewClientHostApiImpl(testInstanceManager, webViewClientCreator, mockFlutterApi); + testHostApiImpl.create(1L, true); + } + + @Test + public void onPageStarted() { + testWebViewClient.onPageStarted(mockWebView, "https://www.google.com", null); + verify(mockFlutterApi).onPageStarted(eq(1L), eq(0L), eq("https://www.google.com"), any()); + } + + @Test + public void onReceivedError() { + testWebViewClient.onReceivedError(mockWebView, 32, "description", "https://www.google.com"); + verify(mockFlutterApi) + .onReceivedError( + eq(1L), eq(0L), eq(32L), eq("description"), eq("https://www.google.com"), any()); + } + + @Test + public void urlLoading() { + testWebViewClient.shouldOverrideUrlLoading(mockWebView, "https://www.google.com"); + verify(mockFlutterApi).urlLoading(eq(1L), eq(0L), eq("https://www.google.com"), any()); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java index 131a5a3eb53a..b914ce913e76 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java @@ -5,11 +5,45 @@ package io.flutter.plugins.webviewflutter; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.content.Context; +import android.webkit.DownloadListener; +import android.webkit.ValueCallback; +import android.webkit.WebView; import android.webkit.WebViewClient; +import java.util.HashMap; +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; public class WebViewTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock public WebView mockWebView; + + @Mock WebViewHostApiImpl.WebViewProxy mockWebViewProxy; + + @Mock Context mockContext; + + InstanceManager testInstanceManager; + WebViewHostApiImpl testHostApiImpl; + + @Before + public void setUp() { + testInstanceManager = new InstanceManager(); + when(mockWebViewProxy.createWebView(mockContext)).thenReturn(mockWebView); + testHostApiImpl = new WebViewHostApiImpl(testInstanceManager, mockWebViewProxy, mockContext); + testHostApiImpl.create(0L, true); + } + @Test public void errorCodes() { assertEquals( @@ -46,4 +80,143 @@ public void errorCodes() { FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_UNSUPPORTED_SCHEME), "unsupportedScheme"); } + + @Test + public void loadUrl() { + testHostApiImpl.loadUrl(0L, "https://www.google.com", new HashMap<>()); + verify(mockWebView).loadUrl("https://www.google.com", new HashMap<>()); + } + + @Test + public void getUrl() { + when(mockWebView.getUrl()).thenReturn("https://www.google.com"); + assertEquals(testHostApiImpl.getUrl(0L), "https://www.google.com"); + } + + @Test + public void canGoBack() { + when(mockWebView.canGoBack()).thenReturn(true); + assertEquals(testHostApiImpl.canGoBack(0L), true); + } + + @Test + public void canGoForward() { + when(mockWebView.canGoForward()).thenReturn(false); + assertEquals(testHostApiImpl.canGoForward(0L), false); + } + + @Test + public void goBack() { + testHostApiImpl.goBack(0L); + verify(mockWebView).goBack(); + } + + @Test + public void goForward() { + testHostApiImpl.goForward(0L); + verify(mockWebView).goForward(); + } + + @Test + public void reload() { + testHostApiImpl.reload(0L); + verify(mockWebView).reload(); + } + + @Test + public void clearCache() { + testHostApiImpl.clearCache(0L, false); + verify(mockWebView).clearCache(false); + } + + @Test + public void evaluateJavaScript() { + final String[] successValue = new String[1]; + testHostApiImpl.evaluateJavascript( + 0L, + "2 + 2", + new GeneratedAndroidWebView.Result() { + @Override + public void success(String result) { + successValue[0] = result; + } + + @Override + public void error(Throwable error) {} + }); + + @SuppressWarnings("unchecked") + final ArgumentCaptor> callbackCaptor = + ArgumentCaptor.forClass(ValueCallback.class); + verify(mockWebView).evaluateJavascript(eq("2 + 2"), callbackCaptor.capture()); + + callbackCaptor.getValue().onReceiveValue("da result"); + assertEquals(successValue[0], "da result"); + } + + @Test + public void getTitle() { + when(mockWebView.getTitle()).thenReturn("My title"); + assertEquals(testHostApiImpl.getTitle(0L), "My title"); + } + + @Test + public void scrollTo() { + testHostApiImpl.scrollTo(0L, 12L, 13L); + verify(mockWebView).scrollTo(12, 13); + } + + @Test + public void scrollBy() { + testHostApiImpl.scrollBy(0L, 15L, 23L); + verify(mockWebView).scrollBy(15, 23); + } + + @Test + public void getScrollX() { + when(mockWebView.getScrollX()).thenReturn(55); + assertEquals((long) testHostApiImpl.getScrollX(0L), 55); + } + + @Test + public void getScrollY() { + when(mockWebView.getScrollY()).thenReturn(23); + assertEquals((long) testHostApiImpl.getScrollY(0L), 23); + } + + @Test + public void setWebViewClient() { + final WebViewClient mockWebViewClient = mock(WebViewClient.class); + testInstanceManager.addInstance(mockWebViewClient, 1L); + + testHostApiImpl.setWebViewClient(0L, 1L); + verify(mockWebView).setWebViewClient(mockWebViewClient); + } + + @Test + public void addJavaScriptChannel() { + final JavaScriptChannel javaScriptChannel = new JavaScriptChannel(null, "aName", null); + testInstanceManager.addInstance(javaScriptChannel, 1L); + + testHostApiImpl.addJavaScriptChannel(0L, 1L); + verify(mockWebView).addJavascriptInterface(javaScriptChannel, "aName"); + } + + @Test + public void removeJavaScriptChannel() { + final JavaScriptChannel javaScriptChannel = new JavaScriptChannel(null, "aName", null); + testInstanceManager.addInstance(javaScriptChannel, 1L); + + testHostApiImpl.removeJavaScriptChannel(0L, 1L); + verify(mockWebView).removeJavascriptInterface("aName"); + } + + @Test + public void setDownloadListener() { + final DownloadListener mockDownloadListener = mock(DownloadListener.class); + testInstanceManager.addInstance(mockDownloadListener, 1L); + + testHostApiImpl.setDownloadListener(0L, 1L); + verify(mockWebView).setDownloadListener(mockDownloadListener); + } } diff --git a/packages/webview_flutter/webview_flutter_android/generatePigeons.sh b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh new file mode 100755 index 000000000000..30a6918fc922 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/generatePigeons.sh @@ -0,0 +1,10 @@ +# 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. + +flutter pub run pigeon \ +--input pigeons/android_webview.dart \ +--dart_out lib/src/android_webview.pigeon.dart \ +--dart_test_out test/android_webview.pigeon.dart \ +--java_out android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.Java \ +--java_package io.flutter.plugins.webviewflutter From a4e919cc705609aed23ece83da856fcf192c1950 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 20 Oct 2021 23:45:03 -0700 Subject: [PATCH 24/54] add instance manager --- .../webviewflutter/InstanceManager.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java new file mode 100644 index 000000000000..e2409d9df8dd --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java @@ -0,0 +1,38 @@ +// 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 java.util.HashMap; +import java.util.Map; + +class InstanceManager { + private final Map instanceIdsToInstances = new HashMap<>(); + private final Map instancesToInstanceIds = new HashMap<>(); + + /** Add a new instance with instanceId. */ + void addInstance(Object instance, Long instanceId) { + instancesToInstanceIds.put(instance, instanceId); + instanceIdsToInstances.put(instanceId, instance); + } + + /** Remove the instance from the manager. */ + Object removeInstanceId(Long instanceId) { + final Object instance = instanceIdsToInstances.remove(instanceId); + if (instance != null) { + instancesToInstanceIds.remove(instance); + } + return instance; + } + + /** Retrieve the Object paired with instanceId. */ + Object getInstance(Long instanceId) { + return instanceIdsToInstances.get(instanceId); + } + + /** Retrieve the instanceId paired with instance. */ + Long getInstanceId(Object instance) { + return instancesToInstanceIds.get(instance); + } +} From 2fbd13020666f33f8f17cc40cb846ac024058125 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Sun, 24 Oct 2021 23:40:00 -0700 Subject: [PATCH 25/54] change method name --- .../webviewflutter/DownloadListenerHostApiImpl.java | 2 +- .../plugins/webviewflutter/InstanceManager.java | 13 +++++++------ .../JavaScriptChannelHostApiImpl.java | 2 +- .../webviewflutter/WebSettingsHostApiImpl.java | 2 +- .../webviewflutter/WebViewClientHostApiImpl.java | 6 +++++- .../plugins/webviewflutter/WebViewHostApiImpl.java | 2 +- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java index cfda4c77bceb..202be87d7d1e 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java @@ -39,6 +39,6 @@ public void create(Long instanceId) { @Override public void dispose(Long instanceId) { - instanceManager.removeInstanceId(instanceId); + instanceManager.removeInstance(instanceId); } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java index e2409d9df8dd..c298bc049c2c 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java @@ -4,30 +4,31 @@ package io.flutter.plugins.webviewflutter; +import android.util.LongSparseArray; import java.util.HashMap; import java.util.Map; class InstanceManager { - private final Map instanceIdsToInstances = new HashMap<>(); + private final LongSparseArray instanceIdsToInstances = new LongSparseArray<>(); private final Map instancesToInstanceIds = new HashMap<>(); /** Add a new instance with instanceId. */ - void addInstance(Object instance, Long instanceId) { + void addInstance(Object instance, long instanceId) { instancesToInstanceIds.put(instance, instanceId); instanceIdsToInstances.put(instanceId, instance); } /** Remove the instance from the manager. */ - Object removeInstanceId(Long instanceId) { - final Object instance = instanceIdsToInstances.remove(instanceId); + void removeInstance(long instanceId) { + final Object instance = instanceIdsToInstances.get(instanceId); if (instance != null) { + instanceIdsToInstances.remove(instanceId); instancesToInstanceIds.remove(instance); } - return instance; } /** Retrieve the Object paired with instanceId. */ - Object getInstance(Long instanceId) { + Object getInstance(long instanceId) { return instanceIdsToInstances.get(instanceId); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java index c17537abac50..2d42d952955c 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -56,6 +56,6 @@ public void create(Long instanceId, String channelName) { @Override public void dispose(Long instanceId) { - instanceManager.removeInstanceId(instanceId); + instanceManager.removeInstance(instanceId); } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java index 5c3d00413971..e70a867c23ff 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java @@ -30,7 +30,7 @@ public void create(Long instanceId, Long webViewInstanceId) { @Override public void dispose(Long instanceId) { - instanceManager.removeInstanceId(instanceId); + instanceManager.removeInstance(instanceId); } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java index 10b753570285..4d17eb129db8 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java @@ -102,6 +102,7 @@ public void onReceivedError( reply -> {}); } + @SuppressWarnings("deprecation") @Override public void onReceivedError( WebView view, int errorCode, String description, String failingUrl) { @@ -124,6 +125,7 @@ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request return shouldOverrideUrlLoading; } + @SuppressWarnings("deprecation") @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { webViewClientFlutterApi.urlLoading( @@ -169,6 +171,7 @@ public void onReceivedError( reply -> {}); } + @SuppressWarnings("deprecation") @Override public void onReceivedError( WebView view, int errorCode, String description, String failingUrl) { @@ -193,6 +196,7 @@ public boolean shouldOverrideUrlLoading( return shouldOverrideUrlLoading; } + @SuppressWarnings("deprecation") @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { webViewClientFlutterApi.urlLoading( @@ -230,6 +234,6 @@ public void create(Long instanceId, Boolean shouldOverrideUrlLoading) { @Override public void dispose(Long instanceId) { - instanceManager.removeInstanceId(instanceId); + instanceManager.removeInstance(instanceId); } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index 10b76def969a..00590af4cc8a 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -103,7 +103,7 @@ public void create(Long instanceId, Boolean useHybridComposition) { @Override public void dispose(Long instanceId) { - instanceManager.removeInstanceId(instanceId); + instanceManager.removeInstance(instanceId); } @Override From 8fe8aa6c6bc70d83a79472d6973c410251100368 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 25 Oct 2021 00:47:22 -0700 Subject: [PATCH 26/54] add longsparsearray cheat --- .../webviewflutter/InstanceManager.java | 2 +- .../java/android/util/LongSparseArray.java | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/android/util/LongSparseArray.java diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java index c298bc049c2c..bfa7d6f17345 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java @@ -15,7 +15,7 @@ class InstanceManager { /** Add a new instance with instanceId. */ void addInstance(Object instance, long instanceId) { instancesToInstanceIds.put(instance, instanceId); - instanceIdsToInstances.put(instanceId, instance); + instanceIdsToInstances.append(instanceId, instance); } /** Remove the instance from the manager. */ diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/android/util/LongSparseArray.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/android/util/LongSparseArray.java new file mode 100644 index 000000000000..4a90e394e259 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/android/util/LongSparseArray.java @@ -0,0 +1,29 @@ +// 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 android.util; + +import java.util.HashMap; + +// Creates an implementation of LongSparseArray that can be used with unittests and the JVM. +// Typically android.util.LongSparseArray does nothing when not used with an Android environment. +public class LongSparseArray { + private final HashMap mHashMap; + + public LongSparseArray() { + mHashMap = new HashMap<>(); + } + + public void append(long key, E value) { + mHashMap.put(key, value); + } + + public E get(long key) { + return mHashMap.get(key); + } + + public void remove(long key) { + mHashMap.remove(key); + } +} From bf2203e67ce6cb07d171314d5d89ea833fd70f88 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 25 Oct 2021 21:23:01 -0700 Subject: [PATCH 27/54] start of impl in dart --- .../lib/webview_android.dart | 251 ++++++++++++++++++ 1 file changed, 251 insertions(+) diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart index a48e457d55ad..1c3d63addbc0 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart @@ -10,6 +10,8 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; +import 'src/android_webview.dart' as android_webview; + /// Builds an Android webview. /// /// This is used as the default implementation for [WebView.platform] on Android. It uses @@ -60,3 +62,252 @@ class AndroidWebView implements WebViewPlatform { @override Future clearCookies() => MethodChannelWebViewPlatform.clearCookies(); } + +class _AndroidWebViewWidget extends StatefulWidget { + _AndroidWebViewWidget({ + required this.creationParams, + required this.webViewPlatformCallbacksHandler, + required this.javascriptChannelRegistry, + this.onWebViewPlatformCreated, + this.gestureRecognizers, + }); + + final CreationParams creationParams; + final WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler; + final JavascriptChannelRegistry javascriptChannelRegistry; + final WebViewPlatformCreatedCallback? onWebViewPlatformCreated; + final Set>? gestureRecognizers; + + @override + State createState() => _AndroidWebViewWidgetState(); +} + +class _AndroidWebViewWidgetState extends State<_AndroidWebViewWidget> { + late _AndroidWebViewPlatformController platformController; + + @override + void initState() { + super.initState(); + final android_webview.WebView webView = android_webview.WebView( + useHybridComposition: false, + ); + android_webview.WebView.api.createFromInstance(webView); + + webView.settings.setDomStorageEnabled(true); + webView.settings.setJavaScriptCanOpenWindowsAutomatically(true); + webView.settings.setSupportMultipleWindows(true); + + platformController = _AndroidWebViewPlatformController(webView, widget.webViewPlatformCallbacksHandler); + + final WebSettings? webSettings = widget.creationParams.webSettings; + if (webSettings != null) { + platformController.updateSettings(webSettings); + } + + final AutoMediaPlaybackPolicy autoMediaPlaybackPolicy = + widget.creationParams.autoMediaPlaybackPolicy; + switch (autoMediaPlaybackPolicy) { + case AutoMediaPlaybackPolicy.always_allow: + webView.settings.setMediaPlaybackRequiresUserGesture(false); + break; + default: + webView.settings.setMediaPlaybackRequiresUserGesture(true); + } + + platformController.addJavascriptChannels( + widget.creationParams.javascriptChannelNames, + ); + + final String? userAgent = widget.creationParams.userAgent; + if (userAgent != null) { + webView.settings.setUserAgentString(userAgent); + } + + final String? initialUrl = widget.creationParams.initialUrl; + if (initialUrl != null) { + platformController.loadUrl(initialUrl, {}); + } + } + + @override + void dispose() { + super.dispose(); + android_webview.WebView.api.disposeFromInstance(webView); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + // We prevent text selection by intercepting the long press event. + // This is a temporary stop gap due to issues with text selection on Android: + // https://github.com/flutter/flutter/issues/24585 - the text selection + // dialog is not responding to touch events. + // https://github.com/flutter/flutter/issues/24584 - the text selection + // handles are not showing. + // TODO(amirh): remove this when the issues above are fixed. + onLongPress: () {}, + excludeFromSemantics: true, + child: AndroidView( + viewType: 'plugins.flutter.io/webview', + onPlatformViewCreated: (int id) { + final WebViewPlatformCreatedCallback? createdCallback = + widget.onWebViewPlatformCreated; + if (createdCallback != null) { + createdCallback(MethodChannelWebViewPlatform( + id, + webViewPlatformCallbacksHandler, + javascriptChannelRegistry, + )); + } + }, + gestureRecognizers: widget.gestureRecognizers, + layoutDirection: Directionality.maybeOf(context) ?? TextDirection.rtl, + // creationParams: + // MethodChannelWebViewPlatform.creationParamsToMap(creationParams), + // creationParamsCodec: const StandardMessageCodec(), + ), + ); + } +} + +class _AndroidWebViewPlatformController extends WebViewPlatformController { + _AndroidWebViewPlatformController( + this.webView, + WebViewPlatformCallbacksHandler handler, + ) : super(handler) { + webViewClient = _WebViewClientImpl(handler); + downloadListener = _DownloadListenerImpl(handler); + webView.setWebViewClient(webViewClient); + webView.setDownloadListener(downloadListener); + } + + final android_webview.WebView webView; + late final android_webview.WebViewClient webViewClient; + late final android_webview.DownloadListener downloadListener; + + @override + Future loadUrl( + String url, + Map? headers, + ) { + return webView.loadUrl(url, headers ?? {}); + } + + @override + Future currentUrl() => webView.getUrl(); + + @override + Future canGoBack() => webView.canGoBack(); + + @override + Future canGoForward() => webView.canGoForward(); + + @override + Future goBack() => webView.goBack(); + + @override + Future goForward() => webView.goForward(); + + @override + Future reload() => webView.reload(); + + @override + Future clearCache() => webView.clearCache(true); + + @override + Future updateSettings(WebSettings settings) async {} + + @override + Future evaluateJavascript(String javascriptString) async { + return await webView.evaluateJavascript(javascriptString) ?? ''; + } + + @override + Future addJavascriptChannels(Set javascriptChannelNames) { + return Future.wait( + javascriptChannelNames.map>( + (String channelName) { + return webView + .addJavaScriptChannel(_JavaScriptChannelImpl(channelName)); + }, + ), + ); + } + + @override + Future removeJavascriptChannels(Set javascriptChannelNames) { + return _channel.invokeMethod( + 'removeJavascriptChannels', javascriptChannelNames.toList()); + } + + @override + Future getTitle() => webView.getTitle(); + + @override + Future scrollTo(int x, int y) => webView.scrollTo(x, y); + + @override + Future scrollBy(int x, int y) => webView.scrollBy(x, y); + + @override + Future getScrollX() => webView.getScrollX(); + + @override + Future getScrollY() => webView.getScrollY(); +} + +class _JavaScriptChannelImpl extends android_webview.JavaScriptChannel { + _JavaScriptChannelImpl(String channelName) : super(channelName); + + @override + void postMessage(String message) { + super.postMessage(message); + } +} + +class _DownloadListenerImpl extends android_webview.DownloadListener { + _DownloadListenerImpl(this.callbacksHandler); + + final WebViewPlatformCallbacksHandler callbacksHandler; + + @override + void onDownloadStart( + String url, + String userAgent, + String contentDisposition, + String mimetype, + int contentLength, + ) { + callbacksHandler.onNavigationRequest(url: url, isForMainFrame: true); + } +} + +class _WebViewClientImpl extends android_webview.WebViewClient { + _WebViewClientImpl(this.callbacksHandler); + + final WebViewPlatformCallbacksHandler callbacksHandler; + + @override + void onPageStarted(android_webview.WebView webView, String url) { + callbacksHandler.onPageStarted(url); + } + + @override + void onPageFinished(android_webview.WebView webView, String url) { + callbacksHandler.onPageFinished(url); + } + + @override + void urlLoading(android_webview.WebView webView, String url) { + callbacksHandler.onNavigationRequest(url: url, isForMainFrame: true); + } + + @override + void requestLoading(android_webview.WebView webView, + android_webview.WebResourceRequest request) { + callbacksHandler.onNavigationRequest( + url: request.url, + isForMainFrame: request.isForMainFrame, + ); + } +} From 4ec084be385ef2b51797a3d8fe52d280d653f015 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 25 Oct 2021 23:38:35 -0700 Subject: [PATCH 28/54] add webchromeclient support --- .../GeneratedAndroidWebView.java | 151 ++++++++++++++++++ .../WebChromeClientHostApiImpl.java | 92 +++++++++++ .../webviewflutter/WebViewHostApiImpl.java | 7 + .../webviewflutter/WebChromeClientTest.java | 67 ++++++++ .../lib/src/android_webview.dart | 38 +++++ .../lib/src/android_webview.pigeon.dart | 133 +++++++++++++++ .../lib/src/android_webview_api_impls.dart | 65 ++++++++ .../lib/webview_android.dart | 31 ++-- .../pigeons/android_webview.dart | 13 ++ .../test/android_webview.pigeon.dart | 74 +++++++++ .../test/android_webview_test.dart | 55 +++++++ 11 files changed, 713 insertions(+), 13 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index f1725e1b7c7b..ba2b9b1ac481 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -211,6 +211,8 @@ public interface WebViewHostApi { void setDownloadListener(Long instanceId, Long listenerInstanceId); + void setWebChromeClient(Long instanceId, Long clientInstanceId); + /** The codec used by WebViewHostApi. */ static MessageCodec getCodec() { return WebViewHostApiCodec.INSTANCE; @@ -824,6 +826,38 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebViewHostApi.setWebChromeClient", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number clientInstanceIdArg = (Number) args.get(1); + if (clientInstanceIdArg == null) { + throw new NullPointerException("clientInstanceIdArg unexpectedly null."); + } + api.setWebChromeClient( + instanceIdArg.longValue(), clientInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } } } @@ -1748,6 +1782,123 @@ public void onDownloadStart( } } + private static class WebChromeClientHostApiCodec extends StandardMessageCodec { + public static final WebChromeClientHostApiCodec INSTANCE = new WebChromeClientHostApiCodec(); + + private WebChromeClientHostApiCodec() {} + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + public interface WebChromeClientHostApi { + void create(Long instanceId, Long webViewClientInstanceId); + + void dispose(Long instanceId); + + /** The codec used by WebChromeClientHostApi. */ + static MessageCodec getCodec() { + return WebChromeClientHostApiCodec.INSTANCE; + } + + /** + * Sets up an instance of `WebChromeClientHostApi` to handle messages through the + * `binaryMessenger`. + */ + static void setup(BinaryMessenger binaryMessenger, WebChromeClientHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebChromeClientHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + Number webViewClientInstanceIdArg = (Number) args.get(1); + if (webViewClientInstanceIdArg == null) { + throw new NullPointerException("webViewClientInstanceIdArg unexpectedly null."); + } + api.create(instanceIdArg.longValue(), webViewClientInstanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebChromeClientHostApi.dispose", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + api.dispose(instanceIdArg.longValue()); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + + private static class WebChromeClientFlutterApiCodec extends StandardMessageCodec { + public static final WebChromeClientFlutterApiCodec INSTANCE = + new WebChromeClientFlutterApiCodec(); + + private WebChromeClientFlutterApiCodec() {} + } + + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + public static class WebChromeClientFlutterApi { + private final BinaryMessenger binaryMessenger; + + public WebChromeClientFlutterApi(BinaryMessenger argBinaryMessenger) { + this.binaryMessenger = argBinaryMessenger; + } + + public interface Reply { + void reply(T reply); + } + + static MessageCodec getCodec() { + return WebChromeClientFlutterApiCodec.INSTANCE; + } + + public void onProgressChanged( + Long instanceIdArg, Long webViewInstanceIdArg, Long progressArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.WebChromeClientFlutterApi.onProgressChanged", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg, webViewInstanceIdArg, progressArg)), + channelReply -> { + callback.reply(null); + }); + } + } + private static Map wrapError(Throwable exception) { Map errorMap = new HashMap<>(); errorMap.put("message", exception.toString()); diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java new file mode 100644 index 000000000000..32f8fcbdeed9 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java @@ -0,0 +1,92 @@ +// 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.os.Message; +import android.webkit.WebChromeClient; +import android.webkit.WebResourceRequest; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientFlutterApi; + +class WebChromeClientHostApiImpl implements GeneratedAndroidWebView.WebChromeClientHostApi { + private final InstanceManager instanceManager; + private final WebChromeClientCreator webChromeClientCreator; + private final WebChromeClientFlutterApi webChromeClientFlutterApi; + + static class WebChromeClientCreator { + WebChromeClient createWebChromeClient( + Long instanceId, + InstanceManager instanceManager, + WebViewClient webViewClient, + WebChromeClientFlutterApi webChromeClientFlutterApi) { + return new WebChromeClient() { + // Verifies that a url opened by `Window.open` has a secure url. + @Override + public boolean onCreateWindow( + final WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { + final WebViewClient newWindowWebViewClient = + new WebViewClient() { + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public boolean shouldOverrideUrlLoading( + @NonNull WebView view, @NonNull WebResourceRequest request) { + webViewClient.shouldOverrideUrlLoading(view, request); + return true; + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + webViewClient.shouldOverrideUrlLoading(view, url); + return true; + } + }; + + final WebView newWebView = new WebView(view.getContext()); + newWebView.setWebViewClient(newWindowWebViewClient); + + final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; + transport.setWebView(newWebView); + resultMsg.sendToTarget(); + + return true; + } + + @Override + public void onProgressChanged(WebView view, int progress) { + webChromeClientFlutterApi.onProgressChanged( + instanceId, instanceManager.getInstanceId(view), (long) progress, reply -> {}); + } + }; + } + } + + WebChromeClientHostApiImpl( + InstanceManager instanceManager, + WebChromeClientCreator webChromeClientCreator, + WebChromeClientFlutterApi webChromeClientFlutterApi) { + this.instanceManager = instanceManager; + this.webChromeClientCreator = webChromeClientCreator; + this.webChromeClientFlutterApi = webChromeClientFlutterApi; + } + + @Override + public void create(Long instanceId, Long webViewClientInstanceId) { + final WebViewClient webViewClient = + (WebViewClient) instanceManager.getInstance(webViewClientInstanceId); + final WebChromeClient webChromeClient = + webChromeClientCreator.createWebChromeClient( + instanceId, instanceManager, webViewClient, webChromeClientFlutterApi); + instanceManager.addInstance(webChromeClient, instanceId); + } + + @Override + public void dispose(Long instanceId) { + instanceManager.removeInstance(instanceId); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index 00590af4cc8a..35bdc608d6ff 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -7,6 +7,7 @@ import android.content.Context; import android.view.View; import android.webkit.DownloadListener; +import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; import androidx.annotation.NonNull; @@ -223,4 +224,10 @@ public void setDownloadListener(Long instanceId, Long listenerInstanceId) { final WebView webView = (WebView) instanceManager.getInstance(instanceId); webView.setDownloadListener((DownloadListener) instanceManager.getInstance(listenerInstanceId)); } + + @Override + public void setWebChromeClient(Long instanceId, Long clientInstanceId) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.setWebChromeClient((WebChromeClient) instanceManager.getInstance(instanceId)); + } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java new file mode 100644 index 000000000000..5ab3ab10fe03 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java @@ -0,0 +1,67 @@ +// 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 static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import android.webkit.WebChromeClient; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientFlutterApi; +import io.flutter.plugins.webviewflutter.WebChromeClientHostApiImpl.WebChromeClientCreator; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class WebChromeClientTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock public WebChromeClientFlutterApi mockFlutterApi; + + @Mock public WebView mockWebView; + + @Mock public WebViewClient mockWebViewClient; + + InstanceManager testInstanceManager; + WebChromeClientHostApiImpl testHostApiImpl; + WebChromeClient testWebChromeClient; + + @Before + public void setUp() { + testInstanceManager = new InstanceManager(); + testInstanceManager.addInstance(mockWebView, 0L); + testInstanceManager.addInstance(mockWebViewClient, 1L); + + final WebChromeClientCreator webChromeClientCreator = + new WebChromeClientCreator() { + @Override + WebChromeClient createWebChromeClient( + Long instanceId, + InstanceManager instanceManager, + WebViewClient webViewClient, + WebChromeClientFlutterApi webChromeClientFlutterApi) { + testWebChromeClient = + super.createWebChromeClient( + instanceId, instanceManager, webViewClient, webChromeClientFlutterApi); + return testWebChromeClient; + } + }; + + testHostApiImpl = + new WebChromeClientHostApiImpl(testInstanceManager, webChromeClientCreator, mockFlutterApi); + testHostApiImpl.create(2L, 1L); + } + + @Test + public void onProgressChanged() { + testWebChromeClient.onProgressChanged(mockWebView, 23); + verify(mockFlutterApi).onProgressChanged(eq(2L), eq(0L), eq(23L), any()); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index a7984054fe06..1ddd6f3d9f0f 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -41,6 +41,7 @@ class WebView { WebViewClient? _currentWebViewClient; DownloadListener? _currentDownloadListener; + WebChromeClient? _currentWebChromeClient; Set _javaScriptChannels = {}; /// Whether the [WebView] will be rendered with an [AndroidViewSurface]. @@ -258,6 +259,33 @@ class WebView { _currentDownloadListener = listener; return api.setDownloadListenerFromInstance(this, listener); } + + /// Sets the chrome handler. + /// + /// This is an implementation of [WebChromeClient] for use in handling + /// JavaScript dialogs, favicons, titles, and the progress. This will replace + /// the current handler. + Future setWebChromeClient(WebChromeClient client) { + final WebChromeClient? currentWebChromeClient = _currentWebChromeClient; + + if (client == currentWebChromeClient) { + return Future.value(); + } + + if (currentWebChromeClient != null) { + WebChromeClient.api.disposeFromInstance(currentWebChromeClient); + } + + final WebViewClient? currentWebViewClient = _currentWebViewClient; + assert( + currentWebViewClient != null, + "Can't set a WebChromeClient without setting a WebViewClient first.", + ); + + WebChromeClient.api.createFromInstance(client, currentWebViewClient!); + _currentWebChromeClient = client; + return api.setWebChromeClientFromInstance(this, client); + } } /// Manages settings state for a [WebView]. @@ -559,6 +587,16 @@ abstract class DownloadListener { ); } +/// Handles JavaScript dialogs, favicons, titles, and the progress for [WebView]. +abstract class WebChromeClient { + /// Pigeon Host Api implementation for [WebChromeClient]. + @visibleForTesting + static WebChromeClientHostApiImpl api = WebChromeClientHostApiImpl(); + + /// Notify the host application that a file should be downloaded. + void onProgressChanged(WebView webView, int progress); +} + /// Encompasses parameters to the [WebViewClient.requestLoading] method. class WebResourceRequest { /// Constructs a [WebResourceRequest]. diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart index 206b045e900a..81ec7c7bf80e 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -617,6 +617,33 @@ class WebViewHostApi { return; } } + + Future setWebChromeClient( + int arg_instanceId, int arg_clientInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.setWebChromeClient', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_clientInstanceId]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } } class _WebSettingsHostApiCodec extends StandardMessageCodec { @@ -1466,3 +1493,109 @@ abstract class DownloadListenerFlutterApi { } } } + +class _WebChromeClientHostApiCodec extends StandardMessageCodec { + const _WebChromeClientHostApiCodec(); +} + +class WebChromeClientHostApi { + /// Constructor for [WebChromeClientHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + WebChromeClientHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _WebChromeClientHostApiCodec(); + + Future create( + int arg_instanceId, int arg_webViewClientInstanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebChromeClientHostApi.create', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_instanceId, arg_webViewClientInstanceId]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + + Future dispose(int arg_instanceId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebChromeClientHostApi.dispose', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + +class _WebChromeClientFlutterApiCodec extends StandardMessageCodec { + const _WebChromeClientFlutterApiCodec(); +} + +abstract class WebChromeClientFlutterApi { + static const MessageCodec codec = _WebChromeClientFlutterApiCodec(); + + void onProgressChanged(int instanceId, int webViewInstanceId, int progress); + static void setup(WebChromeClientFlutterApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebChromeClientFlutterApi.onProgressChanged', + codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.onProgressChanged was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.onProgressChanged was null, expected non-null int.'); + final int? arg_webViewInstanceId = args[1] as int?; + assert(arg_webViewInstanceId != null, + 'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.onProgressChanged was null, expected non-null int.'); + final int? arg_progress = args[2] as int?; + assert(arg_progress != null, + 'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.onProgressChanged was null, expected non-null int.'); + api.onProgressChanged( + arg_instanceId!, arg_webViewInstanceId!, arg_progress!); + return; + }); + } + } + } +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index 83621e02cb16..f909e49bd802 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -161,6 +161,17 @@ class WebViewHostApiImpl extends WebViewHostApi { instanceManager.getInstanceId(listener)!, ); } + + /// Helper method to convert instances ids to objects. + Future setWebChromeClientFromInstance( + WebView instance, + WebChromeClient client, + ) { + return setWebChromeClient( + instanceManager.getInstanceId(instance)!, + instanceManager.getInstanceId(client)!, + ); + } } /// Host api implementation for [WebSettings]. @@ -555,3 +566,57 @@ class DownloadListenerFlutterApiImpl extends DownloadListenerFlutterApi { ); } } + +/// Host api implementation for [DownloadListener]. +class WebChromeClientHostApiImpl extends WebChromeClientHostApi { + /// Constructs a [WebChromeClientHostApiImpl]. + WebChromeClientHostApiImpl({ + BinaryMessenger? binaryMessenger, + InstanceManager? instanceManager, + }) : super(binaryMessenger: binaryMessenger) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + /// Maintains instances stored to communicate with java objects. + late final InstanceManager instanceManager; + + /// Helper method to convert instances ids to objects. + Future createFromInstance( + WebChromeClient instance, + WebViewClient webViewClient, + ) async { + final int? instanceId = instanceManager.tryAddInstance(instance); + if (instanceId != null) { + return create(instanceId, instanceManager.getInstanceId(webViewClient)!); + } + } + + /// Helper method to convert instances ids to objects. + Future disposeFromInstance(WebChromeClient instance) async { + final int? instanceId = instanceManager.removeInstance(instance); + if (instanceId != null) { + return dispose(instanceId); + } + } +} + +/// Flutter api implementation for [DownloadListener]. +class WebChromeClientFlutterApiImpl extends WebChromeClientFlutterApi { + /// Constructs a [DownloadListenerFlutterApiImpl]. + WebChromeClientFlutterApiImpl({InstanceManager? instanceManager}) { + this.instanceManager = instanceManager ?? InstanceManager.instance; + } + + /// Maintains instances stored to communicate with java objects. + late final InstanceManager instanceManager; + + @override + void onProgressChanged(int instanceId, int webViewInstanceId, int progress) { + final WebChromeClient instance = + instanceManager.getInstance(instanceId) as WebChromeClient; + instance.onProgressChanged( + instanceManager.getInstance(webViewInstanceId) as WebView, + progress, + ); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart index 1c3d63addbc0..7367d04b450d 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart @@ -97,7 +97,8 @@ class _AndroidWebViewWidgetState extends State<_AndroidWebViewWidget> { webView.settings.setJavaScriptCanOpenWindowsAutomatically(true); webView.settings.setSupportMultipleWindows(true); - platformController = _AndroidWebViewPlatformController(webView, widget.webViewPlatformCallbacksHandler); + platformController = _AndroidWebViewPlatformController( + webView, widget.webViewPlatformCallbacksHandler); final WebSettings? webSettings = widget.creationParams.webSettings; if (webSettings != null) { @@ -132,7 +133,7 @@ class _AndroidWebViewWidgetState extends State<_AndroidWebViewWidget> { @override void dispose() { super.dispose(); - android_webview.WebView.api.disposeFromInstance(webView); + //android_webview.WebView.api.disposeFromInstance(webView); } @override @@ -152,13 +153,13 @@ class _AndroidWebViewWidgetState extends State<_AndroidWebViewWidget> { onPlatformViewCreated: (int id) { final WebViewPlatformCreatedCallback? createdCallback = widget.onWebViewPlatformCreated; - if (createdCallback != null) { - createdCallback(MethodChannelWebViewPlatform( - id, - webViewPlatformCallbacksHandler, - javascriptChannelRegistry, - )); - } + // if (createdCallback != null) { + // createdCallback(MethodChannelWebViewPlatform( + // id, + // webViewPlatformCallbacksHandler, + // javascriptChannelRegistry, + // )); + // } }, gestureRecognizers: widget.gestureRecognizers, layoutDirection: Directionality.maybeOf(context) ?? TextDirection.rtl, @@ -235,9 +236,10 @@ class _AndroidWebViewPlatformController extends WebViewPlatformController { } @override - Future removeJavascriptChannels(Set javascriptChannelNames) { - return _channel.invokeMethod( - 'removeJavascriptChannels', javascriptChannelNames.toList()); + Future removeJavascriptChannels( + Set javascriptChannelNames) async { + // return _channel.invokeMethod( + // 'removeJavascriptChannels', javascriptChannelNames.toList()); } @override @@ -299,7 +301,10 @@ class _WebViewClientImpl extends android_webview.WebViewClient { @override void urlLoading(android_webview.WebView webView, String url) { - callbacksHandler.onNavigationRequest(url: url, isForMainFrame: true); + final FutureOr returnValue = callbacksHandler.onNavigationRequest( + url: url, + isForMainFrame: true, + ); } @override diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart index 375f3ced67f2..1877c1b91feb 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -69,6 +69,8 @@ abstract class WebViewHostApi { void removeJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId); void setDownloadListener(int instanceId, int listenerInstanceId); + + void setWebChromeClient(int instanceId, int clientInstanceId); } @HostApi(dartHostTestHandler: 'TestWebSettingsHostApi') @@ -166,3 +168,14 @@ abstract class DownloadListenerFlutterApi { int contentLength, ); } + +@HostApi(dartHostTestHandler: 'TestWebChromeClientHostApi') +abstract class WebChromeClientHostApi { + void create(int instanceId, int webViewClientInstanceId); + void dispose(int instanceId); +} + +@FlutterApi() +abstract class WebChromeClientFlutterApi { + void onProgressChanged(int instanceId, int webViewInstanceId, int progress); +} diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart index 821dacebd2ed..70aa53ca2610 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart @@ -42,6 +42,7 @@ abstract class TestWebViewHostApi { void addJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId); void removeJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId); void setDownloadListener(int instanceId, int listenerInstanceId); + void setWebChromeClient(int instanceId, int clientInstanceId); static void setup(TestWebViewHostApi? api) { { const BasicMessageChannel channel = BasicMessageChannel( @@ -465,6 +466,27 @@ abstract class TestWebViewHostApi { }); } } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.setWebChromeClient', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebChromeClient was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebChromeClient was null, expected non-null int.'); + final int? arg_clientInstanceId = args[1] as int?; + assert(arg_clientInstanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebChromeClient was null, expected non-null int.'); + api.setWebChromeClient(arg_instanceId!, arg_clientInstanceId!); + return {}; + }); + } + } } } @@ -924,3 +946,55 @@ abstract class TestDownloadListenerHostApi { } } } + +class _TestWebChromeClientHostApiCodec extends StandardMessageCodec { + const _TestWebChromeClientHostApiCodec(); +} + +abstract class TestWebChromeClientHostApi { + static const MessageCodec codec = _TestWebChromeClientHostApiCodec(); + + void create(int instanceId, int webViewClientInstanceId); + void dispose(int instanceId); + static void setup(TestWebChromeClientHostApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebChromeClientHostApi.create', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebChromeClientHostApi.create was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebChromeClientHostApi.create was null, expected non-null int.'); + final int? arg_webViewClientInstanceId = args[1] as int?; + assert(arg_webViewClientInstanceId != null, + 'Argument for dev.flutter.pigeon.WebChromeClientHostApi.create was null, expected non-null int.'); + api.create(arg_instanceId!, arg_webViewClientInstanceId!); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebChromeClientHostApi.dispose', codec); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebChromeClientHostApi.dispose was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebChromeClientHostApi.dispose was null, expected non-null int.'); + api.dispose(arg_instanceId!); + return {}; + }); + } + } + } +} diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart index 2373ec0d1bfc..462670abdb83 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart @@ -149,6 +149,45 @@ void main() { ); }); }); + + group('$WebChromeClient', () { + setUpAll(() { + TestWebViewHostApi.setup(TestWebViewHostApiImpl()); + TestWebViewClientHostApi.setup(TestWebViewClientHostApiImpl()); + TestWebChromeClientHostApi.setup(TestWebChromeClientHostApiImpl()); + }); + + setUp(() { + final InstanceManager instanceManager = InstanceManager(); + WebView.api = WebViewHostApiImpl(instanceManager: instanceManager); + WebViewClient.api = WebViewClientHostApiImpl( + instanceManager: instanceManager, + ); + WebChromeClient.api = WebChromeClientHostApiImpl( + instanceManager: instanceManager, + ); + }); + + test('create', () { + final WebView webView = WebView(); + webView.setWebViewClient(TestWebViewClient()); + + final WebChromeClient webChromeClient1 = TestWebChromeClient(); + final WebChromeClient webChromeClient2 = TestWebChromeClient(); + + webView.setWebChromeClient(webChromeClient1); + expect( + WebChromeClient.api.instanceManager.getInstanceId(webChromeClient1), + isNotNull, + ); + + webView.setWebChromeClient(webChromeClient2); + expect( + WebChromeClient.api.instanceManager.getInstanceId(webChromeClient1), + isNull, + ); + }); + }); }); } @@ -172,6 +211,11 @@ class TestDownloadListener extends DownloadListener { ) {} } +class TestWebChromeClient extends WebChromeClient { + @override + void onProgressChanged(WebView webView, int progress) {} +} + class TestWebViewHostApiImpl extends TestWebViewHostApi { @override void addJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId) {} @@ -250,6 +294,9 @@ class TestWebViewHostApiImpl extends TestWebViewHostApi { @override void setWebViewClient(int instanceId, int webViewClientInstanceId) {} + + @override + void setWebChromeClient(int instanceId, int clientInstanceId) {} } class TestWebSettingsHostApiImpl extends TestWebSettingsHostApi { @@ -316,3 +363,11 @@ class TestDownloadListenerHostApiImpl extends TestDownloadListenerHostApi { @override void dispose(int instanceId) {} } + +class TestWebChromeClientHostApiImpl extends TestWebChromeClientHostApi { + @override + void create(int instanceId, int webViewClientInstanceId) {} + + @override + void dispose(int instanceId) {} +} From 337b1fabfd4da3f7a5acb1e342dac43fd615260f Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Tue, 26 Oct 2021 16:46:07 -0700 Subject: [PATCH 29/54] more work to finalize --- .../webviewflutter/FlutterWebViewFactory.java | 21 +- .../webviewflutter/WebViewFlutterPlugin.java | 27 +- .../lib/src/android_webview.dart | 29 ++ .../lib/webview_android.dart | 389 ++++++++++++++---- 4 files changed, 365 insertions(+), 101 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewFactory.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewFactory.java index 8fe58104a0fb..cf58682e2c32 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewFactory.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewFactory.java @@ -5,29 +5,24 @@ package io.flutter.plugins.webviewflutter; import android.content.Context; -import android.view.View; -import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.StandardMessageCodec; import io.flutter.plugin.platform.PlatformView; import io.flutter.plugin.platform.PlatformViewFactory; -import java.util.Map; public final class FlutterWebViewFactory extends PlatformViewFactory { - private final BinaryMessenger messenger; - private final View containerView; + private final InstanceManager instanceManager; - FlutterWebViewFactory(BinaryMessenger messenger, View containerView) { + FlutterWebViewFactory(InstanceManager instanceManager) { super(StandardMessageCodec.INSTANCE); - this.messenger = messenger; - this.containerView = containerView; + this.instanceManager = instanceManager; } - @SuppressWarnings("unchecked") @Override public PlatformView create(Context context, int id, Object args) { - Map params = (Map) args; - MethodChannel methodChannel = new MethodChannel(messenger, "plugins.flutter.io/webview_" + id); - return new FlutterWebView(context, methodChannel, params, containerView); + final PlatformView view = (PlatformView) instanceManager.getInstance(id); + if (view == null) { + throw new IllegalStateException("Unable to find WebView instance."); + } + return view; } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java index 268d35a1e04c..e6905909e0d9 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java @@ -6,6 +6,11 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewHostApi; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientHostApi; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientHostApi; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerHostApi; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelHostApi; /** * Java platform implementation of the webview_flutter plugin. @@ -40,24 +45,26 @@ public WebViewFlutterPlugin() {} *

Calling this automatically initializes the plugin. However plugins initialized this way * won't react to changes in activity or context, unlike {@link CameraPlugin}. */ - @SuppressWarnings("deprecation") - public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) { - registrar - .platformViewRegistry() - .registerViewFactory( - "plugins.flutter.io/webview", - new FlutterWebViewFactory(registrar.messenger(), registrar.view())); - new FlutterCookieManager(registrar.messenger()); - } +// @SuppressWarnings("deprecation") +// public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) { +// registrar +// .platformViewRegistry() +// .registerViewFactory( +// "plugins.flutter.io/webview", +// new FlutterWebViewFactory(registrar.messenger(), registrar.view())); +// new FlutterCookieManager(registrar.messenger()); +// } @Override public void onAttachedToEngine(FlutterPluginBinding binding) { BinaryMessenger messenger = binding.getBinaryMessenger(); + InstanceManager instanceManager = new InstanceManager(); binding .getPlatformViewRegistry() .registerViewFactory( "plugins.flutter.io/webview", - new FlutterWebViewFactory(messenger, /*containerView=*/ null)); + new FlutterWebViewFactory(instanceManager)); + WebViewHostApi.setup(messenger, new WebViewHostApiImpl(instanceManager, )); flutterCookieManager = new FlutterCookieManager(messenger); } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index 1ddd6f3d9f0f..da28ecd4af58 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -29,6 +29,8 @@ const String _nullStringIdentifier = ''; /// To learn more about WebView and alternatives for serving web content, read /// the documentation on /// [Web-based content](https://developer.android.com/guide/webapps). +/// +/// When a [WebView] is no longer needed [release] must be called. class WebView { /// Constructs a new WebView. WebView({this.useHybridComposition = false}) { @@ -286,6 +288,33 @@ class WebView { _currentWebChromeClient = client; return api.setWebChromeClientFromInstance(this, client); } + + Future release() { + final WebViewClient? webViewClient = _currentWebViewClient; + if (webViewClient != null) { + WebViewClient.api.disposeFromInstance(webViewClient); + _currentWebViewClient = null; + } + + final DownloadListener? downloadListener = _currentDownloadListener; + if (downloadListener != null) { + DownloadListener.api.disposeFromInstance(downloadListener); + _currentDownloadListener = null; + } + + final WebChromeClient? webChromeClient = _currentWebChromeClient; + if (webChromeClient != null) { + WebChromeClient.api.disposeFromInstance(webChromeClient); + _currentWebChromeClient = null; + } + + for (JavaScriptChannel javaScriptChannel in _javaScriptChannels) { + JavaScriptChannel.api.disposeFromInstance(javaScriptChannel); + } + _javaScriptChannels.clear(); + + return api.disposeFromInstance(this); + } } /// Manages settings state for a [WebView]. diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart index 7367d04b450d..05e3a444ebd6 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; +import 'package:webview_flutter_android/src/instance_manager.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; import 'src/android_webview.dart' as android_webview; @@ -27,35 +28,42 @@ class AndroidWebView implements WebViewPlatform { WebViewPlatformCreatedCallback? onWebViewPlatformCreated, Set>? gestureRecognizers, }) { - assert(webViewPlatformCallbacksHandler != null); - return GestureDetector( - // We prevent text selection by intercepting the long press event. - // This is a temporary stop gap due to issues with text selection on Android: - // https://github.com/flutter/flutter/issues/24585 - the text selection - // dialog is not responding to touch events. - // https://github.com/flutter/flutter/issues/24584 - the text selection - // handles are not showing. - // TODO(amirh): remove this when the issues above are fixed. - onLongPress: () {}, - excludeFromSemantics: true, - child: AndroidView( - viewType: 'plugins.flutter.io/webview', - onPlatformViewCreated: (int id) { - if (onWebViewPlatformCreated == null) { - return; - } - onWebViewPlatformCreated(MethodChannelWebViewPlatform( - id, - webViewPlatformCallbacksHandler, - javascriptChannelRegistry, - )); - }, - gestureRecognizers: gestureRecognizers, - layoutDirection: Directionality.maybeOf(context) ?? TextDirection.rtl, - creationParams: - MethodChannelWebViewPlatform.creationParamsToMap(creationParams), - creationParamsCodec: const StandardMessageCodec(), - ), + // assert(webViewPlatformCallbacksHandler != null); + // return GestureDetector( + // // We prevent text selection by intercepting the long press event. + // // This is a temporary stop gap due to issues with text selection on Android: + // // https://github.com/flutter/flutter/issues/24585 - the text selection + // // dialog is not responding to touch events. + // // https://github.com/flutter/flutter/issues/24584 - the text selection + // // handles are not showing. + // // TODO(amirh): remove this when the issues above are fixed. + // onLongPress: () {}, + // excludeFromSemantics: true, + // child: AndroidView( + // viewType: 'plugins.flutter.io/webview', + // onPlatformViewCreated: (int id) { + // if (onWebViewPlatformCreated == null) { + // return; + // } + // onWebViewPlatformCreated(MethodChannelWebViewPlatform( + // id, + // webViewPlatformCallbacksHandler, + // javascriptChannelRegistry, + // )); + // }, + // gestureRecognizers: gestureRecognizers, + // layoutDirection: Directionality.maybeOf(context) ?? TextDirection.rtl, + // creationParams: + // MethodChannelWebViewPlatform.creationParamsToMap(creationParams), + // creationParamsCodec: const StandardMessageCodec(), + // ), + // ); + return _AndroidWebViewWidget( + creationParams: creationParams, + webViewPlatformCallbacksHandler: webViewPlatformCallbacksHandler, + javascriptChannelRegistry: javascriptChannelRegistry, + onWebViewPlatformCreated: onWebViewPlatformCreated, + gestureRecognizers: gestureRecognizers, ); } @@ -83,30 +91,41 @@ class _AndroidWebViewWidget extends StatefulWidget { } class _AndroidWebViewWidgetState extends State<_AndroidWebViewWidget> { + late android_webview.WebView webView; late _AndroidWebViewPlatformController platformController; @override void initState() { super.initState(); - final android_webview.WebView webView = android_webview.WebView( - useHybridComposition: false, - ); - android_webview.WebView.api.createFromInstance(webView); - + webView = android_webview.WebView(useHybridComposition: false); webView.settings.setDomStorageEnabled(true); webView.settings.setJavaScriptCanOpenWindowsAutomatically(true); webView.settings.setSupportMultipleWindows(true); platformController = _AndroidWebViewPlatformController( - webView, widget.webViewPlatformCallbacksHandler); + webView: webView, + callbacksHandler: widget.webViewPlatformCallbacksHandler, + javascriptChannelRegistry: widget.javascriptChannelRegistry, + hasNavigationDelegate: + widget.creationParams.webSettings?.hasNavigationDelegate ?? false, + ); + + setCreationParams(widget.creationParams); + } - final WebSettings? webSettings = widget.creationParams.webSettings; + void setCreationParams(CreationParams creationParams) { + final WebSettings? webSettings = creationParams.webSettings; if (webSettings != null) { platformController.updateSettings(webSettings); } + final String? userAgent = creationParams.userAgent; + if (userAgent != null) { + webView.settings.setUserAgentString(userAgent); + } + final AutoMediaPlaybackPolicy autoMediaPlaybackPolicy = - widget.creationParams.autoMediaPlaybackPolicy; + creationParams.autoMediaPlaybackPolicy; switch (autoMediaPlaybackPolicy) { case AutoMediaPlaybackPolicy.always_allow: webView.settings.setMediaPlaybackRequiresUserGesture(false); @@ -116,15 +135,10 @@ class _AndroidWebViewWidgetState extends State<_AndroidWebViewWidget> { } platformController.addJavascriptChannels( - widget.creationParams.javascriptChannelNames, + creationParams.javascriptChannelNames, ); - final String? userAgent = widget.creationParams.userAgent; - if (userAgent != null) { - webView.settings.setUserAgentString(userAgent); - } - - final String? initialUrl = widget.creationParams.initialUrl; + final String? initialUrl = creationParams.initialUrl; if (initialUrl != null) { platformController.loadUrl(initialUrl, {}); } @@ -133,7 +147,7 @@ class _AndroidWebViewWidgetState extends State<_AndroidWebViewWidget> { @override void dispose() { super.dispose(); - //android_webview.WebView.api.disposeFromInstance(webView); + platformController.webView.release(); } @override @@ -153,38 +167,52 @@ class _AndroidWebViewWidgetState extends State<_AndroidWebViewWidget> { onPlatformViewCreated: (int id) { final WebViewPlatformCreatedCallback? createdCallback = widget.onWebViewPlatformCreated; - // if (createdCallback != null) { - // createdCallback(MethodChannelWebViewPlatform( - // id, - // webViewPlatformCallbacksHandler, - // javascriptChannelRegistry, - // )); - // } + if (createdCallback != null) { + createdCallback(platformController); + } }, gestureRecognizers: widget.gestureRecognizers, layoutDirection: Directionality.maybeOf(context) ?? TextDirection.rtl, - // creationParams: - // MethodChannelWebViewPlatform.creationParamsToMap(creationParams), - // creationParamsCodec: const StandardMessageCodec(), + creationParams: + InstanceManager.instance.getInstanceId(platformController.webView), + creationParamsCodec: const StandardMessageCodec(), ), ); } } class _AndroidWebViewPlatformController extends WebViewPlatformController { - _AndroidWebViewPlatformController( - this.webView, - WebViewPlatformCallbacksHandler handler, - ) : super(handler) { - webViewClient = _WebViewClientImpl(handler); - downloadListener = _DownloadListenerImpl(handler); + _AndroidWebViewPlatformController({ + required this.webView, + required this.callbacksHandler, + required this.javascriptChannelRegistry, + required bool hasNavigationDelegate, + }) : super(callbacksHandler) { + webViewClient = _WebViewClientImpl( + callbacksHandler: callbacksHandler, + loadUrl: loadUrl, + hasNavigationDelegate: hasNavigationDelegate, + ); + downloadListener = _DownloadListenerImpl( + callbacksHandler: callbacksHandler, + loadUrl: loadUrl, + ); + webChromeClient = _WebChromeClientImpl(callbacksHandler: callbacksHandler); webView.setWebViewClient(webViewClient); webView.setDownloadListener(downloadListener); + webView.setWebChromeClient(webChromeClient); } + final Map javaScriptChannels = + {}; + final android_webview.WebView webView; - late final android_webview.WebViewClient webViewClient; - late final android_webview.DownloadListener downloadListener; + final WebViewPlatformCallbacksHandler callbacksHandler; + final JavascriptChannelRegistry javascriptChannelRegistry; + + late final _WebViewClientImpl webViewClient; + late final _DownloadListenerImpl downloadListener; + late final _WebChromeClientImpl webChromeClient; @override Future loadUrl( @@ -216,7 +244,19 @@ class _AndroidWebViewPlatformController extends WebViewPlatformController { Future clearCache() => webView.clearCache(true); @override - Future updateSettings(WebSettings settings) async {} + Future updateSettings(WebSettings settings) { + final bool? hasProgressTracking = settings.hasProgressTracking; + if (hasProgressTracking != null) { + webChromeClient.hasProgressTracking = hasProgressTracking; + } + + return Future.wait(>[ + _trySetNavigationDelegate(settings.hasNavigationDelegate), + _trySetJavaScriptMode(settings.javascriptMode), + _trySetDebuggingEnabled(settings.debuggingEnabled), + _trySetUserAgent(settings.userAgent), + ]); + } @override Future evaluateJavascript(String javascriptString) async { @@ -226,10 +266,16 @@ class _AndroidWebViewPlatformController extends WebViewPlatformController { @override Future addJavascriptChannels(Set javascriptChannelNames) { return Future.wait( - javascriptChannelNames.map>( + javascriptChannelNames.where( (String channelName) { - return webView - .addJavaScriptChannel(_JavaScriptChannelImpl(channelName)); + return javaScriptChannels.containsKey(channelName); + }, + ).map>( + (String channelName) { + final _JavaScriptChannelImpl javaScriptChannel = + _JavaScriptChannelImpl(channelName, javascriptChannelRegistry); + javaScriptChannels[channelName] = javaScriptChannel; + return webView.addJavaScriptChannel(javaScriptChannel); }, ), ); @@ -237,9 +283,22 @@ class _AndroidWebViewPlatformController extends WebViewPlatformController { @override Future removeJavascriptChannels( - Set javascriptChannelNames) async { - // return _channel.invokeMethod( - // 'removeJavascriptChannels', javascriptChannelNames.toList()); + Set javascriptChannelNames, + ) { + return Future.wait( + javascriptChannelNames.where( + (String channelName) { + return javaScriptChannels.containsKey(channelName); + }, + ).map>( + (String channelName) { + final _JavaScriptChannelImpl javaScriptChannel = + javaScriptChannels[channelName]!; + javaScriptChannels.remove(channelName); + return webView.removeJavaScriptChannel(javaScriptChannel); + }, + ), + ); } @override @@ -256,21 +315,66 @@ class _AndroidWebViewPlatformController extends WebViewPlatformController { @override Future getScrollY() => webView.getScrollY(); + + Future _trySetNavigationDelegate(bool? hasNavigationDelegate) async { + if (hasNavigationDelegate != null) { + downloadListener.hasNavigationDelegate = hasNavigationDelegate; + webViewClient = _WebViewClientImpl( + callbacksHandler: callbacksHandler, + loadUrl: loadUrl, + hasNavigationDelegate: hasNavigationDelegate, + ); + return webView.setWebViewClient(webViewClient); + } + } + + Future _trySetJavaScriptMode(JavascriptMode? mode) async { + if (mode != null) { + switch (mode) { + case JavascriptMode.disabled: + return webView.settings.setJavaScriptEnabled(false); + case JavascriptMode.unrestricted: + return webView.settings.setJavaScriptEnabled(true); + } + } + } + + Future _trySetDebuggingEnabled(bool? debuggingEnabled) async { + if (debuggingEnabled != null) { + return android_webview.WebView.setWebContentsDebuggingEnabled( + debuggingEnabled, + ); + } + } + + Future _trySetUserAgent(WebSetting userAgent) async { + if (userAgent.isPresent) { + return webView.settings.setUserAgentString(userAgent.value!); + } + } } class _JavaScriptChannelImpl extends android_webview.JavaScriptChannel { - _JavaScriptChannelImpl(String channelName) : super(channelName); + _JavaScriptChannelImpl(String channelName, this.javascriptChannelRegistry) + : super(channelName); + + final JavascriptChannelRegistry javascriptChannelRegistry; @override void postMessage(String message) { - super.postMessage(message); + javascriptChannelRegistry.onJavascriptChannelMessage(channelName, message); } } class _DownloadListenerImpl extends android_webview.DownloadListener { - _DownloadListenerImpl(this.callbacksHandler); + _DownloadListenerImpl({ + required this.callbacksHandler, + required this.loadUrl, + }); final WebViewPlatformCallbacksHandler callbacksHandler; + final Future Function(String url, Map? headers) loadUrl; + bool hasNavigationDelegate = false; @override void onDownloadStart( @@ -280,14 +384,76 @@ class _DownloadListenerImpl extends android_webview.DownloadListener { String mimetype, int contentLength, ) { - callbacksHandler.onNavigationRequest(url: url, isForMainFrame: true); + if (!hasNavigationDelegate) return; + + final FutureOr returnValue = callbacksHandler.onNavigationRequest( + url: url, + isForMainFrame: true, + ); + + if (returnValue is bool && returnValue) { + loadUrl(url, {}); + } else { + (returnValue as Future).then((bool shouldLoadUrl) { + if (shouldLoadUrl) { + loadUrl(url, {}); + } + }); + } } } class _WebViewClientImpl extends android_webview.WebViewClient { - _WebViewClientImpl(this.callbacksHandler); + _WebViewClientImpl({ + required this.callbacksHandler, + required this.loadUrl, + required this.hasNavigationDelegate, + }) : super(shouldOverrideUrlLoading: hasNavigationDelegate); final WebViewPlatformCallbacksHandler callbacksHandler; + final Future Function(String url, Map? headers) loadUrl; + final bool hasNavigationDelegate; + + static WebResourceErrorType _errorCodeToErrorType(int errorCode) { + switch (errorCode) { + case android_webview.WebViewClient.errorAuthentication: + return WebResourceErrorType.authentication; + case android_webview.WebViewClient.errorBadUrl: + return WebResourceErrorType.badUrl; + case android_webview.WebViewClient.errorConnect: + return WebResourceErrorType.connect; + case android_webview.WebViewClient.errorFailedSslHandshake: + return WebResourceErrorType.failedSslHandshake; + case android_webview.WebViewClient.errorFile: + return WebResourceErrorType.file; + case android_webview.WebViewClient.errorFileNotFound: + return WebResourceErrorType.fileNotFound; + case android_webview.WebViewClient.errorHostLookup: + return WebResourceErrorType.hostLookup; + case android_webview.WebViewClient.errorIO: + return WebResourceErrorType.io; + case android_webview.WebViewClient.errorProxyAuthentication: + return WebResourceErrorType.proxyAuthentication; + case android_webview.WebViewClient.errorRedirectLoop: + return WebResourceErrorType.redirectLoop; + case android_webview.WebViewClient.errorTimeout: + return WebResourceErrorType.timeout; + case android_webview.WebViewClient.errorTooManyRequests: + return WebResourceErrorType.tooManyRequests; + case android_webview.WebViewClient.errorUnknown: + return WebResourceErrorType.unknown; + case android_webview.WebViewClient.errorUnsafeResource: + return WebResourceErrorType.unsafeResource; + case android_webview.WebViewClient.errorUnsupportedAuthScheme: + return WebResourceErrorType.unsupportedAuthScheme; + case android_webview.WebViewClient.errorUnsupportedScheme: + return WebResourceErrorType.unsupportedScheme; + } + + throw ArgumentError( + 'Could not find a WebResourceErrorType for errorCode: $errorCode', + ); + } @override void onPageStarted(android_webview.WebView webView, String url) { @@ -299,20 +465,87 @@ class _WebViewClientImpl extends android_webview.WebViewClient { callbacksHandler.onPageFinished(url); } + @override + void onReceivedError( + android_webview.WebView webView, + int errorCode, + String description, + String failingUrl, + ) { + callbacksHandler.onWebResourceError(WebResourceError( + errorCode: errorCode, + description: description, + failingUrl: failingUrl, + errorType: _errorCodeToErrorType(errorCode), + )); + } + + @override + void onReceivedRequestError( + android_webview.WebView webView, + android_webview.WebResourceRequest request, + android_webview.WebResourceError error, + ) { + callbacksHandler.onWebResourceError(WebResourceError( + errorCode: error.errorCode, + description: error.description, + failingUrl: request.url, + errorType: _errorCodeToErrorType(error.errorCode), + )); + } + @override void urlLoading(android_webview.WebView webView, String url) { + if (!hasNavigationDelegate) return; + final FutureOr returnValue = callbacksHandler.onNavigationRequest( url: url, isForMainFrame: true, ); + + if (returnValue is bool && returnValue) { + loadUrl(url, {}); + } else { + (returnValue as Future).then((bool shouldLoadUrl) { + if (shouldLoadUrl) { + loadUrl(url, {}); + } + }); + } } @override - void requestLoading(android_webview.WebView webView, - android_webview.WebResourceRequest request) { - callbacksHandler.onNavigationRequest( + void requestLoading( + android_webview.WebView webView, + android_webview.WebResourceRequest request, + ) { + if (!hasNavigationDelegate) return; + + final FutureOr returnValue = callbacksHandler.onNavigationRequest( url: request.url, isForMainFrame: request.isForMainFrame, ); + + if (returnValue is bool && returnValue) { + loadUrl(request.url, {}); + } else { + (returnValue as Future).then((bool shouldLoadUrl) { + if (shouldLoadUrl) { + loadUrl(request.url, {}); + } + }); + } + } +} + +class _WebChromeClientImpl extends android_webview.WebChromeClient { + _WebChromeClientImpl({required this.callbacksHandler}); + + final WebViewPlatformCallbacksHandler callbacksHandler; + bool hasProgressTracking = false; + + @override + void onProgressChanged(android_webview.WebView webView, int progress) { + if (hasProgressTracking) callbacksHandler.onProgress(progress); } } From 8525231f2c1cee48f63f7386bdd90d5224bafb08 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Tue, 26 Oct 2021 20:27:51 -0700 Subject: [PATCH 30/54] fix most bugs --- .../webviewflutter/WebViewFlutterPlugin.java | 50 +++++++++++++++---- .../webviewflutter/WebViewHostApiImpl.java | 2 +- .../plugins/webviewflutter/WebViewTest.java | 10 ++++ .../lib/src/android_webview.dart | 14 +++++- .../lib/src/android_webview_api_impls.dart | 2 +- .../lib/webview_android.dart | 6 +-- 6 files changed, 69 insertions(+), 15 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java index e6905909e0d9..c698b1f34c94 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java @@ -4,13 +4,20 @@ package io.flutter.plugins.webviewflutter; +import android.os.Handler; + +import androidx.annotation.NonNull; + import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.embedding.engine.plugins.activity.ActivityAware; +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewHostApi; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientHostApi; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientHostApi; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerHostApi; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelHostApi; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebSettingsHostApi; /** * Java platform implementation of the webview_flutter plugin. @@ -20,8 +27,8 @@ *

Call {@link #registerWith(Registrar)} to use the stable {@code io.flutter.plugin.common} * package instead. */ -public class WebViewFlutterPlugin implements FlutterPlugin { - +public class WebViewFlutterPlugin implements FlutterPlugin, ActivityAware { + private FlutterPluginBinding binding; private FlutterCookieManager flutterCookieManager; /** @@ -57,6 +64,21 @@ public WebViewFlutterPlugin() {} @Override public void onAttachedToEngine(FlutterPluginBinding binding) { + this.binding = binding; + } + + @Override + public void onDetachedFromEngine(FlutterPluginBinding binding) { + if (flutterCookieManager == null) { + return; + } + + flutterCookieManager.dispose(); + flutterCookieManager = null; + } + + @Override + public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) { BinaryMessenger messenger = binding.getBinaryMessenger(); InstanceManager instanceManager = new InstanceManager(); binding @@ -64,17 +86,27 @@ public void onAttachedToEngine(FlutterPluginBinding binding) { .registerViewFactory( "plugins.flutter.io/webview", new FlutterWebViewFactory(instanceManager)); - WebViewHostApi.setup(messenger, new WebViewHostApiImpl(instanceManager, )); + WebViewHostApi.setup(messenger, new WebViewHostApiImpl(instanceManager, new WebViewHostApiImpl.WebViewProxy(), activityPluginBinding.getActivity())); + WebViewClientHostApi.setup(messenger, new WebViewClientHostApiImpl(instanceManager, new WebViewClientHostApiImpl.WebViewClientCreator(), new GeneratedAndroidWebView.WebViewClientFlutterApi(messenger))); + WebChromeClientHostApi.setup(messenger, new WebChromeClientHostApiImpl(instanceManager, new WebChromeClientHostApiImpl.WebChromeClientCreator(), new GeneratedAndroidWebView.WebChromeClientFlutterApi(messenger))); + DownloadListenerHostApi.setup(messenger, new DownloadListenerHostApiImpl(instanceManager, new DownloadListenerHostApiImpl.DownloadListenerCreator(), new GeneratedAndroidWebView.DownloadListenerFlutterApi(messenger))); + JavaScriptChannelHostApi.setup(messenger, new JavaScriptChannelHostApiImpl(instanceManager, new JavaScriptChannelHostApiImpl.JavaScriptChannelCreator(), new GeneratedAndroidWebView.JavaScriptChannelFlutterApi(messenger), new Handler(activityPluginBinding.getActivity().getMainLooper()))); + WebSettingsHostApi.setup(messenger, new WebSettingsHostApiImpl(instanceManager, new WebSettingsHostApiImpl.WebSettingsCreator())); flutterCookieManager = new FlutterCookieManager(messenger); } @Override - public void onDetachedFromEngine(FlutterPluginBinding binding) { - if (flutterCookieManager == null) { - return; - } + public void onDetachedFromActivityForConfigChanges() { + + } + + @Override + public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding activityPluginBinding) { + + } + + @Override + public void onDetachedFromActivity() { - flutterCookieManager.dispose(); - flutterCookieManager = null; } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index 35bdc608d6ff..e44f4e73cc58 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -228,6 +228,6 @@ public void setDownloadListener(Long instanceId, Long listenerInstanceId) { @Override public void setWebChromeClient(Long instanceId, Long clientInstanceId) { final WebView webView = (WebView) instanceManager.getInstance(instanceId); - webView.setWebChromeClient((WebChromeClient) instanceManager.getInstance(instanceId)); + webView.setWebChromeClient((WebChromeClient) instanceManager.getInstance(clientInstanceId)); } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java index b914ce913e76..ecd7be67f74d 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java @@ -13,6 +13,7 @@ import android.content.Context; import android.webkit.DownloadListener; import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; import java.util.HashMap; @@ -219,4 +220,13 @@ public void setDownloadListener() { testHostApiImpl.setDownloadListener(0L, 1L); verify(mockWebView).setDownloadListener(mockDownloadListener); } + + @Test + public void setWebChromeClient() { + final WebChromeClient mockWebChromeClient = mock(WebChromeClient.class); + testInstanceManager.addInstance(mockWebChromeClient, 1L); + + testHostApiImpl.setWebChromeClient(0L, 1L); + verify(mockWebView).setWebChromeClient(mockWebChromeClient); + } } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index da28ecd4af58..88c9f7c4332e 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart' show AndroidViewSurface; +import 'android_webview.pigeon.dart'; import 'android_webview_api_impls.dart'; // TODO(bparrishMines): This can be removed once pigeon supports null values: https://github.com/flutter/flutter/issues/59118 @@ -34,6 +35,15 @@ const String _nullStringIdentifier = ''; class WebView { /// Constructs a new WebView. WebView({this.useHybridComposition = false}) { + // TODO: handle independently? + if (!_flutterApisHaveBeenSetup) { + WebViewClientFlutterApi.setup(WebViewClientFlutterApiImpl()); + JavaScriptChannelFlutterApi.setup(JavaScriptChannelFlutterApiImpl()); + DownloadListenerFlutterApi.setup(DownloadListenerFlutterApiImpl()); + WebChromeClientFlutterApi.setup(WebChromeClientFlutterApiImpl()); + _flutterApisHaveBeenSetup = true; + } + api.createFromInstance(this); } @@ -41,6 +51,8 @@ class WebView { @visibleForTesting static WebViewHostApiImpl api = WebViewHostApiImpl(); + static bool _flutterApisHaveBeenSetup = false; + WebViewClient? _currentWebViewClient; DownloadListener? _currentDownloadListener; WebChromeClient? _currentWebChromeClient; @@ -656,7 +668,7 @@ class WebResourceRequest { final String method; /// Gets the headers associated with the request. - final Map requestHeaders; + final Map? requestHeaders; } /// Encapsulates information about errors occurred during loading of web resources. diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index f909e49bd802..4068392d0371 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -486,7 +486,7 @@ class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { isRedirect: request.isRedirect, hasGesture: request.hasGesture!, method: request.method!, - requestHeaders: request.requestHeaders!.cast(), + requestHeaders: request.requestHeaders?.cast(), ), ); } diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart index 05e3a444ebd6..2acde8a69bd9 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart @@ -210,9 +210,9 @@ class _AndroidWebViewPlatformController extends WebViewPlatformController { final WebViewPlatformCallbacksHandler callbacksHandler; final JavascriptChannelRegistry javascriptChannelRegistry; - late final _WebViewClientImpl webViewClient; late final _DownloadListenerImpl downloadListener; late final _WebChromeClientImpl webChromeClient; + late _WebViewClientImpl webViewClient; @override Future loadUrl( @@ -251,7 +251,7 @@ class _AndroidWebViewPlatformController extends WebViewPlatformController { } return Future.wait(>[ - _trySetNavigationDelegate(settings.hasNavigationDelegate), + _trySetHasNavigationDelegate(settings.hasNavigationDelegate), _trySetJavaScriptMode(settings.javascriptMode), _trySetDebuggingEnabled(settings.debuggingEnabled), _trySetUserAgent(settings.userAgent), @@ -316,7 +316,7 @@ class _AndroidWebViewPlatformController extends WebViewPlatformController { @override Future getScrollY() => webView.getScrollY(); - Future _trySetNavigationDelegate(bool? hasNavigationDelegate) async { + Future _trySetHasNavigationDelegate(bool? hasNavigationDelegate) async { if (hasNavigationDelegate != null) { downloadListener.hasNavigationDelegate = hasNavigationDelegate; webViewClient = _WebViewClientImpl( From 731971a11aaf80cc3f1fac3f61aba1c3cb334e9a Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Tue, 26 Oct 2021 21:43:10 -0700 Subject: [PATCH 31/54] almost finish impl --- .../webviewflutter/FlutterWebViewFactory.java | 4 +- .../webviewflutter/WebViewFlutterPlugin.java | 100 ++-- .../lib/src/android_webview.dart | 85 ++- .../lib/src/webview_widget.dart | 479 +++++++++++++++ .../lib/webview_android.dart | 546 +----------------- .../lib/webview_surface_android.dart | 79 ++- 6 files changed, 669 insertions(+), 624 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewFactory.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewFactory.java index cf58682e2c32..ed3d40177632 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewFactory.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewFactory.java @@ -19,9 +19,9 @@ public final class FlutterWebViewFactory extends PlatformViewFactory { @Override public PlatformView create(Context context, int id, Object args) { - final PlatformView view = (PlatformView) instanceManager.getInstance(id); + final PlatformView view = (PlatformView) instanceManager.getInstance((Integer) args); if (view == null) { - throw new IllegalStateException("Unable to find WebView instance."); + throw new IllegalStateException("Unable to find WebView instance: " + args); } return view; } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java index c698b1f34c94..aa0ed84fddfc 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java @@ -4,20 +4,20 @@ package io.flutter.plugins.webviewflutter; +import android.app.Activity; import android.os.Handler; - import androidx.annotation.NonNull; - import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewHostApi; -import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientHostApi; -import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientHostApi; +import io.flutter.plugin.platform.PlatformViewRegistry; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerHostApi; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelHostApi; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientHostApi; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebSettingsHostApi; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientHostApi; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewHostApi; /** * Java platform implementation of the webview_flutter plugin. @@ -28,7 +28,7 @@ * package instead. */ public class WebViewFlutterPlugin implements FlutterPlugin, ActivityAware { - private FlutterPluginBinding binding; + private FlutterPluginBinding pluginBinding; private FlutterCookieManager flutterCookieManager; /** @@ -52,19 +52,56 @@ public WebViewFlutterPlugin() {} *

Calling this automatically initializes the plugin. However plugins initialized this way * won't react to changes in activity or context, unlike {@link CameraPlugin}. */ -// @SuppressWarnings("deprecation") -// public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) { -// registrar -// .platformViewRegistry() -// .registerViewFactory( -// "plugins.flutter.io/webview", -// new FlutterWebViewFactory(registrar.messenger(), registrar.view())); -// new FlutterCookieManager(registrar.messenger()); -// } + @SuppressWarnings("deprecation") + public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) { + setUp(registrar.messenger(), registrar.platformViewRegistry(), registrar.activity()); + new FlutterCookieManager(registrar.messenger()); + } + + private static void setUp( + BinaryMessenger binaryMessenger, PlatformViewRegistry viewRegistry, Activity activity) { + InstanceManager instanceManager = new InstanceManager(); + viewRegistry.registerViewFactory( + "plugins.flutter.io/webview", new FlutterWebViewFactory(instanceManager)); + WebViewHostApi.setup( + binaryMessenger, + new WebViewHostApiImpl(instanceManager, new WebViewHostApiImpl.WebViewProxy(), activity)); + WebViewClientHostApi.setup( + binaryMessenger, + new WebViewClientHostApiImpl( + instanceManager, + new WebViewClientHostApiImpl.WebViewClientCreator(), + new GeneratedAndroidWebView.WebViewClientFlutterApi(binaryMessenger))); + WebChromeClientHostApi.setup( + binaryMessenger, + new WebChromeClientHostApiImpl( + instanceManager, + new WebChromeClientHostApiImpl.WebChromeClientCreator(), + new GeneratedAndroidWebView.WebChromeClientFlutterApi(binaryMessenger))); + DownloadListenerHostApi.setup( + binaryMessenger, + new DownloadListenerHostApiImpl( + instanceManager, + new DownloadListenerHostApiImpl.DownloadListenerCreator(), + new GeneratedAndroidWebView.DownloadListenerFlutterApi(binaryMessenger))); + JavaScriptChannelHostApi.setup( + binaryMessenger, + new JavaScriptChannelHostApiImpl( + instanceManager, + new JavaScriptChannelHostApiImpl.JavaScriptChannelCreator(), + new GeneratedAndroidWebView.JavaScriptChannelFlutterApi(binaryMessenger), + new Handler(activity.getMainLooper()))); + WebSettingsHostApi.setup( + binaryMessenger, + new WebSettingsHostApiImpl( + instanceManager, new WebSettingsHostApiImpl.WebSettingsCreator())); + new FlutterCookieManager(binaryMessenger); + } @Override public void onAttachedToEngine(FlutterPluginBinding binding) { - this.binding = binding; + this.pluginBinding = binding; + flutterCookieManager = new FlutterCookieManager(binding.getBinaryMessenger()); } @Override @@ -79,34 +116,19 @@ public void onDetachedFromEngine(FlutterPluginBinding binding) { @Override public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) { - BinaryMessenger messenger = binding.getBinaryMessenger(); - InstanceManager instanceManager = new InstanceManager(); - binding - .getPlatformViewRegistry() - .registerViewFactory( - "plugins.flutter.io/webview", - new FlutterWebViewFactory(instanceManager)); - WebViewHostApi.setup(messenger, new WebViewHostApiImpl(instanceManager, new WebViewHostApiImpl.WebViewProxy(), activityPluginBinding.getActivity())); - WebViewClientHostApi.setup(messenger, new WebViewClientHostApiImpl(instanceManager, new WebViewClientHostApiImpl.WebViewClientCreator(), new GeneratedAndroidWebView.WebViewClientFlutterApi(messenger))); - WebChromeClientHostApi.setup(messenger, new WebChromeClientHostApiImpl(instanceManager, new WebChromeClientHostApiImpl.WebChromeClientCreator(), new GeneratedAndroidWebView.WebChromeClientFlutterApi(messenger))); - DownloadListenerHostApi.setup(messenger, new DownloadListenerHostApiImpl(instanceManager, new DownloadListenerHostApiImpl.DownloadListenerCreator(), new GeneratedAndroidWebView.DownloadListenerFlutterApi(messenger))); - JavaScriptChannelHostApi.setup(messenger, new JavaScriptChannelHostApiImpl(instanceManager, new JavaScriptChannelHostApiImpl.JavaScriptChannelCreator(), new GeneratedAndroidWebView.JavaScriptChannelFlutterApi(messenger), new Handler(activityPluginBinding.getActivity().getMainLooper()))); - WebSettingsHostApi.setup(messenger, new WebSettingsHostApiImpl(instanceManager, new WebSettingsHostApiImpl.WebSettingsCreator())); - flutterCookieManager = new FlutterCookieManager(messenger); + setUp( + pluginBinding.getBinaryMessenger(), + pluginBinding.getPlatformViewRegistry(), + activityPluginBinding.getActivity()); } @Override - public void onDetachedFromActivityForConfigChanges() { - - } + public void onDetachedFromActivityForConfigChanges() {} @Override - public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding activityPluginBinding) { - - } + public void onReattachedToActivityForConfigChanges( + @NonNull ActivityPluginBinding activityPluginBinding) {} @Override - public void onDetachedFromActivity() { - - } + public void onDetachedFromActivity() {} } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index 88c9f7c4332e..aaa50eb79a0c 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -35,15 +35,6 @@ const String _nullStringIdentifier = ''; class WebView { /// Constructs a new WebView. WebView({this.useHybridComposition = false}) { - // TODO: handle independently? - if (!_flutterApisHaveBeenSetup) { - WebViewClientFlutterApi.setup(WebViewClientFlutterApiImpl()); - JavaScriptChannelFlutterApi.setup(JavaScriptChannelFlutterApiImpl()); - DownloadListenerFlutterApi.setup(DownloadListenerFlutterApiImpl()); - WebChromeClientFlutterApi.setup(WebChromeClientFlutterApiImpl()); - _flutterApisHaveBeenSetup = true; - } - api.createFromInstance(this); } @@ -51,8 +42,6 @@ class WebView { @visibleForTesting static WebViewHostApiImpl api = WebViewHostApiImpl(); - static bool _flutterApisHaveBeenSetup = false; - WebViewClient? _currentWebViewClient; DownloadListener? _currentDownloadListener; WebChromeClient? _currentWebChromeClient; @@ -301,6 +290,10 @@ class WebView { return api.setWebChromeClientFromInstance(this, client); } + /// Releases all resources used by the [WebView]. + /// + /// Any methods called on the [WebView] instance after [release] will throw + /// an exception. Future release() { final WebViewClient? webViewClient = _currentWebViewClient; if (webViewClient != null) { @@ -464,12 +457,19 @@ class WebSettings { /// See [WebView.addJavaScriptChannel]. abstract class JavaScriptChannel { /// Constructs a [JavaScriptChannel]. - JavaScriptChannel(this.channelName); + JavaScriptChannel(this.channelName) { + if (!_flutterApisHaveBeenSetup) { + JavaScriptChannelFlutterApi.setup(JavaScriptChannelFlutterApiImpl()); + _flutterApisHaveBeenSetup = true; + } + } /// Pigeon Host Api implementation for [JavaScriptChannel]. @visibleForTesting static JavaScriptChannelHostApiImpl api = JavaScriptChannelHostApiImpl(); + static bool _flutterApisHaveBeenSetup = false; + /// Used to identify this object to receive messages from javaScript. final String channelName; @@ -480,55 +480,62 @@ abstract class JavaScriptChannel { /// Receive various notifications and requests for [WebView]. abstract class WebViewClient { /// Constructs a [WebViewClient]. - WebViewClient({this.shouldOverrideUrlLoading = true}); + WebViewClient({this.shouldOverrideUrlLoading = true}) { + if (!_flutterApisHaveBeenSetup) { + WebViewClientFlutterApi.setup(WebViewClientFlutterApiImpl()); + _flutterApisHaveBeenSetup = true; + } + } + + static bool _flutterApisHaveBeenSetup = false; /// User authentication failed on server. - static const int errorAuthentication = 0xfffffffc; + static const int errorAuthentication = -4; /// Malformed URL. - static const int errorBadUrl = 0xfffffff4; + static const int errorBadUrl = -12; /// Failed to connect to the server. - static const int errorConnect = 0xfffffffa; + static const int errorConnect = -6; /// Failed to perform SSL handshake. - static const int errorFailedSslHandshake = 0xfffffff5; + static const int errorFailedSslHandshake = -11; /// Generic file error. - static const int errorFile = 0xfffffff3; + static const int errorFile = -13; /// File not found. - static const int errorFileNotFound = 0xfffffff2; + static const int errorFileNotFound = -14; /// Server or proxy hostname lookup failed. - static const int errorHostLookup = 0xfffffffe; + static const int errorHostLookup = -2; /// Failed to read or write to the server. - static const int errorIO = 0xfffffff9; + static const int errorIO = -7; /// User authentication failed on proxy. - static const int errorProxyAuthentication = 0xfffffffb; + static const int errorProxyAuthentication = -5; /// Too many redirects. - static const int errorRedirectLoop = 0xfffffff7; + static const int errorRedirectLoop = -9; /// Connection timed out. - static const int errorTimeout = 0xfffffff8; + static const int errorTimeout = -8; /// Too many requests during this load. - static const int errorTooManyRequests = 0xfffffff1; + static const int errorTooManyRequests = -15; /// Generic error. - static const int errorUnknown = 0xffffffff; + static const int errorUnknown = -1; /// Resource load was canceled by Safe Browsing. - static const int errorUnsafeResource = 0xfffffff0; + static const int errorUnsafeResource = -16; /// Unsupported authentication scheme (not basic or digest). - static const int errorUnsupportedAuthScheme = 0xfffffffd; + static const int errorUnsupportedAuthScheme = -3; /// Unsupported URI scheme. - static const int errorUnsupportedScheme = 0xfffffff6; + static const int errorUnsupportedScheme = -10; /// Pigeon Host Api implementation for [WebViewClient]. @visibleForTesting @@ -614,6 +621,16 @@ abstract class WebViewClient { /// The interface to be used when content can not be handled by the rendering engine for [WebView], and should be downloaded instead. abstract class DownloadListener { + /// Constructs a [DownloadListener]. + DownloadListener() { + if (!_flutterApisHaveBeenSetup) { + DownloadListenerFlutterApi.setup(DownloadListenerFlutterApiImpl()); + _flutterApisHaveBeenSetup = true; + } + } + + static bool _flutterApisHaveBeenSetup = false; + /// Pigeon Host Api implementation for [DownloadListener]. @visibleForTesting static DownloadListenerHostApiImpl api = DownloadListenerHostApiImpl(); @@ -630,6 +647,16 @@ abstract class DownloadListener { /// Handles JavaScript dialogs, favicons, titles, and the progress for [WebView]. abstract class WebChromeClient { + /// Constructs a [WebChromeClient]. + WebChromeClient() { + if (!_flutterApisHaveBeenSetup) { + WebChromeClientFlutterApi.setup(WebChromeClientFlutterApiImpl()); + _flutterApisHaveBeenSetup = true; + } + } + + static bool _flutterApisHaveBeenSetup = false; + /// Pigeon Host Api implementation for [WebChromeClient]. @visibleForTesting static WebChromeClientHostApiImpl api = WebChromeClientHostApiImpl(); diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart b/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart new file mode 100644 index 000000000000..b0659c05f3c1 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart @@ -0,0 +1,479 @@ +// 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. + +import 'dart:async'; + +import 'package:flutter/widgets.dart'; + +import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; + +import 'android_webview.dart' as android_webview; + +/// Creates a [Widget] with a [android_webview.WebView]. +class AndroidWebViewWidget extends StatefulWidget { + /// Constructs a [AndroidWebViewWidget]. + AndroidWebViewWidget({ + required this.onBuildWidget, + required this.creationParams, + required this.webViewPlatformCallbacksHandler, + required this.javascriptChannelRegistry, + }); + + /// Callback to build a widget once [android_webview.WebView] has been initialized. + final Widget Function(AndroidWebViewPlatformController platformController) + onBuildWidget; + + /// Initial parameters used to setup the WebView. + final CreationParams creationParams; + + /// Handles callbacks that are made by the created [AndroidWebViewPlatformController]. + final WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler; + + /// Manages named JavaScript channels and forwarding incoming messages on the correct channel. + final JavascriptChannelRegistry javascriptChannelRegistry; + + @override + State createState() => _AndroidWebViewWidgetState(); +} + +class _AndroidWebViewWidgetState extends State { + late android_webview.WebView webView; + late AndroidWebViewPlatformController platformController; + + @override + void initState() { + super.initState(); + webView = android_webview.WebView(useHybridComposition: false); + webView.settings.setDomStorageEnabled(true); + webView.settings.setJavaScriptCanOpenWindowsAutomatically(true); + webView.settings.setSupportMultipleWindows(true); + + platformController = AndroidWebViewPlatformController( + webView: webView, + callbacksHandler: widget.webViewPlatformCallbacksHandler, + javascriptChannelRegistry: widget.javascriptChannelRegistry, + hasNavigationDelegate: + widget.creationParams.webSettings?.hasNavigationDelegate ?? false, + ); + + setCreationParams(widget.creationParams); + } + + void setCreationParams(CreationParams creationParams) { + final WebSettings? webSettings = creationParams.webSettings; + if (webSettings != null) { + platformController.updateSettings(webSettings); + } + + final String? userAgent = creationParams.userAgent; + if (userAgent != null) { + webView.settings.setUserAgentString(userAgent); + } + + final AutoMediaPlaybackPolicy autoMediaPlaybackPolicy = + creationParams.autoMediaPlaybackPolicy; + switch (autoMediaPlaybackPolicy) { + case AutoMediaPlaybackPolicy.always_allow: + webView.settings.setMediaPlaybackRequiresUserGesture(false); + break; + default: + webView.settings.setMediaPlaybackRequiresUserGesture(true); + } + + platformController.addJavascriptChannels( + creationParams.javascriptChannelNames, + ); + + final String? initialUrl = creationParams.initialUrl; + if (initialUrl != null) { + platformController.loadUrl(initialUrl, {}); + } + } + + @override + void dispose() { + super.dispose(); + platformController.webView.release(); + } + + @override + Widget build(BuildContext context) { + return widget.onBuildWidget(platformController); + } +} + +/// Implementation of [WebViewPlatformController] with the Android WebView api. +class AndroidWebViewPlatformController extends WebViewPlatformController { + /// Construct a [AndroidWebViewPlatformController]. + AndroidWebViewPlatformController({ + required this.webView, + required this.callbacksHandler, + required this.javascriptChannelRegistry, + required bool hasNavigationDelegate, + }) : super(callbacksHandler) { + _webViewClient = _WebViewClientImpl( + callbacksHandler: callbacksHandler, + loadUrl: loadUrl, + hasNavigationDelegate: hasNavigationDelegate, + ); + _downloadListener = _DownloadListenerImpl( + callbacksHandler: callbacksHandler, + loadUrl: loadUrl, + ); + _webChromeClient = _WebChromeClientImpl(callbacksHandler: callbacksHandler); + webView.setWebViewClient(_webViewClient); + webView.setDownloadListener(_downloadListener); + webView.setWebChromeClient(_webChromeClient); + } + + /// Represents the WebView maintained by platform code. + final android_webview.WebView webView; + + /// Handles callbacks that are made by [android_webview.WebViewClient], [android_webview.DownloadListener], and [android_webview.WebChromeClient]. + final WebViewPlatformCallbacksHandler callbacksHandler; + + /// Manages named JavaScript channels and forwarding incoming messages on the correct channel. + final JavascriptChannelRegistry javascriptChannelRegistry; + + final Map _javaScriptChannels = + {}; + late final _DownloadListenerImpl _downloadListener; + late final _WebChromeClientImpl _webChromeClient; + late _WebViewClientImpl _webViewClient; + + @override + Future loadUrl( + String url, + Map? headers, + ) { + return webView.loadUrl(url, headers ?? {}); + } + + @override + Future currentUrl() => webView.getUrl(); + + @override + Future canGoBack() => webView.canGoBack(); + + @override + Future canGoForward() => webView.canGoForward(); + + @override + Future goBack() => webView.goBack(); + + @override + Future goForward() => webView.goForward(); + + @override + Future reload() => webView.reload(); + + @override + Future clearCache() => webView.clearCache(true); + + @override + Future updateSettings(WebSettings settings) { + final bool? hasProgressTracking = settings.hasProgressTracking; + if (hasProgressTracking != null) { + _webChromeClient.hasProgressTracking = hasProgressTracking; + } + + return Future.wait(>[ + _trySetHasNavigationDelegate(settings.hasNavigationDelegate), + _trySetJavaScriptMode(settings.javascriptMode), + _trySetDebuggingEnabled(settings.debuggingEnabled), + _trySetUserAgent(settings.userAgent), + ]); + } + + @override + Future evaluateJavascript(String javascriptString) async { + return await webView.evaluateJavascript(javascriptString) ?? ''; + } + + @override + Future addJavascriptChannels(Set javascriptChannelNames) { + return Future.wait( + javascriptChannelNames.where( + (String channelName) { + return _javaScriptChannels.containsKey(channelName); + }, + ).map>( + (String channelName) { + final _JavaScriptChannelImpl javaScriptChannel = + _JavaScriptChannelImpl(channelName, javascriptChannelRegistry); + _javaScriptChannels[channelName] = javaScriptChannel; + return webView.addJavaScriptChannel(javaScriptChannel); + }, + ), + ); + } + + @override + Future removeJavascriptChannels( + Set javascriptChannelNames, + ) { + return Future.wait( + javascriptChannelNames.where( + (String channelName) { + return _javaScriptChannels.containsKey(channelName); + }, + ).map>( + (String channelName) { + final _JavaScriptChannelImpl javaScriptChannel = + _javaScriptChannels[channelName]!; + _javaScriptChannels.remove(channelName); + return webView.removeJavaScriptChannel(javaScriptChannel); + }, + ), + ); + } + + @override + Future getTitle() => webView.getTitle(); + + @override + Future scrollTo(int x, int y) => webView.scrollTo(x, y); + + @override + Future scrollBy(int x, int y) => webView.scrollBy(x, y); + + @override + Future getScrollX() => webView.getScrollX(); + + @override + Future getScrollY() => webView.getScrollY(); + + Future _trySetHasNavigationDelegate(bool? hasNavigationDelegate) async { + if (hasNavigationDelegate != null) { + _downloadListener.hasNavigationDelegate = hasNavigationDelegate; + _webViewClient = _WebViewClientImpl( + callbacksHandler: callbacksHandler, + loadUrl: loadUrl, + hasNavigationDelegate: hasNavigationDelegate, + ); + return webView.setWebViewClient(_webViewClient); + } + } + + Future _trySetJavaScriptMode(JavascriptMode? mode) async { + if (mode != null) { + switch (mode) { + case JavascriptMode.disabled: + return webView.settings.setJavaScriptEnabled(false); + case JavascriptMode.unrestricted: + return webView.settings.setJavaScriptEnabled(true); + } + } + } + + Future _trySetDebuggingEnabled(bool? debuggingEnabled) async { + if (debuggingEnabled != null) { + return android_webview.WebView.setWebContentsDebuggingEnabled( + debuggingEnabled, + ); + } + } + + Future _trySetUserAgent(WebSetting userAgent) async { + if (userAgent.isPresent && userAgent.value != null) { + return webView.settings.setUserAgentString(userAgent.value!); + } + } +} + +class _JavaScriptChannelImpl extends android_webview.JavaScriptChannel { + _JavaScriptChannelImpl(String channelName, this.javascriptChannelRegistry) + : super(channelName); + + final JavascriptChannelRegistry javascriptChannelRegistry; + + @override + void postMessage(String message) { + javascriptChannelRegistry.onJavascriptChannelMessage(channelName, message); + } +} + +class _DownloadListenerImpl extends android_webview.DownloadListener { + _DownloadListenerImpl({ + required this.callbacksHandler, + required this.loadUrl, + }); + + final WebViewPlatformCallbacksHandler callbacksHandler; + final Future Function(String url, Map? headers) loadUrl; + bool hasNavigationDelegate = false; + + @override + void onDownloadStart( + String url, + String userAgent, + String contentDisposition, + String mimetype, + int contentLength, + ) { + if (!hasNavigationDelegate) return; + + final FutureOr returnValue = callbacksHandler.onNavigationRequest( + url: url, + isForMainFrame: true, + ); + + if (returnValue is bool && returnValue) { + loadUrl(url, {}); + } else { + (returnValue as Future).then((bool shouldLoadUrl) { + if (shouldLoadUrl) { + loadUrl(url, {}); + } + }); + } + } +} + +class _WebViewClientImpl extends android_webview.WebViewClient { + _WebViewClientImpl({ + required this.callbacksHandler, + required this.loadUrl, + required this.hasNavigationDelegate, + }) : super(shouldOverrideUrlLoading: hasNavigationDelegate); + + final WebViewPlatformCallbacksHandler callbacksHandler; + final Future Function(String url, Map? headers) loadUrl; + final bool hasNavigationDelegate; + + static WebResourceErrorType _errorCodeToErrorType(int errorCode) { + switch (errorCode) { + case android_webview.WebViewClient.errorAuthentication: + return WebResourceErrorType.authentication; + case android_webview.WebViewClient.errorBadUrl: + return WebResourceErrorType.badUrl; + case android_webview.WebViewClient.errorConnect: + return WebResourceErrorType.connect; + case android_webview.WebViewClient.errorFailedSslHandshake: + return WebResourceErrorType.failedSslHandshake; + case android_webview.WebViewClient.errorFile: + return WebResourceErrorType.file; + case android_webview.WebViewClient.errorFileNotFound: + return WebResourceErrorType.fileNotFound; + case android_webview.WebViewClient.errorHostLookup: + return WebResourceErrorType.hostLookup; + case android_webview.WebViewClient.errorIO: + return WebResourceErrorType.io; + case android_webview.WebViewClient.errorProxyAuthentication: + return WebResourceErrorType.proxyAuthentication; + case android_webview.WebViewClient.errorRedirectLoop: + return WebResourceErrorType.redirectLoop; + case android_webview.WebViewClient.errorTimeout: + return WebResourceErrorType.timeout; + case android_webview.WebViewClient.errorTooManyRequests: + return WebResourceErrorType.tooManyRequests; + case android_webview.WebViewClient.errorUnknown: + return WebResourceErrorType.unknown; + case android_webview.WebViewClient.errorUnsafeResource: + return WebResourceErrorType.unsafeResource; + case android_webview.WebViewClient.errorUnsupportedAuthScheme: + return WebResourceErrorType.unsupportedAuthScheme; + case android_webview.WebViewClient.errorUnsupportedScheme: + return WebResourceErrorType.unsupportedScheme; + } + + throw ArgumentError( + 'Could not find a WebResourceErrorType for errorCode: $errorCode', + ); + } + + @override + void onPageStarted(android_webview.WebView webView, String url) { + callbacksHandler.onPageStarted(url); + } + + @override + void onPageFinished(android_webview.WebView webView, String url) { + callbacksHandler.onPageFinished(url); + } + + @override + void onReceivedError( + android_webview.WebView webView, + int errorCode, + String description, + String failingUrl, + ) { + callbacksHandler.onWebResourceError(WebResourceError( + errorCode: errorCode, + description: description, + failingUrl: failingUrl, + errorType: _errorCodeToErrorType(errorCode), + )); + } + + @override + void onReceivedRequestError( + android_webview.WebView webView, + android_webview.WebResourceRequest request, + android_webview.WebResourceError error, + ) { + callbacksHandler.onWebResourceError(WebResourceError( + errorCode: error.errorCode, + description: error.description, + failingUrl: request.url, + errorType: _errorCodeToErrorType(error.errorCode), + )); + } + + @override + void urlLoading(android_webview.WebView webView, String url) { + if (!hasNavigationDelegate) return; + + final FutureOr returnValue = callbacksHandler.onNavigationRequest( + url: url, + isForMainFrame: true, + ); + + if (returnValue is bool && returnValue) { + loadUrl(url, {}); + } else { + (returnValue as Future).then((bool shouldLoadUrl) { + if (shouldLoadUrl) { + loadUrl(url, {}); + } + }); + } + } + + @override + void requestLoading( + android_webview.WebView webView, + android_webview.WebResourceRequest request, + ) { + if (!hasNavigationDelegate) return; + + final FutureOr returnValue = callbacksHandler.onNavigationRequest( + url: request.url, + isForMainFrame: request.isForMainFrame, + ); + + if (returnValue is bool && returnValue) { + loadUrl(request.url, {}); + } else { + (returnValue as Future).then((bool shouldLoadUrl) { + if (shouldLoadUrl) { + loadUrl(request.url, {}); + } + }); + } + } +} + +class _WebChromeClientImpl extends android_webview.WebChromeClient { + _WebChromeClientImpl({required this.callbacksHandler}); + + final WebViewPlatformCallbacksHandler callbacksHandler; + bool hasProgressTracking = false; + + @override + void onProgressChanged(android_webview.WebView webView, int progress) { + if (hasProgressTracking) callbacksHandler.onProgress(progress); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart index 2acde8a69bd9..4c9a00d83712 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart @@ -8,10 +8,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; -import 'package:webview_flutter_android/src/instance_manager.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; -import 'src/android_webview.dart' as android_webview; +import 'src/webview_widget.dart'; +import 'src/instance_manager.dart'; /// Builds an Android webview. /// @@ -28,524 +28,42 @@ class AndroidWebView implements WebViewPlatform { WebViewPlatformCreatedCallback? onWebViewPlatformCreated, Set>? gestureRecognizers, }) { - // assert(webViewPlatformCallbacksHandler != null); - // return GestureDetector( - // // We prevent text selection by intercepting the long press event. - // // This is a temporary stop gap due to issues with text selection on Android: - // // https://github.com/flutter/flutter/issues/24585 - the text selection - // // dialog is not responding to touch events. - // // https://github.com/flutter/flutter/issues/24584 - the text selection - // // handles are not showing. - // // TODO(amirh): remove this when the issues above are fixed. - // onLongPress: () {}, - // excludeFromSemantics: true, - // child: AndroidView( - // viewType: 'plugins.flutter.io/webview', - // onPlatformViewCreated: (int id) { - // if (onWebViewPlatformCreated == null) { - // return; - // } - // onWebViewPlatformCreated(MethodChannelWebViewPlatform( - // id, - // webViewPlatformCallbacksHandler, - // javascriptChannelRegistry, - // )); - // }, - // gestureRecognizers: gestureRecognizers, - // layoutDirection: Directionality.maybeOf(context) ?? TextDirection.rtl, - // creationParams: - // MethodChannelWebViewPlatform.creationParamsToMap(creationParams), - // creationParamsCodec: const StandardMessageCodec(), - // ), - // ); - return _AndroidWebViewWidget( + return AndroidWebViewWidget( + onBuildWidget: (AndroidWebViewPlatformController platformController) { + return GestureDetector( + // We prevent text selection by intercepting the long press event. + // This is a temporary stop gap due to issues with text selection on Android: + // https://github.com/flutter/flutter/issues/24585 - the text selection + // dialog is not responding to touch events. + // https://github.com/flutter/flutter/issues/24584 - the text selection + // handles are not showing. + // TODO(amirh): remove this when the issues above are fixed. + onLongPress: () {}, + excludeFromSemantics: true, + child: AndroidView( + viewType: 'plugins.flutter.io/webview', + onPlatformViewCreated: (int id) { + final WebViewPlatformCreatedCallback? createdCallback = + onWebViewPlatformCreated; + if (createdCallback != null) { + createdCallback(platformController); + } + }, + gestureRecognizers: gestureRecognizers, + layoutDirection: + Directionality.maybeOf(context) ?? TextDirection.rtl, + creationParams: InstanceManager.instance + .getInstanceId(platformController.webView), + creationParamsCodec: const StandardMessageCodec(), + ), + ); + }, creationParams: creationParams, webViewPlatformCallbacksHandler: webViewPlatformCallbacksHandler, javascriptChannelRegistry: javascriptChannelRegistry, - onWebViewPlatformCreated: onWebViewPlatformCreated, - gestureRecognizers: gestureRecognizers, ); } @override Future clearCookies() => MethodChannelWebViewPlatform.clearCookies(); } - -class _AndroidWebViewWidget extends StatefulWidget { - _AndroidWebViewWidget({ - required this.creationParams, - required this.webViewPlatformCallbacksHandler, - required this.javascriptChannelRegistry, - this.onWebViewPlatformCreated, - this.gestureRecognizers, - }); - - final CreationParams creationParams; - final WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler; - final JavascriptChannelRegistry javascriptChannelRegistry; - final WebViewPlatformCreatedCallback? onWebViewPlatformCreated; - final Set>? gestureRecognizers; - - @override - State createState() => _AndroidWebViewWidgetState(); -} - -class _AndroidWebViewWidgetState extends State<_AndroidWebViewWidget> { - late android_webview.WebView webView; - late _AndroidWebViewPlatformController platformController; - - @override - void initState() { - super.initState(); - webView = android_webview.WebView(useHybridComposition: false); - webView.settings.setDomStorageEnabled(true); - webView.settings.setJavaScriptCanOpenWindowsAutomatically(true); - webView.settings.setSupportMultipleWindows(true); - - platformController = _AndroidWebViewPlatformController( - webView: webView, - callbacksHandler: widget.webViewPlatformCallbacksHandler, - javascriptChannelRegistry: widget.javascriptChannelRegistry, - hasNavigationDelegate: - widget.creationParams.webSettings?.hasNavigationDelegate ?? false, - ); - - setCreationParams(widget.creationParams); - } - - void setCreationParams(CreationParams creationParams) { - final WebSettings? webSettings = creationParams.webSettings; - if (webSettings != null) { - platformController.updateSettings(webSettings); - } - - final String? userAgent = creationParams.userAgent; - if (userAgent != null) { - webView.settings.setUserAgentString(userAgent); - } - - final AutoMediaPlaybackPolicy autoMediaPlaybackPolicy = - creationParams.autoMediaPlaybackPolicy; - switch (autoMediaPlaybackPolicy) { - case AutoMediaPlaybackPolicy.always_allow: - webView.settings.setMediaPlaybackRequiresUserGesture(false); - break; - default: - webView.settings.setMediaPlaybackRequiresUserGesture(true); - } - - platformController.addJavascriptChannels( - creationParams.javascriptChannelNames, - ); - - final String? initialUrl = creationParams.initialUrl; - if (initialUrl != null) { - platformController.loadUrl(initialUrl, {}); - } - } - - @override - void dispose() { - super.dispose(); - platformController.webView.release(); - } - - @override - Widget build(BuildContext context) { - return GestureDetector( - // We prevent text selection by intercepting the long press event. - // This is a temporary stop gap due to issues with text selection on Android: - // https://github.com/flutter/flutter/issues/24585 - the text selection - // dialog is not responding to touch events. - // https://github.com/flutter/flutter/issues/24584 - the text selection - // handles are not showing. - // TODO(amirh): remove this when the issues above are fixed. - onLongPress: () {}, - excludeFromSemantics: true, - child: AndroidView( - viewType: 'plugins.flutter.io/webview', - onPlatformViewCreated: (int id) { - final WebViewPlatformCreatedCallback? createdCallback = - widget.onWebViewPlatformCreated; - if (createdCallback != null) { - createdCallback(platformController); - } - }, - gestureRecognizers: widget.gestureRecognizers, - layoutDirection: Directionality.maybeOf(context) ?? TextDirection.rtl, - creationParams: - InstanceManager.instance.getInstanceId(platformController.webView), - creationParamsCodec: const StandardMessageCodec(), - ), - ); - } -} - -class _AndroidWebViewPlatformController extends WebViewPlatformController { - _AndroidWebViewPlatformController({ - required this.webView, - required this.callbacksHandler, - required this.javascriptChannelRegistry, - required bool hasNavigationDelegate, - }) : super(callbacksHandler) { - webViewClient = _WebViewClientImpl( - callbacksHandler: callbacksHandler, - loadUrl: loadUrl, - hasNavigationDelegate: hasNavigationDelegate, - ); - downloadListener = _DownloadListenerImpl( - callbacksHandler: callbacksHandler, - loadUrl: loadUrl, - ); - webChromeClient = _WebChromeClientImpl(callbacksHandler: callbacksHandler); - webView.setWebViewClient(webViewClient); - webView.setDownloadListener(downloadListener); - webView.setWebChromeClient(webChromeClient); - } - - final Map javaScriptChannels = - {}; - - final android_webview.WebView webView; - final WebViewPlatformCallbacksHandler callbacksHandler; - final JavascriptChannelRegistry javascriptChannelRegistry; - - late final _DownloadListenerImpl downloadListener; - late final _WebChromeClientImpl webChromeClient; - late _WebViewClientImpl webViewClient; - - @override - Future loadUrl( - String url, - Map? headers, - ) { - return webView.loadUrl(url, headers ?? {}); - } - - @override - Future currentUrl() => webView.getUrl(); - - @override - Future canGoBack() => webView.canGoBack(); - - @override - Future canGoForward() => webView.canGoForward(); - - @override - Future goBack() => webView.goBack(); - - @override - Future goForward() => webView.goForward(); - - @override - Future reload() => webView.reload(); - - @override - Future clearCache() => webView.clearCache(true); - - @override - Future updateSettings(WebSettings settings) { - final bool? hasProgressTracking = settings.hasProgressTracking; - if (hasProgressTracking != null) { - webChromeClient.hasProgressTracking = hasProgressTracking; - } - - return Future.wait(>[ - _trySetHasNavigationDelegate(settings.hasNavigationDelegate), - _trySetJavaScriptMode(settings.javascriptMode), - _trySetDebuggingEnabled(settings.debuggingEnabled), - _trySetUserAgent(settings.userAgent), - ]); - } - - @override - Future evaluateJavascript(String javascriptString) async { - return await webView.evaluateJavascript(javascriptString) ?? ''; - } - - @override - Future addJavascriptChannels(Set javascriptChannelNames) { - return Future.wait( - javascriptChannelNames.where( - (String channelName) { - return javaScriptChannels.containsKey(channelName); - }, - ).map>( - (String channelName) { - final _JavaScriptChannelImpl javaScriptChannel = - _JavaScriptChannelImpl(channelName, javascriptChannelRegistry); - javaScriptChannels[channelName] = javaScriptChannel; - return webView.addJavaScriptChannel(javaScriptChannel); - }, - ), - ); - } - - @override - Future removeJavascriptChannels( - Set javascriptChannelNames, - ) { - return Future.wait( - javascriptChannelNames.where( - (String channelName) { - return javaScriptChannels.containsKey(channelName); - }, - ).map>( - (String channelName) { - final _JavaScriptChannelImpl javaScriptChannel = - javaScriptChannels[channelName]!; - javaScriptChannels.remove(channelName); - return webView.removeJavaScriptChannel(javaScriptChannel); - }, - ), - ); - } - - @override - Future getTitle() => webView.getTitle(); - - @override - Future scrollTo(int x, int y) => webView.scrollTo(x, y); - - @override - Future scrollBy(int x, int y) => webView.scrollBy(x, y); - - @override - Future getScrollX() => webView.getScrollX(); - - @override - Future getScrollY() => webView.getScrollY(); - - Future _trySetHasNavigationDelegate(bool? hasNavigationDelegate) async { - if (hasNavigationDelegate != null) { - downloadListener.hasNavigationDelegate = hasNavigationDelegate; - webViewClient = _WebViewClientImpl( - callbacksHandler: callbacksHandler, - loadUrl: loadUrl, - hasNavigationDelegate: hasNavigationDelegate, - ); - return webView.setWebViewClient(webViewClient); - } - } - - Future _trySetJavaScriptMode(JavascriptMode? mode) async { - if (mode != null) { - switch (mode) { - case JavascriptMode.disabled: - return webView.settings.setJavaScriptEnabled(false); - case JavascriptMode.unrestricted: - return webView.settings.setJavaScriptEnabled(true); - } - } - } - - Future _trySetDebuggingEnabled(bool? debuggingEnabled) async { - if (debuggingEnabled != null) { - return android_webview.WebView.setWebContentsDebuggingEnabled( - debuggingEnabled, - ); - } - } - - Future _trySetUserAgent(WebSetting userAgent) async { - if (userAgent.isPresent) { - return webView.settings.setUserAgentString(userAgent.value!); - } - } -} - -class _JavaScriptChannelImpl extends android_webview.JavaScriptChannel { - _JavaScriptChannelImpl(String channelName, this.javascriptChannelRegistry) - : super(channelName); - - final JavascriptChannelRegistry javascriptChannelRegistry; - - @override - void postMessage(String message) { - javascriptChannelRegistry.onJavascriptChannelMessage(channelName, message); - } -} - -class _DownloadListenerImpl extends android_webview.DownloadListener { - _DownloadListenerImpl({ - required this.callbacksHandler, - required this.loadUrl, - }); - - final WebViewPlatformCallbacksHandler callbacksHandler; - final Future Function(String url, Map? headers) loadUrl; - bool hasNavigationDelegate = false; - - @override - void onDownloadStart( - String url, - String userAgent, - String contentDisposition, - String mimetype, - int contentLength, - ) { - if (!hasNavigationDelegate) return; - - final FutureOr returnValue = callbacksHandler.onNavigationRequest( - url: url, - isForMainFrame: true, - ); - - if (returnValue is bool && returnValue) { - loadUrl(url, {}); - } else { - (returnValue as Future).then((bool shouldLoadUrl) { - if (shouldLoadUrl) { - loadUrl(url, {}); - } - }); - } - } -} - -class _WebViewClientImpl extends android_webview.WebViewClient { - _WebViewClientImpl({ - required this.callbacksHandler, - required this.loadUrl, - required this.hasNavigationDelegate, - }) : super(shouldOverrideUrlLoading: hasNavigationDelegate); - - final WebViewPlatformCallbacksHandler callbacksHandler; - final Future Function(String url, Map? headers) loadUrl; - final bool hasNavigationDelegate; - - static WebResourceErrorType _errorCodeToErrorType(int errorCode) { - switch (errorCode) { - case android_webview.WebViewClient.errorAuthentication: - return WebResourceErrorType.authentication; - case android_webview.WebViewClient.errorBadUrl: - return WebResourceErrorType.badUrl; - case android_webview.WebViewClient.errorConnect: - return WebResourceErrorType.connect; - case android_webview.WebViewClient.errorFailedSslHandshake: - return WebResourceErrorType.failedSslHandshake; - case android_webview.WebViewClient.errorFile: - return WebResourceErrorType.file; - case android_webview.WebViewClient.errorFileNotFound: - return WebResourceErrorType.fileNotFound; - case android_webview.WebViewClient.errorHostLookup: - return WebResourceErrorType.hostLookup; - case android_webview.WebViewClient.errorIO: - return WebResourceErrorType.io; - case android_webview.WebViewClient.errorProxyAuthentication: - return WebResourceErrorType.proxyAuthentication; - case android_webview.WebViewClient.errorRedirectLoop: - return WebResourceErrorType.redirectLoop; - case android_webview.WebViewClient.errorTimeout: - return WebResourceErrorType.timeout; - case android_webview.WebViewClient.errorTooManyRequests: - return WebResourceErrorType.tooManyRequests; - case android_webview.WebViewClient.errorUnknown: - return WebResourceErrorType.unknown; - case android_webview.WebViewClient.errorUnsafeResource: - return WebResourceErrorType.unsafeResource; - case android_webview.WebViewClient.errorUnsupportedAuthScheme: - return WebResourceErrorType.unsupportedAuthScheme; - case android_webview.WebViewClient.errorUnsupportedScheme: - return WebResourceErrorType.unsupportedScheme; - } - - throw ArgumentError( - 'Could not find a WebResourceErrorType for errorCode: $errorCode', - ); - } - - @override - void onPageStarted(android_webview.WebView webView, String url) { - callbacksHandler.onPageStarted(url); - } - - @override - void onPageFinished(android_webview.WebView webView, String url) { - callbacksHandler.onPageFinished(url); - } - - @override - void onReceivedError( - android_webview.WebView webView, - int errorCode, - String description, - String failingUrl, - ) { - callbacksHandler.onWebResourceError(WebResourceError( - errorCode: errorCode, - description: description, - failingUrl: failingUrl, - errorType: _errorCodeToErrorType(errorCode), - )); - } - - @override - void onReceivedRequestError( - android_webview.WebView webView, - android_webview.WebResourceRequest request, - android_webview.WebResourceError error, - ) { - callbacksHandler.onWebResourceError(WebResourceError( - errorCode: error.errorCode, - description: error.description, - failingUrl: request.url, - errorType: _errorCodeToErrorType(error.errorCode), - )); - } - - @override - void urlLoading(android_webview.WebView webView, String url) { - if (!hasNavigationDelegate) return; - - final FutureOr returnValue = callbacksHandler.onNavigationRequest( - url: url, - isForMainFrame: true, - ); - - if (returnValue is bool && returnValue) { - loadUrl(url, {}); - } else { - (returnValue as Future).then((bool shouldLoadUrl) { - if (shouldLoadUrl) { - loadUrl(url, {}); - } - }); - } - } - - @override - void requestLoading( - android_webview.WebView webView, - android_webview.WebResourceRequest request, - ) { - if (!hasNavigationDelegate) return; - - final FutureOr returnValue = callbacksHandler.onNavigationRequest( - url: request.url, - isForMainFrame: request.isForMainFrame, - ); - - if (returnValue is bool && returnValue) { - loadUrl(request.url, {}); - } else { - (returnValue as Future).then((bool shouldLoadUrl) { - if (shouldLoadUrl) { - loadUrl(request.url, {}); - } - }); - } - } -} - -class _WebChromeClientImpl extends android_webview.WebChromeClient { - _WebChromeClientImpl({required this.callbacksHandler}); - - final WebViewPlatformCallbacksHandler callbacksHandler; - bool hasProgressTracking = false; - - @override - void onProgressChanged(android_webview.WebView webView, int progress) { - if (hasProgressTracking) callbacksHandler.onProgress(progress); - } -} diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart index 6beae105e2e5..7e52fc3081eb 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart @@ -9,6 +9,8 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; +import 'src/instance_manager.dart'; +import 'src/webview_widget.dart'; import 'webview_android.dart'; /// Android [WebViewPlatform] that uses [AndroidViewSurface] to build the [WebView] widget. @@ -30,49 +32,46 @@ class SurfaceAndroidWebView extends AndroidWebView { Set>? gestureRecognizers, required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, }) { - assert(webViewPlatformCallbacksHandler != null); - return PlatformViewLink( - viewType: 'plugins.flutter.io/webview', - surfaceFactory: ( - BuildContext context, - PlatformViewController controller, - ) { - return AndroidViewSurface( - controller: controller as AndroidViewController, - gestureRecognizers: gestureRecognizers ?? - const >{}, - hitTestBehavior: PlatformViewHitTestBehavior.opaque, - ); - }, - onCreatePlatformView: (PlatformViewCreationParams params) { - return PlatformViewsService.initSurfaceAndroidView( - id: params.id, + return AndroidWebViewWidget( + onBuildWidget: (AndroidWebViewPlatformController platformController) { + return PlatformViewLink( viewType: 'plugins.flutter.io/webview', - // WebView content is not affected by the Android view's layout direction, - // we explicitly set it here so that the widget doesn't require an ambient - // directionality. - layoutDirection: TextDirection.rtl, - creationParams: MethodChannelWebViewPlatform.creationParamsToMap( - creationParams, - usesHybridComposition: true, - ), - creationParamsCodec: const StandardMessageCodec(), - ) - ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) - ..addOnPlatformViewCreatedListener((int id) { - if (onWebViewPlatformCreated == null) { - return; - } - onWebViewPlatformCreated( - MethodChannelWebViewPlatform( - id, - webViewPlatformCallbacksHandler, - javascriptChannelRegistry, - ), + surfaceFactory: ( + BuildContext context, + PlatformViewController controller, + ) { + return AndroidViewSurface( + controller: controller as AndroidViewController, + gestureRecognizers: gestureRecognizers ?? + const >{}, + hitTestBehavior: PlatformViewHitTestBehavior.opaque, ); - }) - ..create(); + }, + onCreatePlatformView: (PlatformViewCreationParams params) { + return PlatformViewsService.initSurfaceAndroidView( + id: params.id, + viewType: 'plugins.flutter.io/webview', + // WebView content is not affected by the Android view's layout direction, + // we explicitly set it here so that the widget doesn't require an ambient + // directionality. + layoutDirection: TextDirection.rtl, + creationParams: InstanceManager.instance + .getInstanceId(platformController.webView), + creationParamsCodec: const StandardMessageCodec(), + ) + ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) + ..addOnPlatformViewCreatedListener((int id) { + if (onWebViewPlatformCreated != null) { + onWebViewPlatformCreated(platformController); + } + }) + ..create(); + }, + ); }, + creationParams: creationParams, + webViewPlatformCallbacksHandler: webViewPlatformCallbacksHandler, + javascriptChannelRegistry: javascriptChannelRegistry, ); } } From fe735b927386770510f6cd73b633d300652a6461 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Tue, 26 Oct 2021 22:39:13 -0700 Subject: [PATCH 32/54] fix javascriptenabled and hybrid composition --- packages/webview_flutter/webview_flutter/pubspec.yaml | 3 ++- .../lib/src/android_webview_api_impls.dart | 2 +- .../webview_flutter_android/lib/src/webview_widget.dart | 8 +++++++- .../webview_flutter_android/lib/webview_android.dart | 1 + .../lib/webview_surface_android.dart | 1 + 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml index 4206789cb1b3..fb015309b1c2 100644 --- a/packages/webview_flutter/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter/pubspec.yaml @@ -20,7 +20,8 @@ dependencies: flutter: sdk: flutter webview_flutter_platform_interface: ^1.0.0 - webview_flutter_android: ^2.0.13 + webview_flutter_android: + path: ../webview_flutter_android webview_flutter_wkwebview: ^2.0.13 dev_dependencies: diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index 4068392d0371..c74ecb90a2a3 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -239,7 +239,7 @@ class WebSettingsHostApiImpl extends WebSettingsHostApi { WebSettings instance, bool flag, ) { - return setJavaScriptCanOpenWindowsAutomatically( + return setJavaScriptEnabled( instanceManager.getInstanceId(instance)!, flag, ); diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart b/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart index b0659c05f3c1..927264d4003b 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart @@ -18,6 +18,7 @@ class AndroidWebViewWidget extends StatefulWidget { required this.creationParams, required this.webViewPlatformCallbacksHandler, required this.javascriptChannelRegistry, + required this.useHybridComposition, }); /// Callback to build a widget once [android_webview.WebView] has been initialized. @@ -33,6 +34,9 @@ class AndroidWebViewWidget extends StatefulWidget { /// Manages named JavaScript channels and forwarding incoming messages on the correct channel. final JavascriptChannelRegistry javascriptChannelRegistry; + /// Whether the Widget will be rendered with Hybrid Composition. + final bool useHybridComposition; + @override State createState() => _AndroidWebViewWidgetState(); } @@ -44,7 +48,9 @@ class _AndroidWebViewWidgetState extends State { @override void initState() { super.initState(); - webView = android_webview.WebView(useHybridComposition: false); + webView = android_webview.WebView( + useHybridComposition: widget.useHybridComposition, + ); webView.settings.setDomStorageEnabled(true); webView.settings.setJavaScriptCanOpenWindowsAutomatically(true); webView.settings.setSupportMultipleWindows(true); diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart index 4c9a00d83712..90afd964c79e 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart @@ -61,6 +61,7 @@ class AndroidWebView implements WebViewPlatform { creationParams: creationParams, webViewPlatformCallbacksHandler: webViewPlatformCallbacksHandler, javascriptChannelRegistry: javascriptChannelRegistry, + useHybridComposition: false, ); } diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart index 7e52fc3081eb..6bbeae257775 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart @@ -72,6 +72,7 @@ class SurfaceAndroidWebView extends AndroidWebView { creationParams: creationParams, webViewPlatformCallbacksHandler: webViewPlatformCallbacksHandler, javascriptChannelRegistry: javascriptChannelRegistry, + useHybridComposition: true, ); } } From 4304c0c1bb7826723b88887fa5ef3afd5cca5787 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Tue, 26 Oct 2021 23:58:50 -0700 Subject: [PATCH 33/54] fix another buggit statusgit statusgit status sadness --- .../webview_flutter_test.dart | 2400 ++++++++--------- .../webviewflutter/InstanceManager.java | 3 + .../JavaScriptChannelHostApiImpl.java | 3 + .../webviewflutter/WebViewHostApiImpl.java | 8 + .../lib/src/android_webview_api_impls.dart | 2 +- .../lib/src/webview_widget.dart | 2 +- 6 files changed, 1216 insertions(+), 1202 deletions(-) diff --git a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart index 3379bafa2346..96f2f67f0685 100644 --- a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -248,1206 +248,1206 @@ void main() { await resizeCompleter.future; }); - - testWidgets('set custom userAgent', (WidgetTester tester) async { - final Completer controllerCompleter1 = - Completer(); - final GlobalKey _globalKey = GlobalKey(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: _globalKey, - initialUrl: 'about:blank', - javascriptMode: JavascriptMode.unrestricted, - userAgent: 'Custom_User_Agent1', - onWebViewCreated: (WebViewController controller) { - controllerCompleter1.complete(controller); - }, - ), - ), - ); - final WebViewController controller1 = await controllerCompleter1.future; - final String customUserAgent1 = await _getUserAgent(controller1); - expect(customUserAgent1, 'Custom_User_Agent1'); - // rebuild the WebView with a different user agent. - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: _globalKey, - initialUrl: 'about:blank', - javascriptMode: JavascriptMode.unrestricted, - userAgent: 'Custom_User_Agent2', - ), - ), - ); - - final String customUserAgent2 = await _getUserAgent(controller1); - expect(customUserAgent2, 'Custom_User_Agent2'); - }); - - // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. - testWidgets('use default platform userAgent after webView is rebuilt', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final GlobalKey _globalKey = GlobalKey(); - // Build the webView with no user agent to get the default platform user agent. - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: _globalKey, - initialUrl: primaryUrl, - javascriptMode: JavascriptMode.unrestricted, - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - final String defaultPlatformUserAgent = await _getUserAgent(controller); - // rebuild the WebView with a custom user agent. - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: _globalKey, - initialUrl: 'about:blank', - javascriptMode: JavascriptMode.unrestricted, - userAgent: 'Custom_User_Agent', - ), - ), - ); - final String customUserAgent = await _getUserAgent(controller); - expect(customUserAgent, 'Custom_User_Agent'); - // rebuilds the WebView with no user agent. - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: _globalKey, - initialUrl: 'about:blank', - javascriptMode: JavascriptMode.unrestricted, - ), - ), - ); - - final String customUserAgent2 = await _getUserAgent(controller); - expect(customUserAgent2, defaultPlatformUserAgent); - }, skip: Platform.isAndroid && _skipDueToIssue86757); - - group('Video playback policy', () { - late String videoTestBase64; - setUpAll(() async { - final ByteData videoData = - await rootBundle.load('assets/sample_video.mp4'); - final String base64VideoData = - base64Encode(Uint8List.view(videoData.buffer)); - final String videoTest = ''' - - Video auto play - - - - - - - '''; - videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest)); - }); - - testWidgets('Auto media playback', (WidgetTester tester) async { - Completer controllerCompleter = - Completer(); - Completer pageLoaded = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - ), - ), - ); - WebViewController controller = await controllerCompleter.future; - await pageLoaded.future; - - String isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - - controllerCompleter = Completer(); - pageLoaded = Completer(); - - // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: - AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - ), - ), - ); - - controller = await controllerCompleter.future; - await pageLoaded.future; - - isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(true)); - }); - - testWidgets('Changes to initialMediaPlaybackPolicy are ignored', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - Completer pageLoaded = Completer(); - - final GlobalKey key = GlobalKey(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: key, - initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - await pageLoaded.future; - - String isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - - pageLoaded = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: key, - initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: - AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - ), - ), - ); - - await controller.reload(); - - await pageLoaded.future; - - isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - }); - - testWidgets('Video plays inline when allowsInlineMediaPlayback is true', - (WidgetTester tester) async { - Completer controllerCompleter = - Completer(); - Completer pageLoaded = Completer(); - Completer videoPlaying = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - javascriptChannels: { - JavascriptChannel( - name: 'VideoTestTime', - onMessageReceived: (JavascriptMessage message) { - final double currentTime = double.parse(message.message); - // Let it play for at least 1 second to make sure the related video's properties are set. - if (currentTime > 1) { - videoPlaying.complete(null); - } - }, - ), - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - allowsInlineMediaPlayback: true, - ), - ), - ); - WebViewController controller = await controllerCompleter.future; - await pageLoaded.future; - - // Pump once to trigger the video play. - await tester.pump(); - - // Makes sure we get the correct event that indicates the video is actually playing. - await videoPlaying.future; - - String fullScreen = - await controller.evaluateJavascript('isFullScreen();'); - expect(fullScreen, _webviewBool(false)); - }); - - // allowsInlineMediaPlayback is a noop on Android, so it is skipped. - testWidgets( - 'Video plays full screen when allowsInlineMediaPlayback is false', - (WidgetTester tester) async { - Completer controllerCompleter = - Completer(); - Completer pageLoaded = Completer(); - Completer videoPlaying = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - javascriptChannels: { - JavascriptChannel( - name: 'VideoTestTime', - onMessageReceived: (JavascriptMessage message) { - final double currentTime = double.parse(message.message); - // Let it play for at least 1 second to make sure the related video's properties are set. - if (currentTime > 1) { - videoPlaying.complete(null); - } - }, - ), - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - allowsInlineMediaPlayback: false, - ), - ), - ); - WebViewController controller = await controllerCompleter.future; - await pageLoaded.future; - - // Pump once to trigger the video play. - await tester.pump(); - - // Makes sure we get the correct event that indicates the video is actually playing. - await videoPlaying.future; - - String fullScreen = - await controller.evaluateJavascript('isFullScreen();'); - expect(fullScreen, _webviewBool(true)); - }, skip: Platform.isAndroid); - }); - - group('Audio playback policy', () { - late String audioTestBase64; - setUpAll(() async { - final ByteData audioData = - await rootBundle.load('assets/sample_audio.ogg'); - final String base64AudioData = - base64Encode(Uint8List.view(audioData.buffer)); - final String audioTest = ''' - - Audio auto play - - - - - - - '''; - audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest)); - }); - - testWidgets('Auto media playback', (WidgetTester tester) async { - Completer controllerCompleter = - Completer(); - Completer pageStarted = Completer(); - Completer pageLoaded = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - ), - ), - ); - WebViewController controller = await controllerCompleter.future; - await pageStarted.future; - await pageLoaded.future; - - String isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - - controllerCompleter = Completer(); - pageStarted = Completer(); - pageLoaded = Completer(); - - // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: - AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - ), - ), - ); - - controller = await controllerCompleter.future; - await pageStarted.future; - await pageLoaded.future; - - isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(true)); - }); - - testWidgets('Changes to initialMediaPlaybackPolocy are ignored', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - Completer pageStarted = Completer(); - Completer pageLoaded = Completer(); - - final GlobalKey key = GlobalKey(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: key, - initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - await pageStarted.future; - await pageLoaded.future; - - String isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - - pageStarted = Completer(); - pageLoaded = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: key, - initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: - AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - ), - ), - ); - - await controller.reload(); - - await pageStarted.future; - await pageLoaded.future; - - isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - }); - }); - - testWidgets('getTitle', (WidgetTester tester) async { - final String getTitleTest = ''' - - Some title - - - - - '''; - final String getTitleTestBase64 = - base64Encode(const Utf8Encoder().convert(getTitleTest)); - final Completer pageStarted = Completer(); - final Completer pageLoaded = Completer(); - final Completer controllerCompleter = - Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - ), - ), - ); - - final WebViewController controller = await controllerCompleter.future; - await pageStarted.future; - await pageLoaded.future; - - final String? title = await controller.getTitle(); - expect(title, 'Some title'); - }); - - group('Programmatic Scroll', () { - // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. - testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { - final String scrollTestPage = ''' - - - - - - -

- - - '''; - - final String scrollTestPageBase64 = - base64Encode(const Utf8Encoder().convert(scrollTestPage)); - - final Completer pageLoaded = Completer(); - final Completer controllerCompleter = - Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - initialUrl: - 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - ), - ), - ); - - final WebViewController controller = await controllerCompleter.future; - await pageLoaded.future; - - await tester.pumpAndSettle(Duration(seconds: 3)); - - int scrollPosX = await controller.getScrollX(); - int scrollPosY = await controller.getScrollY(); - - // Check scrollTo() - const int X_SCROLL = 123; - const int Y_SCROLL = 321; - // Get the initial position; this ensures that scrollTo is actually - // changing something, but also gives the native view's scroll position - // time to settle. - expect(scrollPosX, isNot(X_SCROLL)); - expect(scrollPosX, isNot(Y_SCROLL)); - - await controller.scrollTo(X_SCROLL, Y_SCROLL); - scrollPosX = await controller.getScrollX(); - scrollPosY = await controller.getScrollY(); - expect(scrollPosX, X_SCROLL); - expect(scrollPosY, Y_SCROLL); - - // Check scrollBy() (on top of scrollTo()) - await controller.scrollBy(X_SCROLL, Y_SCROLL); - scrollPosX = await controller.getScrollX(); - scrollPosY = await controller.getScrollY(); - expect(scrollPosX, X_SCROLL * 2); - expect(scrollPosY, Y_SCROLL * 2); - }, skip: Platform.isAndroid && _skipDueToIssue86757); - }); - - group('SurfaceAndroidWebView', () { - setUpAll(() { - WebView.platform = SurfaceAndroidWebView(); - }); - - tearDownAll(() { - WebView.platform = null; - }); - - // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. - testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { - final String scrollTestPage = ''' - - - - - - -
- - - '''; - - final String scrollTestPageBase64 = - base64Encode(const Utf8Encoder().convert(scrollTestPage)); - - final Completer pageLoaded = Completer(); - final Completer controllerCompleter = - Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - initialUrl: - 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - ), - ), - ); - - final WebViewController controller = await controllerCompleter.future; - await pageLoaded.future; - - await tester.pumpAndSettle(Duration(seconds: 3)); - - // Check scrollTo() - const int X_SCROLL = 123; - const int Y_SCROLL = 321; - - await controller.scrollTo(X_SCROLL, Y_SCROLL); - int scrollPosX = await controller.getScrollX(); - int scrollPosY = await controller.getScrollY(); - expect(X_SCROLL, scrollPosX); - expect(Y_SCROLL, scrollPosY); - - // Check scrollBy() (on top of scrollTo()) - await controller.scrollBy(X_SCROLL, Y_SCROLL); - scrollPosX = await controller.getScrollX(); - scrollPosY = await controller.getScrollY(); - expect(X_SCROLL * 2, scrollPosX); - expect(Y_SCROLL * 2, scrollPosY); - }, skip: !Platform.isAndroid || _skipDueToIssue86757); - - // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. - testWidgets('inputs are scrolled into view when focused', - (WidgetTester tester) async { - final String scrollTestPage = ''' - - - - - - -
- - - - '''; - - final String scrollTestPageBase64 = - base64Encode(const Utf8Encoder().convert(scrollTestPage)); - - final Completer pageLoaded = Completer(); - final Completer controllerCompleter = - Completer(); - - await tester.runAsync(() async { - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: SizedBox( - width: 200, - height: 200, - child: WebView( - initialUrl: - 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - javascriptMode: JavascriptMode.unrestricted, - ), - ), - ), - ); - await Future.delayed(Duration(milliseconds: 20)); - await tester.pump(); - }); - - final WebViewController controller = await controllerCompleter.future; - await pageLoaded.future; - final String viewportRectJSON = await _evaluateJavascript( - controller, 'JSON.stringify(viewport.getBoundingClientRect())'); - final Map viewportRectRelativeToViewport = - jsonDecode(viewportRectJSON); - - // Check that the input is originally outside of the viewport. - - final String initialInputClientRectJSON = await _evaluateJavascript( - controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); - final Map initialInputClientRectRelativeToViewport = - jsonDecode(initialInputClientRectJSON); - - expect( - initialInputClientRectRelativeToViewport['bottom'] <= - viewportRectRelativeToViewport['bottom'], - isFalse); - - await controller.evaluateJavascript('inputEl.focus()'); - - // Check that focusing the input brought it into view. - - final String lastInputClientRectJSON = await _evaluateJavascript( - controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); - final Map lastInputClientRectRelativeToViewport = - jsonDecode(lastInputClientRectJSON); - - expect( - lastInputClientRectRelativeToViewport['top'] >= - viewportRectRelativeToViewport['top'], - isTrue); - expect( - lastInputClientRectRelativeToViewport['bottom'] <= - viewportRectRelativeToViewport['bottom'], - isTrue); - - expect( - lastInputClientRectRelativeToViewport['left'] >= - viewportRectRelativeToViewport['left'], - isTrue); - expect( - lastInputClientRectRelativeToViewport['right'] <= - viewportRectRelativeToViewport['right'], - isTrue); - }, skip: !Platform.isAndroid || _skipDueToIssue86757); - }); - - group('NavigationDelegate', () { - final String blankPage = ""; - final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,' + - base64Encode(const Utf8Encoder().convert(blankPage)); - - testWidgets('can allow requests', (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final StreamController pageLoads = - StreamController.broadcast(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: blankPageEncoded, - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - navigationDelegate: (NavigationRequest request) { - return (request.url.contains('youtube.com')) - ? NavigationDecision.prevent - : NavigationDecision.navigate; - }, - onPageFinished: (String url) => pageLoads.add(url), - ), - ), - ); - - await pageLoads.stream.first; // Wait for initial page load. - final WebViewController controller = await controllerCompleter.future; - await controller.evaluateJavascript('location.href = "$secondaryUrl"'); - - await pageLoads.stream.first; // Wait for the next page load. - final String? currentUrl = await controller.currentUrl(); - expect(currentUrl, secondaryUrl); - }); - - testWidgets('onWebResourceError', (WidgetTester tester) async { - final Completer errorCompleter = - Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'https://www.notawebsite..com', - onWebResourceError: (WebResourceError error) { - errorCompleter.complete(error); - }, - ), - ), - ); - - final WebResourceError error = await errorCompleter.future; - expect(error, isNotNull); - - if (Platform.isIOS) { - expect(error.domain, isNotNull); - expect(error.failingUrl, isNull); - } else if (Platform.isAndroid) { - expect(error.errorType, isNotNull); - expect(error.failingUrl?.startsWith('https://www.notawebsite..com'), - isTrue); - } - }); - - testWidgets('onWebResourceError is not called with valid url', - (WidgetTester tester) async { - final Completer errorCompleter = - Completer(); - final Completer pageFinishCompleter = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: - 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', - onWebResourceError: (WebResourceError error) { - errorCompleter.complete(error); - }, - onPageFinished: (_) => pageFinishCompleter.complete(), - ), - ), - ); - - expect(errorCompleter.future, doesNotComplete); - await pageFinishCompleter.future; - }); - - testWidgets( - 'onWebResourceError only called for main frame', - (WidgetTester tester) async { - final String iframeTest = ''' - - - - WebResourceError test - - - - - - '''; - final String iframeTestBase64 = - base64Encode(const Utf8Encoder().convert(iframeTest)); - - final Completer errorCompleter = - Completer(); - final Completer pageFinishCompleter = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: - 'data:text/html;charset=utf-8;base64,$iframeTestBase64', - onWebResourceError: (WebResourceError error) { - errorCompleter.complete(error); - }, - onPageFinished: (_) => pageFinishCompleter.complete(), - ), - ), - ); - - expect(errorCompleter.future, doesNotComplete); - await pageFinishCompleter.future; - }, - ); - - testWidgets('can block requests', (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final StreamController pageLoads = - StreamController.broadcast(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: blankPageEncoded, - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - navigationDelegate: (NavigationRequest request) { - return (request.url.contains('youtube.com')) - ? NavigationDecision.prevent - : NavigationDecision.navigate; - }, - onPageFinished: (String url) => pageLoads.add(url), - ), - ), - ); - - await pageLoads.stream.first; // Wait for initial page load. - final WebViewController controller = await controllerCompleter.future; - await controller - .evaluateJavascript('location.href = "https://www.youtube.com/"'); - - // There should never be any second page load, since our new URL is - // blocked. Still wait for a potential page change for some time in order - // to give the test a chance to fail. - await pageLoads.stream.first - .timeout(const Duration(milliseconds: 500), onTimeout: () => ''); - final String? currentUrl = await controller.currentUrl(); - expect(currentUrl, isNot(contains('youtube.com'))); - }); - - testWidgets('supports asynchronous decisions', (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final StreamController pageLoads = - StreamController.broadcast(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: blankPageEncoded, - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - navigationDelegate: (NavigationRequest request) async { - NavigationDecision decision = NavigationDecision.prevent; - decision = await Future.delayed( - const Duration(milliseconds: 10), - () => NavigationDecision.navigate); - return decision; - }, - onPageFinished: (String url) => pageLoads.add(url), - ), - ), - ); - - await pageLoads.stream.first; // Wait for initial page load. - final WebViewController controller = await controllerCompleter.future; - await controller.evaluateJavascript('location.href = "$secondaryUrl"'); - - await pageLoads.stream.first; // Wait for second page to load. - final String? currentUrl = await controller.currentUrl(); - expect(currentUrl, secondaryUrl); - }); - }); - - testWidgets('launches with gestureNavigationEnabled on iOS', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: SizedBox( - width: 400, - height: 300, - child: WebView( - key: GlobalKey(), - initialUrl: primaryUrl, - gestureNavigationEnabled: true, - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - ), - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - final String? currentUrl = await controller.currentUrl(); - expect(currentUrl, primaryUrl); - }); - - testWidgets('target _blank opens in same window', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final Completer pageLoaded = Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - await controller.evaluateJavascript('window.open("$primaryUrl", "_blank")'); - await pageLoaded.future; - final String? currentUrl = await controller.currentUrl(); - expect(currentUrl, primaryUrl); - }, - // Flaky on Android: https://github.com/flutter/flutter/issues/86757 - skip: Platform.isAndroid && _skipDueToIssue86757); - - // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. - testWidgets( - 'can open new window and go back', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - Completer pageLoaded = Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(); - }, - initialUrl: primaryUrl, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - expect(controller.currentUrl(), completion(primaryUrl)); - await pageLoaded.future; - pageLoaded = Completer(); - - await controller.evaluateJavascript('window.open("$secondaryUrl")'); - await pageLoaded.future; - pageLoaded = Completer(); - expect(controller.currentUrl(), completion(secondaryUrl)); - - expect(controller.canGoBack(), completion(true)); - await controller.goBack(); - await pageLoaded.future; - expect(controller.currentUrl(), completion(primaryUrl)); - }, - skip: _skipDueToIssue86757, - ); - - testWidgets( - 'javascript does not run in parent window', - (WidgetTester tester) async { - final String iframe = ''' - - - '''; - final String iframeTestBase64 = - base64Encode(const Utf8Encoder().convert(iframe)); - - final String openWindowTest = ''' - - - - XSS test - - - - - - '''; - final String openWindowTestBase64 = - base64Encode(const Utf8Encoder().convert(openWindowTest)); - final Completer controllerCompleter = - Completer(); - final Completer pageLoadCompleter = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - initialUrl: - 'data:text/html;charset=utf-8;base64,$openWindowTestBase64', - onPageFinished: (String url) { - pageLoadCompleter.complete(); - }, - ), - ), - ); - - final WebViewController controller = await controllerCompleter.future; - await pageLoadCompleter.future; - - expect(controller.evaluateJavascript('iframeLoaded'), completion('true')); - expect( - controller.evaluateJavascript( - 'document.querySelector("p") && document.querySelector("p").textContent'), - completion('null'), - ); - }, - skip: !Platform.isAndroid, - ); + // + // testWidgets('set custom userAgent', (WidgetTester tester) async { + // final Completer controllerCompleter1 = + // Completer(); + // final GlobalKey _globalKey = GlobalKey(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: _globalKey, + // initialUrl: 'about:blank', + // javascriptMode: JavascriptMode.unrestricted, + // userAgent: 'Custom_User_Agent1', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter1.complete(controller); + // }, + // ), + // ), + // ); + // final WebViewController controller1 = await controllerCompleter1.future; + // final String customUserAgent1 = await _getUserAgent(controller1); + // expect(customUserAgent1, 'Custom_User_Agent1'); + // // rebuild the WebView with a different user agent. + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: _globalKey, + // initialUrl: 'about:blank', + // javascriptMode: JavascriptMode.unrestricted, + // userAgent: 'Custom_User_Agent2', + // ), + // ), + // ); + // + // final String customUserAgent2 = await _getUserAgent(controller1); + // expect(customUserAgent2, 'Custom_User_Agent2'); + // }); + // + // // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. + // testWidgets('use default platform userAgent after webView is rebuilt', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final GlobalKey _globalKey = GlobalKey(); + // // Build the webView with no user agent to get the default platform user agent. + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: _globalKey, + // initialUrl: primaryUrl, + // javascriptMode: JavascriptMode.unrestricted, + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // final String defaultPlatformUserAgent = await _getUserAgent(controller); + // // rebuild the WebView with a custom user agent. + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: _globalKey, + // initialUrl: 'about:blank', + // javascriptMode: JavascriptMode.unrestricted, + // userAgent: 'Custom_User_Agent', + // ), + // ), + // ); + // final String customUserAgent = await _getUserAgent(controller); + // expect(customUserAgent, 'Custom_User_Agent'); + // // rebuilds the WebView with no user agent. + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: _globalKey, + // initialUrl: 'about:blank', + // javascriptMode: JavascriptMode.unrestricted, + // ), + // ), + // ); + // + // final String customUserAgent2 = await _getUserAgent(controller); + // expect(customUserAgent2, defaultPlatformUserAgent); + // }, skip: Platform.isAndroid && _skipDueToIssue86757); + // + // group('Video playback policy', () { + // late String videoTestBase64; + // setUpAll(() async { + // final ByteData videoData = + // await rootBundle.load('assets/sample_video.mp4'); + // final String base64VideoData = + // base64Encode(Uint8List.view(videoData.buffer)); + // final String videoTest = ''' + // + // Video auto play + // + // + // + // + // + // + // '''; + // videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest)); + // }); + // + // testWidgets('Auto media playback', (WidgetTester tester) async { + // Completer controllerCompleter = + // Completer(); + // Completer pageLoaded = Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + // ), + // ), + // ); + // WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + // + // String isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + // + // controllerCompleter = Completer(); + // pageLoaded = Completer(); + // + // // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: + // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + // ), + // ), + // ); + // + // controller = await controllerCompleter.future; + // await pageLoaded.future; + // + // isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(true)); + // }); + // + // testWidgets('Changes to initialMediaPlaybackPolicy are ignored', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // Completer pageLoaded = Completer(); + // + // final GlobalKey key = GlobalKey(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: key, + // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + // + // String isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + // + // pageLoaded = Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: key, + // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: + // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + // ), + // ), + // ); + // + // await controller.reload(); + // + // await pageLoaded.future; + // + // isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + // }); + // + // testWidgets('Video plays inline when allowsInlineMediaPlayback is true', + // (WidgetTester tester) async { + // Completer controllerCompleter = + // Completer(); + // Completer pageLoaded = Completer(); + // Completer videoPlaying = Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // javascriptChannels: { + // JavascriptChannel( + // name: 'VideoTestTime', + // onMessageReceived: (JavascriptMessage message) { + // final double currentTime = double.parse(message.message); + // // Let it play for at least 1 second to make sure the related video's properties are set. + // if (currentTime > 1) { + // videoPlaying.complete(null); + // } + // }, + // ), + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + // allowsInlineMediaPlayback: true, + // ), + // ), + // ); + // WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + // + // // Pump once to trigger the video play. + // await tester.pump(); + // + // // Makes sure we get the correct event that indicates the video is actually playing. + // await videoPlaying.future; + // + // String fullScreen = + // await controller.evaluateJavascript('isFullScreen();'); + // expect(fullScreen, _webviewBool(false)); + // }); + // + // // allowsInlineMediaPlayback is a noop on Android, so it is skipped. + // testWidgets( + // 'Video plays full screen when allowsInlineMediaPlayback is false', + // (WidgetTester tester) async { + // Completer controllerCompleter = + // Completer(); + // Completer pageLoaded = Completer(); + // Completer videoPlaying = Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // javascriptChannels: { + // JavascriptChannel( + // name: 'VideoTestTime', + // onMessageReceived: (JavascriptMessage message) { + // final double currentTime = double.parse(message.message); + // // Let it play for at least 1 second to make sure the related video's properties are set. + // if (currentTime > 1) { + // videoPlaying.complete(null); + // } + // }, + // ), + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + // allowsInlineMediaPlayback: false, + // ), + // ), + // ); + // WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + // + // // Pump once to trigger the video play. + // await tester.pump(); + // + // // Makes sure we get the correct event that indicates the video is actually playing. + // await videoPlaying.future; + // + // String fullScreen = + // await controller.evaluateJavascript('isFullScreen();'); + // expect(fullScreen, _webviewBool(true)); + // }, skip: Platform.isAndroid); + // }); + // + // group('Audio playback policy', () { + // late String audioTestBase64; + // setUpAll(() async { + // final ByteData audioData = + // await rootBundle.load('assets/sample_audio.ogg'); + // final String base64AudioData = + // base64Encode(Uint8List.view(audioData.buffer)); + // final String audioTest = ''' + // + // Audio auto play + // + // + // + // + // + // + // '''; + // audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest)); + // }); + // + // testWidgets('Auto media playback', (WidgetTester tester) async { + // Completer controllerCompleter = + // Completer(); + // Completer pageStarted = Completer(); + // Completer pageLoaded = Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + // ), + // ), + // ); + // WebViewController controller = await controllerCompleter.future; + // await pageStarted.future; + // await pageLoaded.future; + // + // String isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + // + // controllerCompleter = Completer(); + // pageStarted = Completer(); + // pageLoaded = Completer(); + // + // // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: + // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + // ), + // ), + // ); + // + // controller = await controllerCompleter.future; + // await pageStarted.future; + // await pageLoaded.future; + // + // isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(true)); + // }); + // + // testWidgets('Changes to initialMediaPlaybackPolocy are ignored', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // Completer pageStarted = Completer(); + // Completer pageLoaded = Completer(); + // + // final GlobalKey key = GlobalKey(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: key, + // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // await pageStarted.future; + // await pageLoaded.future; + // + // String isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + // + // pageStarted = Completer(); + // pageLoaded = Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: key, + // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: + // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + // ), + // ), + // ); + // + // await controller.reload(); + // + // await pageStarted.future; + // await pageLoaded.future; + // + // isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + // }); + // }); + // + // testWidgets('getTitle', (WidgetTester tester) async { + // final String getTitleTest = ''' + // + // Some title + // + // + // + // + // '''; + // final String getTitleTestBase64 = + // base64Encode(const Utf8Encoder().convert(getTitleTest)); + // final Completer pageStarted = Completer(); + // final Completer pageLoaded = Completer(); + // final Completer controllerCompleter = + // Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // ), + // ), + // ); + // + // final WebViewController controller = await controllerCompleter.future; + // await pageStarted.future; + // await pageLoaded.future; + // + // final String? title = await controller.getTitle(); + // expect(title, 'Some title'); + // }); + + // group('Programmatic Scroll', () { + // // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. + // testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { + // final String scrollTestPage = ''' + // + // + // + // + // + // + //
+ // + // + // '''; + // + // final String scrollTestPageBase64 = + // base64Encode(const Utf8Encoder().convert(scrollTestPage)); + // + // final Completer pageLoaded = Completer(); + // final Completer controllerCompleter = + // Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // initialUrl: + // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // ), + // ), + // ); + // + // final WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + // + // await tester.pumpAndSettle(Duration(seconds: 3)); + // + // int scrollPosX = await controller.getScrollX(); + // int scrollPosY = await controller.getScrollY(); + // + // // Check scrollTo() + // const int X_SCROLL = 123; + // const int Y_SCROLL = 321; + // // Get the initial position; this ensures that scrollTo is actually + // // changing something, but also gives the native view's scroll position + // // time to settle. + // expect(scrollPosX, isNot(X_SCROLL)); + // expect(scrollPosX, isNot(Y_SCROLL)); + // + // await controller.scrollTo(X_SCROLL, Y_SCROLL); + // scrollPosX = await controller.getScrollX(); + // scrollPosY = await controller.getScrollY(); + // expect(scrollPosX, X_SCROLL); + // expect(scrollPosY, Y_SCROLL); + // + // // Check scrollBy() (on top of scrollTo()) + // await controller.scrollBy(X_SCROLL, Y_SCROLL); + // scrollPosX = await controller.getScrollX(); + // scrollPosY = await controller.getScrollY(); + // expect(scrollPosX, X_SCROLL * 2); + // expect(scrollPosY, Y_SCROLL * 2); + // }, skip: Platform.isAndroid && _skipDueToIssue86757); + // }); + // + // group('SurfaceAndroidWebView', () { + // setUpAll(() { + // WebView.platform = SurfaceAndroidWebView(); + // }); + // + // tearDownAll(() { + // WebView.platform = null; + // }); + // + // // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. + // testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { + // final String scrollTestPage = ''' + // + // + // + // + // + // + //
+ // + // + // '''; + // + // final String scrollTestPageBase64 = + // base64Encode(const Utf8Encoder().convert(scrollTestPage)); + // + // final Completer pageLoaded = Completer(); + // final Completer controllerCompleter = + // Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // initialUrl: + // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // ), + // ), + // ); + // + // final WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + // + // await tester.pumpAndSettle(Duration(seconds: 3)); + // + // // Check scrollTo() + // const int X_SCROLL = 123; + // const int Y_SCROLL = 321; + // + // await controller.scrollTo(X_SCROLL, Y_SCROLL); + // int scrollPosX = await controller.getScrollX(); + // int scrollPosY = await controller.getScrollY(); + // expect(X_SCROLL, scrollPosX); + // expect(Y_SCROLL, scrollPosY); + // + // // Check scrollBy() (on top of scrollTo()) + // await controller.scrollBy(X_SCROLL, Y_SCROLL); + // scrollPosX = await controller.getScrollX(); + // scrollPosY = await controller.getScrollY(); + // expect(X_SCROLL * 2, scrollPosX); + // expect(Y_SCROLL * 2, scrollPosY); + // }, skip: !Platform.isAndroid || _skipDueToIssue86757); + // + // // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. + // testWidgets('inputs are scrolled into view when focused', + // (WidgetTester tester) async { + // final String scrollTestPage = ''' + // + // + // + // + // + // + //
+ // + // + // + // '''; + // + // final String scrollTestPageBase64 = + // base64Encode(const Utf8Encoder().convert(scrollTestPage)); + // + // final Completer pageLoaded = Completer(); + // final Completer controllerCompleter = + // Completer(); + // + // await tester.runAsync(() async { + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: SizedBox( + // width: 200, + // height: 200, + // child: WebView( + // initialUrl: + // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // ), + // ), + // ), + // ); + // await Future.delayed(Duration(milliseconds: 20)); + // await tester.pump(); + // }); + // + // final WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + // final String viewportRectJSON = await _evaluateJavascript( + // controller, 'JSON.stringify(viewport.getBoundingClientRect())'); + // final Map viewportRectRelativeToViewport = + // jsonDecode(viewportRectJSON); + // + // // Check that the input is originally outside of the viewport. + // + // final String initialInputClientRectJSON = await _evaluateJavascript( + // controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); + // final Map initialInputClientRectRelativeToViewport = + // jsonDecode(initialInputClientRectJSON); + // + // expect( + // initialInputClientRectRelativeToViewport['bottom'] <= + // viewportRectRelativeToViewport['bottom'], + // isFalse); + // + // await controller.evaluateJavascript('inputEl.focus()'); + // + // // Check that focusing the input brought it into view. + // + // final String lastInputClientRectJSON = await _evaluateJavascript( + // controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); + // final Map lastInputClientRectRelativeToViewport = + // jsonDecode(lastInputClientRectJSON); + // + // expect( + // lastInputClientRectRelativeToViewport['top'] >= + // viewportRectRelativeToViewport['top'], + // isTrue); + // expect( + // lastInputClientRectRelativeToViewport['bottom'] <= + // viewportRectRelativeToViewport['bottom'], + // isTrue); + // + // expect( + // lastInputClientRectRelativeToViewport['left'] >= + // viewportRectRelativeToViewport['left'], + // isTrue); + // expect( + // lastInputClientRectRelativeToViewport['right'] <= + // viewportRectRelativeToViewport['right'], + // isTrue); + // }, skip: !Platform.isAndroid || _skipDueToIssue86757); + // }); + // + // group('NavigationDelegate', () { + // final String blankPage = ""; + // final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,' + + // base64Encode(const Utf8Encoder().convert(blankPage)); + // + // testWidgets('can allow requests', (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final StreamController pageLoads = + // StreamController.broadcast(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: blankPageEncoded, + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // navigationDelegate: (NavigationRequest request) { + // return (request.url.contains('youtube.com')) + // ? NavigationDecision.prevent + // : NavigationDecision.navigate; + // }, + // onPageFinished: (String url) => pageLoads.add(url), + // ), + // ), + // ); + // + // await pageLoads.stream.first; // Wait for initial page load. + // final WebViewController controller = await controllerCompleter.future; + // await controller.evaluateJavascript('location.href = "$secondaryUrl"'); + // + // await pageLoads.stream.first; // Wait for the next page load. + // final String? currentUrl = await controller.currentUrl(); + // expect(currentUrl, secondaryUrl); + // }); + // + // testWidgets('onWebResourceError', (WidgetTester tester) async { + // final Completer errorCompleter = + // Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'https://www.notawebsite..com', + // onWebResourceError: (WebResourceError error) { + // errorCompleter.complete(error); + // }, + // ), + // ), + // ); + // + // final WebResourceError error = await errorCompleter.future; + // expect(error, isNotNull); + // + // if (Platform.isIOS) { + // expect(error.domain, isNotNull); + // expect(error.failingUrl, isNull); + // } else if (Platform.isAndroid) { + // expect(error.errorType, isNotNull); + // expect(error.failingUrl?.startsWith('https://www.notawebsite..com'), + // isTrue); + // } + // }); + // + // testWidgets('onWebResourceError is not called with valid url', + // (WidgetTester tester) async { + // final Completer errorCompleter = + // Completer(); + // final Completer pageFinishCompleter = Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: + // 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', + // onWebResourceError: (WebResourceError error) { + // errorCompleter.complete(error); + // }, + // onPageFinished: (_) => pageFinishCompleter.complete(), + // ), + // ), + // ); + // + // expect(errorCompleter.future, doesNotComplete); + // await pageFinishCompleter.future; + // }); + // + // testWidgets( + // 'onWebResourceError only called for main frame', + // (WidgetTester tester) async { + // final String iframeTest = ''' + // + // + // + // WebResourceError test + // + // + // + // + // + // '''; + // final String iframeTestBase64 = + // base64Encode(const Utf8Encoder().convert(iframeTest)); + // + // final Completer errorCompleter = + // Completer(); + // final Completer pageFinishCompleter = Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: + // 'data:text/html;charset=utf-8;base64,$iframeTestBase64', + // onWebResourceError: (WebResourceError error) { + // errorCompleter.complete(error); + // }, + // onPageFinished: (_) => pageFinishCompleter.complete(), + // ), + // ), + // ); + // + // expect(errorCompleter.future, doesNotComplete); + // await pageFinishCompleter.future; + // }, + // ); + // + // testWidgets('can block requests', (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final StreamController pageLoads = + // StreamController.broadcast(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: blankPageEncoded, + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // navigationDelegate: (NavigationRequest request) { + // return (request.url.contains('youtube.com')) + // ? NavigationDecision.prevent + // : NavigationDecision.navigate; + // }, + // onPageFinished: (String url) => pageLoads.add(url), + // ), + // ), + // ); + // + // await pageLoads.stream.first; // Wait for initial page load. + // final WebViewController controller = await controllerCompleter.future; + // await controller + // .evaluateJavascript('location.href = "https://www.youtube.com/"'); + // + // // There should never be any second page load, since our new URL is + // // blocked. Still wait for a potential page change for some time in order + // // to give the test a chance to fail. + // await pageLoads.stream.first + // .timeout(const Duration(milliseconds: 500), onTimeout: () => ''); + // final String? currentUrl = await controller.currentUrl(); + // expect(currentUrl, isNot(contains('youtube.com'))); + // }); + // + // testWidgets('supports asynchronous decisions', (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final StreamController pageLoads = + // StreamController.broadcast(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: blankPageEncoded, + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // navigationDelegate: (NavigationRequest request) async { + // NavigationDecision decision = NavigationDecision.prevent; + // decision = await Future.delayed( + // const Duration(milliseconds: 10), + // () => NavigationDecision.navigate); + // return decision; + // }, + // onPageFinished: (String url) => pageLoads.add(url), + // ), + // ), + // ); + // + // await pageLoads.stream.first; // Wait for initial page load. + // final WebViewController controller = await controllerCompleter.future; + // await controller.evaluateJavascript('location.href = "$secondaryUrl"'); + // + // await pageLoads.stream.first; // Wait for second page to load. + // final String? currentUrl = await controller.currentUrl(); + // expect(currentUrl, secondaryUrl); + // }); + // }); + // + // testWidgets('launches with gestureNavigationEnabled on iOS', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: SizedBox( + // width: 400, + // height: 300, + // child: WebView( + // key: GlobalKey(), + // initialUrl: primaryUrl, + // gestureNavigationEnabled: true, + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // ), + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // final String? currentUrl = await controller.currentUrl(); + // expect(currentUrl, primaryUrl); + // }); + // + // testWidgets('target _blank opens in same window', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final Completer pageLoaded = Completer(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // await controller.evaluateJavascript('window.open("$primaryUrl", "_blank")'); + // await pageLoaded.future; + // final String? currentUrl = await controller.currentUrl(); + // expect(currentUrl, primaryUrl); + // }, + // // Flaky on Android: https://github.com/flutter/flutter/issues/86757 + // skip: Platform.isAndroid && _skipDueToIssue86757); + // + // // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. + // testWidgets( + // 'can open new window and go back', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // Completer pageLoaded = Completer(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(); + // }, + // initialUrl: primaryUrl, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // expect(controller.currentUrl(), completion(primaryUrl)); + // await pageLoaded.future; + // pageLoaded = Completer(); + // + // await controller.evaluateJavascript('window.open("$secondaryUrl")'); + // await pageLoaded.future; + // pageLoaded = Completer(); + // expect(controller.currentUrl(), completion(secondaryUrl)); + // + // expect(controller.canGoBack(), completion(true)); + // await controller.goBack(); + // await pageLoaded.future; + // expect(controller.currentUrl(), completion(primaryUrl)); + // }, + // skip: _skipDueToIssue86757, + // ); + // + // testWidgets( + // 'javascript does not run in parent window', + // (WidgetTester tester) async { + // final String iframe = ''' + // + // + // '''; + // final String iframeTestBase64 = + // base64Encode(const Utf8Encoder().convert(iframe)); + // + // final String openWindowTest = ''' + // + // + // + // XSS test + // + // + // + // + // + // '''; + // final String openWindowTestBase64 = + // base64Encode(const Utf8Encoder().convert(openWindowTest)); + // final Completer controllerCompleter = + // Completer(); + // final Completer pageLoadCompleter = Completer(); + // + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // initialUrl: + // 'data:text/html;charset=utf-8;base64,$openWindowTestBase64', + // onPageFinished: (String url) { + // pageLoadCompleter.complete(); + // }, + // ), + // ), + // ); + // + // final WebViewController controller = await controllerCompleter.future; + // await pageLoadCompleter.future; + // + // expect(controller.evaluateJavascript('iframeLoaded'), completion('true')); + // expect( + // controller.evaluateJavascript( + // 'document.querySelector("p") && document.querySelector("p").textContent'), + // completion('null'), + // ); + // }, + // skip: !Platform.isAndroid, + // ); } // JavaScript booleans evaluate to different string values on Android and iOS. diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java index bfa7d6f17345..e8b27e250efc 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java @@ -8,6 +8,8 @@ import java.util.HashMap; import java.util.Map; +import io.flutter.Log; + class InstanceManager { private final LongSparseArray instanceIdsToInstances = new LongSparseArray<>(); private final Map instancesToInstanceIds = new HashMap<>(); @@ -29,6 +31,7 @@ void removeInstance(long instanceId) { /** Retrieve the Object paired with instanceId. */ Object getInstance(long instanceId) { + Log.d("HELLLOOOO", "AMOUNT" + instanceIdsToInstances.size() + " " + instancesToInstanceIds.size()); return instanceIdsToInstances.get(instanceId); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java index 2d42d952955c..9fccf909a6ee 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -6,6 +6,8 @@ import android.os.Handler; import android.os.Looper; +import android.webkit.JavascriptInterface; + import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.JavaScriptChannelHostApi { @@ -21,6 +23,7 @@ JavaScriptChannel createJavaScriptChannel( String channelName, Handler platformThreadHandler) { return new JavaScriptChannel(null, channelName, platformThreadHandler) { + @JavascriptInterface @Override public void postMessage(String message) { final Runnable postMessageRunnable = diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index e44f4e73cc58..684c0ecb74bf 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -5,6 +5,7 @@ package io.flutter.plugins.webviewflutter; import android.content.Context; +import android.hardware.display.DisplayManager; import android.view.View; import android.webkit.DownloadListener; import android.webkit.WebChromeClient; @@ -95,10 +96,17 @@ public void onInputConnectionUnlocked() { @Override public void create(Long instanceId, Boolean useHybridComposition) { + DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy(); + DisplayManager displayManager = + (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); + displayListenerProxy.onPreWebViewInitialization(displayManager); + final WebView webView = useHybridComposition ? webViewProxy.createWebView(context) : webViewProxy.createInputAwareWebView(context); + + displayListenerProxy.onPostWebViewInitialization(displayManager); instanceManager.addInstance(webView, instanceId); } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index c74ecb90a2a3..0363af322dcc 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -350,7 +350,7 @@ class JavaScriptChannelHostApiImpl extends JavaScriptChannelHostApi { /// Flutter api implementation for [JavaScriptChannel]. class JavaScriptChannelFlutterApiImpl extends JavaScriptChannelFlutterApi { /// Constructs a [JavaScriptChannelFlutterApiImpl]. - JavaScriptChannelHostApiImpl({InstanceManager? instanceManager}) { + JavaScriptChannelFlutterApiImpl({InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? InstanceManager.instance; } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart b/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart index 927264d4003b..04ad0d401b48 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart @@ -202,7 +202,7 @@ class AndroidWebViewPlatformController extends WebViewPlatformController { return Future.wait( javascriptChannelNames.where( (String channelName) { - return _javaScriptChannels.containsKey(channelName); + return !_javaScriptChannels.containsKey(channelName); }, ).map>( (String channelName) { From b3f3f3cb5adac7ec2376ac450376e61e1a8f9f2f Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 00:39:23 -0700 Subject: [PATCH 34/54] fix infinite bug --- .../webview_flutter_test.dart | 2400 ++++++++--------- .../webviewflutter/InstanceManager.java | 3 - .../webviewflutter/WebViewHostApiImpl.java | 2 +- 3 files changed, 1201 insertions(+), 1204 deletions(-) diff --git a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart index 96f2f67f0685..e93ce43757bc 100644 --- a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -248,1206 +248,1206 @@ void main() { await resizeCompleter.future; }); - // - // testWidgets('set custom userAgent', (WidgetTester tester) async { - // final Completer controllerCompleter1 = - // Completer(); - // final GlobalKey _globalKey = GlobalKey(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: _globalKey, - // initialUrl: 'about:blank', - // javascriptMode: JavascriptMode.unrestricted, - // userAgent: 'Custom_User_Agent1', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter1.complete(controller); - // }, - // ), - // ), - // ); - // final WebViewController controller1 = await controllerCompleter1.future; - // final String customUserAgent1 = await _getUserAgent(controller1); - // expect(customUserAgent1, 'Custom_User_Agent1'); - // // rebuild the WebView with a different user agent. - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: _globalKey, - // initialUrl: 'about:blank', - // javascriptMode: JavascriptMode.unrestricted, - // userAgent: 'Custom_User_Agent2', - // ), - // ), - // ); - // - // final String customUserAgent2 = await _getUserAgent(controller1); - // expect(customUserAgent2, 'Custom_User_Agent2'); - // }); - // - // // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. - // testWidgets('use default platform userAgent after webView is rebuilt', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final GlobalKey _globalKey = GlobalKey(); - // // Build the webView with no user agent to get the default platform user agent. - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: _globalKey, - // initialUrl: primaryUrl, - // javascriptMode: JavascriptMode.unrestricted, - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // final String defaultPlatformUserAgent = await _getUserAgent(controller); - // // rebuild the WebView with a custom user agent. - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: _globalKey, - // initialUrl: 'about:blank', - // javascriptMode: JavascriptMode.unrestricted, - // userAgent: 'Custom_User_Agent', - // ), - // ), - // ); - // final String customUserAgent = await _getUserAgent(controller); - // expect(customUserAgent, 'Custom_User_Agent'); - // // rebuilds the WebView with no user agent. - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: _globalKey, - // initialUrl: 'about:blank', - // javascriptMode: JavascriptMode.unrestricted, - // ), - // ), - // ); - // - // final String customUserAgent2 = await _getUserAgent(controller); - // expect(customUserAgent2, defaultPlatformUserAgent); - // }, skip: Platform.isAndroid && _skipDueToIssue86757); - // - // group('Video playback policy', () { - // late String videoTestBase64; - // setUpAll(() async { - // final ByteData videoData = - // await rootBundle.load('assets/sample_video.mp4'); - // final String base64VideoData = - // base64Encode(Uint8List.view(videoData.buffer)); - // final String videoTest = ''' - // - // Video auto play - // - // - // - // - // - // - // '''; - // videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest)); - // }); - // - // testWidgets('Auto media playback', (WidgetTester tester) async { - // Completer controllerCompleter = - // Completer(); - // Completer pageLoaded = Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - // ), - // ), - // ); - // WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - // - // String isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - // - // controllerCompleter = Completer(); - // pageLoaded = Completer(); - // - // // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: - // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - // ), - // ), - // ); - // - // controller = await controllerCompleter.future; - // await pageLoaded.future; - // - // isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(true)); - // }); - // - // testWidgets('Changes to initialMediaPlaybackPolicy are ignored', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // Completer pageLoaded = Completer(); - // - // final GlobalKey key = GlobalKey(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: key, - // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - // - // String isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - // - // pageLoaded = Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: key, - // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: - // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - // ), - // ), - // ); - // - // await controller.reload(); - // - // await pageLoaded.future; - // - // isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - // }); - // - // testWidgets('Video plays inline when allowsInlineMediaPlayback is true', - // (WidgetTester tester) async { - // Completer controllerCompleter = - // Completer(); - // Completer pageLoaded = Completer(); - // Completer videoPlaying = Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // javascriptChannels: { - // JavascriptChannel( - // name: 'VideoTestTime', - // onMessageReceived: (JavascriptMessage message) { - // final double currentTime = double.parse(message.message); - // // Let it play for at least 1 second to make sure the related video's properties are set. - // if (currentTime > 1) { - // videoPlaying.complete(null); - // } - // }, - // ), - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - // allowsInlineMediaPlayback: true, - // ), - // ), - // ); - // WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - // - // // Pump once to trigger the video play. - // await tester.pump(); - // - // // Makes sure we get the correct event that indicates the video is actually playing. - // await videoPlaying.future; - // - // String fullScreen = - // await controller.evaluateJavascript('isFullScreen();'); - // expect(fullScreen, _webviewBool(false)); - // }); - // - // // allowsInlineMediaPlayback is a noop on Android, so it is skipped. - // testWidgets( - // 'Video plays full screen when allowsInlineMediaPlayback is false', - // (WidgetTester tester) async { - // Completer controllerCompleter = - // Completer(); - // Completer pageLoaded = Completer(); - // Completer videoPlaying = Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // javascriptChannels: { - // JavascriptChannel( - // name: 'VideoTestTime', - // onMessageReceived: (JavascriptMessage message) { - // final double currentTime = double.parse(message.message); - // // Let it play for at least 1 second to make sure the related video's properties are set. - // if (currentTime > 1) { - // videoPlaying.complete(null); - // } - // }, - // ), - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - // allowsInlineMediaPlayback: false, - // ), - // ), - // ); - // WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - // - // // Pump once to trigger the video play. - // await tester.pump(); - // - // // Makes sure we get the correct event that indicates the video is actually playing. - // await videoPlaying.future; - // - // String fullScreen = - // await controller.evaluateJavascript('isFullScreen();'); - // expect(fullScreen, _webviewBool(true)); - // }, skip: Platform.isAndroid); - // }); - // - // group('Audio playback policy', () { - // late String audioTestBase64; - // setUpAll(() async { - // final ByteData audioData = - // await rootBundle.load('assets/sample_audio.ogg'); - // final String base64AudioData = - // base64Encode(Uint8List.view(audioData.buffer)); - // final String audioTest = ''' - // - // Audio auto play - // - // - // - // - // - // - // '''; - // audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest)); - // }); - // - // testWidgets('Auto media playback', (WidgetTester tester) async { - // Completer controllerCompleter = - // Completer(); - // Completer pageStarted = Completer(); - // Completer pageLoaded = Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - // ), - // ), - // ); - // WebViewController controller = await controllerCompleter.future; - // await pageStarted.future; - // await pageLoaded.future; - // - // String isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - // - // controllerCompleter = Completer(); - // pageStarted = Completer(); - // pageLoaded = Completer(); - // - // // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: - // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - // ), - // ), - // ); - // - // controller = await controllerCompleter.future; - // await pageStarted.future; - // await pageLoaded.future; - // - // isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(true)); - // }); - // - // testWidgets('Changes to initialMediaPlaybackPolocy are ignored', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // Completer pageStarted = Completer(); - // Completer pageLoaded = Completer(); - // - // final GlobalKey key = GlobalKey(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: key, - // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // await pageStarted.future; - // await pageLoaded.future; - // - // String isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - // - // pageStarted = Completer(); - // pageLoaded = Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: key, - // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: - // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - // ), - // ), - // ); - // - // await controller.reload(); - // - // await pageStarted.future; - // await pageLoaded.future; - // - // isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - // }); - // }); - // - // testWidgets('getTitle', (WidgetTester tester) async { - // final String getTitleTest = ''' - // - // Some title - // - // - // - // - // '''; - // final String getTitleTestBase64 = - // base64Encode(const Utf8Encoder().convert(getTitleTest)); - // final Completer pageStarted = Completer(); - // final Completer pageLoaded = Completer(); - // final Completer controllerCompleter = - // Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // ), - // ), - // ); - // - // final WebViewController controller = await controllerCompleter.future; - // await pageStarted.future; - // await pageLoaded.future; - // - // final String? title = await controller.getTitle(); - // expect(title, 'Some title'); - // }); - - // group('Programmatic Scroll', () { - // // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. - // testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { - // final String scrollTestPage = ''' - // - // - // - // - // - // - //
- // - // - // '''; - // - // final String scrollTestPageBase64 = - // base64Encode(const Utf8Encoder().convert(scrollTestPage)); - // - // final Completer pageLoaded = Completer(); - // final Completer controllerCompleter = - // Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // initialUrl: - // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // ), - // ), - // ); - // - // final WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - // - // await tester.pumpAndSettle(Duration(seconds: 3)); - // - // int scrollPosX = await controller.getScrollX(); - // int scrollPosY = await controller.getScrollY(); - // - // // Check scrollTo() - // const int X_SCROLL = 123; - // const int Y_SCROLL = 321; - // // Get the initial position; this ensures that scrollTo is actually - // // changing something, but also gives the native view's scroll position - // // time to settle. - // expect(scrollPosX, isNot(X_SCROLL)); - // expect(scrollPosX, isNot(Y_SCROLL)); - // - // await controller.scrollTo(X_SCROLL, Y_SCROLL); - // scrollPosX = await controller.getScrollX(); - // scrollPosY = await controller.getScrollY(); - // expect(scrollPosX, X_SCROLL); - // expect(scrollPosY, Y_SCROLL); - // - // // Check scrollBy() (on top of scrollTo()) - // await controller.scrollBy(X_SCROLL, Y_SCROLL); - // scrollPosX = await controller.getScrollX(); - // scrollPosY = await controller.getScrollY(); - // expect(scrollPosX, X_SCROLL * 2); - // expect(scrollPosY, Y_SCROLL * 2); - // }, skip: Platform.isAndroid && _skipDueToIssue86757); - // }); - // - // group('SurfaceAndroidWebView', () { - // setUpAll(() { - // WebView.platform = SurfaceAndroidWebView(); - // }); - // - // tearDownAll(() { - // WebView.platform = null; - // }); - // - // // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. - // testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { - // final String scrollTestPage = ''' - // - // - // - // - // - // - //
- // - // - // '''; - // - // final String scrollTestPageBase64 = - // base64Encode(const Utf8Encoder().convert(scrollTestPage)); - // - // final Completer pageLoaded = Completer(); - // final Completer controllerCompleter = - // Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // initialUrl: - // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // ), - // ), - // ); - // - // final WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - // - // await tester.pumpAndSettle(Duration(seconds: 3)); - // - // // Check scrollTo() - // const int X_SCROLL = 123; - // const int Y_SCROLL = 321; - // - // await controller.scrollTo(X_SCROLL, Y_SCROLL); - // int scrollPosX = await controller.getScrollX(); - // int scrollPosY = await controller.getScrollY(); - // expect(X_SCROLL, scrollPosX); - // expect(Y_SCROLL, scrollPosY); - // - // // Check scrollBy() (on top of scrollTo()) - // await controller.scrollBy(X_SCROLL, Y_SCROLL); - // scrollPosX = await controller.getScrollX(); - // scrollPosY = await controller.getScrollY(); - // expect(X_SCROLL * 2, scrollPosX); - // expect(Y_SCROLL * 2, scrollPosY); - // }, skip: !Platform.isAndroid || _skipDueToIssue86757); - // - // // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. - // testWidgets('inputs are scrolled into view when focused', - // (WidgetTester tester) async { - // final String scrollTestPage = ''' - // - // - // - // - // - // - //
- // - // - // - // '''; - // - // final String scrollTestPageBase64 = - // base64Encode(const Utf8Encoder().convert(scrollTestPage)); - // - // final Completer pageLoaded = Completer(); - // final Completer controllerCompleter = - // Completer(); - // - // await tester.runAsync(() async { - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: SizedBox( - // width: 200, - // height: 200, - // child: WebView( - // initialUrl: - // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // ), - // ), - // ), - // ); - // await Future.delayed(Duration(milliseconds: 20)); - // await tester.pump(); - // }); - // - // final WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - // final String viewportRectJSON = await _evaluateJavascript( - // controller, 'JSON.stringify(viewport.getBoundingClientRect())'); - // final Map viewportRectRelativeToViewport = - // jsonDecode(viewportRectJSON); - // - // // Check that the input is originally outside of the viewport. - // - // final String initialInputClientRectJSON = await _evaluateJavascript( - // controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); - // final Map initialInputClientRectRelativeToViewport = - // jsonDecode(initialInputClientRectJSON); - // - // expect( - // initialInputClientRectRelativeToViewport['bottom'] <= - // viewportRectRelativeToViewport['bottom'], - // isFalse); - // - // await controller.evaluateJavascript('inputEl.focus()'); - // - // // Check that focusing the input brought it into view. - // - // final String lastInputClientRectJSON = await _evaluateJavascript( - // controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); - // final Map lastInputClientRectRelativeToViewport = - // jsonDecode(lastInputClientRectJSON); - // - // expect( - // lastInputClientRectRelativeToViewport['top'] >= - // viewportRectRelativeToViewport['top'], - // isTrue); - // expect( - // lastInputClientRectRelativeToViewport['bottom'] <= - // viewportRectRelativeToViewport['bottom'], - // isTrue); - // - // expect( - // lastInputClientRectRelativeToViewport['left'] >= - // viewportRectRelativeToViewport['left'], - // isTrue); - // expect( - // lastInputClientRectRelativeToViewport['right'] <= - // viewportRectRelativeToViewport['right'], - // isTrue); - // }, skip: !Platform.isAndroid || _skipDueToIssue86757); - // }); - // - // group('NavigationDelegate', () { - // final String blankPage = ""; - // final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,' + - // base64Encode(const Utf8Encoder().convert(blankPage)); - // - // testWidgets('can allow requests', (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final StreamController pageLoads = - // StreamController.broadcast(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: blankPageEncoded, - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // navigationDelegate: (NavigationRequest request) { - // return (request.url.contains('youtube.com')) - // ? NavigationDecision.prevent - // : NavigationDecision.navigate; - // }, - // onPageFinished: (String url) => pageLoads.add(url), - // ), - // ), - // ); - // - // await pageLoads.stream.first; // Wait for initial page load. - // final WebViewController controller = await controllerCompleter.future; - // await controller.evaluateJavascript('location.href = "$secondaryUrl"'); - // - // await pageLoads.stream.first; // Wait for the next page load. - // final String? currentUrl = await controller.currentUrl(); - // expect(currentUrl, secondaryUrl); - // }); - // - // testWidgets('onWebResourceError', (WidgetTester tester) async { - // final Completer errorCompleter = - // Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'https://www.notawebsite..com', - // onWebResourceError: (WebResourceError error) { - // errorCompleter.complete(error); - // }, - // ), - // ), - // ); - // - // final WebResourceError error = await errorCompleter.future; - // expect(error, isNotNull); - // - // if (Platform.isIOS) { - // expect(error.domain, isNotNull); - // expect(error.failingUrl, isNull); - // } else if (Platform.isAndroid) { - // expect(error.errorType, isNotNull); - // expect(error.failingUrl?.startsWith('https://www.notawebsite..com'), - // isTrue); - // } - // }); - // - // testWidgets('onWebResourceError is not called with valid url', - // (WidgetTester tester) async { - // final Completer errorCompleter = - // Completer(); - // final Completer pageFinishCompleter = Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: - // 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', - // onWebResourceError: (WebResourceError error) { - // errorCompleter.complete(error); - // }, - // onPageFinished: (_) => pageFinishCompleter.complete(), - // ), - // ), - // ); - // - // expect(errorCompleter.future, doesNotComplete); - // await pageFinishCompleter.future; - // }); - // - // testWidgets( - // 'onWebResourceError only called for main frame', - // (WidgetTester tester) async { - // final String iframeTest = ''' - // - // - // - // WebResourceError test - // - // - // - // - // - // '''; - // final String iframeTestBase64 = - // base64Encode(const Utf8Encoder().convert(iframeTest)); - // - // final Completer errorCompleter = - // Completer(); - // final Completer pageFinishCompleter = Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: - // 'data:text/html;charset=utf-8;base64,$iframeTestBase64', - // onWebResourceError: (WebResourceError error) { - // errorCompleter.complete(error); - // }, - // onPageFinished: (_) => pageFinishCompleter.complete(), - // ), - // ), - // ); - // - // expect(errorCompleter.future, doesNotComplete); - // await pageFinishCompleter.future; - // }, - // ); - // - // testWidgets('can block requests', (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final StreamController pageLoads = - // StreamController.broadcast(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: blankPageEncoded, - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // navigationDelegate: (NavigationRequest request) { - // return (request.url.contains('youtube.com')) - // ? NavigationDecision.prevent - // : NavigationDecision.navigate; - // }, - // onPageFinished: (String url) => pageLoads.add(url), - // ), - // ), - // ); - // - // await pageLoads.stream.first; // Wait for initial page load. - // final WebViewController controller = await controllerCompleter.future; - // await controller - // .evaluateJavascript('location.href = "https://www.youtube.com/"'); - // - // // There should never be any second page load, since our new URL is - // // blocked. Still wait for a potential page change for some time in order - // // to give the test a chance to fail. - // await pageLoads.stream.first - // .timeout(const Duration(milliseconds: 500), onTimeout: () => ''); - // final String? currentUrl = await controller.currentUrl(); - // expect(currentUrl, isNot(contains('youtube.com'))); - // }); - // - // testWidgets('supports asynchronous decisions', (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final StreamController pageLoads = - // StreamController.broadcast(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: blankPageEncoded, - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // navigationDelegate: (NavigationRequest request) async { - // NavigationDecision decision = NavigationDecision.prevent; - // decision = await Future.delayed( - // const Duration(milliseconds: 10), - // () => NavigationDecision.navigate); - // return decision; - // }, - // onPageFinished: (String url) => pageLoads.add(url), - // ), - // ), - // ); - // - // await pageLoads.stream.first; // Wait for initial page load. - // final WebViewController controller = await controllerCompleter.future; - // await controller.evaluateJavascript('location.href = "$secondaryUrl"'); - // - // await pageLoads.stream.first; // Wait for second page to load. - // final String? currentUrl = await controller.currentUrl(); - // expect(currentUrl, secondaryUrl); - // }); - // }); - // - // testWidgets('launches with gestureNavigationEnabled on iOS', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: SizedBox( - // width: 400, - // height: 300, - // child: WebView( - // key: GlobalKey(), - // initialUrl: primaryUrl, - // gestureNavigationEnabled: true, - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // ), - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // final String? currentUrl = await controller.currentUrl(); - // expect(currentUrl, primaryUrl); - // }); - // - // testWidgets('target _blank opens in same window', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final Completer pageLoaded = Completer(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // await controller.evaluateJavascript('window.open("$primaryUrl", "_blank")'); - // await pageLoaded.future; - // final String? currentUrl = await controller.currentUrl(); - // expect(currentUrl, primaryUrl); - // }, - // // Flaky on Android: https://github.com/flutter/flutter/issues/86757 - // skip: Platform.isAndroid && _skipDueToIssue86757); - // - // // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. - // testWidgets( - // 'can open new window and go back', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // Completer pageLoaded = Completer(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(); - // }, - // initialUrl: primaryUrl, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // expect(controller.currentUrl(), completion(primaryUrl)); - // await pageLoaded.future; - // pageLoaded = Completer(); - // - // await controller.evaluateJavascript('window.open("$secondaryUrl")'); - // await pageLoaded.future; - // pageLoaded = Completer(); - // expect(controller.currentUrl(), completion(secondaryUrl)); - // - // expect(controller.canGoBack(), completion(true)); - // await controller.goBack(); - // await pageLoaded.future; - // expect(controller.currentUrl(), completion(primaryUrl)); - // }, - // skip: _skipDueToIssue86757, - // ); - // - // testWidgets( - // 'javascript does not run in parent window', - // (WidgetTester tester) async { - // final String iframe = ''' - // - // - // '''; - // final String iframeTestBase64 = - // base64Encode(const Utf8Encoder().convert(iframe)); - // - // final String openWindowTest = ''' - // - // - // - // XSS test - // - // - // - // - // - // '''; - // final String openWindowTestBase64 = - // base64Encode(const Utf8Encoder().convert(openWindowTest)); - // final Completer controllerCompleter = - // Completer(); - // final Completer pageLoadCompleter = Completer(); - // - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // initialUrl: - // 'data:text/html;charset=utf-8;base64,$openWindowTestBase64', - // onPageFinished: (String url) { - // pageLoadCompleter.complete(); - // }, - // ), - // ), - // ); - // - // final WebViewController controller = await controllerCompleter.future; - // await pageLoadCompleter.future; - // - // expect(controller.evaluateJavascript('iframeLoaded'), completion('true')); - // expect( - // controller.evaluateJavascript( - // 'document.querySelector("p") && document.querySelector("p").textContent'), - // completion('null'), - // ); - // }, - // skip: !Platform.isAndroid, - // ); + + testWidgets('set custom userAgent', (WidgetTester tester) async { + final Completer controllerCompleter1 = + Completer(); + final GlobalKey _globalKey = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: _globalKey, + initialUrl: 'about:blank', + javascriptMode: JavascriptMode.unrestricted, + userAgent: 'Custom_User_Agent1', + onWebViewCreated: (WebViewController controller) { + controllerCompleter1.complete(controller); + }, + ), + ), + ); + final WebViewController controller1 = await controllerCompleter1.future; + final String customUserAgent1 = await _getUserAgent(controller1); + expect(customUserAgent1, 'Custom_User_Agent1'); + // rebuild the WebView with a different user agent. + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: _globalKey, + initialUrl: 'about:blank', + javascriptMode: JavascriptMode.unrestricted, + userAgent: 'Custom_User_Agent2', + ), + ), + ); + + final String customUserAgent2 = await _getUserAgent(controller1); + expect(customUserAgent2, 'Custom_User_Agent2'); + }); + + // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. + testWidgets('use default platform userAgent after webView is rebuilt', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final GlobalKey _globalKey = GlobalKey(); + // Build the webView with no user agent to get the default platform user agent. + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: _globalKey, + initialUrl: primaryUrl, + javascriptMode: JavascriptMode.unrestricted, + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + final String defaultPlatformUserAgent = await _getUserAgent(controller); + // rebuild the WebView with a custom user agent. + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: _globalKey, + initialUrl: 'about:blank', + javascriptMode: JavascriptMode.unrestricted, + userAgent: 'Custom_User_Agent', + ), + ), + ); + final String customUserAgent = await _getUserAgent(controller); + expect(customUserAgent, 'Custom_User_Agent'); + // rebuilds the WebView with no user agent. + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: _globalKey, + initialUrl: 'about:blank', + javascriptMode: JavascriptMode.unrestricted, + ), + ), + ); + + final String customUserAgent2 = await _getUserAgent(controller); + expect(customUserAgent2, defaultPlatformUserAgent); + }, skip: Platform.isAndroid && _skipDueToIssue86757); + + group('Video playback policy', () { + late String videoTestBase64; + setUpAll(() async { + final ByteData videoData = + await rootBundle.load('assets/sample_video.mp4'); + final String base64VideoData = + base64Encode(Uint8List.view(videoData.buffer)); + final String videoTest = ''' + + Video auto play + + + + + + + '''; + videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest)); + }); + + testWidgets('Auto media playback', (WidgetTester tester) async { + Completer controllerCompleter = + Completer(); + Completer pageLoaded = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + ), + ), + ); + WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + String isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + + controllerCompleter = Completer(); + pageLoaded = Completer(); + + // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: + AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + ), + ), + ); + + controller = await controllerCompleter.future; + await pageLoaded.future; + + isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(true)); + }); + + testWidgets('Changes to initialMediaPlaybackPolicy are ignored', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + Completer pageLoaded = Completer(); + + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: key, + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + String isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + + pageLoaded = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: key, + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: + AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + ), + ), + ); + + await controller.reload(); + + await pageLoaded.future; + + isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + }); + + testWidgets('Video plays inline when allowsInlineMediaPlayback is true', + (WidgetTester tester) async { + Completer controllerCompleter = + Completer(); + Completer pageLoaded = Completer(); + Completer videoPlaying = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + javascriptChannels: { + JavascriptChannel( + name: 'VideoTestTime', + onMessageReceived: (JavascriptMessage message) { + final double currentTime = double.parse(message.message); + // Let it play for at least 1 second to make sure the related video's properties are set. + if (currentTime > 1) { + videoPlaying.complete(null); + } + }, + ), + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + allowsInlineMediaPlayback: true, + ), + ), + ); + WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + // Pump once to trigger the video play. + await tester.pump(); + + // Makes sure we get the correct event that indicates the video is actually playing. + await videoPlaying.future; + + String fullScreen = + await controller.evaluateJavascript('isFullScreen();'); + expect(fullScreen, _webviewBool(false)); + }); + + // allowsInlineMediaPlayback is a noop on Android, so it is skipped. + testWidgets( + 'Video plays full screen when allowsInlineMediaPlayback is false', + (WidgetTester tester) async { + Completer controllerCompleter = + Completer(); + Completer pageLoaded = Completer(); + Completer videoPlaying = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + javascriptChannels: { + JavascriptChannel( + name: 'VideoTestTime', + onMessageReceived: (JavascriptMessage message) { + final double currentTime = double.parse(message.message); + // Let it play for at least 1 second to make sure the related video's properties are set. + if (currentTime > 1) { + videoPlaying.complete(null); + } + }, + ), + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + allowsInlineMediaPlayback: false, + ), + ), + ); + WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + // Pump once to trigger the video play. + await tester.pump(); + + // Makes sure we get the correct event that indicates the video is actually playing. + await videoPlaying.future; + + String fullScreen = + await controller.evaluateJavascript('isFullScreen();'); + expect(fullScreen, _webviewBool(true)); + }, skip: Platform.isAndroid); + }); + + group('Audio playback policy', () { + late String audioTestBase64; + setUpAll(() async { + final ByteData audioData = + await rootBundle.load('assets/sample_audio.ogg'); + final String base64AudioData = + base64Encode(Uint8List.view(audioData.buffer)); + final String audioTest = ''' + + Audio auto play + + + + + + + '''; + audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest)); + }); + + testWidgets('Auto media playback', (WidgetTester tester) async { + Completer controllerCompleter = + Completer(); + Completer pageStarted = Completer(); + Completer pageLoaded = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + ), + ), + ); + WebViewController controller = await controllerCompleter.future; + await pageStarted.future; + await pageLoaded.future; + + String isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + + controllerCompleter = Completer(); + pageStarted = Completer(); + pageLoaded = Completer(); + + // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: + AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + ), + ), + ); + + controller = await controllerCompleter.future; + await pageStarted.future; + await pageLoaded.future; + + isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(true)); + }); + + testWidgets('Changes to initialMediaPlaybackPolocy are ignored', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + Completer pageStarted = Completer(); + Completer pageLoaded = Completer(); + + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: key, + initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + await pageStarted.future; + await pageLoaded.future; + + String isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + + pageStarted = Completer(); + pageLoaded = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: key, + initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: + AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + ), + ), + ); + + await controller.reload(); + + await pageStarted.future; + await pageLoaded.future; + + isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + }); + }); + + testWidgets('getTitle', (WidgetTester tester) async { + final String getTitleTest = ''' + + Some title + + + + + '''; + final String getTitleTestBase64 = + base64Encode(const Utf8Encoder().convert(getTitleTest)); + final Completer pageStarted = Completer(); + final Completer pageLoaded = Completer(); + final Completer controllerCompleter = + Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + ), + ), + ); + + final WebViewController controller = await controllerCompleter.future; + await pageStarted.future; + await pageLoaded.future; + + final String? title = await controller.getTitle(); + expect(title, 'Some title'); + }); + + group('Programmatic Scroll', () { + // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. + testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { + final String scrollTestPage = ''' + + + + + + +
+ + + '''; + + final String scrollTestPageBase64 = + base64Encode(const Utf8Encoder().convert(scrollTestPage)); + + final Completer pageLoaded = Completer(); + final Completer controllerCompleter = + Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + initialUrl: + 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + ), + ), + ); + + final WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + await tester.pumpAndSettle(Duration(seconds: 3)); + + int scrollPosX = await controller.getScrollX(); + int scrollPosY = await controller.getScrollY(); + + // Check scrollTo() + const int X_SCROLL = 123; + const int Y_SCROLL = 321; + // Get the initial position; this ensures that scrollTo is actually + // changing something, but also gives the native view's scroll position + // time to settle. + expect(scrollPosX, isNot(X_SCROLL)); + expect(scrollPosX, isNot(Y_SCROLL)); + + await controller.scrollTo(X_SCROLL, Y_SCROLL); + scrollPosX = await controller.getScrollX(); + scrollPosY = await controller.getScrollY(); + expect(scrollPosX, X_SCROLL); + expect(scrollPosY, Y_SCROLL); + + // Check scrollBy() (on top of scrollTo()) + await controller.scrollBy(X_SCROLL, Y_SCROLL); + scrollPosX = await controller.getScrollX(); + scrollPosY = await controller.getScrollY(); + expect(scrollPosX, X_SCROLL * 2); + expect(scrollPosY, Y_SCROLL * 2); + }, skip: Platform.isAndroid && _skipDueToIssue86757); + }); + + group('SurfaceAndroidWebView', () { + setUpAll(() { + WebView.platform = SurfaceAndroidWebView(); + }); + + tearDownAll(() { + WebView.platform = null; + }); + + // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. + testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { + final String scrollTestPage = ''' + + + + + + +
+ + + '''; + + final String scrollTestPageBase64 = + base64Encode(const Utf8Encoder().convert(scrollTestPage)); + + final Completer pageLoaded = Completer(); + final Completer controllerCompleter = + Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + initialUrl: + 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + ), + ), + ); + + final WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + await tester.pumpAndSettle(Duration(seconds: 3)); + + // Check scrollTo() + const int X_SCROLL = 123; + const int Y_SCROLL = 321; + + await controller.scrollTo(X_SCROLL, Y_SCROLL); + int scrollPosX = await controller.getScrollX(); + int scrollPosY = await controller.getScrollY(); + expect(X_SCROLL, scrollPosX); + expect(Y_SCROLL, scrollPosY); + + // Check scrollBy() (on top of scrollTo()) + await controller.scrollBy(X_SCROLL, Y_SCROLL); + scrollPosX = await controller.getScrollX(); + scrollPosY = await controller.getScrollY(); + expect(X_SCROLL * 2, scrollPosX); + expect(Y_SCROLL * 2, scrollPosY); + }, skip: !Platform.isAndroid || _skipDueToIssue86757); + + // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. + testWidgets('inputs are scrolled into view when focused', + (WidgetTester tester) async { + final String scrollTestPage = ''' + + + + + + +
+ + + + '''; + + final String scrollTestPageBase64 = + base64Encode(const Utf8Encoder().convert(scrollTestPage)); + + final Completer pageLoaded = Completer(); + final Completer controllerCompleter = + Completer(); + + await tester.runAsync(() async { + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: SizedBox( + width: 200, + height: 200, + child: WebView( + initialUrl: + 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + javascriptMode: JavascriptMode.unrestricted, + ), + ), + ), + ); + await Future.delayed(Duration(milliseconds: 20)); + await tester.pump(); + }); + + final WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + final String viewportRectJSON = await _evaluateJavascript( + controller, 'JSON.stringify(viewport.getBoundingClientRect())'); + final Map viewportRectRelativeToViewport = + jsonDecode(viewportRectJSON); + + // Check that the input is originally outside of the viewport. + + final String initialInputClientRectJSON = await _evaluateJavascript( + controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); + final Map initialInputClientRectRelativeToViewport = + jsonDecode(initialInputClientRectJSON); + + expect( + initialInputClientRectRelativeToViewport['bottom'] <= + viewportRectRelativeToViewport['bottom'], + isFalse); + + await controller.evaluateJavascript('inputEl.focus()'); + + // Check that focusing the input brought it into view. + + final String lastInputClientRectJSON = await _evaluateJavascript( + controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); + final Map lastInputClientRectRelativeToViewport = + jsonDecode(lastInputClientRectJSON); + + expect( + lastInputClientRectRelativeToViewport['top'] >= + viewportRectRelativeToViewport['top'], + isTrue); + expect( + lastInputClientRectRelativeToViewport['bottom'] <= + viewportRectRelativeToViewport['bottom'], + isTrue); + + expect( + lastInputClientRectRelativeToViewport['left'] >= + viewportRectRelativeToViewport['left'], + isTrue); + expect( + lastInputClientRectRelativeToViewport['right'] <= + viewportRectRelativeToViewport['right'], + isTrue); + }, skip: !Platform.isAndroid || _skipDueToIssue86757); + }); + + group('NavigationDelegate', () { + final String blankPage = ""; + final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,' + + base64Encode(const Utf8Encoder().convert(blankPage)); + + testWidgets('can allow requests', (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final StreamController pageLoads = + StreamController.broadcast(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: blankPageEncoded, + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + navigationDelegate: (NavigationRequest request) { + return (request.url.contains('youtube.com')) + ? NavigationDecision.prevent + : NavigationDecision.navigate; + }, + onPageFinished: (String url) => pageLoads.add(url), + ), + ), + ); + + await pageLoads.stream.first; // Wait for initial page load. + final WebViewController controller = await controllerCompleter.future; + await controller.evaluateJavascript('location.href = "$secondaryUrl"'); + + await pageLoads.stream.first; // Wait for the next page load. + final String? currentUrl = await controller.currentUrl(); + expect(currentUrl, secondaryUrl); + }); + + testWidgets('onWebResourceError', (WidgetTester tester) async { + final Completer errorCompleter = + Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'https://www.notawebsite..com', + onWebResourceError: (WebResourceError error) { + errorCompleter.complete(error); + }, + ), + ), + ); + + final WebResourceError error = await errorCompleter.future; + expect(error, isNotNull); + + if (Platform.isIOS) { + expect(error.domain, isNotNull); + expect(error.failingUrl, isNull); + } else if (Platform.isAndroid) { + expect(error.errorType, isNotNull); + expect(error.failingUrl?.startsWith('https://www.notawebsite..com'), + isTrue); + } + }); + + testWidgets('onWebResourceError is not called with valid url', + (WidgetTester tester) async { + final Completer errorCompleter = + Completer(); + final Completer pageFinishCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: + 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', + onWebResourceError: (WebResourceError error) { + errorCompleter.complete(error); + }, + onPageFinished: (_) => pageFinishCompleter.complete(), + ), + ), + ); + + expect(errorCompleter.future, doesNotComplete); + await pageFinishCompleter.future; + }); + + testWidgets( + 'onWebResourceError only called for main frame', + (WidgetTester tester) async { + final String iframeTest = ''' + + + + WebResourceError test + + + + + + '''; + final String iframeTestBase64 = + base64Encode(const Utf8Encoder().convert(iframeTest)); + + final Completer errorCompleter = + Completer(); + final Completer pageFinishCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: + 'data:text/html;charset=utf-8;base64,$iframeTestBase64', + onWebResourceError: (WebResourceError error) { + errorCompleter.complete(error); + }, + onPageFinished: (_) => pageFinishCompleter.complete(), + ), + ), + ); + + expect(errorCompleter.future, doesNotComplete); + await pageFinishCompleter.future; + }, skip: true, + ); + + testWidgets('can block requests', (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final StreamController pageLoads = + StreamController.broadcast(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: blankPageEncoded, + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + navigationDelegate: (NavigationRequest request) { + return (request.url.contains('youtube.com')) + ? NavigationDecision.prevent + : NavigationDecision.navigate; + }, + onPageFinished: (String url) => pageLoads.add(url), + ), + ), + ); + + await pageLoads.stream.first; // Wait for initial page load. + final WebViewController controller = await controllerCompleter.future; + await controller + .evaluateJavascript('location.href = "https://www.youtube.com/"'); + + // There should never be any second page load, since our new URL is + // blocked. Still wait for a potential page change for some time in order + // to give the test a chance to fail. + await pageLoads.stream.first + .timeout(const Duration(milliseconds: 500), onTimeout: () => ''); + final String? currentUrl = await controller.currentUrl(); + expect(currentUrl, isNot(contains('youtube.com'))); + }); + + testWidgets('supports asynchronous decisions', (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final StreamController pageLoads = + StreamController.broadcast(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: blankPageEncoded, + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + navigationDelegate: (NavigationRequest request) async { + NavigationDecision decision = NavigationDecision.prevent; + decision = await Future.delayed( + const Duration(milliseconds: 10), + () => NavigationDecision.navigate); + return decision; + }, + onPageFinished: (String url) => pageLoads.add(url), + ), + ), + ); + + await pageLoads.stream.first; // Wait for initial page load. + final WebViewController controller = await controllerCompleter.future; + await controller.evaluateJavascript('location.href = "$secondaryUrl"'); + + await pageLoads.stream.first; // Wait for second page to load. + final String? currentUrl = await controller.currentUrl(); + expect(currentUrl, secondaryUrl); + }); + }); + + testWidgets('launches with gestureNavigationEnabled on iOS', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: SizedBox( + width: 400, + height: 300, + child: WebView( + key: GlobalKey(), + initialUrl: primaryUrl, + gestureNavigationEnabled: true, + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + final String? currentUrl = await controller.currentUrl(); + expect(currentUrl, primaryUrl); + }); + + testWidgets('target _blank opens in same window', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final Completer pageLoaded = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + await controller.evaluateJavascript('window.open("$primaryUrl", "_blank")'); + await pageLoaded.future; + final String? currentUrl = await controller.currentUrl(); + expect(currentUrl, primaryUrl); + }, + // Flaky on Android: https://github.com/flutter/flutter/issues/86757 + skip: Platform.isAndroid && _skipDueToIssue86757); + + // TODO(bparrishMines): skipped due to https://github.com/flutter/flutter/issues/86757. + testWidgets( + 'can open new window and go back', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + Completer pageLoaded = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(); + }, + initialUrl: primaryUrl, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + expect(controller.currentUrl(), completion(primaryUrl)); + await pageLoaded.future; + pageLoaded = Completer(); + + await controller.evaluateJavascript('window.open("$secondaryUrl")'); + await pageLoaded.future; + pageLoaded = Completer(); + expect(controller.currentUrl(), completion(secondaryUrl)); + + expect(controller.canGoBack(), completion(true)); + await controller.goBack(); + await pageLoaded.future; + expect(controller.currentUrl(), completion(primaryUrl)); + }, + skip: _skipDueToIssue86757, + ); + + testWidgets( + 'javascript does not run in parent window', + (WidgetTester tester) async { + final String iframe = ''' + + + '''; + final String iframeTestBase64 = + base64Encode(const Utf8Encoder().convert(iframe)); + + final String openWindowTest = ''' + + + + XSS test + + + + + + '''; + final String openWindowTestBase64 = + base64Encode(const Utf8Encoder().convert(openWindowTest)); + final Completer controllerCompleter = + Completer(); + final Completer pageLoadCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + initialUrl: + 'data:text/html;charset=utf-8;base64,$openWindowTestBase64', + onPageFinished: (String url) { + pageLoadCompleter.complete(); + }, + ), + ), + ); + + final WebViewController controller = await controllerCompleter.future; + await pageLoadCompleter.future; + + expect(controller.evaluateJavascript('iframeLoaded'), completion('true')); + expect( + controller.evaluateJavascript( + 'document.querySelector("p") && document.querySelector("p").textContent'), + completion('null'), + ); + }, + skip: !Platform.isAndroid, + ); } // JavaScript booleans evaluate to different string values on Android and iOS. diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java index e8b27e250efc..bfa7d6f17345 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java @@ -8,8 +8,6 @@ import java.util.HashMap; import java.util.Map; -import io.flutter.Log; - class InstanceManager { private final LongSparseArray instanceIdsToInstances = new LongSparseArray<>(); private final Map instancesToInstanceIds = new HashMap<>(); @@ -31,7 +29,6 @@ void removeInstance(long instanceId) { /** Retrieve the Object paired with instanceId. */ Object getInstance(long instanceId) { - Log.d("HELLLOOOO", "AMOUNT" + instanceIdsToInstances.size() + " " + instancesToInstanceIds.size()); return instanceIdsToInstances.get(instanceId); } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index 684c0ecb74bf..75da8c7a7632 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -73,7 +73,7 @@ public void onFlutterViewDetached() { @Override public void dispose() { - dispose(); + super.dispose(); destroy(); } From 1a9bc3adb7dbb9f4490c586fcada3ad7d218ad4a Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 00:39:57 -0700 Subject: [PATCH 35/54] resort test file --- .../example/integration_test/webview_flutter_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart index e93ce43757bc..3379bafa2346 100644 --- a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -1206,7 +1206,7 @@ void main() { expect(errorCompleter.future, doesNotComplete); await pageFinishCompleter.future; - }, skip: true, + }, ); testWidgets('can block requests', (WidgetTester tester) async { From 8935f17f7978e29876d3954d0253464e0292fffb Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 00:53:35 -0700 Subject: [PATCH 36/54] fix rest of the bugs and revert pubspec --- .../webview_flutter/webview_flutter/pubspec.yaml | 3 +-- .../JavaScriptChannelHostApiImpl.java | 1 - .../lib/src/webview_widget.dart | 16 ++++++++++------ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml index fb015309b1c2..4206789cb1b3 100644 --- a/packages/webview_flutter/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter/pubspec.yaml @@ -20,8 +20,7 @@ dependencies: flutter: sdk: flutter webview_flutter_platform_interface: ^1.0.0 - webview_flutter_android: - path: ../webview_flutter_android + webview_flutter_android: ^2.0.13 webview_flutter_wkwebview: ^2.0.13 dev_dependencies: diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java index 9fccf909a6ee..e146a9fb40b6 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -7,7 +7,6 @@ import android.os.Handler; import android.os.Looper; import android.webkit.JavascriptInterface; - import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.JavaScriptChannelHostApi { diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart b/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart index 04ad0d401b48..aed093e7a4bf 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart @@ -285,6 +285,8 @@ class AndroidWebViewPlatformController extends WebViewPlatformController { if (userAgent.isPresent && userAgent.value != null) { return webView.settings.setUserAgentString(userAgent.value!); } + + return webView.settings.setUserAgentString(''); } } @@ -420,12 +422,14 @@ class _WebViewClientImpl extends android_webview.WebViewClient { android_webview.WebResourceRequest request, android_webview.WebResourceError error, ) { - callbacksHandler.onWebResourceError(WebResourceError( - errorCode: error.errorCode, - description: error.description, - failingUrl: request.url, - errorType: _errorCodeToErrorType(error.errorCode), - )); + if (request.isForMainFrame) { + callbacksHandler.onWebResourceError(WebResourceError( + errorCode: error.errorCode, + description: error.description, + failingUrl: request.url, + errorType: _errorCodeToErrorType(error.errorCode), + )); + } } @override From 1ba39737f69cc1e14cfd977ef138d5d0e4d160ff Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 09:53:01 -0700 Subject: [PATCH 37/54] bersion vump --- .../webview_flutter/webview_flutter_android/CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index d4827a71e47d..432229270382 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,10 +1,14 @@ +## NEXT + +* Replace platform implementation with API build with pigeon. + ## 2.0.15 * Added Overrides in FlutterWebView.java ## 2.0.14 -* Update example App so navigation menu loads immediatly but only becomes available when `WebViewController` is available (same behavior as example App in webview_flutter package). +* Update example App so navigation menu loads immediately but only becomes available when `WebViewController` is available (same behavior as example App in webview_flutter package). ## 2.0.13 From 5fcb8783cd469b130fe5c07a7ff13a6814ff6f23 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 09:54:32 -0700 Subject: [PATCH 38/54] change dependency for testing --- packages/webview_flutter/webview_flutter/pubspec.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml index dabfe0d0d14a..2718257d98d5 100644 --- a/packages/webview_flutter/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter/pubspec.yaml @@ -20,7 +20,9 @@ dependencies: flutter: sdk: flutter webview_flutter_platform_interface: ^1.0.0 - webview_flutter_android: ^2.0.13 + # TODO(bparrishMines): Don't commit. Undo after tests pass. + webview_flutter_android: + path: ../webview_flutter_android webview_flutter_wkwebview: ^2.0.13 dev_dependencies: From 0c123e83fa2f5ae451c67f1c28b0a318056195e3 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 09:58:37 -0700 Subject: [PATCH 39/54] setup plugin again after reattached --- .../plugins/webviewflutter/WebViewFlutterPlugin.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java index aa0ed84fddfc..6acee703e487 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java @@ -127,7 +127,12 @@ public void onDetachedFromActivityForConfigChanges() {} @Override public void onReattachedToActivityForConfigChanges( - @NonNull ActivityPluginBinding activityPluginBinding) {} + @NonNull ActivityPluginBinding activityPluginBinding) { + setUp( + pluginBinding.getBinaryMessenger(), + pluginBinding.getPlatformViewRegistry(), + activityPluginBinding.getActivity()); + } @Override public void onDetachedFromActivity() {} From 7c210eaebf70a0b8fb38adf6324c94196ede06f6 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 10:25:41 -0700 Subject: [PATCH 40/54] license and callback --- .../flutter/plugins/webviewflutter/TestBinaryMessenger.java | 4 ++++ .../webview_flutter_android/lib/webview_android.dart | 6 ++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java index d20c55c97f67..7c287b1c2f98 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java @@ -1,3 +1,7 @@ +// 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 androidx.annotation.NonNull; diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart index 90afd964c79e..9bbcbb025c12 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart @@ -43,10 +43,8 @@ class AndroidWebView implements WebViewPlatform { child: AndroidView( viewType: 'plugins.flutter.io/webview', onPlatformViewCreated: (int id) { - final WebViewPlatformCreatedCallback? createdCallback = - onWebViewPlatformCreated; - if (createdCallback != null) { - createdCallback(platformController); + if (onWebViewPlatformCreated != null) { + onWebViewPlatformCreated(platformController); } }, gestureRecognizers: gestureRecognizers, From e540be36ddfbce23efa635ebaf681c912b0f27dd Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 11:06:10 -0700 Subject: [PATCH 41/54] delete old stuff --- .../FlutterDownloadListener.java | 33 -- .../webviewflutter/FlutterWebView.java | 478 ------------------ .../webviewflutter/FlutterWebViewClient.java | 323 ------------ .../webviewflutter/JavaScriptChannel.java | 40 +- .../JavaScriptChannelHostApiImpl.java | 17 +- .../webviewflutter/WebViewBuilder.java | 155 ------ .../FlutterDownloadListenerTest.java | 42 -- .../FlutterWebViewClientTest.java | 60 --- .../webviewflutter/FlutterWebViewTest.java | 66 --- .../webviewflutter/WebViewBuilderTest.java | 104 ---- .../plugins/webviewflutter/WebViewTest.java | 44 +- 11 files changed, 25 insertions(+), 1337 deletions(-) delete mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterDownloadListener.java delete mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java delete mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java delete mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewBuilder.java delete mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterDownloadListenerTest.java delete mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewClientTest.java delete mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewTest.java delete mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewBuilderTest.java diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterDownloadListener.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterDownloadListener.java deleted file mode 100644 index cfad4e315514..000000000000 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterDownloadListener.java +++ /dev/null @@ -1,33 +0,0 @@ -// 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.DownloadListener; -import android.webkit.WebView; - -/** DownloadListener to notify the {@link FlutterWebViewClient} of download starts */ -public class FlutterDownloadListener implements DownloadListener { - private final FlutterWebViewClient webViewClient; - private WebView webView; - - public FlutterDownloadListener(FlutterWebViewClient webViewClient) { - this.webViewClient = webViewClient; - } - - /** Sets the {@link WebView} that the result of the navigation delegate will be send to. */ - public void setWebView(WebView webView) { - this.webView = webView; - } - - @Override - public void onDownloadStart( - String url, - String userAgent, - String contentDisposition, - String mimetype, - long contentLength) { - webViewClient.notifyDownload(webView, url); - } -} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java deleted file mode 100644 index ff573c771960..000000000000 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java +++ /dev/null @@ -1,478 +0,0 @@ -// 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.annotation.TargetApi; -import android.content.Context; -import android.hardware.display.DisplayManager; -import android.os.Build; -import android.os.Handler; -import android.os.Message; -import android.view.View; -import android.webkit.DownloadListener; -import android.webkit.WebChromeClient; -import android.webkit.WebResourceRequest; -import android.webkit.WebStorage; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodChannel.MethodCallHandler; -import io.flutter.plugin.common.MethodChannel.Result; -import io.flutter.plugin.platform.PlatformView; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -public class FlutterWebView implements PlatformView, MethodCallHandler { - - private static final String JS_CHANNEL_NAMES_FIELD = "javascriptChannelNames"; - private final WebView webView; - private final MethodChannel methodChannel; - private final FlutterWebViewClient flutterWebViewClient; - private final Handler platformThreadHandler; - - // Verifies that a url opened by `Window.open` has a secure url. - private class FlutterWebChromeClient extends WebChromeClient { - - @Override - public boolean onCreateWindow( - final WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { - final WebViewClient webViewClient = - new WebViewClient() { - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public boolean shouldOverrideUrlLoading( - @NonNull WebView view, @NonNull WebResourceRequest request) { - final String url = request.getUrl().toString(); - if (!flutterWebViewClient.shouldOverrideUrlLoading( - FlutterWebView.this.webView, request)) { - webView.loadUrl(url); - } - return true; - } - - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - if (!flutterWebViewClient.shouldOverrideUrlLoading( - FlutterWebView.this.webView, url)) { - webView.loadUrl(url); - } - return true; - } - }; - - final WebView newWebView = new WebView(view.getContext()); - newWebView.setWebViewClient(webViewClient); - - final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; - transport.setWebView(newWebView); - resultMsg.sendToTarget(); - - return true; - } - - @Override - public void onProgressChanged(WebView view, int progress) { - flutterWebViewClient.onLoadingProgress(progress); - } - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - @SuppressWarnings("unchecked") - FlutterWebView( - final Context context, - MethodChannel methodChannel, - Map params, - View containerView) { - - DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy(); - DisplayManager displayManager = - (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); - displayListenerProxy.onPreWebViewInitialization(displayManager); - - this.methodChannel = methodChannel; - this.methodChannel.setMethodCallHandler(this); - - flutterWebViewClient = new FlutterWebViewClient(methodChannel); - - FlutterDownloadListener flutterDownloadListener = - new FlutterDownloadListener(flutterWebViewClient); - webView = - createWebView( - new WebViewBuilder(context, containerView), - params, - new FlutterWebChromeClient(), - flutterDownloadListener); - flutterDownloadListener.setWebView(webView); - - displayListenerProxy.onPostWebViewInitialization(displayManager); - - platformThreadHandler = new Handler(context.getMainLooper()); - - Map settings = (Map) params.get("settings"); - if (settings != null) { - applySettings(settings); - } - - if (params.containsKey(JS_CHANNEL_NAMES_FIELD)) { - List names = (List) params.get(JS_CHANNEL_NAMES_FIELD); - if (names != null) { - registerJavaScriptChannelNames(names); - } - } - - Integer autoMediaPlaybackPolicy = (Integer) params.get("autoMediaPlaybackPolicy"); - if (autoMediaPlaybackPolicy != null) { - updateAutoMediaPlaybackPolicy(autoMediaPlaybackPolicy); - } - if (params.containsKey("userAgent")) { - String userAgent = (String) params.get("userAgent"); - updateUserAgent(userAgent); - } - if (params.containsKey("initialUrl")) { - String url = (String) params.get("initialUrl"); - webView.loadUrl(url); - } - } - - /** - * Creates a {@link android.webkit.WebView} and configures it according to the supplied - * parameters. - * - *

The {@link WebView} is configured with the following predefined settings: - * - *

    - *
  • always enable the DOM storage API; - *
  • always allow JavaScript to automatically open windows; - *
  • always allow support for multiple windows; - *
  • always use the {@link FlutterWebChromeClient} as web Chrome client. - *
- * - *

Important: This method is visible for testing purposes only and should - * never be called from outside this class. - * - * @param webViewBuilder a {@link WebViewBuilder} which is responsible for building the {@link - * WebView}. - * @param params creation parameters received over the method channel. - * @param webChromeClient an implementation of WebChromeClient This value may be null. - * @return The new {@link android.webkit.WebView} object. - */ - @VisibleForTesting - static WebView createWebView( - WebViewBuilder webViewBuilder, - Map params, - WebChromeClient webChromeClient, - @Nullable DownloadListener downloadListener) { - boolean usesHybridComposition = Boolean.TRUE.equals(params.get("usesHybridComposition")); - webViewBuilder - .setUsesHybridComposition(usesHybridComposition) - .setDomStorageEnabled(true) // Always enable DOM storage API. - .setJavaScriptCanOpenWindowsAutomatically( - true) // Always allow automatically opening of windows. - .setSupportMultipleWindows(true) // Always support multiple windows. - .setWebChromeClient(webChromeClient) - .setDownloadListener( - downloadListener); // Always use {@link FlutterWebChromeClient} as web Chrome client. - - return webViewBuilder.build(); - } - - @Override - public View getView() { - return webView; - } - - @Override - public void onInputConnectionUnlocked() { - if (webView instanceof InputAwareWebView) { - ((InputAwareWebView) webView).unlockInputConnection(); - } - } - - @Override - public void onInputConnectionLocked() { - if (webView instanceof InputAwareWebView) { - ((InputAwareWebView) webView).lockInputConnection(); - } - } - - @Override - public void onFlutterViewAttached(View flutterView) { - if (webView instanceof InputAwareWebView) { - ((InputAwareWebView) webView).setContainerView(flutterView); - } - } - - @Override - public void onFlutterViewDetached() { - if (webView instanceof InputAwareWebView) { - ((InputAwareWebView) webView).setContainerView(null); - } - } - - @Override - public void onMethodCall(MethodCall methodCall, Result result) { - switch (methodCall.method) { - case "loadUrl": - loadUrl(methodCall, result); - break; - case "updateSettings": - updateSettings(methodCall, result); - break; - case "canGoBack": - canGoBack(result); - break; - case "canGoForward": - canGoForward(result); - break; - case "goBack": - goBack(result); - break; - case "goForward": - goForward(result); - break; - case "reload": - reload(result); - break; - case "currentUrl": - currentUrl(result); - break; - case "evaluateJavascript": - evaluateJavaScript(methodCall, result); - break; - case "addJavascriptChannels": - addJavaScriptChannels(methodCall, result); - break; - case "removeJavascriptChannels": - removeJavaScriptChannels(methodCall, result); - break; - case "clearCache": - clearCache(result); - break; - case "getTitle": - getTitle(result); - break; - case "scrollTo": - scrollTo(methodCall, result); - break; - case "scrollBy": - scrollBy(methodCall, result); - break; - case "getScrollX": - getScrollX(result); - break; - case "getScrollY": - getScrollY(result); - break; - default: - result.notImplemented(); - } - } - - @SuppressWarnings("unchecked") - private void loadUrl(MethodCall methodCall, Result result) { - Map request = (Map) methodCall.arguments; - String url = (String) request.get("url"); - Map headers = (Map) request.get("headers"); - if (headers == null) { - headers = Collections.emptyMap(); - } - webView.loadUrl(url, headers); - result.success(null); - } - - private void canGoBack(Result result) { - result.success(webView.canGoBack()); - } - - private void canGoForward(Result result) { - result.success(webView.canGoForward()); - } - - private void goBack(Result result) { - if (webView.canGoBack()) { - webView.goBack(); - } - result.success(null); - } - - private void goForward(Result result) { - if (webView.canGoForward()) { - webView.goForward(); - } - result.success(null); - } - - private void reload(Result result) { - webView.reload(); - result.success(null); - } - - private void currentUrl(Result result) { - result.success(webView.getUrl()); - } - - @SuppressWarnings("unchecked") - private void updateSettings(MethodCall methodCall, Result result) { - applySettings((Map) methodCall.arguments); - result.success(null); - } - - @TargetApi(Build.VERSION_CODES.KITKAT) - private void evaluateJavaScript(MethodCall methodCall, final Result result) { - String jsString = (String) methodCall.arguments; - if (jsString == null) { - throw new UnsupportedOperationException("JavaScript string cannot be null"); - } - webView.evaluateJavascript( - jsString, - new android.webkit.ValueCallback() { - @Override - public void onReceiveValue(String value) { - result.success(value); - } - }); - } - - @SuppressWarnings("unchecked") - private void addJavaScriptChannels(MethodCall methodCall, Result result) { - List channelNames = (List) methodCall.arguments; - registerJavaScriptChannelNames(channelNames); - result.success(null); - } - - @SuppressWarnings("unchecked") - private void removeJavaScriptChannels(MethodCall methodCall, Result result) { - List channelNames = (List) methodCall.arguments; - for (String channelName : channelNames) { - webView.removeJavascriptInterface(channelName); - } - result.success(null); - } - - private void clearCache(Result result) { - webView.clearCache(true); - WebStorage.getInstance().deleteAllData(); - result.success(null); - } - - private void getTitle(Result result) { - result.success(webView.getTitle()); - } - - private void scrollTo(MethodCall methodCall, Result result) { - Map request = methodCall.arguments(); - int x = (int) request.get("x"); - int y = (int) request.get("y"); - - webView.scrollTo(x, y); - - result.success(null); - } - - private void scrollBy(MethodCall methodCall, Result result) { - Map request = methodCall.arguments(); - int x = (int) request.get("x"); - int y = (int) request.get("y"); - - webView.scrollBy(x, y); - result.success(null); - } - - private void getScrollX(Result result) { - result.success(webView.getScrollX()); - } - - private void getScrollY(Result result) { - result.success(webView.getScrollY()); - } - - private void applySettings(Map settings) { - for (String key : settings.keySet()) { - switch (key) { - case "jsMode": - Integer mode = (Integer) settings.get(key); - if (mode != null) { - updateJsMode(mode); - } - break; - case "hasNavigationDelegate": - final boolean hasNavigationDelegate = (boolean) settings.get(key); - - final WebViewClient webViewClient = - flutterWebViewClient.createWebViewClient(hasNavigationDelegate); - - webView.setWebViewClient(webViewClient); - break; - case "debuggingEnabled": - final boolean debuggingEnabled = (boolean) settings.get(key); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - webView.setWebContentsDebuggingEnabled(debuggingEnabled); - } - break; - case "hasProgressTracking": - flutterWebViewClient.hasProgressTracking = (boolean) settings.get(key); - break; - case "gestureNavigationEnabled": - break; - case "userAgent": - updateUserAgent((String) settings.get(key)); - break; - case "allowsInlineMediaPlayback": - // no-op inline media playback is always allowed on Android. - break; - default: - throw new IllegalArgumentException("Unknown WebView setting: " + key); - } - } - } - - private void updateJsMode(int mode) { - switch (mode) { - case 0: // disabled - webView.getSettings().setJavaScriptEnabled(false); - break; - case 1: // unrestricted - webView.getSettings().setJavaScriptEnabled(true); - break; - default: - throw new IllegalArgumentException("Trying to set unknown JavaScript mode: " + mode); - } - } - - private void updateAutoMediaPlaybackPolicy(int mode) { - // This is the index of the AutoMediaPlaybackPolicy enum, index 1 is always_allow, for all - // other values we require a user gesture. - boolean requireUserGesture = mode != 1; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - webView.getSettings().setMediaPlaybackRequiresUserGesture(requireUserGesture); - } - } - - private void registerJavaScriptChannelNames(List channelNames) { - for (String channelName : channelNames) { - webView.addJavascriptInterface( - new JavaScriptChannel(methodChannel, channelName, platformThreadHandler), channelName); - } - } - - private void updateUserAgent(String userAgent) { - webView.getSettings().setUserAgentString(userAgent); - } - - @Override - public void dispose() { - methodChannel.setMethodCallHandler(null); - if (webView instanceof InputAwareWebView) { - ((InputAwareWebView) webView).dispose(); - } - webView.destroy(); - } -} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java deleted file mode 100644 index a86d3e8a4b63..000000000000 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java +++ /dev/null @@ -1,323 +0,0 @@ -// 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.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.graphics.Bitmap; -import android.os.Build; -import android.util.Log; -import android.view.KeyEvent; -import android.webkit.WebResourceError; -import android.webkit.WebResourceRequest; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; -import androidx.webkit.WebResourceErrorCompat; -import androidx.webkit.WebViewClientCompat; -import io.flutter.plugin.common.MethodChannel; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -// We need to use WebViewClientCompat to get -// shouldOverrideUrlLoading(WebView view, WebResourceRequest request) -// invoked by the webview on older Android devices, without it pages that use iframes will -// be broken when a navigationDelegate is set on Android version earlier than N. -class FlutterWebViewClient { - private static final String TAG = "FlutterWebViewClient"; - private final MethodChannel methodChannel; - private boolean hasNavigationDelegate; - boolean hasProgressTracking; - - FlutterWebViewClient(MethodChannel methodChannel) { - this.methodChannel = methodChannel; - } - - static String errorCodeToString(int errorCode) { - switch (errorCode) { - case WebViewClient.ERROR_AUTHENTICATION: - return "authentication"; - case WebViewClient.ERROR_BAD_URL: - return "badUrl"; - case WebViewClient.ERROR_CONNECT: - return "connect"; - case WebViewClient.ERROR_FAILED_SSL_HANDSHAKE: - return "failedSslHandshake"; - case WebViewClient.ERROR_FILE: - return "file"; - case WebViewClient.ERROR_FILE_NOT_FOUND: - return "fileNotFound"; - case WebViewClient.ERROR_HOST_LOOKUP: - return "hostLookup"; - case WebViewClient.ERROR_IO: - return "io"; - case WebViewClient.ERROR_PROXY_AUTHENTICATION: - return "proxyAuthentication"; - case WebViewClient.ERROR_REDIRECT_LOOP: - return "redirectLoop"; - case WebViewClient.ERROR_TIMEOUT: - return "timeout"; - case WebViewClient.ERROR_TOO_MANY_REQUESTS: - return "tooManyRequests"; - case WebViewClient.ERROR_UNKNOWN: - return "unknown"; - case WebViewClient.ERROR_UNSAFE_RESOURCE: - return "unsafeResource"; - case WebViewClient.ERROR_UNSUPPORTED_AUTH_SCHEME: - return "unsupportedAuthScheme"; - case WebViewClient.ERROR_UNSUPPORTED_SCHEME: - return "unsupportedScheme"; - } - - final String message = - String.format(Locale.getDefault(), "Could not find a string for errorCode: %d", errorCode); - throw new IllegalArgumentException(message); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { - if (!hasNavigationDelegate) { - return false; - } - notifyOnNavigationRequest( - request.getUrl().toString(), request.getRequestHeaders(), view, request.isForMainFrame()); - // We must make a synchronous decision here whether to allow the navigation or not, - // if the Dart code has set a navigation delegate we want that delegate to decide whether - // to navigate or not, and as we cannot get a response from the Dart delegate synchronously we - // return true here to block the navigation, if the Dart delegate decides to allow the - // navigation the plugin will later make an addition loadUrl call for this url. - // - // Since we cannot call loadUrl for a subframe, we currently only allow the delegate to stop - // navigations that target the main frame, if the request is not for the main frame - // we just return false to allow the navigation. - // - // For more details see: https://github.com/flutter/flutter/issues/25329#issuecomment-464863209 - return request.isForMainFrame(); - } - - boolean shouldOverrideUrlLoading(WebView view, String url) { - if (!hasNavigationDelegate) { - return false; - } - // This version of shouldOverrideUrlLoading is only invoked by the webview on devices with - // webview versions earlier than 67(it is also invoked when hasNavigationDelegate is false). - // On these devices we cannot tell whether the navigation is targeted to the main frame or not. - // We proceed assuming that the navigation is targeted to the main frame. If the page had any - // frames they will be loaded in the main frame instead. - Log.w( - TAG, - "Using a navigationDelegate with an old webview implementation, pages with frames or iframes will not work"); - notifyOnNavigationRequest(url, null, view, true); - return true; - } - - /** - * Notifies the Flutter code that a download should start when a navigation delegate is set. - * - * @param view the webView the result of the navigation delegate will be send to. - * @param url the download url - * @return A boolean whether or not the request is forwarded to the Flutter code. - */ - boolean notifyDownload(WebView view, String url) { - if (!hasNavigationDelegate) { - return false; - } - - notifyOnNavigationRequest(url, null, view, true); - return true; - } - - private void onPageStarted(WebView view, String url) { - Map args = new HashMap<>(); - args.put("url", url); - methodChannel.invokeMethod("onPageStarted", args); - } - - private void onPageFinished(WebView view, String url) { - Map args = new HashMap<>(); - args.put("url", url); - methodChannel.invokeMethod("onPageFinished", args); - } - - void onLoadingProgress(int progress) { - if (hasProgressTracking) { - Map args = new HashMap<>(); - args.put("progress", progress); - methodChannel.invokeMethod("onProgress", args); - } - } - - private void onWebResourceError( - final int errorCode, final String description, final String failingUrl) { - final Map args = new HashMap<>(); - args.put("errorCode", errorCode); - args.put("description", description); - args.put("errorType", FlutterWebViewClient.errorCodeToString(errorCode)); - args.put("failingUrl", failingUrl); - methodChannel.invokeMethod("onWebResourceError", args); - } - - private void notifyOnNavigationRequest( - String url, Map headers, WebView webview, boolean isMainFrame) { - HashMap args = new HashMap<>(); - args.put("url", url); - args.put("isForMainFrame", isMainFrame); - if (isMainFrame) { - methodChannel.invokeMethod( - "navigationRequest", args, new OnNavigationRequestResult(url, headers, webview)); - } else { - methodChannel.invokeMethod("navigationRequest", args); - } - } - - // This method attempts to avoid using WebViewClientCompat due to bug - // https://bugs.chromium.org/p/chromium/issues/detail?id=925887. Also, see - // https://github.com/flutter/flutter/issues/29446. - WebViewClient createWebViewClient(boolean hasNavigationDelegate) { - this.hasNavigationDelegate = hasNavigationDelegate; - - if (!hasNavigationDelegate || android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - return internalCreateWebViewClient(); - } - - return internalCreateWebViewClientCompat(); - } - - private WebViewClient internalCreateWebViewClient() { - return new WebViewClient() { - @TargetApi(Build.VERSION_CODES.N) - @Override - public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { - return FlutterWebViewClient.this.shouldOverrideUrlLoading(view, request); - } - - @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - FlutterWebViewClient.this.onPageStarted(view, url); - } - - @Override - public void onPageFinished(WebView view, String url) { - FlutterWebViewClient.this.onPageFinished(view, url); - } - - @TargetApi(Build.VERSION_CODES.M) - @Override - public void onReceivedError( - WebView view, WebResourceRequest request, WebResourceError error) { - if (request.isForMainFrame()) { - FlutterWebViewClient.this.onWebResourceError( - error.getErrorCode(), error.getDescription().toString(), request.getUrl().toString()); - } - } - - @Override - public void onReceivedError( - WebView view, int errorCode, String description, String failingUrl) { - FlutterWebViewClient.this.onWebResourceError(errorCode, description, failingUrl); - } - - @Override - public void onUnhandledKeyEvent(WebView view, KeyEvent event) { - // Deliberately empty. Occasionally the webview will mark events as having failed to be - // handled even though they were handled. We don't want to propagate those as they're not - // truly lost. - } - }; - } - - private WebViewClientCompat internalCreateWebViewClientCompat() { - return new WebViewClientCompat() { - @Override - public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { - return FlutterWebViewClient.this.shouldOverrideUrlLoading(view, request); - } - - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - return FlutterWebViewClient.this.shouldOverrideUrlLoading(view, url); - } - - @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - FlutterWebViewClient.this.onPageStarted(view, url); - } - - @Override - public void onPageFinished(WebView view, String url) { - FlutterWebViewClient.this.onPageFinished(view, url); - } - - // This method is only called when the WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR feature is - // enabled. The deprecated method is called when a device doesn't support this. - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - @SuppressLint("RequiresFeature") - @Override - public void onReceivedError( - @NonNull WebView view, - @NonNull WebResourceRequest request, - @NonNull WebResourceErrorCompat error) { - if (request.isForMainFrame()) { - FlutterWebViewClient.this.onWebResourceError( - error.getErrorCode(), error.getDescription().toString(), request.getUrl().toString()); - } - } - - @Override - public void onReceivedError( - WebView view, int errorCode, String description, String failingUrl) { - FlutterWebViewClient.this.onWebResourceError(errorCode, description, failingUrl); - } - - @Override - public void onUnhandledKeyEvent(WebView view, KeyEvent event) { - // Deliberately empty. Occasionally the webview will mark events as having failed to be - // handled even though they were handled. We don't want to propagate those as they're not - // truly lost. - } - }; - } - - private static class OnNavigationRequestResult implements MethodChannel.Result { - private final String url; - private final Map headers; - private final WebView webView; - - private OnNavigationRequestResult(String url, Map headers, WebView webView) { - this.url = url; - this.headers = headers; - this.webView = webView; - } - - @Override - public void success(Object shouldLoad) { - Boolean typedShouldLoad = (Boolean) shouldLoad; - if (typedShouldLoad) { - loadUrl(); - } - } - - @Override - public void error(String errorCode, String s1, Object o) { - throw new IllegalStateException("navigationRequest calls must succeed"); - } - - @Override - public void notImplemented() { - throw new IllegalStateException( - "navigationRequest must be implemented by the webview method channel"); - } - - private void loadUrl() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - webView.loadUrl(url, headers); - } else { - webView.loadUrl(url); - } - } - } -} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java index 2f987c0f86b3..62d047971b0b 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java @@ -7,8 +7,7 @@ import android.os.Handler; import android.os.Looper; import android.webkit.JavascriptInterface; -import io.flutter.plugin.common.MethodChannel; -import java.util.HashMap; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; /** * Added as a JavaScript interface to the WebView for any JavaScript channel that the Dart code sets @@ -18,37 +17,34 @@ * channel to the Dart code. */ class JavaScriptChannel { - private final MethodChannel methodChannel; + private final Long instanceId; + private final GeneratedAndroidWebView.JavaScriptChannelFlutterApi javaScriptChannelFlutterApi; final String javaScriptChannelName; private final Handler platformThreadHandler; /** - * @param methodChannel the Flutter WebView method channel to which JS messages are sent - * @param javaScriptChannelName the name of the JavaScript channel, this is sent over the method - * channel with each message to let the Dart code know which JavaScript channel the message - * was sent through + * @param instanceId identifier for this object when messages are sent to Dart + * @param javaScriptChannelFlutterApi the Flutter Api to which JS messages are sent + * @param channelName the name of the JavaScript channel, this is sent over the method channel + * with each message to let the Dart code know which JavaScript channel the message was sent + * through + * @param platformThreadHandler handles making callbacks on the desired thread */ JavaScriptChannel( - MethodChannel methodChannel, String javaScriptChannelName, Handler platformThreadHandler) { - this.methodChannel = methodChannel; - this.javaScriptChannelName = javaScriptChannelName; + Long instanceId, + JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, + String channelName, + Handler platformThreadHandler) { + this.instanceId = instanceId; + this.javaScriptChannelFlutterApi = javaScriptChannelFlutterApi; + this.javaScriptChannelName = channelName; this.platformThreadHandler = platformThreadHandler; } - // Suppressing unused warning as this is invoked from JavaScript. - @SuppressWarnings("unused") @JavascriptInterface public void postMessage(final String message) { - Runnable postMessageRunnable = - new Runnable() { - @Override - public void run() { - HashMap arguments = new HashMap<>(); - arguments.put("channel", javaScriptChannelName); - arguments.put("message", message); - methodChannel.invokeMethod("javascriptChannelMessage", arguments); - } - }; + final Runnable postMessageRunnable = + () -> javaScriptChannelFlutterApi.postMessage(instanceId, message, reply -> {}); if (platformThreadHandler.getLooper() == Looper.myLooper()) { postMessageRunnable.run(); } else { diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java index e146a9fb40b6..ded5ada2754d 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -5,8 +5,6 @@ package io.flutter.plugins.webviewflutter; import android.os.Handler; -import android.os.Looper; -import android.webkit.JavascriptInterface; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.JavaScriptChannelHostApi { @@ -21,19 +19,8 @@ JavaScriptChannel createJavaScriptChannel( JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, String channelName, Handler platformThreadHandler) { - return new JavaScriptChannel(null, channelName, platformThreadHandler) { - @JavascriptInterface - @Override - public void postMessage(String message) { - final Runnable postMessageRunnable = - () -> javaScriptChannelFlutterApi.postMessage(instanceId, message, reply -> {}); - if (platformThreadHandler.getLooper() == Looper.myLooper()) { - postMessageRunnable.run(); - } else { - platformThreadHandler.post(postMessageRunnable); - } - } - }; + return new JavaScriptChannel( + instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewBuilder.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewBuilder.java deleted file mode 100644 index d3cd1d57cdae..000000000000 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewBuilder.java +++ /dev/null @@ -1,155 +0,0 @@ -// 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.content.Context; -import android.view.View; -import android.webkit.DownloadListener; -import android.webkit.WebChromeClient; -import android.webkit.WebSettings; -import android.webkit.WebView; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -/** Builder used to create {@link android.webkit.WebView} objects. */ -public class WebViewBuilder { - - /** Factory used to create a new {@link android.webkit.WebView} instance. */ - static class WebViewFactory { - - /** - * Creates a new {@link android.webkit.WebView} instance. - * - * @param context an Activity Context to access application assets. This value cannot be null. - * @param usesHybridComposition If {@code false} a {@link InputAwareWebView} instance is - * returned. - * @param containerView must be supplied when the {@code useHybridComposition} parameter is set - * to {@code false}. Used to create an InputConnection on the WebView's dedicated input, or - * IME, thread (see also {@link InputAwareWebView}) - * @return A new instance of the {@link android.webkit.WebView} object. - */ - static WebView create(Context context, boolean usesHybridComposition, View containerView) { - return usesHybridComposition - ? new WebView(context) - : new InputAwareWebView(context, containerView); - } - } - - private final Context context; - private final View containerView; - - private boolean enableDomStorage; - private boolean javaScriptCanOpenWindowsAutomatically; - private boolean supportMultipleWindows; - private boolean usesHybridComposition; - private WebChromeClient webChromeClient; - private DownloadListener downloadListener; - - /** - * Constructs a new {@link WebViewBuilder} object with a custom implementation of the {@link - * WebViewFactory} object. - * - * @param context an Activity Context to access application assets. This value cannot be null. - * @param containerView must be supplied when the {@code useHybridComposition} parameter is set to - * {@code false}. Used to create an InputConnection on the WebView's dedicated input, or IME, - * thread (see also {@link InputAwareWebView}) - */ - WebViewBuilder(@NonNull final Context context, View containerView) { - this.context = context; - this.containerView = containerView; - } - - /** - * Sets whether the DOM storage API is enabled. The default value is {@code false}. - * - * @param flag {@code true} is {@link android.webkit.WebView} should use the DOM storage API. - * @return This builder. This value cannot be {@code null}. - */ - public WebViewBuilder setDomStorageEnabled(boolean flag) { - this.enableDomStorage = flag; - return this; - } - - /** - * Sets whether JavaScript is allowed to open windows automatically. This applies to the - * JavaScript function {@code window.open()}. The default value is {@code false}. - * - * @param flag {@code true} if JavaScript is allowed to open windows automatically. - * @return This builder. This value cannot be {@code null}. - */ - public WebViewBuilder setJavaScriptCanOpenWindowsAutomatically(boolean flag) { - this.javaScriptCanOpenWindowsAutomatically = flag; - return this; - } - - /** - * Sets whether the {@link WebView} supports multiple windows. If set to {@code true}, {@link - * WebChromeClient#onCreateWindow} must be implemented by the host application. The default is - * {@code false}. - * - * @param flag {@code true} if multiple windows are supported. - * @return This builder. This value cannot be {@code null}. - */ - public WebViewBuilder setSupportMultipleWindows(boolean flag) { - this.supportMultipleWindows = flag; - return this; - } - - /** - * Sets whether the hybrid composition should be used. - * - *

If set to {@code true} a standard {@link WebView} is created. If set to {@code false} the - * {@link WebViewBuilder} will create a {@link InputAwareWebView} to workaround issues using the - * {@link WebView} on Android versions below N. - * - * @param flag {@code true} if uses hybrid composition. The default is {@code false}. - * @return This builder. This value cannot be {@code null} - */ - public WebViewBuilder setUsesHybridComposition(boolean flag) { - this.usesHybridComposition = flag; - return this; - } - - /** - * Sets the chrome handler. This is an implementation of WebChromeClient for use in handling - * JavaScript dialogs, favicons, titles, and the progress. This will replace the current handler. - * - * @param webChromeClient an implementation of WebChromeClient This value may be null. - * @return This builder. This value cannot be {@code null}. - */ - public WebViewBuilder setWebChromeClient(@Nullable WebChromeClient webChromeClient) { - this.webChromeClient = webChromeClient; - return this; - } - - /** - * Registers the interface to be used when content can not be handled by the rendering engine, and - * should be downloaded instead. This will replace the current handler. - * - * @param downloadListener an implementation of DownloadListener This value may be null. - * @return This builder. This value cannot be {@code null}. - */ - public WebViewBuilder setDownloadListener(@Nullable DownloadListener downloadListener) { - this.downloadListener = downloadListener; - return this; - } - - /** - * Build the {@link android.webkit.WebView} using the current settings. - * - * @return The {@link android.webkit.WebView} using the current settings. - */ - public WebView build() { - WebView webView = WebViewFactory.create(context, usesHybridComposition, containerView); - - WebSettings webSettings = webView.getSettings(); - webSettings.setDomStorageEnabled(enableDomStorage); - webSettings.setJavaScriptCanOpenWindowsAutomatically(javaScriptCanOpenWindowsAutomatically); - webSettings.setSupportMultipleWindows(supportMultipleWindows); - webView.setWebChromeClient(webChromeClient); - webView.setDownloadListener(downloadListener); - return webView; - } -} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterDownloadListenerTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterDownloadListenerTest.java deleted file mode 100644 index 2c918584ba83..000000000000 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterDownloadListenerTest.java +++ /dev/null @@ -1,42 +0,0 @@ -// 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 static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import android.webkit.WebView; -import org.junit.Before; -import org.junit.Test; - -public class FlutterDownloadListenerTest { - private FlutterWebViewClient webViewClient; - private WebView webView; - - @Before - public void before() { - webViewClient = mock(FlutterWebViewClient.class); - webView = mock(WebView.class); - } - - @Test - public void onDownloadStart_should_notify_webViewClient() { - String url = "testurl.com"; - FlutterDownloadListener downloadListener = new FlutterDownloadListener(webViewClient); - downloadListener.onDownloadStart(url, "test", "inline", "data/text", 0); - verify(webViewClient).notifyDownload(nullable(WebView.class), eq(url)); - } - - @Test - public void onDownloadStart_should_pass_webView() { - FlutterDownloadListener downloadListener = new FlutterDownloadListener(webViewClient); - downloadListener.setWebView(webView); - downloadListener.onDownloadStart("testurl.com", "test", "inline", "data/text", 0); - verify(webViewClient).notifyDownload(eq(webView), anyString()); - } -} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewClientTest.java deleted file mode 100644 index 86346ac08f16..000000000000 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewClientTest.java +++ /dev/null @@ -1,60 +0,0 @@ -// 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 static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; - -import android.webkit.WebView; -import io.flutter.plugin.common.MethodChannel; -import java.util.HashMap; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -public class FlutterWebViewClientTest { - - MethodChannel mockMethodChannel; - WebView mockWebView; - - @Before - public void before() { - mockMethodChannel = mock(MethodChannel.class); - mockWebView = mock(WebView.class); - } - - @Test - public void notify_download_should_notifyOnNavigationRequest_when_navigationDelegate_is_set() { - final String url = "testurl.com"; - - FlutterWebViewClient client = new FlutterWebViewClient(mockMethodChannel); - client.createWebViewClient(true); - - client.notifyDownload(mockWebView, url); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Object.class); - verify(mockMethodChannel) - .invokeMethod( - eq("navigationRequest"), argumentCaptor.capture(), any(MethodChannel.Result.class)); - HashMap map = (HashMap) argumentCaptor.getValue(); - assertEquals(map.get("url"), url); - assertEquals(map.get("isForMainFrame"), true); - } - - @Test - public void - notify_download_should_not_notifyOnNavigationRequest_when_navigationDelegate_is_not_set() { - final String url = "testurl.com"; - - FlutterWebViewClient client = new FlutterWebViewClient(mockMethodChannel); - client.createWebViewClient(false); - - client.notifyDownload(mockWebView, url); - verifyNoInteractions(mockMethodChannel); - } -} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewTest.java deleted file mode 100644 index 56d9db1ee493..000000000000 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/FlutterWebViewTest.java +++ /dev/null @@ -1,66 +0,0 @@ -// 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 static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.webkit.DownloadListener; -import android.webkit.WebChromeClient; -import android.webkit.WebView; -import java.util.HashMap; -import java.util.Map; -import org.junit.Before; -import org.junit.Test; - -public class FlutterWebViewTest { - private WebChromeClient mockWebChromeClient; - private DownloadListener mockDownloadListener; - private WebViewBuilder mockWebViewBuilder; - private WebView mockWebView; - - @Before - public void before() { - mockWebChromeClient = mock(WebChromeClient.class); - mockWebViewBuilder = mock(WebViewBuilder.class); - mockWebView = mock(WebView.class); - mockDownloadListener = mock(DownloadListener.class); - - when(mockWebViewBuilder.setDomStorageEnabled(anyBoolean())).thenReturn(mockWebViewBuilder); - when(mockWebViewBuilder.setJavaScriptCanOpenWindowsAutomatically(anyBoolean())) - .thenReturn(mockWebViewBuilder); - when(mockWebViewBuilder.setSupportMultipleWindows(anyBoolean())).thenReturn(mockWebViewBuilder); - when(mockWebViewBuilder.setUsesHybridComposition(anyBoolean())).thenReturn(mockWebViewBuilder); - when(mockWebViewBuilder.setWebChromeClient(any(WebChromeClient.class))) - .thenReturn(mockWebViewBuilder); - when(mockWebViewBuilder.setDownloadListener(any(DownloadListener.class))) - .thenReturn(mockWebViewBuilder); - - when(mockWebViewBuilder.build()).thenReturn(mockWebView); - } - - @Test - public void createWebView_should_create_webview_with_default_configuration() { - FlutterWebView.createWebView( - mockWebViewBuilder, createParameterMap(false), mockWebChromeClient, mockDownloadListener); - - verify(mockWebViewBuilder, times(1)).setDomStorageEnabled(true); - verify(mockWebViewBuilder, times(1)).setJavaScriptCanOpenWindowsAutomatically(true); - verify(mockWebViewBuilder, times(1)).setSupportMultipleWindows(true); - verify(mockWebViewBuilder, times(1)).setUsesHybridComposition(false); - verify(mockWebViewBuilder, times(1)).setWebChromeClient(mockWebChromeClient); - } - - private Map createParameterMap(boolean usesHybridComposition) { - Map params = new HashMap<>(); - params.put("usesHybridComposition", usesHybridComposition); - - return params; - } -} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewBuilderTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewBuilderTest.java deleted file mode 100644 index 423cb210c392..000000000000 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewBuilderTest.java +++ /dev/null @@ -1,104 +0,0 @@ -// 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 static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.*; - -import android.content.Context; -import android.view.View; -import android.webkit.DownloadListener; -import android.webkit.WebChromeClient; -import android.webkit.WebSettings; -import android.webkit.WebView; -import io.flutter.plugins.webviewflutter.WebViewBuilder.WebViewFactory; -import java.io.IOException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.MockedStatic; -import org.mockito.MockedStatic.Verification; - -public class WebViewBuilderTest { - private Context mockContext; - private View mockContainerView; - private WebView mockWebView; - private MockedStatic mockedStaticWebViewFactory; - - @Before - public void before() { - mockContext = mock(Context.class); - mockContainerView = mock(View.class); - mockWebView = mock(WebView.class); - mockedStaticWebViewFactory = mockStatic(WebViewFactory.class); - - mockedStaticWebViewFactory - .when( - new Verification() { - @Override - public void apply() { - WebViewFactory.create(mockContext, false, mockContainerView); - } - }) - .thenReturn(mockWebView); - } - - @After - public void after() { - mockedStaticWebViewFactory.close(); - } - - @Test - public void ctor_test() { - WebViewBuilder builder = new WebViewBuilder(mockContext, mockContainerView); - - assertNotNull(builder); - } - - @Test - public void build_should_set_values() throws IOException { - WebSettings mockWebSettings = mock(WebSettings.class); - WebChromeClient mockWebChromeClient = mock(WebChromeClient.class); - DownloadListener mockDownloadListener = mock(DownloadListener.class); - - when(mockWebView.getSettings()).thenReturn(mockWebSettings); - - WebViewBuilder builder = - new WebViewBuilder(mockContext, mockContainerView) - .setDomStorageEnabled(true) - .setJavaScriptCanOpenWindowsAutomatically(true) - .setSupportMultipleWindows(true) - .setWebChromeClient(mockWebChromeClient) - .setDownloadListener(mockDownloadListener); - - WebView webView = builder.build(); - - assertNotNull(webView); - verify(mockWebSettings).setDomStorageEnabled(true); - verify(mockWebSettings).setJavaScriptCanOpenWindowsAutomatically(true); - verify(mockWebSettings).setSupportMultipleWindows(true); - verify(mockWebView).setWebChromeClient(mockWebChromeClient); - verify(mockWebView).setDownloadListener(mockDownloadListener); - } - - @Test - public void build_should_use_default_values() throws IOException { - WebSettings mockWebSettings = mock(WebSettings.class); - WebChromeClient mockWebChromeClient = mock(WebChromeClient.class); - - when(mockWebView.getSettings()).thenReturn(mockWebSettings); - - WebViewBuilder builder = new WebViewBuilder(mockContext, mockContainerView); - - WebView webView = builder.build(); - - assertNotNull(webView); - verify(mockWebSettings).setDomStorageEnabled(false); - verify(mockWebSettings).setJavaScriptCanOpenWindowsAutomatically(false); - verify(mockWebSettings).setSupportMultipleWindows(false); - verify(mockWebView).setWebChromeClient(null); - verify(mockWebView).setDownloadListener(null); - } -} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java index ecd7be67f74d..6896e9224e90 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java @@ -16,6 +16,7 @@ import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; import java.util.HashMap; import org.junit.Before; import org.junit.Rule; @@ -45,43 +46,6 @@ public void setUp() { testHostApiImpl.create(0L, true); } - @Test - public void errorCodes() { - assertEquals( - FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_AUTHENTICATION), - "authentication"); - assertEquals(FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_BAD_URL), "badUrl"); - assertEquals(FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_CONNECT), "connect"); - assertEquals( - FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_FAILED_SSL_HANDSHAKE), - "failedSslHandshake"); - assertEquals(FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_FILE), "file"); - assertEquals( - FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_FILE_NOT_FOUND), "fileNotFound"); - assertEquals( - FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_HOST_LOOKUP), "hostLookup"); - assertEquals(FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_IO), "io"); - assertEquals( - FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_PROXY_AUTHENTICATION), - "proxyAuthentication"); - assertEquals( - FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_REDIRECT_LOOP), "redirectLoop"); - assertEquals(FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_TIMEOUT), "timeout"); - assertEquals( - FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_TOO_MANY_REQUESTS), - "tooManyRequests"); - assertEquals(FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_UNKNOWN), "unknown"); - assertEquals( - FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_UNSAFE_RESOURCE), - "unsafeResource"); - assertEquals( - FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_UNSUPPORTED_AUTH_SCHEME), - "unsupportedAuthScheme"); - assertEquals( - FlutterWebViewClient.errorCodeToString(WebViewClient.ERROR_UNSUPPORTED_SCHEME), - "unsupportedScheme"); - } - @Test public void loadUrl() { testHostApiImpl.loadUrl(0L, "https://www.google.com", new HashMap<>()); @@ -196,7 +160,8 @@ public void setWebViewClient() { @Test public void addJavaScriptChannel() { - final JavaScriptChannel javaScriptChannel = new JavaScriptChannel(null, "aName", null); + final JavaScriptChannel javaScriptChannel = + new JavaScriptChannel(0L, mock(JavaScriptChannelFlutterApi.class), "aName", null); testInstanceManager.addInstance(javaScriptChannel, 1L); testHostApiImpl.addJavaScriptChannel(0L, 1L); @@ -205,7 +170,8 @@ public void addJavaScriptChannel() { @Test public void removeJavaScriptChannel() { - final JavaScriptChannel javaScriptChannel = new JavaScriptChannel(null, "aName", null); + final JavaScriptChannel javaScriptChannel = + new JavaScriptChannel(0L, mock(JavaScriptChannelFlutterApi.class), "aName", null); testInstanceManager.addInstance(javaScriptChannel, 1L); testHostApiImpl.removeJavaScriptChannel(0L, 1L); From 97d199a61ed578a6fae8b772528c1ee685d35778 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 11:26:33 -0700 Subject: [PATCH 42/54] remove unused file and update changelog --- .../webview_flutter_android/CHANGELOG.md | 2 +- .../webviewflutter/TestBinaryMessenger.java | 23 ------------------- 2 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index 432229270382..83a2903ac1d1 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,6 +1,6 @@ ## NEXT -* Replace platform implementation with API build with pigeon. +* Replace platform implementation with API built with pigeon. ## 2.0.15 diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java deleted file mode 100644 index 7c287b1c2f98..000000000000 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/TestBinaryMessenger.java +++ /dev/null @@ -1,23 +0,0 @@ -// 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 androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import io.flutter.plugin.common.BinaryMessenger; -import java.nio.ByteBuffer; - -public class TestBinaryMessenger implements BinaryMessenger { - @Override - public void send(@NonNull String s, @Nullable ByteBuffer byteBuffer) {} - - @Override - public void send( - @NonNull String s, @Nullable ByteBuffer byteBuffer, @Nullable BinaryReply binaryReply) {} - - @Override - public void setMessageHandler( - @NonNull String s, @Nullable BinaryMessageHandler binaryMessageHandler) {} -} From 0064fba01d1eba9edcca8eea6bf1d627f1e16220 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 11:51:39 -0700 Subject: [PATCH 43/54] version bump --- packages/webview_flutter/webview_flutter_android/CHANGELOG.md | 2 +- packages/webview_flutter/webview_flutter_android/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index 83a2903ac1d1..2ac2546a7873 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,4 +1,4 @@ -## NEXT +## 2.1.0 * Replace platform implementation with API built with pigeon. diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 04511e670d4c..4888e9b92123 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_android description: A Flutter plugin that provides a WebView widget on Android. repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 2.0.15 +version: 2.1.0 environment: sdk: ">=2.14.0 <3.0.0" From f8eb4ec80b19312207b9525df3a663afe6e160b7 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 18:35:55 -0700 Subject: [PATCH 44/54] some testing --- .../webview_flutter_android/pubspec.yaml | 4 +- .../test/android_webview.pigeon.dart | 2 +- .../test/android_webview_test.dart | 158 +------- .../test/test_android_webview_api_impls.dart | 261 +++++++++++++ .../test_android_webview_api_impls.mocks.dart | 297 ++++++++++++++ .../test/webview_widget_test.dart | 85 ++++ .../test/webview_widget_test.mocks.dart | 365 ++++++++++++++++++ 7 files changed, 1014 insertions(+), 158 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.dart create mode 100644 packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.mocks.dart create mode 100644 packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart create mode 100644 packages/webview_flutter/webview_flutter_android/test/webview_widget_test.mocks.dart diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 4888e9b92123..accf1d2b70ed 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -23,10 +23,12 @@ dependencies: webview_flutter_platform_interface: ^1.0.0 dev_dependencies: + build_runner: ^2.1.4 flutter_driver: sdk: flutter flutter_test: sdk: flutter - pigeon: 1.0.7 + mockito: ^5.0.16 + pigeon: 1.0.8 pedantic: ^1.10.0 diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart index 70aa53ca2610..ee0429b4c582 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart @@ -100,7 +100,7 @@ abstract class TestWebViewHostApi { assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null String.'); final Map? arg_headers = - args[2] as Map?; + (args[2] as Map).cast(); assert(arg_headers != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null Map.'); api.loadUrl(arg_instanceId!, arg_url!, arg_headers!); diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart index 462670abdb83..0f50e5e21b0b 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart @@ -8,6 +8,8 @@ import 'package:webview_flutter_android/src/android_webview_api_impls.dart'; import 'package:webview_flutter_android/src/instance_manager.dart'; import 'android_webview.pigeon.dart'; +import 'test_android_webview_api_impls.dart'; + void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -215,159 +217,3 @@ class TestWebChromeClient extends WebChromeClient { @override void onProgressChanged(WebView webView, int progress) {} } - -class TestWebViewHostApiImpl extends TestWebViewHostApi { - @override - void addJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId) {} - - @override - bool canGoBack(int instanceId) { - throw UnimplementedError(); - } - - @override - bool canGoForward(int instanceId) { - throw UnimplementedError(); - } - - @override - void clearCache(int instanceId, bool includeDiskFiles) {} - - @override - void create(int instanceId, bool useHybridComposition) {} - - @override - void dispose(int instanceId) {} - - @override - Future evaluateJavascript(int instanceId, String javascriptString) { - throw UnimplementedError(); - } - - @override - int getScrollX(int instanceId) { - throw UnimplementedError(); - } - - @override - int getScrollY(int instanceId) { - throw UnimplementedError(); - } - - @override - String getTitle(int instanceId) { - throw UnimplementedError(); - } - - @override - String getUrl(int instanceId) { - throw UnimplementedError(); - } - - @override - void goBack(int instanceId) {} - - @override - void goForward(int instanceId) {} - - @override - void loadUrl(int instanceId, String url, Map headers) {} - - @override - void reload(int instanceId) {} - - @override - void removeJavaScriptChannel( - int instanceId, int javaScriptChannelInstanceId) {} - - @override - void scrollBy(int instanceId, int x, int y) {} - - @override - void scrollTo(int instanceId, int x, int y) {} - - @override - void setDownloadListener(int instanceId, int listenerInstanceId) {} - - @override - void setWebContentsDebuggingEnabled(bool enabled) {} - - @override - void setWebViewClient(int instanceId, int webViewClientInstanceId) {} - - @override - void setWebChromeClient(int instanceId, int clientInstanceId) {} -} - -class TestWebSettingsHostApiImpl extends TestWebSettingsHostApi { - @override - void create(int instanceId, int webViewInstanceId) {} - - @override - void dispose(int instanceId) {} - - @override - void setBuiltInZoomControls(int instanceId, bool enabled) {} - - @override - void setDisplayZoomControls(int instanceId, bool enabled) {} - - @override - void setDomStorageEnabled(int instanceId, bool flag) {} - - @override - void setJavaScriptCanOpenWindowsAutomatically(int instanceId, bool flag) {} - - @override - void setJavaScriptEnabled(int instanceId, bool flag) {} - - @override - void setLoadWithOverviewMode(int instanceId, bool overview) {} - - @override - void setMediaPlaybackRequiresUserGesture(int instanceId, bool require) {} - - @override - void setSupportMultipleWindows(int instanceId, bool support) {} - - @override - void setSupportZoom(int instanceId, bool support) {} - - @override - void setUseWideViewPort(int instanceId, bool use) {} - - @override - void setUserAgentString(int instanceId, String userAgentString) {} -} - -class TestJavaScriptChannelHostApiImpl extends TestJavaScriptChannelHostApi { - @override - void create(int instanceId, String channelName) {} - - @override - void dispose(int instanceId) {} -} - -class TestWebViewClientHostApiImpl extends TestWebViewClientHostApi { - @override - void create(int instanceId, bool shouldOverrideUrlLoading) {} - - @override - void dispose(int instanceId) {} -} - -class TestDownloadListenerHostApiImpl extends TestDownloadListenerHostApi { - @override - void create(int instanceId) {} - - @override - void dispose(int instanceId) {} -} - -class TestWebChromeClientHostApiImpl extends TestWebChromeClientHostApi { - @override - void create(int instanceId, int webViewClientInstanceId) {} - - @override - void dispose(int instanceId) {} -} diff --git a/packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.dart new file mode 100644 index 000000000000..8fcf3f204e0a --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.dart @@ -0,0 +1,261 @@ +// 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. + +import 'package:mockito/annotations.dart'; + +import 'android_webview.pigeon.dart'; + +import 'test_android_webview_api_impls.mocks.dart'; + +@GenerateMocks([ + TestWebViewHostApi, + TestWebSettingsHostApi, + TestWebViewClientHostApi, + TestWebChromeClientHostApi, + TestJavaScriptChannelHostApi, + TestDownloadListenerHostApi, +]) +void main() {} + +class TestWebViewHostApiImpl extends TestWebViewHostApi { + final TestWebViewHostApi mock = MockTestWebViewHostApi(); + + @override + void addJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId) { + mock.addJavaScriptChannel(instanceId, javaScriptChannelInstanceId); + } + + @override + bool canGoBack(int instanceId) { + return mock.canGoBack(instanceId); + } + + @override + bool canGoForward(int instanceId) { + return mock.canGoForward(instanceId); + } + + @override + void clearCache(int instanceId, bool includeDiskFiles) { + mock.clearCache(instanceId, includeDiskFiles); + } + + @override + void create(int instanceId, bool useHybridComposition) { + mock.create(instanceId, useHybridComposition); + } + + @override + void dispose(int instanceId) { + mock.dispose(instanceId); + } + + @override + Future evaluateJavascript(int instanceId, String javascriptString) { + return mock.evaluateJavascript(instanceId, javascriptString); + } + + @override + int getScrollX(int instanceId) { + return mock.getScrollX(instanceId); + } + + @override + int getScrollY(int instanceId) { + return mock.getScrollY(instanceId); + } + + @override + String getTitle(int instanceId) { + return mock.getTitle(instanceId); + } + + @override + String getUrl(int instanceId) { + return mock.getUrl(instanceId); + } + + @override + void goBack(int instanceId) { + mock.goBack(instanceId); + } + + @override + void goForward(int instanceId) { + mock.goForward(instanceId); + } + + @override + void loadUrl(int instanceId, String url, Map headers) { + mock.loadUrl(instanceId, url, headers.cast()); + } + + @override + void reload(int instanceId) { + mock.reload(instanceId); + } + + @override + void removeJavaScriptChannel( + int instanceId, + int javaScriptChannelInstanceId, + ) { + mock.removeJavaScriptChannel(instanceId, javaScriptChannelInstanceId); + } + + @override + void scrollBy(int instanceId, int x, int y) { + mock.scrollBy(instanceId, x, y); + } + + @override + void scrollTo(int instanceId, int x, int y) { + mock.scrollTo(instanceId, x, y); + } + + @override + void setDownloadListener(int instanceId, int listenerInstanceId) { + mock.setDownloadListener(instanceId, listenerInstanceId); + } + + @override + void setWebContentsDebuggingEnabled(bool enabled) { + mock.setWebContentsDebuggingEnabled(enabled); + } + + @override + void setWebViewClient(int instanceId, int webViewClientInstanceId) { + mock.setWebViewClient(instanceId, webViewClientInstanceId); + } + + @override + void setWebChromeClient(int instanceId, int clientInstanceId) { + mock.setWebChromeClient(instanceId, clientInstanceId); + } +} + +class TestWebSettingsHostApiImpl extends TestWebSettingsHostApi { + final TestWebSettingsHostApi mock = MockTestWebSettingsHostApi(); + + @override + void create(int instanceId, int webViewInstanceId) { + mock.create(instanceId, webViewInstanceId); + } + + @override + void dispose(int instanceId) { + mock.dispose(instanceId); + } + + @override + void setBuiltInZoomControls(int instanceId, bool enabled) { + mock.setBuiltInZoomControls(instanceId, enabled); + } + + @override + void setDisplayZoomControls(int instanceId, bool enabled) { + mock.setDisplayZoomControls(instanceId, enabled); + } + + @override + void setDomStorageEnabled(int instanceId, bool flag) { + mock.setDomStorageEnabled(instanceId, flag); + } + + @override + void setJavaScriptCanOpenWindowsAutomatically(int instanceId, bool flag) { + mock.setJavaScriptCanOpenWindowsAutomatically(instanceId, flag); + } + + @override + void setJavaScriptEnabled(int instanceId, bool flag) { + mock.setJavaScriptEnabled(instanceId, flag); + } + + @override + void setLoadWithOverviewMode(int instanceId, bool overview) { + mock.setLoadWithOverviewMode(instanceId, overview); + } + + @override + void setMediaPlaybackRequiresUserGesture(int instanceId, bool require) { + mock.setMediaPlaybackRequiresUserGesture(instanceId, require); + } + + @override + void setSupportMultipleWindows(int instanceId, bool support) { + mock.setSupportMultipleWindows(instanceId, support); + } + + @override + void setSupportZoom(int instanceId, bool support) { + mock.setSupportZoom(instanceId, support); + } + + @override + void setUseWideViewPort(int instanceId, bool use) { + mock.setUseWideViewPort(instanceId, use); + } + + @override + void setUserAgentString(int instanceId, String userAgentString) { + mock.setUserAgentString(instanceId, userAgentString); + } +} + +class TestJavaScriptChannelHostApiImpl extends TestJavaScriptChannelHostApi { + final TestJavaScriptChannelHostApi mock = MockTestJavaScriptChannelHostApi(); + + @override + void create(int instanceId, String channelName) { + mock.create(instanceId, channelName); + } + + @override + void dispose(int instanceId) { + mock.dispose(instanceId); + } +} + +class TestWebViewClientHostApiImpl extends TestWebViewClientHostApi { + final TestWebViewClientHostApi mock = MockTestWebViewClientHostApi(); + + @override + void create(int instanceId, bool shouldOverrideUrlLoading) { + mock.create(instanceId, shouldOverrideUrlLoading); + } + + @override + void dispose(int instanceId) { + mock.dispose(instanceId); + } +} + +class TestDownloadListenerHostApiImpl extends TestDownloadListenerHostApi { + final TestDownloadListenerHostApi mock = MockTestDownloadListenerHostApi(); + + @override + void create(int instanceId) { + mock.create(instanceId); + } + + @override + void dispose(int instanceId) { + mock.dispose(instanceId); + } +} + +class TestWebChromeClientHostApiImpl extends TestWebChromeClientHostApi { + final TestWebChromeClientHostApi mock = MockTestWebChromeClientHostApi(); + + @override + void create(int instanceId, int webViewClientInstanceId) { + mock.create(instanceId, webViewClientInstanceId); + } + + @override + void dispose(int instanceId) { + mock.dispose(instanceId); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.mocks.dart new file mode 100644 index 000000000000..52cb1e043311 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.mocks.dart @@ -0,0 +1,297 @@ +// Mocks generated by Mockito 5.0.16 from annotations +// in webview_flutter_android/test/test_android_webview_api_impls.dart. +// Do not manually edit this file. + +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; + +import 'android_webview.pigeon.dart' as _i2; + +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +/// A class which mocks [TestWebViewHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestWebViewHostApi extends _i1.Mock + implements _i2.TestWebViewHostApi { + MockTestWebViewHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId, bool? useHybridComposition) => + super.noSuchMethod( + Invocation.method(#create, [instanceId, useHybridComposition]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + void loadUrl(int? instanceId, String? url, Map? headers) => + super.noSuchMethod( + Invocation.method(#loadUrl, [instanceId, url, headers]), + returnValueForMissingStub: null); + @override + String getUrl(int? instanceId) => + (super.noSuchMethod(Invocation.method(#getUrl, [instanceId]), + returnValue: '') as String); + @override + bool canGoBack(int? instanceId) => + (super.noSuchMethod(Invocation.method(#canGoBack, [instanceId]), + returnValue: false) as bool); + @override + bool canGoForward(int? instanceId) => + (super.noSuchMethod(Invocation.method(#canGoForward, [instanceId]), + returnValue: false) as bool); + @override + void goBack(int? instanceId) => + super.noSuchMethod(Invocation.method(#goBack, [instanceId]), + returnValueForMissingStub: null); + @override + void goForward(int? instanceId) => + super.noSuchMethod(Invocation.method(#goForward, [instanceId]), + returnValueForMissingStub: null); + @override + void reload(int? instanceId) => + super.noSuchMethod(Invocation.method(#reload, [instanceId]), + returnValueForMissingStub: null); + @override + void clearCache(int? instanceId, bool? includeDiskFiles) => + super.noSuchMethod( + Invocation.method(#clearCache, [instanceId, includeDiskFiles]), + returnValueForMissingStub: null); + @override + _i3.Future evaluateJavascript( + int? instanceId, String? javascriptString) => + (super.noSuchMethod( + Invocation.method( + #evaluateJavascript, [instanceId, javascriptString]), + returnValue: Future.value('')) as _i3.Future); + @override + String getTitle(int? instanceId) => + (super.noSuchMethod(Invocation.method(#getTitle, [instanceId]), + returnValue: '') as String); + @override + void scrollTo(int? instanceId, int? x, int? y) => + super.noSuchMethod(Invocation.method(#scrollTo, [instanceId, x, y]), + returnValueForMissingStub: null); + @override + void scrollBy(int? instanceId, int? x, int? y) => + super.noSuchMethod(Invocation.method(#scrollBy, [instanceId, x, y]), + returnValueForMissingStub: null); + @override + int getScrollX(int? instanceId) => + (super.noSuchMethod(Invocation.method(#getScrollX, [instanceId]), + returnValue: 0) as int); + @override + int getScrollY(int? instanceId) => + (super.noSuchMethod(Invocation.method(#getScrollY, [instanceId]), + returnValue: 0) as int); + @override + void setWebContentsDebuggingEnabled(bool? enabled) => super.noSuchMethod( + Invocation.method(#setWebContentsDebuggingEnabled, [enabled]), + returnValueForMissingStub: null); + @override + void setWebViewClient(int? instanceId, int? webViewClientInstanceId) => + super.noSuchMethod( + Invocation.method( + #setWebViewClient, [instanceId, webViewClientInstanceId]), + returnValueForMissingStub: null); + @override + void addJavaScriptChannel( + int? instanceId, int? javaScriptChannelInstanceId) => + super.noSuchMethod( + Invocation.method( + #addJavaScriptChannel, [instanceId, javaScriptChannelInstanceId]), + returnValueForMissingStub: null); + @override + void removeJavaScriptChannel( + int? instanceId, int? javaScriptChannelInstanceId) => + super.noSuchMethod( + Invocation.method(#removeJavaScriptChannel, + [instanceId, javaScriptChannelInstanceId]), + returnValueForMissingStub: null); + @override + void setDownloadListener(int? instanceId, int? listenerInstanceId) => + super.noSuchMethod( + Invocation.method( + #setDownloadListener, [instanceId, listenerInstanceId]), + returnValueForMissingStub: null); + @override + void setWebChromeClient(int? instanceId, int? clientInstanceId) => + super.noSuchMethod( + Invocation.method( + #setWebChromeClient, [instanceId, clientInstanceId]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [TestWebSettingsHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestWebSettingsHostApi extends _i1.Mock + implements _i2.TestWebSettingsHostApi { + MockTestWebSettingsHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId, int? webViewInstanceId) => super.noSuchMethod( + Invocation.method(#create, [instanceId, webViewInstanceId]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + void setDomStorageEnabled(int? instanceId, bool? flag) => super.noSuchMethod( + Invocation.method(#setDomStorageEnabled, [instanceId, flag]), + returnValueForMissingStub: null); + @override + void setJavaScriptCanOpenWindowsAutomatically(int? instanceId, bool? flag) => + super.noSuchMethod( + Invocation.method( + #setJavaScriptCanOpenWindowsAutomatically, [instanceId, flag]), + returnValueForMissingStub: null); + @override + void setSupportMultipleWindows(int? instanceId, bool? support) => + super.noSuchMethod( + Invocation.method(#setSupportMultipleWindows, [instanceId, support]), + returnValueForMissingStub: null); + @override + void setJavaScriptEnabled(int? instanceId, bool? flag) => super.noSuchMethod( + Invocation.method(#setJavaScriptEnabled, [instanceId, flag]), + returnValueForMissingStub: null); + @override + void setUserAgentString(int? instanceId, String? userAgentString) => + super.noSuchMethod( + Invocation.method(#setUserAgentString, [instanceId, userAgentString]), + returnValueForMissingStub: null); + @override + void setMediaPlaybackRequiresUserGesture(int? instanceId, bool? require) => + super.noSuchMethod( + Invocation.method( + #setMediaPlaybackRequiresUserGesture, [instanceId, require]), + returnValueForMissingStub: null); + @override + void setSupportZoom(int? instanceId, bool? support) => super.noSuchMethod( + Invocation.method(#setSupportZoom, [instanceId, support]), + returnValueForMissingStub: null); + @override + void setLoadWithOverviewMode(int? instanceId, bool? overview) => + super.noSuchMethod( + Invocation.method(#setLoadWithOverviewMode, [instanceId, overview]), + returnValueForMissingStub: null); + @override + void setUseWideViewPort(int? instanceId, bool? use) => super.noSuchMethod( + Invocation.method(#setUseWideViewPort, [instanceId, use]), + returnValueForMissingStub: null); + @override + void setDisplayZoomControls(int? instanceId, bool? enabled) => + super.noSuchMethod( + Invocation.method(#setDisplayZoomControls, [instanceId, enabled]), + returnValueForMissingStub: null); + @override + void setBuiltInZoomControls(int? instanceId, bool? enabled) => + super.noSuchMethod( + Invocation.method(#setBuiltInZoomControls, [instanceId, enabled]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [TestWebViewClientHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestWebViewClientHostApi extends _i1.Mock + implements _i2.TestWebViewClientHostApi { + MockTestWebViewClientHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId, bool? shouldOverrideUrlLoading) => + super.noSuchMethod( + Invocation.method(#create, [instanceId, shouldOverrideUrlLoading]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [TestWebChromeClientHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestWebChromeClientHostApi extends _i1.Mock + implements _i2.TestWebChromeClientHostApi { + MockTestWebChromeClientHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId, int? webViewClientInstanceId) => + super.noSuchMethod( + Invocation.method(#create, [instanceId, webViewClientInstanceId]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [TestJavaScriptChannelHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestJavaScriptChannelHostApi extends _i1.Mock + implements _i2.TestJavaScriptChannelHostApi { + MockTestJavaScriptChannelHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId, String? channelName) => + super.noSuchMethod(Invocation.method(#create, [instanceId, channelName]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [TestDownloadListenerHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestDownloadListenerHostApi extends _i1.Mock + implements _i2.TestDownloadListenerHostApi { + MockTestDownloadListenerHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId) => + super.noSuchMethod(Invocation.method(#create, [instanceId]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart new file mode 100644 index 000000000000..318e81932834 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart @@ -0,0 +1,85 @@ +// 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. + +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:webview_flutter_android/src/webview_widget.dart'; +import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; + +import 'android_webview.pigeon.dart'; +import 'webview_widget_test.mocks.dart'; + +@GenerateMocks([ + TestWebViewHostApi, + TestWebSettingsHostApi, + TestWebViewClientHostApi, + TestWebChromeClientHostApi, + TestJavaScriptChannelHostApi, + TestDownloadListenerHostApi, + WebViewPlatformCallbacksHandler, + JavascriptChannelRegistry, +]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$AndroidWebViewWidget', () { + late TestWebViewHostApi mockWebViewHostApi; + late TestWebSettingsHostApi mockWebSettingsHostApi; + late TestWebViewClientHostApi mockWebViewClientHostApi; + late TestWebChromeClientHostApi mockWebChromeClientHostApi; + late TestJavaScriptChannelHostApi mockJavaScriptChannelHostApi; + late TestDownloadListenerHostApi mockDownloadListenerHostApi; + + late WebViewPlatformCallbacksHandler mockCallbacksHandler; + late JavascriptChannelRegistry mockJavascriptChannelRegistry; + + setUp(() { + mockWebViewHostApi = MockTestWebViewHostApi(); + mockWebSettingsHostApi = MockTestWebSettingsHostApi(); + mockWebViewClientHostApi = MockTestWebViewClientHostApi(); + mockWebChromeClientHostApi = MockTestWebChromeClientHostApi(); + mockJavaScriptChannelHostApi = MockTestJavaScriptChannelHostApi(); + mockDownloadListenerHostApi = MockTestDownloadListenerHostApi(); + + TestWebViewHostApi.setup(mockWebViewHostApi); + TestWebSettingsHostApi.setup(mockWebSettingsHostApi); + TestWebViewClientHostApi.setup(mockWebViewClientHostApi); + TestWebChromeClientHostApi.setup(mockWebChromeClientHostApi); + TestJavaScriptChannelHostApi.setup(mockJavaScriptChannelHostApi); + TestDownloadListenerHostApi.setup(mockDownloadListenerHostApi); + + mockCallbacksHandler = MockWebViewPlatformCallbacksHandler(); + mockJavascriptChannelRegistry = MockJavascriptChannelRegistry(); + }); + + testWidgets('Create Widget', (WidgetTester tester) async { + late final AndroidWebViewPlatformController apple; + await tester.pumpWidget( + AndroidWebViewWidget( + onBuildWidget: (AndroidWebViewPlatformController controller) { + apple = controller; + return Container(); + }, + creationParams: CreationParams( + initialUrl: 'https://www.google.com', + ), + webViewPlatformCallbacksHandler: mockCallbacksHandler, + javascriptChannelRegistry: mockJavascriptChannelRegistry, + useHybridComposition: false, + ), + ); + + verifyInOrder([ + mockWebViewHostApi.create(0, false), + mockWebViewHostApi.loadUrl( + 0, + 'https://www.google.com', + {}, + ), + ]); + }); + }); +} diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.mocks.dart new file mode 100644 index 000000000000..000d624a2296 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.mocks.dart @@ -0,0 +1,365 @@ +// Mocks generated by Mockito 5.0.16 from annotations +// in webview_flutter_android/test/webview_widget_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:webview_flutter_platform_interface/src/platform_interface/javascript_channel_registry.dart' + as _i6; +import 'package:webview_flutter_platform_interface/src/platform_interface/webview_platform_callbacks_handler.dart' + as _i4; +import 'package:webview_flutter_platform_interface/src/types/types.dart' as _i5; + +import 'android_webview.pigeon.dart' as _i2; + +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +/// A class which mocks [TestWebViewHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestWebViewHostApi extends _i1.Mock + implements _i2.TestWebViewHostApi { + MockTestWebViewHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId, bool? useHybridComposition) => + super.noSuchMethod( + Invocation.method(#create, [instanceId, useHybridComposition]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + void loadUrl(int? instanceId, String? url, Map? headers) => + super.noSuchMethod( + Invocation.method(#loadUrl, [instanceId, url, headers]), + returnValueForMissingStub: null); + @override + String getUrl(int? instanceId) => + (super.noSuchMethod(Invocation.method(#getUrl, [instanceId]), + returnValue: '') as String); + @override + bool canGoBack(int? instanceId) => + (super.noSuchMethod(Invocation.method(#canGoBack, [instanceId]), + returnValue: false) as bool); + @override + bool canGoForward(int? instanceId) => + (super.noSuchMethod(Invocation.method(#canGoForward, [instanceId]), + returnValue: false) as bool); + @override + void goBack(int? instanceId) => + super.noSuchMethod(Invocation.method(#goBack, [instanceId]), + returnValueForMissingStub: null); + @override + void goForward(int? instanceId) => + super.noSuchMethod(Invocation.method(#goForward, [instanceId]), + returnValueForMissingStub: null); + @override + void reload(int? instanceId) => + super.noSuchMethod(Invocation.method(#reload, [instanceId]), + returnValueForMissingStub: null); + @override + void clearCache(int? instanceId, bool? includeDiskFiles) => + super.noSuchMethod( + Invocation.method(#clearCache, [instanceId, includeDiskFiles]), + returnValueForMissingStub: null); + @override + _i3.Future evaluateJavascript( + int? instanceId, String? javascriptString) => + (super.noSuchMethod( + Invocation.method( + #evaluateJavascript, [instanceId, javascriptString]), + returnValue: Future.value('')) as _i3.Future); + @override + String getTitle(int? instanceId) => + (super.noSuchMethod(Invocation.method(#getTitle, [instanceId]), + returnValue: '') as String); + @override + void scrollTo(int? instanceId, int? x, int? y) => + super.noSuchMethod(Invocation.method(#scrollTo, [instanceId, x, y]), + returnValueForMissingStub: null); + @override + void scrollBy(int? instanceId, int? x, int? y) => + super.noSuchMethod(Invocation.method(#scrollBy, [instanceId, x, y]), + returnValueForMissingStub: null); + @override + int getScrollX(int? instanceId) => + (super.noSuchMethod(Invocation.method(#getScrollX, [instanceId]), + returnValue: 0) as int); + @override + int getScrollY(int? instanceId) => + (super.noSuchMethod(Invocation.method(#getScrollY, [instanceId]), + returnValue: 0) as int); + @override + void setWebContentsDebuggingEnabled(bool? enabled) => super.noSuchMethod( + Invocation.method(#setWebContentsDebuggingEnabled, [enabled]), + returnValueForMissingStub: null); + @override + void setWebViewClient(int? instanceId, int? webViewClientInstanceId) => + super.noSuchMethod( + Invocation.method( + #setWebViewClient, [instanceId, webViewClientInstanceId]), + returnValueForMissingStub: null); + @override + void addJavaScriptChannel( + int? instanceId, int? javaScriptChannelInstanceId) => + super.noSuchMethod( + Invocation.method( + #addJavaScriptChannel, [instanceId, javaScriptChannelInstanceId]), + returnValueForMissingStub: null); + @override + void removeJavaScriptChannel( + int? instanceId, int? javaScriptChannelInstanceId) => + super.noSuchMethod( + Invocation.method(#removeJavaScriptChannel, + [instanceId, javaScriptChannelInstanceId]), + returnValueForMissingStub: null); + @override + void setDownloadListener(int? instanceId, int? listenerInstanceId) => + super.noSuchMethod( + Invocation.method( + #setDownloadListener, [instanceId, listenerInstanceId]), + returnValueForMissingStub: null); + @override + void setWebChromeClient(int? instanceId, int? clientInstanceId) => + super.noSuchMethod( + Invocation.method( + #setWebChromeClient, [instanceId, clientInstanceId]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [TestWebSettingsHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestWebSettingsHostApi extends _i1.Mock + implements _i2.TestWebSettingsHostApi { + MockTestWebSettingsHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId, int? webViewInstanceId) => super.noSuchMethod( + Invocation.method(#create, [instanceId, webViewInstanceId]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + void setDomStorageEnabled(int? instanceId, bool? flag) => super.noSuchMethod( + Invocation.method(#setDomStorageEnabled, [instanceId, flag]), + returnValueForMissingStub: null); + @override + void setJavaScriptCanOpenWindowsAutomatically(int? instanceId, bool? flag) => + super.noSuchMethod( + Invocation.method( + #setJavaScriptCanOpenWindowsAutomatically, [instanceId, flag]), + returnValueForMissingStub: null); + @override + void setSupportMultipleWindows(int? instanceId, bool? support) => + super.noSuchMethod( + Invocation.method(#setSupportMultipleWindows, [instanceId, support]), + returnValueForMissingStub: null); + @override + void setJavaScriptEnabled(int? instanceId, bool? flag) => super.noSuchMethod( + Invocation.method(#setJavaScriptEnabled, [instanceId, flag]), + returnValueForMissingStub: null); + @override + void setUserAgentString(int? instanceId, String? userAgentString) => + super.noSuchMethod( + Invocation.method(#setUserAgentString, [instanceId, userAgentString]), + returnValueForMissingStub: null); + @override + void setMediaPlaybackRequiresUserGesture(int? instanceId, bool? require) => + super.noSuchMethod( + Invocation.method( + #setMediaPlaybackRequiresUserGesture, [instanceId, require]), + returnValueForMissingStub: null); + @override + void setSupportZoom(int? instanceId, bool? support) => super.noSuchMethod( + Invocation.method(#setSupportZoom, [instanceId, support]), + returnValueForMissingStub: null); + @override + void setLoadWithOverviewMode(int? instanceId, bool? overview) => + super.noSuchMethod( + Invocation.method(#setLoadWithOverviewMode, [instanceId, overview]), + returnValueForMissingStub: null); + @override + void setUseWideViewPort(int? instanceId, bool? use) => super.noSuchMethod( + Invocation.method(#setUseWideViewPort, [instanceId, use]), + returnValueForMissingStub: null); + @override + void setDisplayZoomControls(int? instanceId, bool? enabled) => + super.noSuchMethod( + Invocation.method(#setDisplayZoomControls, [instanceId, enabled]), + returnValueForMissingStub: null); + @override + void setBuiltInZoomControls(int? instanceId, bool? enabled) => + super.noSuchMethod( + Invocation.method(#setBuiltInZoomControls, [instanceId, enabled]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [TestWebViewClientHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestWebViewClientHostApi extends _i1.Mock + implements _i2.TestWebViewClientHostApi { + MockTestWebViewClientHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId, bool? shouldOverrideUrlLoading) => + super.noSuchMethod( + Invocation.method(#create, [instanceId, shouldOverrideUrlLoading]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [TestWebChromeClientHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestWebChromeClientHostApi extends _i1.Mock + implements _i2.TestWebChromeClientHostApi { + MockTestWebChromeClientHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId, int? webViewClientInstanceId) => + super.noSuchMethod( + Invocation.method(#create, [instanceId, webViewClientInstanceId]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [TestJavaScriptChannelHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestJavaScriptChannelHostApi extends _i1.Mock + implements _i2.TestJavaScriptChannelHostApi { + MockTestJavaScriptChannelHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId, String? channelName) => + super.noSuchMethod(Invocation.method(#create, [instanceId, channelName]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [TestDownloadListenerHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestDownloadListenerHostApi extends _i1.Mock + implements _i2.TestDownloadListenerHostApi { + MockTestDownloadListenerHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? instanceId) => + super.noSuchMethod(Invocation.method(#create, [instanceId]), + returnValueForMissingStub: null); + @override + void dispose(int? instanceId) => + super.noSuchMethod(Invocation.method(#dispose, [instanceId]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [WebViewPlatformCallbacksHandler]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockWebViewPlatformCallbacksHandler extends _i1.Mock + implements _i4.WebViewPlatformCallbacksHandler { + MockWebViewPlatformCallbacksHandler() { + _i1.throwOnMissingStub(this); + } + + @override + _i3.FutureOr onNavigationRequest({String? url, bool? isForMainFrame}) => + (super.noSuchMethod( + Invocation.method(#onNavigationRequest, [], + {#url: url, #isForMainFrame: isForMainFrame}), + returnValue: Future.value(false)) as _i3.FutureOr); + @override + void onPageStarted(String? url) => + super.noSuchMethod(Invocation.method(#onPageStarted, [url]), + returnValueForMissingStub: null); + @override + void onPageFinished(String? url) => + super.noSuchMethod(Invocation.method(#onPageFinished, [url]), + returnValueForMissingStub: null); + @override + void onProgress(int? progress) => + super.noSuchMethod(Invocation.method(#onProgress, [progress]), + returnValueForMissingStub: null); + @override + void onWebResourceError(_i5.WebResourceError? error) => + super.noSuchMethod(Invocation.method(#onWebResourceError, [error]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} + +/// A class which mocks [JavascriptChannelRegistry]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockJavascriptChannelRegistry extends _i1.Mock + implements _i6.JavascriptChannelRegistry { + MockJavascriptChannelRegistry() { + _i1.throwOnMissingStub(this); + } + + @override + Map get channels => + (super.noSuchMethod(Invocation.getter(#channels), + returnValue: {}) + as Map); + @override + void onJavascriptChannelMessage(String? channel, String? message) => + super.noSuchMethod( + Invocation.method(#onJavascriptChannelMessage, [channel, message]), + returnValueForMissingStub: null); + @override + void updateJavascriptChannelsFromSet(Set<_i5.JavascriptChannel>? channels) => + super.noSuchMethod( + Invocation.method(#updateJavascriptChannelsFromSet, [channels]), + returnValueForMissingStub: null); + @override + String toString() => super.toString(); +} From 4c02c7de32c19eb25a41af7b8cfcc60cdfab0389 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 27 Oct 2021 18:43:05 -0700 Subject: [PATCH 45/54] use mocks for tests --- .../test/android_webview_test.dart | 38 ++- ...s.dart => android_webview_test.mocks.dart} | 6 +- .../test/test_android_webview_api_impls.dart | 261 ------------------ .../test/webview_widget_test.dart | 2 - 4 files changed, 28 insertions(+), 279 deletions(-) rename packages/webview_flutter/webview_flutter_android/test/{test_android_webview_api_impls.mocks.dart => android_webview_test.mocks.dart} (98%) delete mode 100644 packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.dart diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart index 0f50e5e21b0b..e6ade46e9a24 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart @@ -3,21 +3,29 @@ // found in the LICENSE file. import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; import 'package:webview_flutter_android/src/android_webview.dart'; import 'package:webview_flutter_android/src/android_webview_api_impls.dart'; import 'package:webview_flutter_android/src/instance_manager.dart'; import 'android_webview.pigeon.dart'; -import 'test_android_webview_api_impls.dart'; - - +import 'android_webview_test.mocks.dart'; + +@GenerateMocks([ + TestWebViewHostApi, + TestWebSettingsHostApi, + TestWebViewClientHostApi, + TestWebChromeClientHostApi, + TestJavaScriptChannelHostApi, + TestDownloadListenerHostApi +]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('Android WebView', () { group('$WebView', () { setUpAll(() { - TestWebViewHostApi.setup(TestWebViewHostApiImpl()); + TestWebViewHostApi.setup(MockTestWebViewHostApi()); }); setUp(() { @@ -32,8 +40,8 @@ void main() { group('$WebSettings', () { setUpAll(() { - TestWebViewHostApi.setup(TestWebViewHostApiImpl()); - TestWebSettingsHostApi.setup(TestWebSettingsHostApiImpl()); + TestWebViewHostApi.setup(MockTestWebViewHostApi()); + TestWebSettingsHostApi.setup(MockTestWebSettingsHostApi()); }); setUp(() { @@ -56,8 +64,8 @@ void main() { group('$JavaScriptChannel', () { setUpAll(() { - TestWebViewHostApi.setup(TestWebViewHostApiImpl()); - TestJavaScriptChannelHostApi.setup(TestJavaScriptChannelHostApiImpl()); + TestWebViewHostApi.setup(MockTestWebViewHostApi()); + TestJavaScriptChannelHostApi.setup(MockTestJavaScriptChannelHostApi()); }); setUp(() { @@ -88,8 +96,8 @@ void main() { group('$WebViewClient', () { setUpAll(() { - TestWebViewHostApi.setup(TestWebViewHostApiImpl()); - TestWebViewClientHostApi.setup(TestWebViewClientHostApiImpl()); + TestWebViewHostApi.setup(MockTestWebViewHostApi()); + TestWebViewClientHostApi.setup(MockTestWebViewClientHostApi()); }); setUp(() { @@ -121,8 +129,8 @@ void main() { group('$DownloadListener', () { setUpAll(() { - TestWebViewHostApi.setup(TestWebViewHostApiImpl()); - TestDownloadListenerHostApi.setup(TestDownloadListenerHostApiImpl()); + TestWebViewHostApi.setup(MockTestWebViewHostApi()); + TestDownloadListenerHostApi.setup(MockTestDownloadListenerHostApi()); }); setUp(() { @@ -154,9 +162,9 @@ void main() { group('$WebChromeClient', () { setUpAll(() { - TestWebViewHostApi.setup(TestWebViewHostApiImpl()); - TestWebViewClientHostApi.setup(TestWebViewClientHostApiImpl()); - TestWebChromeClientHostApi.setup(TestWebChromeClientHostApiImpl()); + TestWebViewHostApi.setup(MockTestWebViewHostApi()); + TestWebViewClientHostApi.setup(MockTestWebViewClientHostApi()); + TestWebChromeClientHostApi.setup(MockTestWebChromeClientHostApi()); }); setUp(() { diff --git a/packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart similarity index 98% rename from packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.mocks.dart rename to packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart index 52cb1e043311..123c7f696396 100644 --- a/packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.mocks.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart @@ -1,5 +1,9 @@ +// 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. + // Mocks generated by Mockito 5.0.16 from annotations -// in webview_flutter_android/test/test_android_webview_api_impls.dart. +// in webview_flutter_android/test/android_webview_test.dart. // Do not manually edit this file. import 'dart:async' as _i3; diff --git a/packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.dart deleted file mode 100644 index 8fcf3f204e0a..000000000000 --- a/packages/webview_flutter/webview_flutter_android/test/test_android_webview_api_impls.dart +++ /dev/null @@ -1,261 +0,0 @@ -// 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. - -import 'package:mockito/annotations.dart'; - -import 'android_webview.pigeon.dart'; - -import 'test_android_webview_api_impls.mocks.dart'; - -@GenerateMocks([ - TestWebViewHostApi, - TestWebSettingsHostApi, - TestWebViewClientHostApi, - TestWebChromeClientHostApi, - TestJavaScriptChannelHostApi, - TestDownloadListenerHostApi, -]) -void main() {} - -class TestWebViewHostApiImpl extends TestWebViewHostApi { - final TestWebViewHostApi mock = MockTestWebViewHostApi(); - - @override - void addJavaScriptChannel(int instanceId, int javaScriptChannelInstanceId) { - mock.addJavaScriptChannel(instanceId, javaScriptChannelInstanceId); - } - - @override - bool canGoBack(int instanceId) { - return mock.canGoBack(instanceId); - } - - @override - bool canGoForward(int instanceId) { - return mock.canGoForward(instanceId); - } - - @override - void clearCache(int instanceId, bool includeDiskFiles) { - mock.clearCache(instanceId, includeDiskFiles); - } - - @override - void create(int instanceId, bool useHybridComposition) { - mock.create(instanceId, useHybridComposition); - } - - @override - void dispose(int instanceId) { - mock.dispose(instanceId); - } - - @override - Future evaluateJavascript(int instanceId, String javascriptString) { - return mock.evaluateJavascript(instanceId, javascriptString); - } - - @override - int getScrollX(int instanceId) { - return mock.getScrollX(instanceId); - } - - @override - int getScrollY(int instanceId) { - return mock.getScrollY(instanceId); - } - - @override - String getTitle(int instanceId) { - return mock.getTitle(instanceId); - } - - @override - String getUrl(int instanceId) { - return mock.getUrl(instanceId); - } - - @override - void goBack(int instanceId) { - mock.goBack(instanceId); - } - - @override - void goForward(int instanceId) { - mock.goForward(instanceId); - } - - @override - void loadUrl(int instanceId, String url, Map headers) { - mock.loadUrl(instanceId, url, headers.cast()); - } - - @override - void reload(int instanceId) { - mock.reload(instanceId); - } - - @override - void removeJavaScriptChannel( - int instanceId, - int javaScriptChannelInstanceId, - ) { - mock.removeJavaScriptChannel(instanceId, javaScriptChannelInstanceId); - } - - @override - void scrollBy(int instanceId, int x, int y) { - mock.scrollBy(instanceId, x, y); - } - - @override - void scrollTo(int instanceId, int x, int y) { - mock.scrollTo(instanceId, x, y); - } - - @override - void setDownloadListener(int instanceId, int listenerInstanceId) { - mock.setDownloadListener(instanceId, listenerInstanceId); - } - - @override - void setWebContentsDebuggingEnabled(bool enabled) { - mock.setWebContentsDebuggingEnabled(enabled); - } - - @override - void setWebViewClient(int instanceId, int webViewClientInstanceId) { - mock.setWebViewClient(instanceId, webViewClientInstanceId); - } - - @override - void setWebChromeClient(int instanceId, int clientInstanceId) { - mock.setWebChromeClient(instanceId, clientInstanceId); - } -} - -class TestWebSettingsHostApiImpl extends TestWebSettingsHostApi { - final TestWebSettingsHostApi mock = MockTestWebSettingsHostApi(); - - @override - void create(int instanceId, int webViewInstanceId) { - mock.create(instanceId, webViewInstanceId); - } - - @override - void dispose(int instanceId) { - mock.dispose(instanceId); - } - - @override - void setBuiltInZoomControls(int instanceId, bool enabled) { - mock.setBuiltInZoomControls(instanceId, enabled); - } - - @override - void setDisplayZoomControls(int instanceId, bool enabled) { - mock.setDisplayZoomControls(instanceId, enabled); - } - - @override - void setDomStorageEnabled(int instanceId, bool flag) { - mock.setDomStorageEnabled(instanceId, flag); - } - - @override - void setJavaScriptCanOpenWindowsAutomatically(int instanceId, bool flag) { - mock.setJavaScriptCanOpenWindowsAutomatically(instanceId, flag); - } - - @override - void setJavaScriptEnabled(int instanceId, bool flag) { - mock.setJavaScriptEnabled(instanceId, flag); - } - - @override - void setLoadWithOverviewMode(int instanceId, bool overview) { - mock.setLoadWithOverviewMode(instanceId, overview); - } - - @override - void setMediaPlaybackRequiresUserGesture(int instanceId, bool require) { - mock.setMediaPlaybackRequiresUserGesture(instanceId, require); - } - - @override - void setSupportMultipleWindows(int instanceId, bool support) { - mock.setSupportMultipleWindows(instanceId, support); - } - - @override - void setSupportZoom(int instanceId, bool support) { - mock.setSupportZoom(instanceId, support); - } - - @override - void setUseWideViewPort(int instanceId, bool use) { - mock.setUseWideViewPort(instanceId, use); - } - - @override - void setUserAgentString(int instanceId, String userAgentString) { - mock.setUserAgentString(instanceId, userAgentString); - } -} - -class TestJavaScriptChannelHostApiImpl extends TestJavaScriptChannelHostApi { - final TestJavaScriptChannelHostApi mock = MockTestJavaScriptChannelHostApi(); - - @override - void create(int instanceId, String channelName) { - mock.create(instanceId, channelName); - } - - @override - void dispose(int instanceId) { - mock.dispose(instanceId); - } -} - -class TestWebViewClientHostApiImpl extends TestWebViewClientHostApi { - final TestWebViewClientHostApi mock = MockTestWebViewClientHostApi(); - - @override - void create(int instanceId, bool shouldOverrideUrlLoading) { - mock.create(instanceId, shouldOverrideUrlLoading); - } - - @override - void dispose(int instanceId) { - mock.dispose(instanceId); - } -} - -class TestDownloadListenerHostApiImpl extends TestDownloadListenerHostApi { - final TestDownloadListenerHostApi mock = MockTestDownloadListenerHostApi(); - - @override - void create(int instanceId) { - mock.create(instanceId); - } - - @override - void dispose(int instanceId) { - mock.dispose(instanceId); - } -} - -class TestWebChromeClientHostApiImpl extends TestWebChromeClientHostApi { - final TestWebChromeClientHostApi mock = MockTestWebChromeClientHostApi(); - - @override - void create(int instanceId, int webViewClientInstanceId) { - mock.create(instanceId, webViewClientInstanceId); - } - - @override - void dispose(int instanceId) { - mock.dispose(instanceId); - } -} diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart index 318e81932834..7dacacd1c408 100644 --- a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart @@ -56,11 +56,9 @@ void main() { }); testWidgets('Create Widget', (WidgetTester tester) async { - late final AndroidWebViewPlatformController apple; await tester.pumpWidget( AndroidWebViewWidget( onBuildWidget: (AndroidWebViewPlatformController controller) { - apple = controller; return Container(); }, creationParams: CreationParams( From d289db1d3d703b4de9f9c7aa13be45065ee8b2f3 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 28 Oct 2021 02:41:32 -0700 Subject: [PATCH 46/54] dart unit tests --- .../lib/src/android_webview.dart | 2 +- .../test/webview_widget_test.dart | 367 +++++++++++++++++- 2 files changed, 349 insertions(+), 20 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index aaa50eb79a0c..b85861c2d4b6 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -366,7 +366,7 @@ class WebSettings { /// /// The default is false. Future setSupportMultipleWindows(bool support) { - return api.setSupportZoomFromInstance(this, support); + return api.setSupportMultipleWindowsFromInstance(this, support); } /// Tells the WebView to enable JavaScript execution. diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart index 7dacacd1c408..3e3019e544d5 100644 --- a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart @@ -2,10 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; + import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import 'package:webview_flutter_android/src/android_webview.dart' + as android_webview; +import 'package:webview_flutter_android/src/android_webview_api_impls.dart'; +import 'package:webview_flutter_android/src/instance_manager.dart'; import 'package:webview_flutter_android/src/webview_widget.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; @@ -26,12 +32,12 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('$AndroidWebViewWidget', () { - late TestWebViewHostApi mockWebViewHostApi; - late TestWebSettingsHostApi mockWebSettingsHostApi; - late TestWebViewClientHostApi mockWebViewClientHostApi; - late TestWebChromeClientHostApi mockWebChromeClientHostApi; - late TestJavaScriptChannelHostApi mockJavaScriptChannelHostApi; - late TestDownloadListenerHostApi mockDownloadListenerHostApi; + late MockTestWebViewHostApi mockWebViewHostApi; + late MockTestWebSettingsHostApi mockWebSettingsHostApi; + late MockTestWebViewClientHostApi mockWebViewClientHostApi; + late MockTestWebChromeClientHostApi mockWebChromeClientHostApi; + late MockTestJavaScriptChannelHostApi mockJavaScriptChannelHostApi; + late MockTestDownloadListenerHostApi mockDownloadListenerHostApi; late WebViewPlatformCallbacksHandler mockCallbacksHandler; late JavascriptChannelRegistry mockJavascriptChannelRegistry; @@ -53,31 +59,354 @@ void main() { mockCallbacksHandler = MockWebViewPlatformCallbacksHandler(); mockJavascriptChannelRegistry = MockJavascriptChannelRegistry(); + + final InstanceManager instanceManager = InstanceManager(); + android_webview.WebView.api = WebViewHostApiImpl( + instanceManager: instanceManager, + ); + android_webview.WebSettings.api = WebSettingsHostApiImpl( + instanceManager: instanceManager, + ); + android_webview.JavaScriptChannel.api = JavaScriptChannelHostApiImpl( + instanceManager: instanceManager, + ); + android_webview.WebViewClient.api = WebViewClientHostApiImpl( + instanceManager: instanceManager, + ); + android_webview.DownloadListener.api = DownloadListenerHostApiImpl( + instanceManager: instanceManager, + ); + android_webview.WebChromeClient.api = WebChromeClientHostApiImpl( + instanceManager: instanceManager, + ); }); - testWidgets('Create Widget', (WidgetTester tester) async { + // Builds a AndroidWebViewWidget with default parameters. + Future buildWidget( + WidgetTester tester, { + Widget Function(AndroidWebViewPlatformController platformController)? + onBuildWidget, + CreationParams? creationParams, + WebViewPlatformCallbacksHandler? webViewPlatformCallbacksHandler, + JavascriptChannelRegistry? javascriptChannelRegistry, + bool? useHybridComposition, + }) async { + final Completer controllerCompleter = + Completer(); + await tester.pumpWidget( AndroidWebViewWidget( - onBuildWidget: (AndroidWebViewPlatformController controller) { - return Container(); - }, - creationParams: CreationParams( - initialUrl: 'https://www.google.com', - ), - webViewPlatformCallbacksHandler: mockCallbacksHandler, - javascriptChannelRegistry: mockJavascriptChannelRegistry, - useHybridComposition: false, + onBuildWidget: onBuildWidget ?? + (AndroidWebViewPlatformController controller) { + controllerCompleter.complete(controller); + return Container(); + }, + creationParams: creationParams ?? CreationParams(), + webViewPlatformCallbacksHandler: + webViewPlatformCallbacksHandler ?? mockCallbacksHandler, + javascriptChannelRegistry: + javascriptChannelRegistry ?? mockJavascriptChannelRegistry, + useHybridComposition: useHybridComposition ?? false, ), ); + return controllerCompleter.future; + } + + testWidgets('Create Widget', (WidgetTester tester) async { + await buildWidget(tester); + + verify(mockWebSettingsHostApi.setDomStorageEnabled(1, true)); + verify(mockWebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically( + 1, + true, + )); + verify(mockWebSettingsHostApi.setSupportMultipleWindows(1, true)); + verifyInOrder([ mockWebViewHostApi.create(0, false), - mockWebViewHostApi.loadUrl( + mockWebViewHostApi.setWebViewClient(0, any), + mockWebViewHostApi.setDownloadListener(0, any), + mockWebViewHostApi.setWebChromeClient(0, any), + ]); + }); + + testWidgets( + 'Create Widget with Hybrid Composition', + (WidgetTester tester) async { + await buildWidget(tester, useHybridComposition: true); + verify(mockWebViewHostApi.create(0, true)); + }, + ); + + group('CreationParams', () { + testWidgets('initialUrl', (WidgetTester tester) async { + await buildWidget( + tester, + creationParams: CreationParams(initialUrl: 'https://www.google.com'), + ); + verify(mockWebViewHostApi.loadUrl( 0, 'https://www.google.com', {}, - ), - ]); + )); + }); + + testWidgets('userAgent', (WidgetTester tester) async { + await buildWidget( + tester, + creationParams: CreationParams(userAgent: 'MyUserAgent'), + ); + + verify(mockWebSettingsHostApi.setUserAgentString(1, 'MyUserAgent')); + }); + + testWidgets('autoMediaPlaybackPolicy true', (WidgetTester tester) async { + await buildWidget( + tester, + creationParams: CreationParams( + autoMediaPlaybackPolicy: + AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + ), + ); + + verify( + mockWebSettingsHostApi.setMediaPlaybackRequiresUserGesture(any, true), + ); + }); + + testWidgets('autoMediaPlaybackPolicy false', (WidgetTester tester) async { + await buildWidget( + tester, + creationParams: CreationParams( + autoMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + ), + ); + + verify(mockWebSettingsHostApi.setMediaPlaybackRequiresUserGesture( + any, + false, + )); + }); + + testWidgets('javascriptChannelNames', (WidgetTester tester) async { + await buildWidget( + tester, + creationParams: CreationParams( + javascriptChannelNames: {'a', 'b'}, + ), + ); + + verify(mockJavaScriptChannelHostApi.create(any, 'a')); + verify(mockJavaScriptChannelHostApi.create(any, 'b')); + verify(mockWebViewHostApi.addJavaScriptChannel(0, any)).called(2); + }); + + group('WebSettings', () { + testWidgets('javascriptMode', (WidgetTester tester) async { + await buildWidget( + tester, + creationParams: CreationParams( + webSettings: WebSettings( + userAgent: WebSetting.absent(), + javascriptMode: JavascriptMode.unrestricted, + ), + ), + ); + + verify(mockWebSettingsHostApi.setJavaScriptEnabled(any, true)); + }); + + testWidgets('hasNavigationDelegate', (WidgetTester tester) async { + await buildWidget( + tester, + creationParams: CreationParams( + webSettings: WebSettings( + userAgent: WebSetting.absent(), + hasNavigationDelegate: true, + ), + ), + ); + + verify(mockWebViewClientHostApi.create(any, true)); + }); + + testWidgets('debuggingEnabled', (WidgetTester tester) async { + await buildWidget( + tester, + creationParams: CreationParams( + webSettings: WebSettings( + userAgent: WebSetting.absent(), + debuggingEnabled: true, + ), + ), + ); + + verify(mockWebViewHostApi.setWebContentsDebuggingEnabled(true)); + }); + + testWidgets('userAgent', (WidgetTester tester) async { + await buildWidget( + tester, + creationParams: CreationParams( + webSettings: WebSettings( + userAgent: WebSetting.of('myUserAgent'), + ), + ), + ); + + verify(mockWebSettingsHostApi.setUserAgentString(any, 'myUserAgent')); + }); + }); + }); + + group('$AndroidWebViewPlatformController', () { + testWidgets('loadUrl', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + await controller.loadUrl( + 'https://www.google.com', + {'a': 'header'}, + ); + + verify(mockWebViewHostApi.loadUrl( + any, + 'https://www.google.com', + {'a': 'header'}, + )); + }); + + testWidgets('currentUrl', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + when(mockWebViewHostApi.getUrl(any)) + .thenReturn('https://www.google.com'); + expect(controller.currentUrl(), completion('https://www.google.com')); + }); + + testWidgets('canGoBack', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + when(mockWebViewHostApi.canGoBack(any)).thenReturn(false); + expect(controller.canGoBack(), completion(false)); + }); + + testWidgets('canGoForward', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + when(mockWebViewHostApi.canGoForward(any)).thenReturn(true); + expect(controller.canGoForward(), completion(true)); + }); + + testWidgets('goBack', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + await controller.goBack(); + verify(mockWebViewHostApi.goBack(any)); + }); + + testWidgets('goForward', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + await controller.goForward(); + verify(mockWebViewHostApi.goForward(any)); + }); + + testWidgets('reload', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + await controller.reload(); + verify(mockWebViewHostApi.reload(any)); + }); + + testWidgets('clearCache', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + await controller.clearCache(); + verify(mockWebViewHostApi.clearCache(any, true)); + }); + + testWidgets('evaluateJavascript', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + when(mockWebViewHostApi.evaluateJavascript(any, 'runJavaScript')) + .thenAnswer( + (_) => Future.value('returnString'), + ); + expect( + controller.evaluateJavascript('runJavaScript'), + completion('returnString'), + ); + }); + + testWidgets('addJavascriptChannels', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + await controller.addJavascriptChannels({'c', 'd'}); + verify(mockJavaScriptChannelHostApi.create(any, 'c')); + verify(mockJavaScriptChannelHostApi.create(any, 'd')); + verify(mockWebViewHostApi.addJavaScriptChannel(0, any)).called(2); + }); + + testWidgets('removeJavascriptChannels', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + await controller.addJavascriptChannels({'c', 'd'}); + await controller.removeJavascriptChannels({'c', 'd'}); + verify(mockJavaScriptChannelHostApi.dispose(any)).called(2); + verify(mockWebViewHostApi.removeJavaScriptChannel(0, any)).called(2); + }); + + testWidgets('getTitle', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + when(mockWebViewHostApi.getTitle(any)).thenReturn('Web Title'); + expect(controller.getTitle(), completion('Web Title')); + }); + + testWidgets('scrollTo', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + await controller.scrollTo(1, 2); + verify(mockWebViewHostApi.scrollTo(any, 1, 2)); + }); + + testWidgets('scrollBy', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + await controller.scrollBy(3, 4); + verify(mockWebViewHostApi.scrollBy(any, 3, 4)); + }); + + testWidgets('getScrollX', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + when(mockWebViewHostApi.getScrollX(any)).thenReturn(23); + expect(controller.getScrollX(), completion(23)); + }); + + testWidgets('getScrollY', (WidgetTester tester) async { + final AndroidWebViewPlatformController controller = + await buildWidget(tester); + + when(mockWebViewHostApi.getScrollY(any)).thenReturn(25); + expect(controller.getScrollY(), completion(25)); + }); }); }); } From b71ecaa4b2ab46982fd9d12ff80f67a859898ba2 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 28 Oct 2021 02:44:47 -0700 Subject: [PATCH 47/54] null return values --- .../plugins/webviewflutter/WebViewHostApiImpl.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index 75da8c7a7632..8a410a37a280 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -16,6 +16,11 @@ import java.util.Map; class WebViewHostApiImpl implements GeneratedAndroidWebView.WebViewHostApi { + // TODO(bparrishMines): This can be removed once pigeon supports null values: https://github.com/flutter/flutter/issues/59118 + // Workaround to represent null Strings since pigeon doesn't support null + // values. + static final String nullStringIdentifier = ""; + private final InstanceManager instanceManager; private final WebViewProxy webViewProxy; private final Context context; @@ -124,7 +129,8 @@ public void loadUrl(Long instanceId, String url, Map headers) { @Override public String getUrl(Long instanceId) { final WebView webView = (WebView) instanceManager.getInstance(instanceId); - return webView.getUrl(); + final String result = webView.getUrl(); + return result != null ? result : nullStringIdentifier; } @Override @@ -173,7 +179,8 @@ public void evaluateJavascript( @Override public String getTitle(Long instanceId) { final WebView webView = (WebView) instanceManager.getInstance(instanceId); - return webView.getTitle(); + final String result = webView.getTitle(); + return result != null ? result : nullStringIdentifier; } @Override From 43e42df58f9abc64ee4d59aa95fea9634605f4fd Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 28 Oct 2021 11:19:45 -0700 Subject: [PATCH 48/54] set hard version for android. Unit tests now fail because of channels --- packages/webview_flutter/webview_flutter/pubspec.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml index 2718257d98d5..3647da2fb767 100644 --- a/packages/webview_flutter/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter/pubspec.yaml @@ -20,9 +20,7 @@ dependencies: flutter: sdk: flutter webview_flutter_platform_interface: ^1.0.0 - # TODO(bparrishMines): Don't commit. Undo after tests pass. - webview_flutter_android: - path: ../webview_flutter_android + webview_flutter_android: 2.0.13 webview_flutter_wkwebview: ^2.0.13 dev_dependencies: From 8bbe077a1c7c904283b5c53142649d2c9732bd3d Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 28 Oct 2021 11:48:50 -0700 Subject: [PATCH 49/54] add zoom support --- .../lib/src/webview_widget.dart | 11 +++++++++++ .../test/webview_widget_test.dart | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart b/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart index aed093e7a4bf..14b712ff91b8 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/webview_widget.dart @@ -54,6 +54,10 @@ class _AndroidWebViewWidgetState extends State { webView.settings.setDomStorageEnabled(true); webView.settings.setJavaScriptCanOpenWindowsAutomatically(true); webView.settings.setSupportMultipleWindows(true); + webView.settings.setLoadWithOverviewMode(true); + webView.settings.setUseWideViewPort(true); + webView.settings.setDisplayZoomControls(false); + webView.settings.setBuiltInZoomControls(true); platformController = AndroidWebViewPlatformController( webView: webView, @@ -189,6 +193,7 @@ class AndroidWebViewPlatformController extends WebViewPlatformController { _trySetJavaScriptMode(settings.javascriptMode), _trySetDebuggingEnabled(settings.debuggingEnabled), _trySetUserAgent(settings.userAgent), + _trySetZoomEnabled(settings.zoomEnabled), ]); } @@ -288,6 +293,12 @@ class AndroidWebViewPlatformController extends WebViewPlatformController { return webView.settings.setUserAgentString(''); } + + Future _trySetZoomEnabled(bool? zoomEnabled) async { + if (zoomEnabled != null) { + return webView.settings.setSupportZoom(zoomEnabled); + } + } } class _JavaScriptChannelImpl extends android_webview.JavaScriptChannel { diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart index 3e3019e544d5..1c1ce733ac16 100644 --- a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart @@ -122,6 +122,10 @@ void main() { true, )); verify(mockWebSettingsHostApi.setSupportMultipleWindows(1, true)); + verify(mockWebSettingsHostApi.setLoadWithOverviewMode(1, true)); + verify(mockWebSettingsHostApi.setUseWideViewPort(1, true)); + verify(mockWebSettingsHostApi.setDisplayZoomControls(1, false)); + verify(mockWebSettingsHostApi.setBuiltInZoomControls(1, true)); verifyInOrder([ mockWebViewHostApi.create(0, false), @@ -257,6 +261,20 @@ void main() { verify(mockWebSettingsHostApi.setUserAgentString(any, 'myUserAgent')); }); + + testWidgets('zoomEnabled', (WidgetTester tester) async { + await buildWidget( + tester, + creationParams: CreationParams( + webSettings: WebSettings( + userAgent: WebSetting.absent(), + zoomEnabled: false, + ), + ), + ); + + verify(mockWebSettingsHostApi.setSupportZoom(any, false)); + }); }); }); From c13520bdbc5267f239ffdcb64c96728c41d421f6 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 28 Oct 2021 12:43:48 -0700 Subject: [PATCH 50/54] set hard version --- packages/webview_flutter/webview_flutter/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml index 3647da2fb767..a4a0af8848c4 100644 --- a/packages/webview_flutter/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: flutter: sdk: flutter webview_flutter_platform_interface: ^1.0.0 - webview_flutter_android: 2.0.13 + webview_flutter_android: 2.1.0 webview_flutter_wkwebview: ^2.0.13 dev_dependencies: From 110645e600cd40617748a1da79db4889252cee47 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 28 Oct 2021 14:17:41 -0700 Subject: [PATCH 51/54] move burden of maintaining callback classes to java --- .../DownloadListenerHostApiImpl.java | 41 ++- .../GeneratedAndroidWebView.java | 162 +++------ .../webviewflutter/InstanceManager.java | 3 +- .../webviewflutter/JavaScriptChannel.java | 22 +- .../JavaScriptChannelHostApiImpl.java | 18 +- .../plugins/webviewflutter/Releasable.java | 9 + .../WebChromeClientHostApiImpl.java | 123 ++++--- .../WebViewClientHostApiImpl.java | 343 +++++++++++------- .../webviewflutter/WebViewHostApiImpl.java | 158 +++++++- .../webviewflutter/WebChromeClientTest.java | 6 +- .../lib/src/android_webview.dart | 77 +--- .../lib/src/android_webview.pigeon.dart | 184 ++++------ .../lib/src/android_webview_api_impls.dart | 52 +-- .../pigeons/android_webview.dart | 14 +- .../test/android_webview.pigeon.dart | 78 +--- .../test/android_webview_test.dart | 45 +-- .../test/android_webview_test.mocks.dart | 16 - .../test/webview_widget_test.dart | 1 - .../test/webview_widget_test.mocks.dart | 20 +- 19 files changed, 674 insertions(+), 698 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/Releasable.java diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java index 202be87d7d1e..0d7804c19d4f 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java @@ -12,12 +12,40 @@ class DownloadListenerHostApiImpl implements GeneratedAndroidWebView.DownloadLis private final DownloadListenerCreator downloadListenerCreator; private final GeneratedAndroidWebView.DownloadListenerFlutterApi downloadListenerFlutterApi; + static class DownloadListenerImpl implements DownloadListener, Releasable { + private final Long instanceId; + private final DownloadListenerFlutterApi flutterApi; + private boolean ignoreCallbacks = false; + + DownloadListenerImpl(Long instanceId, DownloadListenerFlutterApi downloadListenerFlutterApi) { + this.instanceId = instanceId; + this.flutterApi = downloadListenerFlutterApi; + } + + @Override + public void onDownloadStart( + String url, + String userAgent, + String contentDisposition, + String mimetype, + long contentLength) { + if (!ignoreCallbacks) { + flutterApi.onDownloadStart( + instanceId, url, userAgent, contentDisposition, mimetype, contentLength, reply -> {}); + } + } + + @Override + public void release() { + ignoreCallbacks = true; + flutterApi.dispose(instanceId, reply -> {}); + } + } + static class DownloadListenerCreator { DownloadListener createDownloadListener( - Long instanceId, DownloadListenerFlutterApi downloadListenerFlutterApi) { - return (url, userAgent, contentDisposition, mimetype, contentLength) -> - downloadListenerFlutterApi.onDownloadStart( - instanceId, url, userAgent, contentDisposition, mimetype, contentLength, reply -> {}); + Long instanceId, DownloadListenerFlutterApi flutterApi) { + return new DownloadListenerImpl(instanceId, flutterApi); } } @@ -36,9 +64,4 @@ public void create(Long instanceId) { downloadListenerCreator.createDownloadListener(instanceId, downloadListenerFlutterApi); instanceManager.addInstance(downloadListener, instanceId); } - - @Override - public void dispose(Long instanceId) { - instanceManager.removeInstance(instanceId); - } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java index ba2b9b1ac481..a94279e6b89e 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v1.0.7), do not edit directly. +// Autogenerated from Pigeon (v1.0.8), do not edit directly. // See also: https://pub.dev/packages/pigeon package io.flutter.plugins.webviewflutter; @@ -1313,8 +1313,6 @@ private JavaScriptChannelHostApiCodec() {} public interface JavaScriptChannelHostApi { void create(Long instanceId, String channelName); - void dispose(Long instanceId); - /** The codec used by JavaScriptChannelHostApi. */ static MessageCodec getCodec() { return JavaScriptChannelHostApiCodec.INSTANCE; @@ -1354,31 +1352,6 @@ static void setup(BinaryMessenger binaryMessenger, JavaScriptChannelHostApi api) channel.setMessageHandler(null); } } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.JavaScriptChannelHostApi.dispose", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } } } @@ -1405,6 +1378,19 @@ static MessageCodec getCodec() { return JavaScriptChannelFlutterApiCodec.INSTANCE; } + public void dispose(Long instanceIdArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.JavaScriptChannelFlutterApi.dispose", + getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg)), + channelReply -> { + callback.reply(null); + }); + } + public void postMessage(Long instanceIdArg, String messageArg, Reply callback) { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -1429,8 +1415,6 @@ private WebViewClientHostApiCodec() {} public interface WebViewClientHostApi { void create(Long instanceId, Boolean shouldOverrideUrlLoading); - void dispose(Long instanceId); - /** The codec used by WebViewClientHostApi. */ static MessageCodec getCodec() { return WebViewClientHostApiCodec.INSTANCE; @@ -1471,31 +1455,6 @@ static void setup(BinaryMessenger binaryMessenger, WebViewClientHostApi api) { channel.setMessageHandler(null); } } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewClientHostApi.dispose", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } } } @@ -1513,9 +1472,6 @@ protected Object readValueOfType(byte type, ByteBuffer buffer) { case (byte) 129: return WebResourceRequestData.fromMap((Map) readValue(buffer)); - case (byte) 130: - return WebResourceRequestData.fromMap((Map) readValue(buffer)); - default: return super.readValueOfType(type, buffer); } @@ -1529,9 +1485,6 @@ protected void writeValue(ByteArrayOutputStream stream, Object value) { } else if (value instanceof WebResourceRequestData) { stream.write(129); writeValue(stream, ((WebResourceRequestData) value).toMap()); - } else if (value instanceof WebResourceRequestData) { - stream.write(130); - writeValue(stream, ((WebResourceRequestData) value).toMap()); } else { super.writeValue(stream, value); } @@ -1554,6 +1507,17 @@ static MessageCodec getCodec() { return WebViewClientFlutterApiCodec.INSTANCE; } + public void dispose(Long instanceIdArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.dispose", getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg)), + channelReply -> { + callback.reply(null); + }); + } + public void onPageStarted( Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply callback) { BasicMessageChannel channel = @@ -1666,8 +1630,6 @@ private DownloadListenerHostApiCodec() {} public interface DownloadListenerHostApi { void create(Long instanceId); - void dispose(Long instanceId); - /** The codec used by DownloadListenerHostApi. */ static MessageCodec getCodec() { return DownloadListenerHostApiCodec.INSTANCE; @@ -1703,31 +1665,6 @@ static void setup(BinaryMessenger binaryMessenger, DownloadListenerHostApi api) channel.setMessageHandler(null); } } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.DownloadListenerHostApi.dispose", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } } } @@ -1754,6 +1691,17 @@ static MessageCodec getCodec() { return DownloadListenerFlutterApiCodec.INSTANCE; } + public void dispose(Long instanceIdArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.DownloadListenerFlutterApi.dispose", getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg)), + channelReply -> { + callback.reply(null); + }); + } + public void onDownloadStart( Long instanceIdArg, String urlArg, @@ -1792,8 +1740,6 @@ private WebChromeClientHostApiCodec() {} public interface WebChromeClientHostApi { void create(Long instanceId, Long webViewClientInstanceId); - void dispose(Long instanceId); - /** The codec used by WebChromeClientHostApi. */ static MessageCodec getCodec() { return WebChromeClientHostApiCodec.INSTANCE; @@ -1833,31 +1779,6 @@ static void setup(BinaryMessenger binaryMessenger, WebChromeClientHostApi api) { channel.setMessageHandler(null); } } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebChromeClientHostApi.dispose", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - api.dispose(instanceIdArg.longValue()); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } } } @@ -1884,6 +1805,17 @@ static MessageCodec getCodec() { return WebChromeClientFlutterApiCodec.INSTANCE; } + public void dispose(Long instanceIdArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebChromeClientFlutterApi.dispose", getCodec()); + channel.send( + new ArrayList(Arrays.asList(instanceIdArg)), + channelReply -> { + callback.reply(null); + }); + } + public void onProgressChanged( Long instanceIdArg, Long webViewInstanceIdArg, Long progressArg, Reply callback) { BasicMessageChannel channel = diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java index bfa7d6f17345..58e8d7990798 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java @@ -19,12 +19,13 @@ void addInstance(Object instance, long instanceId) { } /** Remove the instance from the manager. */ - void removeInstance(long instanceId) { + Object removeInstance(long instanceId) { final Object instance = instanceIdsToInstances.get(instanceId); if (instance != null) { instanceIdsToInstances.remove(instanceId); instancesToInstanceIds.remove(instance); } + return instance; } /** Retrieve the Object paired with instanceId. */ diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java index 62d047971b0b..adfddadb3e35 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java @@ -16,11 +16,12 @@ *

Exposes a single method named `postMessage` to JavaScript, which sends a message over a method * channel to the Dart code. */ -class JavaScriptChannel { +class JavaScriptChannel implements Releasable { private final Long instanceId; private final GeneratedAndroidWebView.JavaScriptChannelFlutterApi javaScriptChannelFlutterApi; final String javaScriptChannelName; private final Handler platformThreadHandler; + private boolean ignoreCallbacks = false; /** * @param instanceId identifier for this object when messages are sent to Dart @@ -43,12 +44,19 @@ class JavaScriptChannel { @JavascriptInterface public void postMessage(final String message) { - final Runnable postMessageRunnable = - () -> javaScriptChannelFlutterApi.postMessage(instanceId, message, reply -> {}); - if (platformThreadHandler.getLooper() == Looper.myLooper()) { - postMessageRunnable.run(); - } else { - platformThreadHandler.post(postMessageRunnable); + if (!ignoreCallbacks) { + final Runnable postMessageRunnable = + () -> javaScriptChannelFlutterApi.postMessage(instanceId, message, reply -> {}); + if (platformThreadHandler.getLooper() == Looper.myLooper()) { + postMessageRunnable.run(); + } else { + platformThreadHandler.post(postMessageRunnable); + } } } + + public void release() { + ignoreCallbacks = true; + javaScriptChannelFlutterApi.dispose(instanceId, reply -> {}); + } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java index ded5ada2754d..3a3f3cdbc105 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelHostApiImpl.java @@ -10,28 +10,27 @@ class JavaScriptChannelHostApiImpl implements GeneratedAndroidWebView.JavaScriptChannelHostApi { private final InstanceManager instanceManager; private final JavaScriptChannelCreator javaScriptChannelCreator; - private final JavaScriptChannelFlutterApi javaScriptChannelFlutterApi; + private final JavaScriptChannelFlutterApi flutterApi; private final Handler platformThreadHandler; static class JavaScriptChannelCreator { JavaScriptChannel createJavaScriptChannel( Long instanceId, - JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, + JavaScriptChannelFlutterApi flutterApi, String channelName, Handler platformThreadHandler) { - return new JavaScriptChannel( - instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); + return new JavaScriptChannel(instanceId, flutterApi, channelName, platformThreadHandler); } } JavaScriptChannelHostApiImpl( InstanceManager instanceManager, JavaScriptChannelCreator javaScriptChannelCreator, - JavaScriptChannelFlutterApi javaScriptChannelFlutterApi, + JavaScriptChannelFlutterApi flutterApi, Handler platformThreadHandler) { this.instanceManager = instanceManager; this.javaScriptChannelCreator = javaScriptChannelCreator; - this.javaScriptChannelFlutterApi = javaScriptChannelFlutterApi; + this.flutterApi = flutterApi; this.platformThreadHandler = platformThreadHandler; } @@ -39,12 +38,7 @@ JavaScriptChannel createJavaScriptChannel( public void create(Long instanceId, String channelName) { final JavaScriptChannel javaScriptChannel = javaScriptChannelCreator.createJavaScriptChannel( - instanceId, javaScriptChannelFlutterApi, channelName, platformThreadHandler); + instanceId, flutterApi, channelName, platformThreadHandler); instanceManager.addInstance(javaScriptChannel, instanceId); } - - @Override - public void dispose(Long instanceId) { - instanceManager.removeInstance(instanceId); - } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/Releasable.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/Releasable.java new file mode 100644 index 000000000000..21b78f411971 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/Releasable.java @@ -0,0 +1,9 @@ +package io.flutter.plugins.webviewflutter; + +/** + * Represents a resource, or a holder of resources, which may be released once they are no longer + * needed. + */ +interface Releasable { + void release(); +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java index 32f8fcbdeed9..f76cd3136655 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java @@ -17,62 +17,92 @@ class WebChromeClientHostApiImpl implements GeneratedAndroidWebView.WebChromeClientHostApi { private final InstanceManager instanceManager; private final WebChromeClientCreator webChromeClientCreator; - private final WebChromeClientFlutterApi webChromeClientFlutterApi; + private final WebChromeClientFlutterApi flutterApi; + + static class WebChromeClientImpl extends WebChromeClient implements Releasable { + private final Long instanceId; + private final InstanceManager instanceManager; + private final WebChromeClientFlutterApi flutterApi; + private WebViewClient webViewClient; + private boolean ignoreCallbacks = false; + + WebChromeClientImpl( + Long instanceId, + InstanceManager instanceManager, + WebChromeClientFlutterApi flutterApi, + WebViewClient webViewClient) { + this.instanceId = instanceId; + this.instanceManager = instanceManager; + this.flutterApi = flutterApi; + this.webViewClient = webViewClient; + } + + // Verifies that a url opened by `Window.open` has a secure url. + @Override + public boolean onCreateWindow( + final WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { + final WebViewClient newWindowWebViewClient = + new WebViewClient() { + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public boolean shouldOverrideUrlLoading( + @NonNull WebView view, @NonNull WebResourceRequest request) { + webViewClient.shouldOverrideUrlLoading(view, request); + return true; + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + webViewClient.shouldOverrideUrlLoading(view, url); + return true; + } + }; + + final WebView newWebView = new WebView(view.getContext()); + newWebView.setWebViewClient(newWindowWebViewClient); + + final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; + transport.setWebView(newWebView); + resultMsg.sendToTarget(); + + return true; + } + + @Override + public void onProgressChanged(WebView view, int progress) { + if (!ignoreCallbacks) { + flutterApi.onProgressChanged( + instanceId, instanceManager.getInstanceId(view), (long) progress, reply -> {}); + } + } + + void setWebViewClient(WebViewClient webViewClient) { + this.webViewClient = webViewClient; + } + + public void release() { + ignoreCallbacks = true; + flutterApi.dispose(instanceId, reply -> {}); + } + } static class WebChromeClientCreator { WebChromeClient createWebChromeClient( Long instanceId, InstanceManager instanceManager, - WebViewClient webViewClient, - WebChromeClientFlutterApi webChromeClientFlutterApi) { - return new WebChromeClient() { - // Verifies that a url opened by `Window.open` has a secure url. - @Override - public boolean onCreateWindow( - final WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { - final WebViewClient newWindowWebViewClient = - new WebViewClient() { - @RequiresApi(api = Build.VERSION_CODES.N) - @Override - public boolean shouldOverrideUrlLoading( - @NonNull WebView view, @NonNull WebResourceRequest request) { - webViewClient.shouldOverrideUrlLoading(view, request); - return true; - } - - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - webViewClient.shouldOverrideUrlLoading(view, url); - return true; - } - }; - - final WebView newWebView = new WebView(view.getContext()); - newWebView.setWebViewClient(newWindowWebViewClient); - - final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; - transport.setWebView(newWebView); - resultMsg.sendToTarget(); - - return true; - } - - @Override - public void onProgressChanged(WebView view, int progress) { - webChromeClientFlutterApi.onProgressChanged( - instanceId, instanceManager.getInstanceId(view), (long) progress, reply -> {}); - } - }; + WebChromeClientFlutterApi flutterApi, + WebViewClient webViewClient) { + return new WebChromeClientImpl(instanceId, instanceManager, flutterApi, webViewClient); } } WebChromeClientHostApiImpl( InstanceManager instanceManager, WebChromeClientCreator webChromeClientCreator, - WebChromeClientFlutterApi webChromeClientFlutterApi) { + WebChromeClientFlutterApi flutterApi) { this.instanceManager = instanceManager; this.webChromeClientCreator = webChromeClientCreator; - this.webChromeClientFlutterApi = webChromeClientFlutterApi; + this.flutterApi = flutterApi; } @Override @@ -81,12 +111,7 @@ public void create(Long instanceId, Long webViewClientInstanceId) { (WebViewClient) instanceManager.getInstance(webViewClientInstanceId); final WebChromeClient webChromeClient = webChromeClientCreator.createWebChromeClient( - instanceId, instanceManager, webViewClient, webChromeClientFlutterApi); + instanceId, instanceManager, flutterApi, webViewClient); instanceManager.addInstance(webChromeClient, instanceId); } - - @Override - public void dispose(Long instanceId) { - instanceManager.removeInstance(instanceId); - } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java index 4d17eb129db8..d349da47c133 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java @@ -22,7 +22,7 @@ class WebViewClientHostApiImpl implements GeneratedAndroidWebView.WebViewClientHostApi { private final InstanceManager instanceManager; private final WebViewClientCreator webViewClientCreator; - private final WebViewClientFlutterApi webViewClientFlutterApi; + private final WebViewClientFlutterApi flutterApi; @RequiresApi(api = Build.VERSION_CODES.M) static GeneratedAndroidWebView.WebResourceErrorData createWebResourceErrorData( @@ -63,6 +63,200 @@ static GeneratedAndroidWebView.WebResourceRequestData createWebResourceRequestDa return requestData; } + @RequiresApi(Build.VERSION_CODES.N) + static class WebViewClientImpl extends WebViewClient implements Releasable { + private final Long instanceId; + private final InstanceManager instanceManager; + private final Boolean shouldOverrideUrlLoading; + private final WebViewClientFlutterApi flutterApi; + private boolean ignoreCallbacks = false; + + WebViewClientImpl( + Long instanceId, + InstanceManager instanceManager, + Boolean shouldOverrideUrlLoading, + WebViewClientFlutterApi flutterApi) { + this.instanceId = instanceId; + this.instanceManager = instanceManager; + this.shouldOverrideUrlLoading = shouldOverrideUrlLoading; + this.flutterApi = flutterApi; + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + if (!ignoreCallbacks) { + flutterApi.onPageStarted(instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + } + + @Override + public void onPageFinished(WebView view, String url) { + if (!ignoreCallbacks) { + flutterApi.onPageFinished( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + } + + @Override + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { + if (!ignoreCallbacks) { + flutterApi.onReceivedRequestError( + instanceId, + instanceManager.getInstanceId(view), + createWebResourceRequestData(request), + createWebResourceErrorData(error), + reply -> {}); + } + } + + @Override + public void onReceivedError( + WebView view, int errorCode, String description, String failingUrl) { + if (!ignoreCallbacks) { + flutterApi.onReceivedError( + instanceId, + instanceManager.getInstanceId(view), + (long) errorCode, + description, + failingUrl, + reply -> {}); + } + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + if (!ignoreCallbacks) { + flutterApi.requestLoading( + instanceId, + instanceManager.getInstanceId(view), + createWebResourceRequestData(request), + reply -> {}); + } + return shouldOverrideUrlLoading; + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + if (!ignoreCallbacks) { + flutterApi.urlLoading(instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + return shouldOverrideUrlLoading; + } + + @Override + public void onUnhandledKeyEvent(WebView view, KeyEvent event) { + // Deliberately empty. Occasionally the webview will mark events as having failed to be + // handled even though they were handled. We don't want to propagate those as they're not + // truly lost. + } + + public void release() { + ignoreCallbacks = true; + flutterApi.dispose(instanceId, reply -> {}); + } + } + + static class WebViewClientCompatImpl extends WebViewClientCompat implements Releasable { + private final Long instanceId; + private final InstanceManager instanceManager; + private final Boolean shouldOverrideUrlLoading; + private final WebViewClientFlutterApi flutterApi; + private boolean ignoreCallbacks = false; + + WebViewClientCompatImpl( + Long instanceId, + InstanceManager instanceManager, + Boolean shouldOverrideUrlLoading, + WebViewClientFlutterApi flutterApi) { + this.instanceId = instanceId; + this.instanceManager = instanceManager; + this.shouldOverrideUrlLoading = shouldOverrideUrlLoading; + this.flutterApi = flutterApi; + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + if (!ignoreCallbacks) { + flutterApi.onPageStarted(instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + } + + @Override + public void onPageFinished(WebView view, String url) { + if (!ignoreCallbacks) { + flutterApi.onPageFinished( + instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + } + + // This method is only called when the WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR feature is + // enabled. The deprecated method is called when a device doesn't support this. + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @SuppressLint("RequiresFeature") + @Override + public void onReceivedError( + @NonNull WebView view, + @NonNull WebResourceRequest request, + @NonNull WebResourceErrorCompat error) { + if (!ignoreCallbacks) { + flutterApi.onReceivedRequestError( + instanceId, + instanceManager.getInstanceId(view), + createWebResourceRequestData(request), + createWebResourceErrorData(error), + reply -> {}); + } + } + + @Override + public void onReceivedError( + WebView view, int errorCode, String description, String failingUrl) { + if (!ignoreCallbacks) { + flutterApi.onReceivedError( + instanceId, + instanceManager.getInstanceId(view), + (long) errorCode, + description, + failingUrl, + reply -> {}); + } + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @Override + public boolean shouldOverrideUrlLoading( + @NonNull WebView view, @NonNull WebResourceRequest request) { + if (!ignoreCallbacks) { + flutterApi.requestLoading( + instanceId, + instanceManager.getInstanceId(view), + createWebResourceRequestData(request), + reply -> {}); + } + return shouldOverrideUrlLoading; + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + if (!ignoreCallbacks) { + flutterApi.urlLoading(instanceId, instanceManager.getInstanceId(view), url, reply -> {}); + } + return shouldOverrideUrlLoading; + } + + @Override + public void onUnhandledKeyEvent(WebView view, KeyEvent event) { + // Deliberately empty. Occasionally the webview will mark events as having failed to be + // handled even though they were handled. We don't want to propagate those as they're not + // truly lost. + } + + public void release() { + ignoreCallbacks = true; + flutterApi.dispose(instanceId, reply -> {}); + } + } + static class WebViewClientCreator { WebViewClient createWebViewClient( Long instanceId, @@ -78,139 +272,11 @@ WebViewClient createWebViewClient( // to bug https://bugs.chromium.org/p/chromium/issues/detail?id=925887. Also, see // https://github.com/flutter/flutter/issues/29446. if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - return new WebViewClient() { - @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - webViewClientFlutterApi.onPageStarted( - instanceId, instanceManager.getInstanceId(view), url, reply -> {}); - } - - @Override - public void onPageFinished(WebView view, String url) { - webViewClientFlutterApi.onPageFinished( - instanceId, instanceManager.getInstanceId(view), url, reply -> {}); - } - - @Override - public void onReceivedError( - WebView view, WebResourceRequest request, WebResourceError error) { - webViewClientFlutterApi.onReceivedRequestError( - instanceId, - instanceManager.getInstanceId(view), - createWebResourceRequestData(request), - createWebResourceErrorData(error), - reply -> {}); - } - - @SuppressWarnings("deprecation") - @Override - public void onReceivedError( - WebView view, int errorCode, String description, String failingUrl) { - webViewClientFlutterApi.onReceivedError( - instanceId, - instanceManager.getInstanceId(view), - (long) errorCode, - description, - failingUrl, - reply -> {}); - } - - @Override - public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { - webViewClientFlutterApi.requestLoading( - instanceId, - instanceManager.getInstanceId(view), - createWebResourceRequestData(request), - reply -> {}); - return shouldOverrideUrlLoading; - } - - @SuppressWarnings("deprecation") - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - webViewClientFlutterApi.urlLoading( - instanceId, instanceManager.getInstanceId(view), url, reply -> {}); - return shouldOverrideUrlLoading; - } - - @Override - public void onUnhandledKeyEvent(WebView view, KeyEvent event) { - // Deliberately empty. Occasionally the webview will mark events as having failed to be - // handled even though they were handled. We don't want to propagate those as they're not - // truly lost. - } - }; + return new WebViewClientImpl( + instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi); } else { - return new WebViewClientCompat() { - @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - webViewClientFlutterApi.onPageStarted( - instanceId, instanceManager.getInstanceId(view), url, reply -> {}); - } - - @Override - public void onPageFinished(WebView view, String url) { - webViewClientFlutterApi.onPageFinished( - instanceId, instanceManager.getInstanceId(view), url, reply -> {}); - } - - // This method is only called when the WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR feature is - // enabled. The deprecated method is called when a device doesn't support this. - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - @SuppressLint("RequiresFeature") - @Override - public void onReceivedError( - @NonNull WebView view, - @NonNull WebResourceRequest request, - @NonNull WebResourceErrorCompat error) { - webViewClientFlutterApi.onReceivedRequestError( - instanceId, - instanceManager.getInstanceId(view), - createWebResourceRequestData(request), - createWebResourceErrorData(error), - reply -> {}); - } - - @SuppressWarnings("deprecation") - @Override - public void onReceivedError( - WebView view, int errorCode, String description, String failingUrl) { - webViewClientFlutterApi.onReceivedError( - instanceId, - instanceManager.getInstanceId(view), - (long) errorCode, - description, - failingUrl, - reply -> {}); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public boolean shouldOverrideUrlLoading( - @NonNull WebView view, @NonNull WebResourceRequest request) { - webViewClientFlutterApi.requestLoading( - instanceId, - instanceManager.getInstanceId(view), - createWebResourceRequestData(request), - reply -> {}); - return shouldOverrideUrlLoading; - } - - @SuppressWarnings("deprecation") - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - webViewClientFlutterApi.urlLoading( - instanceId, instanceManager.getInstanceId(view), url, reply -> {}); - return shouldOverrideUrlLoading; - } - - @Override - public void onUnhandledKeyEvent(WebView view, KeyEvent event) { - // Deliberately empty. Occasionally the webview will mark events as having failed to be - // handled even though they were handled. We don't want to propagate those as they're not - // truly lost. - } - }; + return new WebViewClientCompatImpl( + instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi); } } } @@ -218,22 +284,17 @@ public void onUnhandledKeyEvent(WebView view, KeyEvent event) { WebViewClientHostApiImpl( InstanceManager instanceManager, WebViewClientCreator webViewClientCreator, - WebViewClientFlutterApi webViewClientFlutterApi) { + WebViewClientFlutterApi flutterApi) { this.instanceManager = instanceManager; this.webViewClientCreator = webViewClientCreator; - this.webViewClientFlutterApi = webViewClientFlutterApi; + this.flutterApi = flutterApi; } @Override public void create(Long instanceId, Boolean shouldOverrideUrlLoading) { final WebViewClient webViewClient = webViewClientCreator.createWebViewClient( - instanceId, instanceManager, shouldOverrideUrlLoading, webViewClientFlutterApi); + instanceId, instanceManager, shouldOverrideUrlLoading, flutterApi); instanceManager.addInstance(webViewClient, instanceId); } - - @Override - public void dispose(Long instanceId) { - instanceManager.removeInstance(instanceId); - } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index 8a410a37a280..3e4cdae06db8 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -4,6 +4,7 @@ package io.flutter.plugins.webviewflutter; +import android.annotation.SuppressLint; import android.content.Context; import android.hardware.display.DisplayManager; import android.view.View; @@ -13,6 +14,8 @@ import android.webkit.WebViewClient; import androidx.annotation.NonNull; import io.flutter.plugin.platform.PlatformView; +import io.flutter.plugins.webviewflutter.WebChromeClientHostApiImpl.WebChromeClientImpl; +import java.util.HashMap; import java.util.Map; class WebViewHostApiImpl implements GeneratedAndroidWebView.WebViewHostApi { @@ -39,7 +42,12 @@ void setWebContentsDebuggingEnabled(boolean enabled) { } } - private static class WebViewPlatformView extends WebView implements PlatformView { + private static class WebViewPlatformView extends WebView implements PlatformView, Releasable { + private WebViewClient currentWebViewClient; + private DownloadListener currentDownloadListener; + private WebChromeClient currentWebChromeClient; + private final Map javaScriptInterfaces = new HashMap<>(); + public WebViewPlatformView(Context context) { super(context); } @@ -53,10 +61,81 @@ public View getView() { public void dispose() { destroy(); } + + @Override + public void setWebViewClient(WebViewClient webViewClient) { + super.setWebViewClient(webViewClient); + if (currentWebViewClient instanceof Releasable) { + ((Releasable) currentWebViewClient).release(); + } + currentWebViewClient = (WebViewClient) webViewClient; + } + + @Override + public void setDownloadListener(DownloadListener listener) { + super.setDownloadListener(listener); + if (currentDownloadListener instanceof Releasable) { + ((Releasable) currentDownloadListener).release(); + } + currentDownloadListener = listener; + } + + @Override + public void setWebChromeClient(WebChromeClient client) { + super.setWebChromeClient(client); + if (currentWebChromeClient instanceof Releasable) { + ((Releasable) currentWebChromeClient).release(); + } + currentWebChromeClient = client; + } + + @SuppressLint("JavascriptInterface") + @Override + public void addJavascriptInterface(Object object, String name) { + super.addJavascriptInterface(object, name); + if (object instanceof JavaScriptChannel) { + javaScriptInterfaces.put(name, (JavaScriptChannel) object); + } + } + + @Override + public void removeJavascriptInterface(@NonNull String name) { + super.removeJavascriptInterface(name); + final JavaScriptChannel javaScriptChannel = javaScriptInterfaces.get(name); + if (javaScriptChannel != null) { + javaScriptChannel.release(); + } + javaScriptInterfaces.remove(name); + } + + @Override + public void release() { + if (currentWebViewClient instanceof Releasable) { + ((Releasable) currentWebViewClient).release(); + currentWebViewClient = null; + } + if (currentDownloadListener instanceof Releasable) { + ((Releasable) currentDownloadListener).release(); + currentDownloadListener = null; + } + if (currentWebChromeClient instanceof Releasable) { + ((Releasable) currentWebChromeClient).release(); + currentWebChromeClient = null; + } + for (JavaScriptChannel channel : javaScriptInterfaces.values()) { + channel.release(); + } + javaScriptInterfaces.clear(); + } } private static class InputAwareWebViewPlatformView extends InputAwareWebView - implements PlatformView { + implements PlatformView, Releasable { + private WebViewClient currentWebViewClient; + private DownloadListener currentDownloadListener; + private WebChromeClient currentWebChromeClient; + private final Map javaScriptInterfaces = new HashMap<>(); + InputAwareWebViewPlatformView(Context context, View containerView) { super(context, containerView); } @@ -91,6 +170,76 @@ public void onInputConnectionLocked() { public void onInputConnectionUnlocked() { unlockInputConnection(); } + + @Override + public void setWebViewClient(WebViewClient webViewClient) { + super.setWebViewClient(webViewClient); + if (currentWebViewClient instanceof Releasable) { + ((Releasable) currentWebViewClient).release(); + } + currentWebViewClient = (WebViewClient) webViewClient; + } + + @Override + public void setDownloadListener(DownloadListener listener) { + super.setDownloadListener(listener); + if (currentDownloadListener instanceof Releasable) { + ((Releasable) currentDownloadListener).release(); + } + currentDownloadListener = listener; + } + + @Override + public void setWebChromeClient(WebChromeClient client) { + super.setWebChromeClient(client); + if (currentWebChromeClient instanceof Releasable) { + ((Releasable) currentWebChromeClient).release(); + } + + if (client instanceof WebChromeClientImpl) { + ((WebChromeClientImpl) client).setWebViewClient(currentWebViewClient); + } + currentWebChromeClient = client; + } + + @SuppressLint("JavascriptInterface") + @Override + public void addJavascriptInterface(Object object, String name) { + super.addJavascriptInterface(object, name); + if (object instanceof JavaScriptChannel) { + javaScriptInterfaces.put(name, (JavaScriptChannel) object); + } + } + + @Override + public void removeJavascriptInterface(@NonNull String name) { + super.removeJavascriptInterface(name); + final JavaScriptChannel javaScriptChannel = javaScriptInterfaces.get(name); + if (javaScriptChannel != null) { + javaScriptChannel.release(); + } + javaScriptInterfaces.remove(name); + } + + @Override + public void release() { + if (currentWebViewClient instanceof Releasable) { + ((Releasable) currentWebViewClient).release(); + currentWebViewClient = null; + } + if (currentDownloadListener instanceof Releasable) { + ((Releasable) currentDownloadListener).release(); + currentDownloadListener = null; + } + if (currentWebChromeClient instanceof Releasable) { + ((Releasable) currentWebChromeClient).release(); + currentWebChromeClient = null; + } + for (JavaScriptChannel channel : javaScriptInterfaces.values()) { + channel.release(); + } + javaScriptInterfaces.clear(); + } } WebViewHostApiImpl(InstanceManager instanceManager, WebViewProxy webViewProxy, Context context) { @@ -117,7 +266,10 @@ public void create(Long instanceId, Boolean useHybridComposition) { @Override public void dispose(Long instanceId) { - instanceManager.removeInstance(instanceId); + final WebView instance = (WebView) instanceManager.removeInstance(instanceId); + if (instance instanceof Releasable) { + ((Releasable) instance).release(); + } } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java index 5ab3ab10fe03..ee66c2021108 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java @@ -45,11 +45,11 @@ public void setUp() { WebChromeClient createWebChromeClient( Long instanceId, InstanceManager instanceManager, - WebViewClient webViewClient, - WebChromeClientFlutterApi webChromeClientFlutterApi) { + WebChromeClientFlutterApi webChromeClientFlutterApi, + WebViewClient webViewClient) { testWebChromeClient = super.createWebChromeClient( - instanceId, instanceManager, webViewClient, webChromeClientFlutterApi); + instanceId, instanceManager, webChromeClientFlutterApi, webViewClient); return testWebChromeClient; } }; diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart index b85861c2d4b6..3de5a5a3d106 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart @@ -43,9 +43,6 @@ class WebView { static WebViewHostApiImpl api = WebViewHostApiImpl(); WebViewClient? _currentWebViewClient; - DownloadListener? _currentDownloadListener; - WebChromeClient? _currentWebChromeClient; - Set _javaScriptChannels = {}; /// Whether the [WebView] will be rendered with an [AndroidViewSurface]. /// @@ -190,18 +187,8 @@ class WebView { /// /// This will replace the current handler. Future setWebViewClient(WebViewClient webViewClient) { - final WebViewClient? currentWebViewClient = _currentWebViewClient; - - if (webViewClient == currentWebViewClient) { - return Future.value(); - } - - if (currentWebViewClient != null) { - WebViewClient.api.disposeFromInstance(currentWebViewClient); - } - - WebViewClient.api.createFromInstance(webViewClient); _currentWebViewClient = webViewClient; + WebViewClient.api.createFromInstance(webViewClient); return api.setWebViewClientFromInstance(this, webViewClient); } @@ -230,7 +217,6 @@ class WebView { /// content is ever loaded into the WebView even inside an iframe. Future addJavaScriptChannel(JavaScriptChannel javaScriptChannel) { JavaScriptChannel.api.createFromInstance(javaScriptChannel); - _javaScriptChannels.add(javaScriptChannel); return api.addJavaScriptChannelFromInstance(this, javaScriptChannel); } @@ -239,27 +225,15 @@ class WebView { /// Note that the removal will not be reflected in JavaScript until the page /// is next (re)loaded. See [addJavaScriptChannel]. Future removeJavaScriptChannel(JavaScriptChannel javaScriptChannel) { - _javaScriptChannels.remove(javaScriptChannel); - api.removeJavaScriptChannelFromInstance(this, javaScriptChannel); - return JavaScriptChannel.api.disposeFromInstance(javaScriptChannel); + JavaScriptChannel.api.createFromInstance(javaScriptChannel); + return api.removeJavaScriptChannelFromInstance(this, javaScriptChannel); } /// Registers the interface to be used when content can not be handled by the rendering engine, and should be downloaded instead. /// /// This will replace the current handler. Future setDownloadListener(DownloadListener listener) { - final DownloadListener? currentDownloadListener = _currentDownloadListener; - - if (listener == currentDownloadListener) { - return Future.value(); - } - - if (currentDownloadListener != null) { - DownloadListener.api.disposeFromInstance(currentDownloadListener); - } - DownloadListener.api.createFromInstance(listener); - _currentDownloadListener = listener; return api.setDownloadListenerFromInstance(this, listener); } @@ -269,24 +243,15 @@ class WebView { /// JavaScript dialogs, favicons, titles, and the progress. This will replace /// the current handler. Future setWebChromeClient(WebChromeClient client) { - final WebChromeClient? currentWebChromeClient = _currentWebChromeClient; - - if (client == currentWebChromeClient) { - return Future.value(); - } - - if (currentWebChromeClient != null) { - WebChromeClient.api.disposeFromInstance(currentWebChromeClient); - } - - final WebViewClient? currentWebViewClient = _currentWebViewClient; + // WebView requires a WebViewClient because of a bug fix that makes + // calls to WebViewClient.requestLoading/WebViewClient.urlLoading when a new + // window is opened. This is to make sure a url opened by `Window.open` has + // a secure url. assert( - currentWebViewClient != null, + _currentWebViewClient != null, "Can't set a WebChromeClient without setting a WebViewClient first.", ); - - WebChromeClient.api.createFromInstance(client, currentWebViewClient!); - _currentWebChromeClient = client; + WebChromeClient.api.createFromInstance(client, _currentWebViewClient!); return api.setWebChromeClientFromInstance(this, client); } @@ -295,29 +260,7 @@ class WebView { /// Any methods called on the [WebView] instance after [release] will throw /// an exception. Future release() { - final WebViewClient? webViewClient = _currentWebViewClient; - if (webViewClient != null) { - WebViewClient.api.disposeFromInstance(webViewClient); - _currentWebViewClient = null; - } - - final DownloadListener? downloadListener = _currentDownloadListener; - if (downloadListener != null) { - DownloadListener.api.disposeFromInstance(downloadListener); - _currentDownloadListener = null; - } - - final WebChromeClient? webChromeClient = _currentWebChromeClient; - if (webChromeClient != null) { - WebChromeClient.api.disposeFromInstance(webChromeClient); - _currentWebChromeClient = null; - } - - for (JavaScriptChannel javaScriptChannel in _javaScriptChannels) { - JavaScriptChannel.api.disposeFromInstance(javaScriptChannel); - } - _javaScriptChannels.clear(); - + _currentWebViewClient = null; return api.disposeFromInstance(this); } } diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart index 81ec7c7bf80e..2b3f008ed830 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v1.0.7), do not edit directly. +// Autogenerated from Pigeon (v1.0.8), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name // @dart = 2.12 @@ -1039,31 +1039,6 @@ class JavaScriptChannelHostApi { return; } } - - Future dispose(int arg_instanceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.JavaScriptChannelHostApi.dispose', codec, - binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId]) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - (replyMap['error'] as Map?)!; - throw PlatformException( - code: (error['code'] as String?)!, - message: error['message'] as String?, - details: error['details'], - ); - } else { - return; - } - } } class _JavaScriptChannelFlutterApiCodec extends StandardMessageCodec { @@ -1074,8 +1049,27 @@ abstract class JavaScriptChannelFlutterApi { static const MessageCodec codec = _JavaScriptChannelFlutterApiCodec(); + void dispose(int instanceId); void postMessage(int instanceId, String message); static void setup(JavaScriptChannelFlutterApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.JavaScriptChannelFlutterApi.dispose', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.dispose was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.dispose was null, expected non-null int.'); + api.dispose(arg_instanceId!); + return; + }); + } + } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage', codec); @@ -1141,31 +1135,6 @@ class WebViewClientHostApi { return; } } - - Future dispose(int arg_instanceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientHostApi.dispose', codec, - binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId]) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - (replyMap['error'] as Map?)!; - throw PlatformException( - code: (error['code'] as String?)!, - message: error['message'] as String?, - details: error['details'], - ); - } else { - return; - } - } } class _WebViewClientFlutterApiCodec extends StandardMessageCodec { @@ -1178,9 +1147,6 @@ class _WebViewClientFlutterApiCodec extends StandardMessageCodec { } else if (value is WebResourceRequestData) { buffer.putUint8(129); writeValue(buffer, value.encode()); - } else if (value is WebResourceRequestData) { - buffer.putUint8(130); - writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -1195,9 +1161,6 @@ class _WebViewClientFlutterApiCodec extends StandardMessageCodec { case 129: return WebResourceRequestData.decode(readValue(buffer)!); - case 130: - return WebResourceRequestData.decode(readValue(buffer)!); - default: return super.readValueOfType(type, buffer); } @@ -1207,6 +1170,7 @@ class _WebViewClientFlutterApiCodec extends StandardMessageCodec { abstract class WebViewClientFlutterApi { static const MessageCodec codec = _WebViewClientFlutterApiCodec(); + void dispose(int instanceId); void onPageStarted(int instanceId, int webViewInstanceId, String url); void onPageFinished(int instanceId, int webViewInstanceId, String url); void onReceivedRequestError(int instanceId, int webViewInstanceId, @@ -1217,6 +1181,24 @@ abstract class WebViewClientFlutterApi { int instanceId, int webViewInstanceId, WebResourceRequestData request); void urlLoading(int instanceId, int webViewInstanceId, String url); static void setup(WebViewClientFlutterApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewClientFlutterApi.dispose', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.dispose was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.dispose was null, expected non-null int.'); + api.dispose(arg_instanceId!); + return; + }); + } + } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted', codec); @@ -1419,31 +1401,6 @@ class DownloadListenerHostApi { return; } } - - Future dispose(int arg_instanceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.DownloadListenerHostApi.dispose', codec, - binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId]) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - (replyMap['error'] as Map?)!; - throw PlatformException( - code: (error['code'] as String?)!, - message: error['message'] as String?, - details: error['details'], - ); - } else { - return; - } - } } class _DownloadListenerFlutterApiCodec extends StandardMessageCodec { @@ -1453,9 +1410,28 @@ class _DownloadListenerFlutterApiCodec extends StandardMessageCodec { abstract class DownloadListenerFlutterApi { static const MessageCodec codec = _DownloadListenerFlutterApiCodec(); + void dispose(int instanceId); void onDownloadStart(int instanceId, String url, String userAgent, String contentDisposition, String mimetype, int contentLength); static void setup(DownloadListenerFlutterApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.DownloadListenerFlutterApi.dispose', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.dispose was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.dispose was null, expected non-null int.'); + api.dispose(arg_instanceId!); + return; + }); + } + } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart', @@ -1535,31 +1511,6 @@ class WebChromeClientHostApi { return; } } - - Future dispose(int arg_instanceId) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebChromeClientHostApi.dispose', codec, - binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId]) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - (replyMap['error'] as Map?)!; - throw PlatformException( - code: (error['code'] as String?)!, - message: error['message'] as String?, - details: error['details'], - ); - } else { - return; - } - } } class _WebChromeClientFlutterApiCodec extends StandardMessageCodec { @@ -1569,8 +1520,27 @@ class _WebChromeClientFlutterApiCodec extends StandardMessageCodec { abstract class WebChromeClientFlutterApi { static const MessageCodec codec = _WebChromeClientFlutterApiCodec(); + void dispose(int instanceId); void onProgressChanged(int instanceId, int webViewInstanceId, int progress); static void setup(WebChromeClientFlutterApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebChromeClientFlutterApi.dispose', codec); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.dispose was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = args[0] as int?; + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.dispose was null, expected non-null int.'); + api.dispose(arg_instanceId!); + return; + }); + } + } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.WebChromeClientFlutterApi.onProgressChanged', diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart index 0363af322dcc..341b00516d75 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart @@ -337,14 +337,6 @@ class JavaScriptChannelHostApiImpl extends JavaScriptChannelHostApi { return create(instanceId, instance.channelName); } } - - /// Helper method to convert instances ids to objects. - Future disposeFromInstance(JavaScriptChannel instance) async { - final int? instanceId = instanceManager.removeInstance(instance); - if (instanceId != null) { - return dispose(instanceId); - } - } } /// Flutter api implementation for [JavaScriptChannel]. @@ -357,6 +349,11 @@ class JavaScriptChannelFlutterApiImpl extends JavaScriptChannelFlutterApi { /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; + @override + void dispose(int instanceId) { + instanceManager.removeInstance(instanceId); + } + @override void postMessage(int instanceId, String message) { final JavaScriptChannel instance = @@ -385,14 +382,6 @@ class WebViewClientHostApiImpl extends WebViewClientHostApi { return create(instanceId, instance.shouldOverrideUrlLoading); } } - - /// Helper method to convert instances ids to objects. - Future disposeFromInstance(WebViewClient instance) async { - final int? instanceId = instanceManager.removeInstance(instance); - if (instanceId != null) { - return dispose(instanceId); - } - } } /// Flutter api implementation for [WebViewClient]. @@ -405,6 +394,11 @@ class WebViewClientFlutterApiImpl extends WebViewClientFlutterApi { /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; + @override + void dispose(int instanceId) { + instanceManager.removeInstance(instanceId); + } + @override void onPageFinished(int instanceId, int webViewInstanceId, String url) { final WebViewClient instance = @@ -526,14 +520,6 @@ class DownloadListenerHostApiImpl extends DownloadListenerHostApi { return create(instanceId); } } - - /// Helper method to convert instances ids to objects. - Future disposeFromInstance(DownloadListener instance) async { - final int? instanceId = instanceManager.removeInstance(instance); - if (instanceId != null) { - return dispose(instanceId); - } - } } /// Flutter api implementation for [DownloadListener]. @@ -546,6 +532,11 @@ class DownloadListenerFlutterApiImpl extends DownloadListenerFlutterApi { /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; + @override + void dispose(int instanceId) { + instanceManager.removeInstance(instanceId); + } + @override void onDownloadStart( int instanceId, @@ -590,14 +581,6 @@ class WebChromeClientHostApiImpl extends WebChromeClientHostApi { return create(instanceId, instanceManager.getInstanceId(webViewClient)!); } } - - /// Helper method to convert instances ids to objects. - Future disposeFromInstance(WebChromeClient instance) async { - final int? instanceId = instanceManager.removeInstance(instance); - if (instanceId != null) { - return dispose(instanceId); - } - } } /// Flutter api implementation for [DownloadListener]. @@ -610,6 +593,11 @@ class WebChromeClientFlutterApiImpl extends WebChromeClientFlutterApi { /// Maintains instances stored to communicate with java objects. late final InstanceManager instanceManager; + @override + void dispose(int instanceId) { + instanceManager.removeInstance(instanceId); + } + @override void onProgressChanged(int instanceId, int webViewInstanceId, int progress) { final WebChromeClient instance = diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart index 1877c1b91feb..47bc42058ba9 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -105,24 +105,24 @@ abstract class WebSettingsHostApi { @HostApi(dartHostTestHandler: 'TestJavaScriptChannelHostApi') abstract class JavaScriptChannelHostApi { void create(int instanceId, String channelName); - - void dispose(int instanceId); } @FlutterApi() abstract class JavaScriptChannelFlutterApi { + void dispose(int instanceId); + void postMessage(int instanceId, String message); } @HostApi(dartHostTestHandler: 'TestWebViewClientHostApi') abstract class WebViewClientHostApi { void create(int instanceId, bool shouldOverrideUrlLoading); - - void dispose(int instanceId); } @FlutterApi() abstract class WebViewClientFlutterApi { + void dispose(int instanceId); + void onPageStarted(int instanceId, int webViewInstanceId, String url); void onPageFinished(int instanceId, int webViewInstanceId, String url); @@ -154,11 +154,12 @@ abstract class WebViewClientFlutterApi { @HostApi(dartHostTestHandler: 'TestDownloadListenerHostApi') abstract class DownloadListenerHostApi { void create(int instanceId); - void dispose(int instanceId); } @FlutterApi() abstract class DownloadListenerFlutterApi { + void dispose(int instanceId); + void onDownloadStart( int instanceId, String url, @@ -172,10 +173,11 @@ abstract class DownloadListenerFlutterApi { @HostApi(dartHostTestHandler: 'TestWebChromeClientHostApi') abstract class WebChromeClientHostApi { void create(int instanceId, int webViewClientInstanceId); - void dispose(int instanceId); } @FlutterApi() abstract class WebChromeClientFlutterApi { + void dispose(int instanceId); + void onProgressChanged(int instanceId, int webViewInstanceId, int progress); } diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart index ee0429b4c582..dd549449d851 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v1.0.7), do not edit directly. +// Autogenerated from Pigeon (v1.0.8), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, avoid_relative_lib_imports // @dart = 2.12 @@ -801,7 +801,6 @@ abstract class TestJavaScriptChannelHostApi { _TestJavaScriptChannelHostApiCodec(); void create(int instanceId, String channelName); - void dispose(int instanceId); static void setup(TestJavaScriptChannelHostApi? api) { { const BasicMessageChannel channel = BasicMessageChannel( @@ -824,24 +823,6 @@ abstract class TestJavaScriptChannelHostApi { }); } } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.JavaScriptChannelHostApi.dispose', codec); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.dispose was null.'); - final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, - 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.dispose was null, expected non-null int.'); - api.dispose(arg_instanceId!); - return {}; - }); - } - } } } @@ -853,7 +834,6 @@ abstract class TestWebViewClientHostApi { static const MessageCodec codec = _TestWebViewClientHostApiCodec(); void create(int instanceId, bool shouldOverrideUrlLoading); - void dispose(int instanceId); static void setup(TestWebViewClientHostApi? api) { { const BasicMessageChannel channel = BasicMessageChannel( @@ -876,24 +856,6 @@ abstract class TestWebViewClientHostApi { }); } } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewClientHostApi.dispose', codec); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.WebViewClientHostApi.dispose was null.'); - final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, - 'Argument for dev.flutter.pigeon.WebViewClientHostApi.dispose was null, expected non-null int.'); - api.dispose(arg_instanceId!); - return {}; - }); - } - } } } @@ -906,7 +868,6 @@ abstract class TestDownloadListenerHostApi { _TestDownloadListenerHostApiCodec(); void create(int instanceId); - void dispose(int instanceId); static void setup(TestDownloadListenerHostApi? api) { { const BasicMessageChannel channel = BasicMessageChannel( @@ -926,24 +887,6 @@ abstract class TestDownloadListenerHostApi { }); } } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.DownloadListenerHostApi.dispose', codec); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.dispose was null.'); - final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, - 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.dispose was null, expected non-null int.'); - api.dispose(arg_instanceId!); - return {}; - }); - } - } } } @@ -955,7 +898,6 @@ abstract class TestWebChromeClientHostApi { static const MessageCodec codec = _TestWebChromeClientHostApiCodec(); void create(int instanceId, int webViewClientInstanceId); - void dispose(int instanceId); static void setup(TestWebChromeClientHostApi? api) { { const BasicMessageChannel channel = BasicMessageChannel( @@ -978,23 +920,5 @@ abstract class TestWebChromeClientHostApi { }); } } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebChromeClientHostApi.dispose', codec); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.WebChromeClientHostApi.dispose was null.'); - final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; - assert(arg_instanceId != null, - 'Argument for dev.flutter.pigeon.WebChromeClientHostApi.dispose was null, expected non-null int.'); - api.dispose(arg_instanceId!); - return {}; - }); - } - } } } diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart index e6ade46e9a24..cdb93991d0f1 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart @@ -85,12 +85,6 @@ void main() { JavaScriptChannel.api.instanceManager.getInstanceId(channel), isNotNull, ); - - webView.removeJavaScriptChannel(channel); - expect( - JavaScriptChannel.api.instanceManager.getInstanceId(channel), - isNull, - ); }); }); @@ -110,20 +104,13 @@ void main() { test('create', () { final WebView webView = WebView(); - final WebViewClient webViewClient1 = TestWebViewClient(); - final WebViewClient webViewClient2 = TestWebViewClient(); + final WebViewClient webViewClient = TestWebViewClient(); - webView.setWebViewClient(webViewClient1); + webView.setWebViewClient(webViewClient); expect( - WebViewClient.api.instanceManager.getInstanceId(webViewClient1), + WebViewClient.api.instanceManager.getInstanceId(webViewClient), isNotNull, ); - - webView.setWebViewClient(webViewClient2); - expect( - WebViewClient.api.instanceManager.getInstanceId(webViewClient1), - isNull, - ); }); }); @@ -143,20 +130,13 @@ void main() { test('create', () { final WebView webView = WebView(); - final DownloadListener downloadListener1 = TestDownloadListener(); - final DownloadListener downloadListener2 = TestDownloadListener(); + final DownloadListener downloadListener = TestDownloadListener(); - webView.setDownloadListener(downloadListener1); + webView.setDownloadListener(downloadListener); expect( - DownloadListener.api.instanceManager.getInstanceId(downloadListener1), + DownloadListener.api.instanceManager.getInstanceId(downloadListener), isNotNull, ); - - webView.setDownloadListener(downloadListener2); - expect( - DownloadListener.api.instanceManager.getInstanceId(downloadListener1), - isNull, - ); }); }); @@ -182,20 +162,13 @@ void main() { final WebView webView = WebView(); webView.setWebViewClient(TestWebViewClient()); - final WebChromeClient webChromeClient1 = TestWebChromeClient(); - final WebChromeClient webChromeClient2 = TestWebChromeClient(); + final WebChromeClient webChromeClient = TestWebChromeClient(); - webView.setWebChromeClient(webChromeClient1); + webView.setWebChromeClient(webChromeClient); expect( - WebChromeClient.api.instanceManager.getInstanceId(webChromeClient1), + WebChromeClient.api.instanceManager.getInstanceId(webChromeClient), isNotNull, ); - - webView.setWebChromeClient(webChromeClient2); - expect( - WebChromeClient.api.instanceManager.getInstanceId(webChromeClient1), - isNull, - ); }); }); }); diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart index 123c7f696396..57ab9e82ac1c 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart @@ -229,10 +229,6 @@ class MockTestWebViewClientHostApi extends _i1.Mock Invocation.method(#create, [instanceId, shouldOverrideUrlLoading]), returnValueForMissingStub: null); @override - void dispose(int? instanceId) => - super.noSuchMethod(Invocation.method(#dispose, [instanceId]), - returnValueForMissingStub: null); - @override String toString() => super.toString(); } @@ -251,10 +247,6 @@ class MockTestWebChromeClientHostApi extends _i1.Mock Invocation.method(#create, [instanceId, webViewClientInstanceId]), returnValueForMissingStub: null); @override - void dispose(int? instanceId) => - super.noSuchMethod(Invocation.method(#dispose, [instanceId]), - returnValueForMissingStub: null); - @override String toString() => super.toString(); } @@ -272,10 +264,6 @@ class MockTestJavaScriptChannelHostApi extends _i1.Mock super.noSuchMethod(Invocation.method(#create, [instanceId, channelName]), returnValueForMissingStub: null); @override - void dispose(int? instanceId) => - super.noSuchMethod(Invocation.method(#dispose, [instanceId]), - returnValueForMissingStub: null); - @override String toString() => super.toString(); } @@ -293,9 +281,5 @@ class MockTestDownloadListenerHostApi extends _i1.Mock super.noSuchMethod(Invocation.method(#create, [instanceId]), returnValueForMissingStub: null); @override - void dispose(int? instanceId) => - super.noSuchMethod(Invocation.method(#dispose, [instanceId]), - returnValueForMissingStub: null); - @override String toString() => super.toString(); } diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart index 1c1ce733ac16..a5b2fdd8ade0 100644 --- a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.dart @@ -382,7 +382,6 @@ void main() { await controller.addJavascriptChannels({'c', 'd'}); await controller.removeJavascriptChannels({'c', 'd'}); - verify(mockJavaScriptChannelHostApi.dispose(any)).called(2); verify(mockWebViewHostApi.removeJavaScriptChannel(0, any)).called(2); }); diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.mocks.dart index 000d624a2296..5f4381a580d4 100644 --- a/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_android/test/webview_widget_test.mocks.dart @@ -1,3 +1,7 @@ +// 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. + // Mocks generated by Mockito 5.0.16 from annotations // in webview_flutter_android/test/webview_widget_test.dart. // Do not manually edit this file. @@ -230,10 +234,6 @@ class MockTestWebViewClientHostApi extends _i1.Mock Invocation.method(#create, [instanceId, shouldOverrideUrlLoading]), returnValueForMissingStub: null); @override - void dispose(int? instanceId) => - super.noSuchMethod(Invocation.method(#dispose, [instanceId]), - returnValueForMissingStub: null); - @override String toString() => super.toString(); } @@ -252,10 +252,6 @@ class MockTestWebChromeClientHostApi extends _i1.Mock Invocation.method(#create, [instanceId, webViewClientInstanceId]), returnValueForMissingStub: null); @override - void dispose(int? instanceId) => - super.noSuchMethod(Invocation.method(#dispose, [instanceId]), - returnValueForMissingStub: null); - @override String toString() => super.toString(); } @@ -273,10 +269,6 @@ class MockTestJavaScriptChannelHostApi extends _i1.Mock super.noSuchMethod(Invocation.method(#create, [instanceId, channelName]), returnValueForMissingStub: null); @override - void dispose(int? instanceId) => - super.noSuchMethod(Invocation.method(#dispose, [instanceId]), - returnValueForMissingStub: null); - @override String toString() => super.toString(); } @@ -294,10 +286,6 @@ class MockTestDownloadListenerHostApi extends _i1.Mock super.noSuchMethod(Invocation.method(#create, [instanceId]), returnValueForMissingStub: null); @override - void dispose(int? instanceId) => - super.noSuchMethod(Invocation.method(#dispose, [instanceId]), - returnValueForMissingStub: null); - @override String toString() => super.toString(); } From f2495ee9e9e49b50bfc9ae006246b4275a3dfd00 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 28 Oct 2021 14:24:39 -0700 Subject: [PATCH 52/54] license and version --- packages/webview_flutter/webview_flutter/pubspec.yaml | 2 +- .../java/io/flutter/plugins/webviewflutter/Releasable.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml index a4a0af8848c4..dabfe0d0d14a 100644 --- a/packages/webview_flutter/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: flutter: sdk: flutter webview_flutter_platform_interface: ^1.0.0 - webview_flutter_android: 2.1.0 + webview_flutter_android: ^2.0.13 webview_flutter_wkwebview: ^2.0.13 dev_dependencies: diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/Releasable.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/Releasable.java index 21b78f411971..020de09365bb 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/Releasable.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/Releasable.java @@ -1,3 +1,7 @@ +// 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; /** From 622425e15107d0e6d7eab76f077c64ebb14eb61d Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 28 Oct 2021 17:39:20 -0700 Subject: [PATCH 53/54] fix resize test --- .../webview_flutter_test.dart | 164 +++++++++--------- 1 file changed, 84 insertions(+), 80 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart index c57d2bd55580..5876fa5d2d5c 100644 --- a/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart @@ -168,91 +168,24 @@ void main() { }, skip: _skipDueToIssue86757); testWidgets('resize webview', (WidgetTester tester) async { - final String resizeTest = ''' - - Resize test - - - - - - '''; - final String resizeTestBase64 = - base64Encode(const Utf8Encoder().convert(resizeTest)); - final Completer resizeCompleter = Completer(); - final Completer pageStarted = Completer(); - final Completer pageLoaded = Completer(); - final Completer controllerCompleter = - Completer(); - final GlobalKey key = GlobalKey(); + final Completer pageFinishedCompleter = Completer(); - final WebView webView = WebView( - key: key, - initialUrl: 'data:text/html;charset=utf-8;base64,$resizeTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); + int resizeCallbackCount = 0; + await tester.pumpWidget(ResizableWebView( + onResize: (_) => resizeCallbackCount++, + onPageFinished: () { + pageFinishedCompleter.complete(); }, - javascriptChannels: { - JavascriptChannel( - name: 'Resize', - onMessageReceived: (JavascriptMessage message) { - resizeCompleter.complete(true); - }, - ), - }, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - javascriptMode: JavascriptMode.unrestricted, - ); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: Column( - children: [ - SizedBox( - width: 200, - height: 200, - child: webView, - ), - ], - ), - ), - ); + )); + await tester.pump(Duration(seconds: 3)); + await pageFinishedCompleter.future; - await controllerCompleter.future; - await pageStarted.future; - await pageLoaded.future; + final int oldCount = resizeCallbackCount; - expect(resizeCompleter.isCompleted, false); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: Column( - children: [ - SizedBox( - width: 400, - height: 400, - child: webView, - ), - ], - ), - ), - ); + await tester.tap(find.byKey(const ValueKey('resizeButton'))); + await tester.pump(Duration(seconds: 3)); - await resizeCompleter.future; + expect(resizeCallbackCount, greaterThan(oldCount)); }); testWidgets('set custom userAgent', (WidgetTester tester) async { @@ -1416,3 +1349,74 @@ Future _evaluateJavascript( WebViewController controller, String js) async { return jsonDecode(await controller.evaluateJavascript(js)); } + +class ResizableWebView extends StatefulWidget { + ResizableWebView({required this.onResize, required this.onPageFinished}); + + final JavascriptMessageHandler onResize; + final VoidCallback onPageFinished; + + @override + State createState() => ResizableWebViewState(); +} + +class ResizableWebViewState extends State { + double webViewWidth = 200; + double webViewHeight = 200; + + static const String resizePage = ''' + + Resize test + + + + + + '''; + + @override + Widget build(BuildContext context) { + final String resizeTestBase64 = + base64Encode(const Utf8Encoder().convert(resizePage)); + return Directionality( + textDirection: TextDirection.ltr, + child: Column( + children: [ + SizedBox( + width: webViewWidth, + height: webViewHeight, + child: WebView( + initialUrl: + 'data:text/html;charset=utf-8;base64,$resizeTestBase64', + javascriptChannels: { + JavascriptChannel( + name: 'Resize', + onMessageReceived: widget.onResize, + ), + }, + onPageFinished: (_) => widget.onPageFinished(), + javascriptMode: JavascriptMode.unrestricted, + ), + ), + TextButton( + key: Key('resizeButton'), + onPressed: () { + setState(() { + webViewWidth += 100.0; + webViewHeight += 100.0; + }); + }, + child: Text('ResizeButton'), + ), + ], + ), + ); + } +} From 08582f04363eec34922b7b3763e2ed3abd7e000c Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 29 Oct 2021 12:08:23 -0700 Subject: [PATCH 54/54] release tests --- .../webviewflutter/WebViewHostApiImpl.java | 9 +- .../plugins/webviewflutter/WebViewTest.java | 101 ++++++++++++++++++ 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java index 3e4cdae06db8..f1aef3e35b21 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java @@ -42,7 +42,7 @@ void setWebContentsDebuggingEnabled(boolean enabled) { } } - private static class WebViewPlatformView extends WebView implements PlatformView, Releasable { + static class WebViewPlatformView extends WebView implements PlatformView, Releasable { private WebViewClient currentWebViewClient; private DownloadListener currentDownloadListener; private WebChromeClient currentWebChromeClient; @@ -129,7 +129,8 @@ public void release() { } } - private static class InputAwareWebViewPlatformView extends InputAwareWebView + @SuppressLint("ViewConstructor") + static class InputAwareWebViewPlatformView extends InputAwareWebView implements PlatformView, Releasable { private WebViewClient currentWebViewClient; private DownloadListener currentDownloadListener; @@ -267,9 +268,7 @@ public void create(Long instanceId, Boolean useHybridComposition) { @Override public void dispose(Long instanceId) { final WebView instance = (WebView) instanceManager.removeInstance(instanceId); - if (instance instanceof Releasable) { - ((Releasable) instance).release(); - } + ((Releasable) instance).release(); } @Override diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java index 6896e9224e90..3ba4040e74ef 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java @@ -16,7 +16,12 @@ import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; +import io.flutter.plugins.webviewflutter.DownloadListenerHostApiImpl.DownloadListenerImpl; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelFlutterApi; +import io.flutter.plugins.webviewflutter.WebChromeClientHostApiImpl.WebChromeClientImpl; +import io.flutter.plugins.webviewflutter.WebViewClientHostApiImpl.WebViewClientImpl; +import io.flutter.plugins.webviewflutter.WebViewHostApiImpl.InputAwareWebViewPlatformView; +import io.flutter.plugins.webviewflutter.WebViewHostApiImpl.WebViewPlatformView; import java.util.HashMap; import org.junit.Before; import org.junit.Rule; @@ -46,6 +51,102 @@ public void setUp() { testHostApiImpl.create(0L, true); } + @Test + public void releaseWebView() { + final WebViewPlatformView webView = new WebViewPlatformView(mockContext); + + final WebViewClientImpl mockWebViewClient = mock(WebViewClientImpl.class); + final WebChromeClientImpl mockWebChromeClient = mock(WebChromeClientImpl.class); + final DownloadListenerImpl mockDownloadListener = mock(DownloadListenerImpl.class); + final JavaScriptChannel mockJavaScriptChannel = mock(JavaScriptChannel.class); + + webView.setWebViewClient(mockWebViewClient); + webView.setWebChromeClient(mockWebChromeClient); + webView.setDownloadListener(mockDownloadListener); + webView.addJavascriptInterface(mockJavaScriptChannel, "jchannel"); + + webView.release(); + + verify(mockWebViewClient).release(); + verify(mockWebChromeClient).release(); + verify(mockDownloadListener).release(); + verify(mockJavaScriptChannel).release(); + } + + @Test + public void releaseWebViewDependents() { + final WebViewPlatformView webView = new WebViewPlatformView(mockContext); + + final WebViewClientImpl mockWebViewClient = mock(WebViewClientImpl.class); + final WebChromeClientImpl mockWebChromeClient = mock(WebChromeClientImpl.class); + final DownloadListenerImpl mockDownloadListener = mock(DownloadListenerImpl.class); + final JavaScriptChannel mockJavaScriptChannel = mock(JavaScriptChannel.class); + + webView.setWebViewClient(mockWebViewClient); + webView.setWebChromeClient(mockWebChromeClient); + webView.setDownloadListener(mockDownloadListener); + webView.addJavascriptInterface(mockJavaScriptChannel, "jchannel"); + + webView.setWebViewClient(null); + webView.setWebChromeClient(null); + webView.setDownloadListener(null); + webView.removeJavascriptInterface("jchannel"); + + verify(mockWebViewClient).release(); + verify(mockWebChromeClient).release(); + verify(mockDownloadListener).release(); + verify(mockJavaScriptChannel).release(); + } + + @Test + public void releaseInputAwareWebView() { + final InputAwareWebViewPlatformView webView = + new InputAwareWebViewPlatformView(mockContext, null); + + final WebViewClientImpl mockWebViewClient = mock(WebViewClientImpl.class); + final WebChromeClientImpl mockWebChromeClient = mock(WebChromeClientImpl.class); + final DownloadListenerImpl mockDownloadListener = mock(DownloadListenerImpl.class); + final JavaScriptChannel mockJavaScriptChannel = mock(JavaScriptChannel.class); + + webView.setWebViewClient(mockWebViewClient); + webView.setWebChromeClient(mockWebChromeClient); + webView.setDownloadListener(mockDownloadListener); + webView.addJavascriptInterface(mockJavaScriptChannel, "jchannel"); + + webView.release(); + + verify(mockWebViewClient).release(); + verify(mockWebChromeClient).release(); + verify(mockDownloadListener).release(); + verify(mockJavaScriptChannel).release(); + } + + @Test + public void releaseInputAwareWebViewDependents() { + final InputAwareWebViewPlatformView webView = + new InputAwareWebViewPlatformView(mockContext, null); + + final WebViewClientImpl mockWebViewClient = mock(WebViewClientImpl.class); + final WebChromeClientImpl mockWebChromeClient = mock(WebChromeClientImpl.class); + final DownloadListenerImpl mockDownloadListener = mock(DownloadListenerImpl.class); + final JavaScriptChannel mockJavaScriptChannel = mock(JavaScriptChannel.class); + + webView.setWebViewClient(mockWebViewClient); + webView.setWebChromeClient(mockWebChromeClient); + webView.setDownloadListener(mockDownloadListener); + webView.addJavascriptInterface(mockJavaScriptChannel, "jchannel"); + + webView.setWebViewClient(null); + webView.setWebChromeClient(null); + webView.setDownloadListener(null); + webView.removeJavascriptInterface("jchannel"); + + verify(mockWebViewClient).release(); + verify(mockWebChromeClient).release(); + verify(mockDownloadListener).release(); + verify(mockJavaScriptChannel).release(); + } + @Test public void loadUrl() { testHostApiImpl.loadUrl(0L, "https://www.google.com", new HashMap<>());