) response;
+ Integer action = (Integer) responseMap.get("action");
+
+ Log.d(LOG_TAG, "\n\naction: " + action);
+
+ if (action != null) {
+ switch (action) {
+ case 0:
+ handler.cancel();
+ return;
+ case 1:
+ String username = (String) responseMap.get("username");
+ String password = (String) responseMap.get("password");
+ Boolean permanentPersistence = (Boolean) responseMap.get("permanentPersistence");
+ if (permanentPersistence != null && permanentPersistence && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ WebViewDatabase.getInstance(view.getContext()).setHttpAuthUsernamePassword(host, realm, username, password);
+ }
+ handler.proceed(username, password);
+ return;
+ case 2:
+ handler.useHttpAuthUsernamePassword();
+ return;
+ }
+ }
+ }
+
+ handler.cancel();
+ }
+
+ @Override
+ public void error(String s, String s1, Object o) {
+ Log.e(LOG_TAG, s + ", " + s1);
+ }
+
+ @Override
+ public void notImplemented() {
+ handler.cancel();
+ }
+ });
}
@Override
@@ -324,9 +372,6 @@ public class InAppWebViewClient extends WebViewClient {
Boolean report = (Boolean) responseMap.get("report");
Integer action = (Integer) responseMap.get("action");
- Log.d(LOG_TAG, "\n\nreport: " + report);
- Log.d(LOG_TAG, "\n\naction: " + action);
-
report = report != null ? report : true;
if (action != null) {
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java
index e240cedf..6bbfdf7d 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java
@@ -19,6 +19,7 @@ public class InAppWebViewOptions extends Options {
public boolean clearCache = false;
public String userAgent = "";
public boolean javaScriptEnabled = true;
+ public boolean debuggingEnabled = false;
public boolean javaScriptCanOpenWindowsAutomatically = false;
public boolean mediaPlaybackRequiresUserGesture = true;
public Integer textZoom = 100;
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InputAwareWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InputAwareWebView.java
new file mode 100644
index 00000000..7c6754d7
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InputAwareWebView.java
@@ -0,0 +1,169 @@
+package com.pichillilorenzo.flutter_inappbrowser.InAppWebView;
+
+import static android.content.Context.INPUT_METHOD_SERVICE;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.webkit.WebView;
+
+/**
+ * A WebView subclass that mirrors the same implementation hacks that the system WebView does in
+ * order to correctly create an InputConnection.
+ *
+ * https://github.com/flutter/plugins/blob/master/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java
+ */
+public class InputAwareWebView extends WebView {
+ public View containerView;
+
+ private View threadedInputConnectionProxyView;
+ private ThreadedInputConnectionProxyAdapterView proxyAdapterView;
+
+ public InputAwareWebView(Context context, View containerView) {
+ super(context);
+ this.containerView = containerView;
+ }
+
+ public InputAwareWebView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ this.containerView = null;
+ }
+
+ public InputAwareWebView(Context context) {
+ super(context);
+ this.containerView = null;
+ }
+
+ public InputAwareWebView(Context context, AttributeSet attrs, int defaultStyle) {
+ super(context, attrs, defaultStyle);
+ this.containerView = null;
+ }
+
+ /**
+ * Set our proxy adapter view to use its cached input connection instead of creating new ones.
+ *
+ * This is used to avoid losing our input connection when the virtual display is resized.
+ */
+ public void lockInputConnection() {
+ if (proxyAdapterView == null) {
+ return;
+ }
+
+ proxyAdapterView.setLocked(true);
+ }
+
+ /** Sets the proxy adapter view back to its default behavior. */
+ public void unlockInputConnection() {
+ if (proxyAdapterView == null) {
+ return;
+ }
+
+ proxyAdapterView.setLocked(false);
+ }
+
+ /** Restore the original InputConnection, if needed. */
+ void dispose() {
+ resetInputConnection();
+ }
+
+ /**
+ * Creates an InputConnection from the IME thread when needed.
+ *
+ *
We only need to create a {@link ThreadedInputConnectionProxyAdapterView} and create an
+ * InputConnectionProxy on the IME thread when WebView is doing the same thing. So we rely on the
+ * system calling this method for WebView's proxy view in order to know when we need to create our
+ * own.
+ *
+ *
This method would normally be called for any View that used the InputMethodManager. We rely
+ * on flutter/engine filtering the calls we receive down to the ones in our hierarchy and the
+ * system WebView in order to know whether or not the system WebView expects an InputConnection on
+ * the IME thread.
+ */
+ @Override
+ public boolean checkInputConnectionProxy(final View view) {
+ if (containerView == null)
+ return super.checkInputConnectionProxy(view);
+ // Check to see if the view param is WebView's ThreadedInputConnectionProxyView.
+ View previousProxy = threadedInputConnectionProxyView;
+ threadedInputConnectionProxyView = view;
+ if (previousProxy == view) {
+ // This isn't a new ThreadedInputConnectionProxyView. Ignore it.
+ return super.checkInputConnectionProxy(view);
+ }
+
+ // We've never seen this before, so we make the assumption that this is WebView's
+ // ThreadedInputConnectionProxyView. We are making the assumption that the only view that could
+ // possibly be interacting with the IMM here is WebView's ThreadedInputConnectionProxyView.
+ proxyAdapterView =
+ new ThreadedInputConnectionProxyAdapterView(
+ /*containerView=*/ containerView,
+ /*targetView=*/ view,
+ /*imeHandler=*/ view.getHandler());
+ setInputConnectionTarget(/*targetView=*/ proxyAdapterView);
+ return super.checkInputConnectionProxy(view);
+ }
+
+ /**
+ * Ensure that input creation happens back on {@link #containerView}'s thread once this view no
+ * longer has focus.
+ *
+ *
The logic in {@link #checkInputConnectionProxy} forces input creation to happen on Webview's
+ * thread for all connections. We undo it here so users will be able to go back to typing in
+ * Flutter UIs as expected.
+ */
+ @Override
+ public void clearFocus() {
+ super.clearFocus();
+ if (containerView != null)
+ resetInputConnection();
+ }
+
+ /**
+ * Ensure that input creation happens back on {@link #containerView}.
+ *
+ *
The logic in {@link #checkInputConnectionProxy} forces input creation to happen on Webview's
+ * thread for all connections. We undo it here so users will be able to go back to typing in
+ * Flutter UIs as expected.
+ */
+ private void resetInputConnection() {
+ if (proxyAdapterView == null) {
+ // No need to reset the InputConnection to the default thread if we've never changed it.
+ return;
+ }
+ setInputConnectionTarget(/*targetView=*/ containerView);
+ }
+
+ /**
+ * This is the crucial trick that gets the InputConnection creation to happen on the correct
+ * thread pre Android N.
+ * https://cs.chromium.org/chromium/src/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java?l=169&rcl=f0698ee3e4483fad5b0c34159276f71cfaf81f3a
+ *
+ *
{@code targetView} should have a {@link View#getHandler} method with the thread that future
+ * InputConnections should be created on.
+ */
+ private void setInputConnectionTarget(final View targetView) {
+ targetView.requestFocus();
+ containerView.post(
+ new Runnable() {
+ @Override
+ public void run() {
+ InputMethodManager imm =
+ (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
+ // This is a hack to make InputMethodManager believe that the target view now has focus.
+ // As a result, InputMethodManager will think that targetView is focused, and will call
+ // getHandler() of the view when creating input connection.
+
+ // Step 1: Set targetView as InputMethodManager#mNextServedView. This does not affect
+ // the real window focus.
+ targetView.onWindowFocusChanged(true);
+
+ // Step 2: Have InputMethodManager focus in on targetView. As a result, IMM will call
+ // onCreateInputConnection() on targetView on the same thread as
+ // targetView.getHandler(). It will also call subsequent InputConnection methods on this
+ // thread. This is the IME thread in cases where targetView is our proxyAdapterView.
+ imm.isActive(containerView);
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/ThreadedInputConnectionProxyAdapterView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/ThreadedInputConnectionProxyAdapterView.java
new file mode 100644
index 00000000..b3bb970d
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/ThreadedInputConnectionProxyAdapterView.java
@@ -0,0 +1,99 @@
+package com.pichillilorenzo.flutter_inappbrowser.InAppWebView;
+
+import android.os.Handler;
+import android.os.IBinder;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+/**
+ * A fake View only exposed to InputMethodManager.
+ *
+ * https://github.com/flutter/plugins/blob/master/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java
+ */
+final class ThreadedInputConnectionProxyAdapterView extends View {
+ final Handler imeHandler;
+ final IBinder windowToken;
+ final View containerView;
+ final View rootView;
+ final View targetView;
+
+ private boolean triggerDelayed = true;
+ private boolean isLocked = false;
+ private InputConnection cachedConnection;
+
+ ThreadedInputConnectionProxyAdapterView(View containerView, View targetView, Handler imeHandler) {
+ super(containerView.getContext());
+ this.imeHandler = imeHandler;
+ this.containerView = containerView;
+ this.targetView = targetView;
+ windowToken = containerView.getWindowToken();
+ rootView = containerView.getRootView();
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ setVisibility(VISIBLE);
+ }
+
+ /** Returns whether or not this is currently asynchronously acquiring an input connection. */
+ boolean isTriggerDelayed() {
+ return triggerDelayed;
+ }
+
+ /** Sets whether or not this should use its previously cached input connection. */
+ void setLocked(boolean locked) {
+ isLocked = locked;
+ }
+
+ /**
+ * This is expected to be called on the IME thread. See the setup required for this in {@link
+ * InputAwareWebView#checkInputConnectionProxy(View)}.
+ *
+ *
Delegates to ThreadedInputConnectionProxyView to get WebView's input connection.
+ */
+ @Override
+ public InputConnection onCreateInputConnection(final EditorInfo outAttrs) {
+ triggerDelayed = false;
+ InputConnection inputConnection =
+ (isLocked) ? cachedConnection : targetView.onCreateInputConnection(outAttrs);
+ triggerDelayed = true;
+ cachedConnection = inputConnection;
+ return inputConnection;
+ }
+
+ @Override
+ public boolean checkInputConnectionProxy(View view) {
+ return true;
+ }
+
+ @Override
+ public boolean hasWindowFocus() {
+ // None of our views here correctly report they have window focus because of how we're embedding
+ // the platform view inside of a virtual display.
+ return true;
+ }
+
+ @Override
+ public View getRootView() {
+ return rootView;
+ }
+
+ @Override
+ public boolean onCheckIsTextEditor() {
+ return true;
+ }
+
+ @Override
+ public boolean isFocused() {
+ return true;
+ }
+
+ @Override
+ public IBinder getWindowToken() {
+ return windowToken;
+ }
+
+ @Override
+ public Handler getHandler() {
+ return imeHandler;
+ }
+}
\ No newline at end of file
diff --git a/example/lib/inline_example.screen.dart b/example/lib/inline_example.screen.dart
index 02b1d444..a7d32a2f 100644
--- a/example/lib/inline_example.screen.dart
+++ b/example/lib/inline_example.screen.dart
@@ -70,6 +70,7 @@ class _InlineExampleScreenState extends State {
initialHeaders: {},
initialOptions: [
InAppWebViewOptions(
+ clearCache: true,
useShouldOverrideUrlLoading: true,
useOnTargetBlank: true,
//useOnLoadResource: true,
diff --git a/ios/Classes/InAppWebView.swift b/ios/Classes/InAppWebView.swift
index 39aa13b7..ea489830 100755
--- a/ios/Classes/InAppWebView.swift
+++ b/ios/Classes/InAppWebView.swift
@@ -202,7 +202,10 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
scrollView.showsVerticalScrollIndicator = (options?.verticalScrollBarEnabled)!
scrollView.showsHorizontalScrollIndicator = (options?.horizontalScrollBarEnabled)!
-
+
+
+ // options.debuggingEnabled is always enabled for iOS.
+
if (options?.clearCache)! {
clearCache()
}
@@ -745,6 +748,54 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
}
}
+ public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
+ let host = challenge.protectionSpace.host
+ let realm = challenge.protectionSpace.realm
+ onReceivedHttpAuthRequest(host: host, realm: realm, result: {(result) -> Void in
+ if result is FlutterError {
+ print((result as! FlutterError).message)
+ }
+ else if (result as? NSObject) == FlutterMethodNotImplemented {
+ completionHandler(.performDefaultHandling, nil)
+ }
+ else {
+ //WKWebsiteDataStore.default()
+ //URLCredentialStorage()
+ var response: [String: Any]
+ if let r = result {
+ response = r as! [String: Any]
+ var action = response["action"] as? Int
+ action = action != nil ? action : 0;
+ switch action {
+ case 0:
+ completionHandler(.cancelAuthenticationChallenge, nil)
+ break
+ case 1:
+ let username = response["username"] as! String
+ let password = response["password"] as! String
+ let permanentPersistence = response["permanentPersistence"] as? Bool ?? false
+ let persistence = (permanentPersistence) ? URLCredential.Persistence.permanent : URLCredential.Persistence.forSession
+ let credential = URLCredential(user: username, password: password, persistence: persistence)
+ completionHandler(.useCredential, credential)
+ break
+ case 2:
+ if let credential = challenge.proposedCredential {
+ completionHandler(.useCredential, credential)
+ }
+ else {
+ completionHandler(.performDefaultHandling, nil)
+ }
+ break
+ default:
+ completionHandler(.performDefaultHandling, nil)
+ }
+ return;
+ }
+ completionHandler(.performDefaultHandling, nil)
+ }
+ })
+ }
+
fileprivate func createAlertDialog(message: String?, responseMessage: String?, confirmButtonTitle: String?, completionHandler: @escaping () -> Void) {
let title = responseMessage != nil && !responseMessage!.isEmpty ? responseMessage : message
let okButton = confirmButtonTitle != nil && !confirmButtonTitle!.isEmpty ? confirmButtonTitle : NSLocalizedString("Ok", comment: "")
@@ -765,7 +816,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onJsAlert(message: message, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
- completionHandler()
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
self.createAlertDialog(message: message, responseMessage: nil, confirmButtonTitle: nil, completionHandler: completionHandler)
@@ -824,7 +874,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onJsConfirm(message: message, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
- completionHandler(false)
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
self.createConfirmDialog(message: message, responseMessage: nil, confirmButtonTitle: nil, cancelButtonTitle: nil, completionHandler: completionHandler)
@@ -898,7 +947,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
onJsPrompt(message: message, defaultValue: defaultValue, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message)
- completionHandler(nil)
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
self.createPromptDialog(message: message, defaultValue: defaultValue, responseMessage: nil, confirmButtonTitle: nil, cancelButtonTitle: nil, value: nil, completionHandler: completionHandler)
@@ -1053,6 +1101,16 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
}
}
+ public func onReceivedHttpAuthRequest(host: String, realm: String?, result: FlutterResult?) {
+ var arguments: [String: Any] = ["host": host, "realm": realm as Any]
+ if IABController != nil {
+ arguments["uuid"] = IABController!.uuid
+ }
+ if let channel = getChannel() {
+ channel.invokeMethod("onReceivedHttpAuthRequest", arguments: arguments, result: result)
+ }
+ }
+
public func onJsAlert(message: String, result: FlutterResult?) {
var arguments: [String: Any] = ["message": message]
if IABController != nil {
diff --git a/ios/Classes/InAppWebViewOptions.swift b/ios/Classes/InAppWebViewOptions.swift
index 37110d23..7db8c7c5 100755
--- a/ios/Classes/InAppWebViewOptions.swift
+++ b/ios/Classes/InAppWebViewOptions.swift
@@ -18,6 +18,7 @@ public class InAppWebViewOptions: Options {
var clearCache = false
var userAgent = ""
var javaScriptEnabled = true
+ var debuggingEnabled = true
var javaScriptCanOpenWindowsAutomatically = false
var mediaPlaybackRequiresUserGesture = true
var verticalScrollBarEnabled = true
@@ -25,7 +26,7 @@ public class InAppWebViewOptions: Options {
var resourceCustomSchemes: [String] = []
var contentBlockers: [[String: [String : Any]]] = []
var minimumFontSize = 0;
-
+
var disallowOverScroll = false
var enableViewportScale = false
//var keyboardDisplayRequiresUserAction = true
diff --git a/lib/src/in_app_browser.dart b/lib/src/in_app_browser.dart
index 6118b062..da329dd6 100644
--- a/lib/src/in_app_browser.dart
+++ b/lib/src/in_app_browser.dart
@@ -406,6 +406,15 @@ class InAppBrowser {
}
+ ///Event fires when a WebView received an HTTP authentication request. The default behavior is to cancel the request.
+ ///
+ ///[host] represents the host requiring authentication.
+ ///
+ ///[realm] represents the realm for which authentication is required
+ Future onReceivedHttpAuthRequest(String url, String realm) {
+
+ }
+
void throwIsAlreadyOpened({String message = ''}) {
if (this.isOpened()) {
throw Exception(['Error: ${ (message.isEmpty) ? '' : message + ' '}The browser is already opened.']);
diff --git a/lib/src/in_app_webview.dart b/lib/src/in_app_webview.dart
index d9f47e4f..db804f2b 100644
--- a/lib/src/in_app_webview.dart
+++ b/lib/src/in_app_webview.dart
@@ -176,6 +176,13 @@ class InAppWebView extends StatefulWidget {
///**NOTE**: available only for Android.
final onSafeBrowsingHitCallback onSafeBrowsingHit;
+ ///Event fires when a WebView received an HTTP authentication request. The default behavior is to cancel the request.
+ ///
+ ///[host] represents the host requiring authentication.
+ ///
+ ///[realm] represents the realm for which authentication is required
+ final onReceivedHttpAuthRequestCallback onReceivedHttpAuthRequest;
+
///Initial url that will be loaded.
final String initialUrl;
///Initial asset file that will be loaded. See [InAppWebView.loadFile()] for explanation.
@@ -219,6 +226,7 @@ class InAppWebView extends StatefulWidget {
this.onJsConfirm,
this.onJsPrompt,
this.onSafeBrowsingHit,
+ this.onReceivedHttpAuthRequest,
this.gestureRecognizers,
}) : super(key: key);
@@ -468,6 +476,14 @@ class InAppWebViewController {
else if (_inAppBrowser != null)
return (await _inAppBrowser.onSafeBrowsingHit(url, threatType))?.toMap();
break;
+ case "onReceivedHttpAuthRequest":
+ String host = call.arguments["host"];
+ String realm = call.arguments["realm"];
+ if (_widget != null && _widget.onReceivedHttpAuthRequest != null)
+ return (await _widget.onReceivedHttpAuthRequest(this, host, realm))?.toMap();
+ else if (_inAppBrowser != null)
+ return (await _inAppBrowser.onReceivedHttpAuthRequest(host, realm))?.toMap();
+ break;
case "onCallJsHandler":
String handlerName = call.arguments["handlerName"];
// decode args to json
diff --git a/lib/src/types.dart b/lib/src/types.dart
index 707c9591..fef73fac 100644
--- a/lib/src/types.dart
+++ b/lib/src/types.dart
@@ -270,6 +270,34 @@ class SafeBrowsingResponse {
}
}
+class HttpAuthResponseAction {
+ final int _value;
+ const HttpAuthResponseAction._internal(this._value);
+ toValue() => _value;
+
+ static const CANCEL = const HttpAuthResponseAction._internal(0);
+ static const PROCEED = const HttpAuthResponseAction._internal(1);
+ static const USE_HTTP_AUTH_USERNAME_PASSWORD = const HttpAuthResponseAction._internal(2);
+}
+
+class HttpAuthResponse {
+ String username;
+ String password;
+ bool permanentPersistence;
+ HttpAuthResponseAction action;
+
+ HttpAuthResponse({this.username = "", this.password = "", this.permanentPersistence = false, this.action = HttpAuthResponseAction.CANCEL});
+
+ Map toMap() {
+ return {
+ "username": username,
+ "password": password,
+ "permanentPersistence": permanentPersistence,
+ "action": action?.toValue()
+ };
+ }
+}
+
typedef onWebViewCreatedCallback = void Function(InAppWebViewController controller);
typedef onWebViewLoadStartCallback = void Function(InAppWebViewController controller, String url);
typedef onWebViewLoadStopCallback = void Function(InAppWebViewController controller, String url);
@@ -286,4 +314,5 @@ typedef onGeolocationPermissionsShowPromptCallback = Future Function(InAppWebViewController controller, String message);
typedef onJsConfirmCallback = Future Function(InAppWebViewController controller, String message);
typedef onJsPromptCallback = Future Function(InAppWebViewController controller, String message, String defaultValue);
-typedef onSafeBrowsingHitCallback = Future Function(InAppWebViewController controller, String url, SafeBrowsingThreat threatType);
\ No newline at end of file
+typedef onSafeBrowsingHitCallback = Future Function(InAppWebViewController controller, String url, SafeBrowsingThreat threatType);
+typedef onReceivedHttpAuthRequestCallback = Future Function(InAppWebViewController controller, String url, String realm);
\ No newline at end of file
diff --git a/lib/src/webview_options.dart b/lib/src/webview_options.dart
index e81cfebc..01175647 100644
--- a/lib/src/webview_options.dart
+++ b/lib/src/webview_options.dart
@@ -22,6 +22,7 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions {
bool clearCache;
String userAgent;
bool javaScriptEnabled;
+ bool debuggingEnabled;
bool javaScriptCanOpenWindowsAutomatically;
bool mediaPlaybackRequiresUserGesture;
int textZoom;
@@ -32,7 +33,7 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions {
List contentBlockers;
InAppWebViewOptions({this.useShouldOverrideUrlLoading = false, this.useOnLoadResource = false, this.useOnDownloadStart = false, this.useOnTargetBlank = false,
- this.clearCache = false, this.userAgent = "", this.javaScriptEnabled = true, this.javaScriptCanOpenWindowsAutomatically = false,
+ this.clearCache = false, this.userAgent = "", this.javaScriptEnabled = true, this.debuggingEnabled = false, this.javaScriptCanOpenWindowsAutomatically = false,
this.mediaPlaybackRequiresUserGesture = true, this.textZoom = 100, this.minimumFontSize, this.verticalScrollBarEnabled = true, this.horizontalScrollBarEnabled = true,
this.resourceCustomSchemes = const [], this.contentBlockers = const []}) {
if (this.minimumFontSize == null)