From 06668703c4d3bffb03deaac0228a41d56e11a000 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Mon, 31 Oct 2022 02:09:00 +0100 Subject: [PATCH] Removed willSuppressErrorPage WebView Android setting in favor of disableDefaultErrorPage, Added isMultiProcessEnabled static method on InAppWebViewController for Android, Added onContentSizeChanged WebView event for iOS, Added onPermissionRequestCanceled and onRequestFocus WebView events for Android, Added defaultVideoPoster WebView setting for Android, Added TracingController for Android WebViews --- CHANGELOG.md | 15 +- .../InAppWebViewFlutterPlugin.java | 8 + .../InAppWebViewStatic.java | 8 + .../TracingControllerChannelDelegate.java | 77 ++++++ .../tracing/TracingControllerManager.java | 60 +++++ .../tracing/TracingSettings.java | 61 +++++ .../webview/WebViewChannelDelegate.java | 16 ++ .../webview/in_app_webview/InAppWebView.java | 8 +- .../InAppWebViewChromeClient.java | 37 ++- .../in_app_webview/InAppWebViewClient.java | 4 +- .../in_app_webview/InAppWebViewSettings.java | 13 +- .../integration_test/in_app_webview/main.dart | 2 + .../on_content_size_changed.dart | 38 +++ .../in_app_webview/on_permission_request.dart | 68 ++++- .../service_worker_controller/main.dart | 6 +- .../tracing_controller/main.dart | 16 ++ .../tracing_controller/start_and_stop.dart | 63 +++++ .../webview_flutter_test.dart | 2 + .../ios/Flutter/flutter_export_environment.sh | 7 +- example/pubspec.yaml | 2 +- ios/Classes/InAppWebView/InAppWebView.swift | 15 ++ .../InAppWebView/WebViewChannelDelegate.swift | 8 + ios/Classes/Types/CGSize.swift | 21 ++ lib/src/android/main.dart | 1 + lib/src/android/tracing_controller.dart | 154 ++++++++++++ lib/src/android/tracing_controller.g.dart | 71 ++++++ lib/src/in_app_browser/in_app_browser.dart | 35 ++- .../headless_in_app_webview.dart | 237 ++++++++++-------- lib/src/in_app_webview/in_app_webview.dart | 15 ++ .../in_app_webview_controller.dart | 56 +++++ .../in_app_webview_settings.dart | 24 +- .../in_app_webview_settings.g.dart | 30 +-- lib/src/in_app_webview/webview.dart | 41 ++- lib/src/types/main.dart | 2 + lib/src/types/tracing_category.dart | 43 ++++ lib/src/types/tracing_category.g.dart | 124 +++++++++ lib/src/types/tracing_mode.dart | 23 ++ lib/src/types/tracing_mode.g.dart | 84 +++++++ pubspec.yaml | 2 +- 39 files changed, 1332 insertions(+), 165 deletions(-) create mode 100755 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingControllerChannelDelegate.java create mode 100755 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingControllerManager.java create mode 100755 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingSettings.java create mode 100644 example/integration_test/in_app_webview/on_content_size_changed.dart create mode 100644 example/integration_test/tracing_controller/main.dart create mode 100644 example/integration_test/tracing_controller/start_and_stop.dart create mode 100644 ios/Classes/Types/CGSize.swift create mode 100644 lib/src/android/tracing_controller.dart create mode 100644 lib/src/android/tracing_controller.g.dart create mode 100644 lib/src/types/tracing_category.dart create mode 100644 lib/src/types/tracing_category.g.dart create mode 100644 lib/src/types/tracing_mode.dart create mode 100644 lib/src/types/tracing_mode.g.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ccc102b..43aec0b9 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## 6.0.0-beta.12 + +- Removed `willSuppressErrorPage` WebView Android setting in favor of `disableDefaultErrorPage`. +- Added `isMultiProcessEnabled` static method on `InAppWebViewController` for Android +- Added `onContentSizeChanged` WebView event for iOS +- Added `onPermissionRequestCanceled`, `onRequestFocus` WebView events for Android +- Added `defaultVideoPoster` WebView setting for Android +- Added `TracingController` for Android WebViews + +### BREAKING CHANGES + +- Removed `willSuppressErrorPage` WebView Android setting. Use `disableDefaultErrorPage` instead. + ## 6.0.0-beta.11 - Fixed "[webRTC / macOS] onPermissionRequest not called on HeadlessInAppWebView" [#1405](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1405) @@ -19,7 +32,7 @@ - Added `onNavigationEvent`, `onServiceConnected`, `onRelationshipValidationResult` events on `ChromeSafariBrowser` for Android - Added `mayLaunchUrl`, `launchUrl`, `updateActionButton`, `validateRelationship`, `setSecondaryToolbar`, `updateSecondaryToolbar` methods on `ChromeSafariBrowser` for Android - Added `startAnimations`, `exitAnimations`, `navigationBarColor`, `navigationBarDividerColor`, `secondaryToolbarColor`, `alwaysUseBrowserUI` ChromeSafariBrowser settings for Android -- Added `getMaxToolbarItems` static methods on `ChromeSafariBrowser` for Android +- Added `getMaxToolbarItems` static method on `ChromeSafariBrowser` for Android - Added `ChromeSafariBrowserMenuItem.image` property for iOS - Added `didLoadSuccessfully` optional argument on `ChromeSafariBrowser.onCompletedInitialLoad` event for iOS - Added `onInitialLoadDidRedirect`, `onWillOpenInBrowser` events on `ChromeSafariBrowser` for iOS diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java index 886b3da8..04ffb490 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java @@ -16,6 +16,7 @@ import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.Headless import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobManager; import com.pichillilorenzo.flutter_inappwebview.proxy.ProxyManager; import com.pichillilorenzo.flutter_inappwebview.service_worker.ServiceWorkerManager; +import com.pichillilorenzo.flutter_inappwebview.tracing.TracingControllerManager; import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; @@ -54,6 +55,8 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware { @Nullable public PrintJobManager printJobManager; @Nullable + public TracingControllerManager tracingControllerManager; + @Nullable public static ValueCallback filePathCallbackLegacy; @Nullable public static ValueCallback filePathCallback; @@ -121,6 +124,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { printJobManager = new PrintJobManager(); } + tracingControllerManager = new TracingControllerManager(this); } @Override @@ -173,6 +177,10 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware { printJobManager.dispose(); printJobManager = null; } + if (tracingControllerManager != null) { + tracingControllerManager.dispose(); + tracingControllerManager = null; + } filePathCallbackLegacy = null; filePathCallback = null; } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java index 8ceea978..5b53a048 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java @@ -122,6 +122,14 @@ public class InAppWebViewStatic extends ChannelDelegateImpl { result.success(null); } break; + case "isMultiProcessEnabled": + if (WebViewFeature.isFeatureSupported(WebViewFeature.MULTI_PROCESS)) { + result.success(WebViewCompat.isMultiProcessEnabled()); + } + else { + result.success(false); + } + break; default: result.notImplemented(); } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingControllerChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingControllerChannelDelegate.java new file mode 100755 index 00000000..d5e136a2 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingControllerChannelDelegate.java @@ -0,0 +1,77 @@ +package com.pichillilorenzo.flutter_inappwebview.tracing; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.webkit.TracingConfig; +import androidx.webkit.TracingController; +import androidx.webkit.WebViewFeature; + +import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.util.Map; +import java.util.concurrent.Executors; + +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; + +public class TracingControllerChannelDelegate extends ChannelDelegateImpl { + @Nullable + private TracingControllerManager tracingControllerManager; + + public TracingControllerChannelDelegate(@NonNull TracingControllerManager tracingControllerManager, @NonNull MethodChannel channel) { + super(channel); + this.tracingControllerManager = tracingControllerManager; + } + + @Override + public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { + TracingController tracingController = TracingControllerManager.tracingController; + + switch (call.method) { + case "isTracing": + if (tracingController != null) { + result.success(tracingController.isTracing()); + } else { + result.success(false); + } + break; + case "start": + if (tracingController != null && WebViewFeature.isFeatureSupported(WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE)) { + Map settingsMap = (Map) call.argument("settings"); + TracingSettings settings = new TracingSettings(); + settings.parse(settingsMap); + TracingConfig config = TracingControllerManager.buildTracingConfig(settings); + tracingController.start(config); + result.success(true); + } else { + result.success(false); + } + break; + case "stop": + if (tracingController != null && WebViewFeature.isFeatureSupported(WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE)) { + String filePath = (String) call.argument("filePath"); + try { + result.success(tracingController.stop( + filePath != null ? new FileOutputStream(filePath) : null, + Executors.newSingleThreadExecutor())); + } catch (FileNotFoundException e) { + e.printStackTrace(); + result.success(false); + } + } else { + result.success(false); + } + break; + default: + result.notImplemented(); + } + } + + @Override + public void dispose() { + super.dispose(); + tracingControllerManager = null; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingControllerManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingControllerManager.java new file mode 100755 index 00000000..77aa3f99 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingControllerManager.java @@ -0,0 +1,60 @@ +package com.pichillilorenzo.flutter_inappwebview.tracing; + +import androidx.annotation.Nullable; +import androidx.webkit.TracingConfig; +import androidx.webkit.TracingController; +import androidx.webkit.WebViewFeature; + +import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; +import com.pichillilorenzo.flutter_inappwebview.types.Disposable; + +import io.flutter.plugin.common.MethodChannel; + +public class TracingControllerManager implements Disposable { + protected static final String LOG_TAG = "TracingControllerMan"; + public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_tracingcontroller"; + + @Nullable + public TracingControllerChannelDelegate channelDelegate; + @Nullable + public static TracingController tracingController; + @Nullable + public InAppWebViewFlutterPlugin plugin; + + public TracingControllerManager(final InAppWebViewFlutterPlugin plugin) { + this.plugin = plugin; + final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME); + this.channelDelegate = new TracingControllerChannelDelegate(this, channel); + if (WebViewFeature.isFeatureSupported(WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE)) { + tracingController = TracingController.getInstance(); + } else { + tracingController = null; + } + } + + public static TracingConfig buildTracingConfig(TracingSettings settings) { + TracingConfig.Builder builder = new TracingConfig.Builder(); + for (Object category : settings.categories) { + if (category instanceof String) { + builder.addCategories((String) category); + } + if (category instanceof Integer) { + builder.addCategories((Integer) category); + } + } + if (settings.tracingMode != null) { + builder.setTracingMode(settings.tracingMode); + } + return builder.build(); + } + + @Override + public void dispose() { + if (channelDelegate != null) { + channelDelegate.dispose(); + channelDelegate = null; + } + tracingController = null; + plugin = null; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingSettings.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingSettings.java new file mode 100755 index 00000000..fd434799 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/tracing/TracingSettings.java @@ -0,0 +1,61 @@ +package com.pichillilorenzo.flutter_inappwebview.tracing; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.webkit.TracingController; + +import com.pichillilorenzo.flutter_inappwebview.ISettings; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class TracingSettings implements ISettings { + + public static final String LOG_TAG = "TracingSettings"; + + @NonNull + public List categories = new ArrayList<>(); + @Nullable + public Integer tracingMode; + + @NonNull + @Override + public TracingSettings parse(@NonNull Map settings) { + for (Map.Entry pair : settings.entrySet()) { + String key = pair.getKey(); + Object value = pair.getValue(); + if (value == null) { + continue; + } + + switch (key) { + case "categories": + categories = (List) value; + break; + case "tracingMode": + tracingMode = (Integer) value; + break; + } + } + + return this; + } + + @NonNull + @Override + public Map toMap() { + Map settings = new HashMap<>(); + settings.put("categories", categories); + settings.put("tracingMode", tracingMode); + return settings; + } + + @NonNull + @Override + public Map getRealSettings(@NonNull TracingController tracingController) { + Map realSettings = toMap(); + return realSettings; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/WebViewChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/WebViewChannelDelegate.java index b161a194..6e480a19 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/WebViewChannelDelegate.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/WebViewChannelDelegate.java @@ -952,6 +952,15 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl { channel.invokeMethod("onPermissionRequest", obj, callback); } + public void onPermissionRequestCanceled(String origin, List resources) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("origin", origin); + obj.put("resources", resources); + channel.invokeMethod("onPermissionRequestCanceled", obj); + } + public static class ShouldOverrideUrlLoadingCallback extends BaseCallbackResultImpl { @Nullable @Override @@ -1287,6 +1296,13 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl { channel.invokeMethod("onPrintRequest", obj, callback); } + public void onRequestFocus() { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + channel.invokeMethod("onRequestFocus", obj); + } + @Override public void dispose() { super.dispose(); diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebView.java index b4e58793..ad24f259 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebView.java @@ -382,7 +382,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie } if (WebViewFeature.isFeatureSupported(WebViewFeature.SUPPRESS_ERROR_PAGE)) { - WebSettingsCompat.setWillSuppressErrorPage(settings, customSettings.willSuppressErrorPage); + WebSettingsCompat.setWillSuppressErrorPage(settings, customSettings.disableDefaultErrorPage); } if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { WebSettingsCompat.setAlgorithmicDarkeningAllowed(settings, customSettings.algorithmicDarkeningAllowed); @@ -1033,10 +1033,10 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie setHorizontalScrollbarTrackDrawable(new ColorDrawable(Color.parseColor(newCustomSettings.horizontalScrollbarTrackColor))); } - if (newSettingsMap.get("willSuppressErrorPage") != null && - !Util.objEquals(customSettings.willSuppressErrorPage, newCustomSettings.willSuppressErrorPage) && + if (newSettingsMap.get("disableDefaultErrorPage") != null && + !Util.objEquals(customSettings.disableDefaultErrorPage, newCustomSettings.disableDefaultErrorPage) && WebViewFeature.isFeatureSupported(WebViewFeature.SUPPRESS_ERROR_PAGE)) { - WebSettingsCompat.setWillSuppressErrorPage(settings, newCustomSettings.willSuppressErrorPage); + WebSettingsCompat.setWillSuppressErrorPage(settings, newCustomSettings.disableDefaultErrorPage); } if (newSettingsMap.get("algorithmicDarkeningAllowed") != null && !Util.objEquals(customSettings.algorithmicDarkeningAllowed, newCustomSettings.algorithmicDarkeningAllowed) && diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewChromeClient.java index 95291151..ff629268 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewChromeClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewChromeClient.java @@ -3,11 +3,13 @@ package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview; import android.Manifest; import android.annotation.TargetApi; import android.app.Activity; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Color; import android.net.Uri; import android.os.Build; @@ -18,6 +20,7 @@ import android.os.Parcelable; import android.provider.MediaStore; import android.util.Log; import android.view.Gravity; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -33,6 +36,8 @@ import android.webkit.WebView; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -42,6 +47,7 @@ import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFileProvider; +import com.pichillilorenzo.flutter_inappwebview.R; import com.pichillilorenzo.flutter_inappwebview.types.CreateWindowAction; import com.pichillilorenzo.flutter_inappwebview.in_app_browser.ActivityResultListener; import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserDelegate; @@ -125,8 +131,17 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR plugin.activityPluginBinding.addActivityResultListener(this); } + @Nullable @Override public Bitmap getDefaultVideoPoster() { + if (inAppWebView != null && inAppWebView.customSettings.defaultVideoPoster != null) { + final byte[] data = inAppWebView.customSettings.defaultVideoPoster; + BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); + bitmapOptions.inMutable = true; + return BitmapFactory.decodeByteArray( + data, 0, data.length, bitmapOptions + ); + } return Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888); } @@ -680,7 +695,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR defaultBehaviour(null); } }; - + if (inAppWebView != null && inAppWebView.channelDelegate != null) { inAppWebView.channelDelegate.onGeolocationPermissionsShowPrompt(origin, resultCallback); } else { @@ -699,7 +714,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR public boolean onConsoleMessage(ConsoleMessage consoleMessage) { if (inAppWebView != null && inAppWebView.channelDelegate != null) { inAppWebView.channelDelegate.onConsoleMessage( - consoleMessage.message(), + consoleMessage.message(), consoleMessage.messageLevel().ordinal()); } return true; @@ -732,7 +747,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR if (inAppBrowserDelegate != null) { inAppBrowserDelegate.didChangeTitle(title); } - + InAppWebView webView = (InAppWebView) view; if (webView.channelDelegate != null) { @@ -1238,6 +1253,22 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR } } + @Override + public void onRequestFocus(WebView view) { + if(inAppWebView != null && inAppWebView.channelDelegate != null) { + inAppWebView.channelDelegate.onRequestFocus(); + } + } + + @Override + public void onPermissionRequestCanceled(PermissionRequest request) { + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && + inAppWebView != null && inAppWebView.channelDelegate != null) { + inAppWebView.channelDelegate.onPermissionRequestCanceled(request.getOrigin().toString(), + Arrays.asList(request.getResources())); + } + } + @Nullable private Activity getActivity() { if (inAppBrowserDelegate != null) { diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewClient.java index ead03e50..f7db6ed4 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewClient.java @@ -289,11 +289,13 @@ public class InAppWebViewClient extends WebViewClient { } } + @SuppressLint("RestrictedApi") @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { final InAppWebView webView = (InAppWebView) view; - if (webView.customSettings.disableDefaultErrorPage) { + if (!WebViewFeature.isFeatureSupported(WebViewFeature.SUPPRESS_ERROR_PAGE) && + webView.customSettings.disableDefaultErrorPage) { webView.stopLoading(); webView.loadUrl("about:blank"); } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewSettings.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewSettings.java index 3dcb3d9c..5e415ebf 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewSettings.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewSettings.java @@ -114,13 +114,14 @@ public class InAppWebViewSettings implements ISettings { public String horizontalScrollbarThumbColor; @Nullable public String horizontalScrollbarTrackColor; - public Boolean willSuppressErrorPage = false; public Boolean algorithmicDarkeningAllowed = false; @Nullable public Integer requestedWithHeaderMode; public Boolean enterpriseAuthenticationAppLinkPolicyEnabled = true; @Nullable public Map webViewAssetLoader; + @Nullable + public byte[] defaultVideoPoster; @NonNull @Override @@ -379,9 +380,6 @@ public class InAppWebViewSettings implements ISettings { case "horizontalScrollbarTrackColor": horizontalScrollbarTrackColor = (String) value; break; - case "willSuppressErrorPage": - willSuppressErrorPage = (Boolean) value; - break; case "algorithmicDarkeningAllowed": algorithmicDarkeningAllowed = (Boolean) value; break; @@ -397,6 +395,9 @@ public class InAppWebViewSettings implements ISettings { case "webViewAssetLoader": webViewAssetLoader = (Map) value; break; + case "defaultVideoPoster": + defaultVideoPoster = (byte[]) value; + break; } } @@ -489,11 +490,11 @@ public class InAppWebViewSettings implements ISettings { settings.put("verticalScrollbarTrackColor", verticalScrollbarTrackColor); settings.put("horizontalScrollbarThumbColor", horizontalScrollbarThumbColor); settings.put("horizontalScrollbarTrackColor", horizontalScrollbarTrackColor); - settings.put("willSuppressErrorPage", willSuppressErrorPage); settings.put("algorithmicDarkeningAllowed", algorithmicDarkeningAllowed); settings.put("requestedWithHeaderMode", requestedWithHeaderMode); settings.put("enterpriseAuthenticationAppLinkPolicyEnabled", enterpriseAuthenticationAppLinkPolicyEnabled); settings.put("allowBackgroundAudioPlaying", allowBackgroundAudioPlaying); + settings.put("defaultVideoPoster", defaultVideoPoster); return settings; } @@ -580,7 +581,7 @@ public class InAppWebViewSettings implements ISettings { realSettings.put("rendererPriorityPolicy", rendererPriorityPolicy); } if (WebViewFeature.isFeatureSupported(WebViewFeature.SUPPRESS_ERROR_PAGE)) { - realSettings.put("willSuppressErrorPage", WebSettingsCompat.willSuppressErrorPage(settings)); + realSettings.put("disableDefaultErrorPage", WebSettingsCompat.willSuppressErrorPage(settings)); } if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { realSettings.put("algorithmicDarkeningAllowed", WebSettingsCompat.isAlgorithmicDarkeningAllowed(settings)); diff --git a/example/integration_test/in_app_webview/main.dart b/example/integration_test/in_app_webview/main.dart index 0f83208c..c1dff0c2 100644 --- a/example/integration_test/in_app_webview/main.dart +++ b/example/integration_test/in_app_webview/main.dart @@ -37,6 +37,7 @@ import 'load_file.dart'; import 'load_file_url.dart'; import 'load_url.dart'; import 'on_console_message.dart'; +import 'on_content_size_changed.dart'; import 'on_download_start_request.dart'; import 'on_js_before_unload.dart'; import 'on_received_error.dart'; @@ -172,5 +173,6 @@ void main() { applePayAPI(); handlesURLScheme(); webViewAssetLoader(); + onContentSizeChanged(); }, skip: shouldSkip); } diff --git a/example/integration_test/in_app_webview/on_content_size_changed.dart b/example/integration_test/in_app_webview/on_content_size_changed.dart new file mode 100644 index 00000000..67e8e1b2 --- /dev/null +++ b/example/integration_test/in_app_webview/on_content_size_changed.dart @@ -0,0 +1,38 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../constants.dart'; + +void onContentSizeChanged() { + final shouldSkip = kIsWeb + ? true + : ![ + TargetPlatform.iOS, + TargetPlatform.macOS, + ].contains(defaultTargetPlatform); + + testWidgets('onContentSizeChanged', (WidgetTester tester) async { + final Completer onContentSizeChangedCompleter = + Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: InAppWebView( + key: GlobalKey(), + initialUrlRequest: URLRequest(url: TEST_CROSS_PLATFORM_URL_1), + onContentSizeChanged: (controller, oldContentSize, newContentSize) { + if (!onContentSizeChangedCompleter.isCompleted) { + onContentSizeChangedCompleter.complete(); + } + }, + ), + ), + ); + + await expectLater(onContentSizeChangedCompleter.future, completes); + }, skip: shouldSkip); +} diff --git a/example/integration_test/in_app_webview/on_permission_request.dart b/example/integration_test/in_app_webview/on_permission_request.dart index 2b8c7a8a..16b74627 100644 --- a/example/integration_test/in_app_webview/on_permission_request.dart +++ b/example/integration_test/in_app_webview/on_permission_request.dart @@ -16,8 +16,7 @@ void onPermissionRequest() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - var expectedValue = []; - expectedValue = [PermissionResourceType.CAMERA]; + final expectedValue = [PermissionResourceType.CAMERA]; testWidgets('onPermissionRequest', (WidgetTester tester) async { final Completer controllerCompleter = @@ -38,8 +37,7 @@ void onPermissionRequest() { onLoadStop: (controller, url) { pageLoaded.complete(); }, - onPermissionRequest: - (controller, PermissionRequest permissionRequest) async { + onPermissionRequest: (controller, permissionRequest) async { onPermissionRequestCompleter.complete(permissionRequest.resources); return PermissionResponse( resources: permissionRequest.resources, @@ -59,4 +57,66 @@ void onPermissionRequest() { expect(listEquals(resources, expectedValue), true); }, skip: shouldSkip); + + final shouldSkip2 = kIsWeb + ? true + : ![ + TargetPlatform.android, + ].contains(defaultTargetPlatform); + + testWidgets('onPermissionRequestCanceled', (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final Completer pageLoaded = Completer(); + final Completer> onPermissionRequestCompleter = + Completer>(); + final Completer> + onPermissionRequestCancelCompleter = + Completer>(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: InAppWebView( + key: GlobalKey(), + initialUrlRequest: URLRequest(url: TEST_PERMISSION_SITE), + onWebViewCreated: (controller) { + controllerCompleter.complete(controller); + }, + onLoadStop: (controller, url) { + if (pageLoaded.isCompleted) { + pageLoaded.complete(); + } + }, + onPermissionRequest: (controller, permissionRequest) async { + onPermissionRequestCompleter.complete(permissionRequest.resources); + await Future.delayed(Duration(seconds: 30)); + return PermissionResponse( + resources: permissionRequest.resources, + action: PermissionResponseAction.GRANT); + }, + onPermissionRequestCanceled: (controller, permissionRequest) { + onPermissionRequestCancelCompleter + .complete(permissionRequest.resources); + }, + ), + ), + ); + + final InAppWebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + await controller.evaluateJavascript( + source: "document.querySelector('#camera').click();"); + await tester.pump(); + + final List resources = + await onPermissionRequestCompleter.future; + expect(listEquals(resources, expectedValue), true); + + controller.reload(); + + final List canceledResources = + await onPermissionRequestCancelCompleter.future; + expect(listEquals(canceledResources, expectedValue), true); + }, skip: shouldSkip2); } diff --git a/example/integration_test/service_worker_controller/main.dart b/example/integration_test/service_worker_controller/main.dart index 9b0a7204..192b4954 100644 --- a/example/integration_test/service_worker_controller/main.dart +++ b/example/integration_test/service_worker_controller/main.dart @@ -5,7 +5,11 @@ import 'set_service_worker_client.dart'; import 'should_intercept_request.dart'; void main() { - final shouldSkip = kIsWeb; + final shouldSkip = kIsWeb + ? true + : ![ + TargetPlatform.android, + ].contains(defaultTargetPlatform); group('Service Worker Controller', () { shouldInterceptRequest(); diff --git a/example/integration_test/tracing_controller/main.dart b/example/integration_test/tracing_controller/main.dart new file mode 100644 index 00000000..86347e94 --- /dev/null +++ b/example/integration_test/tracing_controller/main.dart @@ -0,0 +1,16 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'start_and_stop.dart'; + +void main() { + final shouldSkip = kIsWeb + ? true + : ![ + TargetPlatform.android, + ].contains(defaultTargetPlatform); + + group('Tracing Controller', () { + startAndStop(); + }, skip: shouldSkip); +} diff --git a/example/integration_test/tracing_controller/start_and_stop.dart b/example/integration_test/tracing_controller/start_and_stop.dart new file mode 100644 index 00000000..04292ae1 --- /dev/null +++ b/example/integration_test/tracing_controller/start_and_stop.dart @@ -0,0 +1,63 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path_provider/path_provider.dart'; + +import '../constants.dart'; + +void startAndStop() { + final shouldSkip = kIsWeb + ? true + : ![ + TargetPlatform.android, + ].contains(defaultTargetPlatform); + + testWidgets('start and stop', (WidgetTester tester) async { + final Completer pageLoaded = Completer(); + + final tracingAvailable = await WebViewFeature.isFeatureSupported( + WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE); + + if (!tracingAvailable) { + return; + } + + final tracingController = TracingController.instance(); + expect(await tracingController.isTracing(), false); + await tracingController.start( + settings: TracingSettings( + tracingMode: TracingMode.RECORD_CONTINUOUSLY, + categories: [ + TracingCategory.CATEGORIES_ANDROID_WEBVIEW, + "blink*" + ])); + expect(await tracingController.isTracing(), true); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: InAppWebView( + key: GlobalKey(), + initialUrlRequest: URLRequest(url: TEST_CROSS_PLATFORM_URL_1), + onLoadStop: (controller, url) { + if (!pageLoaded.isCompleted) { + pageLoaded.complete(); + } + }, + ), + ), + ); + + await pageLoaded.future; + + Directory appDocDir = await getApplicationDocumentsDirectory(); + String traceFilePath = '${appDocDir.path}${Platform.pathSeparator}trace.json'; + expect( + await tracingController.stop(filePath: traceFilePath), true); + expect(await tracingController.isTracing(), false); + }, skip: shouldSkip); +} diff --git a/example/integration_test/webview_flutter_test.dart b/example/integration_test/webview_flutter_test.dart index fb7828d5..fb3386f3 100644 --- a/example/integration_test/webview_flutter_test.dart +++ b/example/integration_test/webview_flutter_test.dart @@ -12,6 +12,7 @@ import 'cookie_manager/main.dart' as cookie_manager_tests; import 'in_app_browser/main.dart' as in_app_browser_tests; import 'chrome_safari_browser/main.dart' as chrome_safari_browser_tests; import 'in_app_localhost_server/main.dart' as in_app_localhost_server_tests; +import 'tracing_controller/main.dart' as tracing_controller_tests; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); @@ -37,6 +38,7 @@ void main() { find_interaction_controller_tests.main(); service_worker_controller_tests.main(); proxy_controller_tests.main(); + tracing_controller_tests.main(); headless_in_app_webview_tests.main(); cookie_manager_tests.main(); in_app_browser_tests.main(); diff --git a/example/ios/Flutter/flutter_export_environment.sh b/example/ios/Flutter/flutter_export_environment.sh index f90e8505..70b11672 100755 --- a/example/ios/Flutter/flutter_export_environment.sh +++ b/example/ios/Flutter/flutter_export_environment.sh @@ -1,13 +1,14 @@ #!/bin/sh # This is a generated file; do not edit or check into version control. -export "FLUTTER_ROOT=/Users/lorenzopichilli/fvm/versions/3.3.5" +export "FLUTTER_ROOT=/Users/lorenzopichilli/fvm/versions/3.3.6" export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example" export "COCOAPODS_PARALLEL_CODE_SIGN=true" -export "FLUTTER_TARGET=lib/main.dart" +export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart" export "FLUTTER_BUILD_DIR=build" export "FLUTTER_BUILD_NAME=1.0.0" export "FLUTTER_BUILD_NUMBER=1" +export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==" export "DART_OBFUSCATION=false" export "TRACK_WIDGET_CREATION=true" export "TREE_SHAKE_ICONS=false" -export "PACKAGE_CONFIG=.dart_tool/package_config.json" +export "PACKAGE_CONFIG=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/.dart_tool/package_config.json" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index a49055bd..1a3687bd 100755 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -13,7 +13,7 @@ publish_to: none environment: sdk: ">=2.14.0 <3.0.0" - flutter: ">=2.5.0" + flutter: ">=3.0.0" dependencies: flutter: diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift index f1bccad3..1506aab5 100755 --- a/ios/Classes/InAppWebView/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -291,6 +291,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, scrollView.addGestureRecognizer(self.panGestureRecognizer) scrollView.addObserver(self, forKeyPath: #keyPath(UIScrollView.contentOffset), options: [.new, .old], context: nil) scrollView.addObserver(self, forKeyPath: #keyPath(UIScrollView.zoomScale), options: [.new, .old], context: nil) + scrollView.addObserver(self, forKeyPath: #keyPath(UIScrollView.contentSize), options: [.new, .old], context: nil) addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), @@ -664,6 +665,14 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, self.onScrollChanged(startedByUser: startedByUser, oldContentOffset: oldContentOffset) } } + } else if keyPath == #keyPath(UIScrollView.contentSize) { + if let newContentSize = change?[.newKey] as? CGSize, + let oldContentSize = change?[.oldKey] as? CGSize, + newContentSize != oldContentSize { + DispatchQueue.main.async { + self.onContentSizeChanged(oldContentSize: oldContentSize) + } + } } else if #available(iOS 15.0, *) { if keyPath == #keyPath(WKWebView.cameraCaptureState) || keyPath == #keyPath(WKWebView.microphoneCaptureState) { @@ -2376,6 +2385,11 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, } } + public func onContentSizeChanged(oldContentSize: CGSize) { + channelDelegate?.onContentSizeChanged(oldContentSize: oldContentSize, + newContentSize: scrollView.contentSize) + } + public func scrollViewDidZoom(_ scrollView: UIScrollView) { let newScale = Float(scrollView.zoomScale) if newScale != oldZoomScale { @@ -3111,6 +3125,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { // } scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.contentOffset)) scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.zoomScale)) + scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.contentSize)) resumeTimers() stopLoading() disposeWebMessageChannels() diff --git a/ios/Classes/InAppWebView/WebViewChannelDelegate.swift b/ios/Classes/InAppWebView/WebViewChannelDelegate.swift index a56a1988..960dd50f 100644 --- a/ios/Classes/InAppWebView/WebViewChannelDelegate.swift +++ b/ios/Classes/InAppWebView/WebViewChannelDelegate.swift @@ -695,6 +695,14 @@ public class WebViewChannelDelegate : ChannelDelegate { channel?.invokeMethod("onScrollChanged", arguments: arguments) } + public func onContentSizeChanged(oldContentSize: CGSize, newContentSize: CGSize) { + let arguments: [String: Any?] = [ + "oldContentSize": oldContentSize.toMap(), + "newContentSize": newContentSize.toMap() + ] + channel?.invokeMethod("onContentSizeChanged", arguments: arguments) + } + public func onDownloadStartRequest(request: DownloadStartRequest) { channel?.invokeMethod("onDownloadStartRequest", arguments: request.toMap()) } diff --git a/ios/Classes/Types/CGSize.swift b/ios/Classes/Types/CGSize.swift new file mode 100644 index 00000000..730861e7 --- /dev/null +++ b/ios/Classes/Types/CGSize.swift @@ -0,0 +1,21 @@ +// +// CGSize.swift +// flutter_inappwebview +// +// Created by Lorenzo Pichilli on 28/10/22. +// + +import Foundation + +extension CGSize { + public static func fromMap(map: [String: Double]) -> CGSize { + return CGSize(width: map["width"]!, height: map["height"]!) + } + + public func toMap () -> [String:Any?] { + return [ + "width": width, + "height": height + ] + } +} diff --git a/lib/src/android/main.dart b/lib/src/android/main.dart index e9142dd6..b9471411 100644 --- a/lib/src/android/main.dart +++ b/lib/src/android/main.dart @@ -8,3 +8,4 @@ export 'webview_asset_loader.dart' AssetsPathHandler, ResourcesPathHandler, InternalStoragePathHandler; +export 'tracing_controller.dart' show TracingController, TracingSettings; diff --git a/lib/src/android/tracing_controller.dart b/lib/src/android/tracing_controller.dart new file mode 100644 index 00000000..893cd8c4 --- /dev/null +++ b/lib/src/android/tracing_controller.dart @@ -0,0 +1,154 @@ +import 'dart:async'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import '../types/tracing_mode.dart'; +import 'webview_feature.dart'; +import '../in_app_webview/webview.dart'; +import '../types/main.dart'; + +part 'tracing_controller.g.dart'; + +///Manages tracing of [WebView]s. +///In particular provides functionality for the app to enable/disable tracing of parts of code and to collect tracing data. +///This is useful for profiling performance issues, debugging and memory usage analysis in production and real life scenarios. +/// +///The resulting trace data is sent back as a byte sequence in json format. +///This file can be loaded in "chrome://tracing" for further analysis. +/// +///**Supported Platforms/Implementations**: +///- Android native WebView ([Official API - TracingController](https://developer.android.com/reference/androidx/webkit/TracingController)) +class TracingController { + static TracingController? _instance; + static const MethodChannel _channel = const MethodChannel( + 'com.pichillilorenzo/flutter_inappwebview_tracingcontroller'); + + TracingController._(); + + ///Gets the [TracingController] shared instance. + /// + ///This method should only be called if [WebViewFeature.isFeatureSupported] returns `true` + ///for [WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE]. + static TracingController instance() { + return (_instance != null) ? _instance! : _init(); + } + + static TracingController _init() { + _channel.setMethodCallHandler((call) async { + try { + return await _handleMethod(call); + } on Error catch (e) { + print(e); + print(e.stackTrace); + } + }); + _instance = TracingController._(); + return _instance!; + } + + static Future _handleMethod(MethodCall call) async { + // TracingController controller = TracingController.instance(); + switch (call.method) { + default: + throw UnimplementedError("Unimplemented ${call.method} method"); + } + // return null; + } + + ///Starts tracing all [WebView]s. + ///Depending on the trace mode in trace config specifies how the trace events are recorded. + ///For tracing modes [TracingMode.RECORD_UNTIL_FULL] and [TracingMode.RECORD_CONTINUOUSLY] + ///the events are recorded using an internal buffer and flushed to the outputStream + ///when [stop] is called. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - TracingController.start](https://developer.android.com/reference/android/webkit/TracingController#start(android.webkit.TracingConfig))) + Future start({required TracingSettings settings}) async { + Map args = {}; + args.putIfAbsent("settings", () => settings.toMap()); + await _channel.invokeMethod('start', args); + } + + ///Stops tracing and flushes tracing data to the specified output stream. + ///The data is sent to the specified output stream in json format typically in + ///chunks. + /// + ///Returns `false` if the WebView framework was not tracing at the time of the call, + ///`true` otherwise. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - TracingController.stop](https://developer.android.com/reference/android/webkit/TracingController#stop(java.io.OutputStream,%20java.util.concurrent.Executor))) + Future stop({String? filePath}) async { + Map args = {}; + args.putIfAbsent("filePath", () => filePath); + return await _channel.invokeMethod('stop', args); + } + + ///Returns whether the WebView framework is tracing. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - TracingController.isTracing](https://developer.android.com/reference/android/webkit/TracingController#isTracing())) + Future isTracing() async { + Map args = {}; + return await _channel.invokeMethod('isTracing', args); + } +} + +List _deserializeCategories(List categories) { + List deserializedCategories = []; + for (dynamic category in categories) { + if (category is String) { + deserializedCategories.add(category); + } else if (category is int) { + final mode = TracingCategory.fromNativeValue(category); + if (mode != null) { + deserializedCategories.add(mode); + } + } + } + return deserializedCategories; +} + +List _serializeCategories(List categories) { + List serializedCategories = []; + for (dynamic category in categories) { + if (category is String) { + serializedCategories.add(category); + } else if (category is TracingCategory) { + serializedCategories.add(category.toNativeValue()); + } + } + return serializedCategories; +} + +///Class that represents the settings used to configure the [TracingController]. +/// +///**Supported Platforms/Implementations**: +///- Android native WebView ([Official API - TracingConfig](https://developer.android.com/reference/androidx/webkit/TracingConfig)) +@ExchangeableObject(copyMethod: true) +class TracingSettings_ { + ///Adds predefined [TracingCategory] and/or custom [String] sets of categories to be included in the trace output. + /// + ///Note that the categories are defined by the currently-in-use version of WebView. + ///They live in chromium code and are not part of the Android API. + ///See [chromium documentation on tracing](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool) + ///for more details. + /// + ///A category pattern can contain wildcards, e.g. `"blink*"` or full category name e.g. `"renderer.scheduler"`. + @ExchangeableObjectProperty( + deserializer: _deserializeCategories, serializer: _serializeCategories) + List categories; + + ///The tracing mode for this configuration. + ///When tracingMode is not set explicitly, the default is [TracingMode.RECORD_CONTINUOUSLY]. + TracingMode_? tracingMode; + + @ExchangeableObjectConstructor() + TracingSettings_({this.categories = const [], this.tracingMode}) { + assert( + this + .categories + .map((e) => e.runtimeType is String || e.runtimeType is TracingCategory) + .contains(false), + "categories must contain only String or TracingCategory items"); + } +} diff --git a/lib/src/android/tracing_controller.g.dart b/lib/src/android/tracing_controller.g.dart new file mode 100644 index 00000000..f9695db8 --- /dev/null +++ b/lib/src/android/tracing_controller.g.dart @@ -0,0 +1,71 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'tracing_controller.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represents the settings used to configure the [TracingController]. +/// +///**Supported Platforms/Implementations**: +///- Android native WebView ([Official API - TracingConfig](https://developer.android.com/reference/androidx/webkit/TracingConfig)) +class TracingSettings { + ///Adds predefined [TracingCategory] and/or custom [String] sets of categories to be included in the trace output. + /// + ///Note that the categories are defined by the currently-in-use version of WebView. + ///They live in chromium code and are not part of the Android API. + ///See [chromium documentation on tracing](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool) + ///for more details. + /// + ///A category pattern can contain wildcards, e.g. `"blink*"` or full category name e.g. `"renderer.scheduler"`. + List categories; + + ///The tracing mode for this configuration. + ///When tracingMode is not set explicitly, the default is [TracingMode.RECORD_CONTINUOUSLY]. + TracingMode? tracingMode; + TracingSettings({this.categories = const [], this.tracingMode}) { + assert( + this + .categories + .map((e) => + e.runtimeType is String || e.runtimeType is TracingCategory) + .contains(false), + "categories must contain only String or TracingCategory items"); + } + + ///Gets a possible [TracingSettings] instance from a [Map] value. + static TracingSettings? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = TracingSettings( + tracingMode: TracingMode.fromNativeValue(map['tracingMode']), + ); + instance.categories = _deserializeCategories(map['categories']); + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "categories": _serializeCategories(categories), + "tracingMode": tracingMode?.toNativeValue(), + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + ///Returns a copy of TracingSettings. + TracingSettings copy() { + return TracingSettings.fromMap(toMap()) ?? TracingSettings(); + } + + @override + String toString() { + return 'TracingSettings{categories: $categories, tracingMode: $tracingMode}'; + } +} diff --git a/lib/src/in_app_browser/in_app_browser.dart b/lib/src/in_app_browser/in_app_browser.dart index 4081a04b..47c69080 100755 --- a/lib/src/in_app_browser/in_app_browser.dart +++ b/lib/src/in_app_browser/in_app_browser.dart @@ -969,9 +969,8 @@ class InAppBrowser { ///Event fired when the WebView is requesting permission to access the specified resources and the permission currently isn't granted or denied. /// - ///[origin] represents the origin of the web page which is trying to access the restricted resources. - /// - ///[resources] represents the array of resources the web content wants to access. + ///[permissionRequest] represents the permission request with an array of resources the web content wants to access + ///and the origin of the web page which is trying to access the restricted resources. /// ///**NOTE for Android**: available only on Android 23+. /// @@ -1197,6 +1196,25 @@ class InAppBrowser { ///- Android native WebView ([Official API - WebViewClient.onReceivedLoginRequest](https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedLoginRequest(android.webkit.WebView,%20java.lang.String,%20java.lang.String,%20java.lang.String))) void onReceivedLoginRequest(LoginRequest loginRequest) {} + ///Notify the host application that the given permission request has been canceled. Any related UI should therefore be hidden. + /// + ///[permissionRequest] represents the permission request that needs be canceled + ///with an array of resources the web content wants to access + ///and the origin of the web page which is trying to access the restricted resources. + /// + ///**NOTE for Android**: available only on Android 21+. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebChromeClient.onPermissionRequestCanceled](https://developer.android.com/reference/android/webkit/WebChromeClient#onPermissionRequestCanceled(android.webkit.PermissionRequest))) + void onPermissionRequestCanceled(PermissionRequest permissionRequest) {} + + ///Request display and focus for this WebView. + ///This may happen due to another WebView opening a link in this WebView and requesting that this WebView be displayed. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebChromeClient.onRequestFocus](https://developer.android.com/reference/android/webkit/WebChromeClient#onRequestFocus(android.webkit.WebView))) + void onRequestFocus() {} + ///Use [onWebContentProcessDidTerminate] instead. @Deprecated('Use onWebContentProcessDidTerminate instead') void iosOnWebContentProcessDidTerminate() {} @@ -1277,6 +1295,7 @@ class InAppBrowser { MediaCaptureState? newState, ) {} + ///Event fired when a change in the microphone capture state occurred. ///Event fired when a change in the microphone capture state occurred. /// ///**NOTE for iOS**: available only on iOS 15.0+. @@ -1291,6 +1310,16 @@ class InAppBrowser { MediaCaptureState? newState, ) {} + ///Event fired when the content size of the [WebView] changes. + /// + ///[oldContentSize] represents the old content size value. + /// + ///[newContentSize] represents the new content size value. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + void onContentSizeChanged(Size oldContentSize, Size newContentSize) {} + void throwIfAlreadyOpened({String message = ''}) { if (this.isOpened()) { throw InAppBrowserAlreadyOpenedException([ diff --git a/lib/src/in_app_webview/headless_in_app_webview.dart b/lib/src/in_app_webview/headless_in_app_webview.dart index 0943066f..625a170a 100644 --- a/lib/src/in_app_webview/headless_in_app_webview.dart +++ b/lib/src/in_app_webview/headless_in_app_webview.dart @@ -52,113 +52,124 @@ class HeadlessInAppWebView implements WebView, Disposable { ///**NOTE for Android**: `Size` width and height values will be converted to `int` values because they cannot have `double` values. final Size initialSize; - HeadlessInAppWebView({ - this.initialSize = const Size(-1, -1), - this.windowId, - this.initialUrlRequest, - this.initialFile, - this.initialData, - @Deprecated('Use initialSettings instead') this.initialOptions, - this.initialSettings, - this.contextMenu, - this.initialUserScripts, - this.pullToRefreshController, - this.findInteractionController, - this.implementation = WebViewImplementation.NATIVE, - this.onWebViewCreated, - this.onLoadStart, - this.onLoadStop, - @Deprecated("Use onReceivedError instead") this.onLoadError, - this.onReceivedError, - @Deprecated("Use onReceivedHttpError instead") this.onLoadHttpError, - this.onReceivedHttpError, - this.onProgressChanged, - this.onConsoleMessage, - this.shouldOverrideUrlLoading, - this.onLoadResource, - this.onScrollChanged, - @Deprecated('Use onDownloadStartRequest instead') this.onDownloadStart, - this.onDownloadStartRequest, - @Deprecated('Use onLoadResourceWithCustomScheme instead') - this.onLoadResourceCustomScheme, - this.onLoadResourceWithCustomScheme, - this.onCreateWindow, - this.onCloseWindow, - this.onJsAlert, - this.onJsConfirm, - this.onJsPrompt, - this.onReceivedHttpAuthRequest, - this.onReceivedServerTrustAuthRequest, - this.onReceivedClientCertRequest, - @Deprecated('Use FindInteractionController.onFindResultReceived instead') - this.onFindResultReceived, - this.shouldInterceptAjaxRequest, - this.onAjaxReadyStateChange, - this.onAjaxProgress, - this.shouldInterceptFetchRequest, - this.onUpdateVisitedHistory, - @Deprecated("Use onPrintRequest instead") this.onPrint, - this.onPrintRequest, - this.onLongPressHitTestResult, - this.onEnterFullscreen, - this.onExitFullscreen, - this.onPageCommitVisible, - this.onTitleChanged, - this.onWindowFocus, - this.onWindowBlur, - this.onOverScrolled, - @Deprecated('Use onSafeBrowsingHit instead') this.androidOnSafeBrowsingHit, - this.onSafeBrowsingHit, - @Deprecated('Use onPermissionRequest instead') - this.androidOnPermissionRequest, - this.onPermissionRequest, - @Deprecated('Use onGeolocationPermissionsShowPrompt instead') - this.androidOnGeolocationPermissionsShowPrompt, - this.onGeolocationPermissionsShowPrompt, - @Deprecated('Use onGeolocationPermissionsHidePrompt instead') - this.androidOnGeolocationPermissionsHidePrompt, - this.onGeolocationPermissionsHidePrompt, - @Deprecated('Use shouldInterceptRequest instead') - this.androidShouldInterceptRequest, - this.shouldInterceptRequest, - @Deprecated('Use onRenderProcessGone instead') - this.androidOnRenderProcessGone, - this.onRenderProcessGone, - @Deprecated('Use onRenderProcessResponsive instead') - this.androidOnRenderProcessResponsive, - this.onRenderProcessResponsive, - @Deprecated('Use onRenderProcessUnresponsive instead') - this.androidOnRenderProcessUnresponsive, - this.onRenderProcessUnresponsive, - @Deprecated('Use onFormResubmission instead') - this.androidOnFormResubmission, - this.onFormResubmission, - @Deprecated('Use onZoomScaleChanged instead') this.androidOnScaleChanged, - @Deprecated('Use onReceivedIcon instead') this.androidOnReceivedIcon, - this.onReceivedIcon, - @Deprecated('Use onReceivedTouchIconUrl instead') - this.androidOnReceivedTouchIconUrl, - this.onReceivedTouchIconUrl, - @Deprecated('Use onJsBeforeUnload instead') this.androidOnJsBeforeUnload, - this.onJsBeforeUnload, - @Deprecated('Use onReceivedLoginRequest instead') - this.androidOnReceivedLoginRequest, - this.onReceivedLoginRequest, - @Deprecated('Use onWebContentProcessDidTerminate instead') - this.iosOnWebContentProcessDidTerminate, - this.onWebContentProcessDidTerminate, - @Deprecated('Use onDidReceiveServerRedirectForProvisionalNavigation instead') - this.iosOnDidReceiveServerRedirectForProvisionalNavigation, - this.onDidReceiveServerRedirectForProvisionalNavigation, - @Deprecated('Use onNavigationResponse instead') - this.iosOnNavigationResponse, - this.onNavigationResponse, - @Deprecated('Use shouldAllowDeprecatedTLS instead') - this.iosShouldAllowDeprecatedTLS, - this.shouldAllowDeprecatedTLS, - this.onCameraCaptureStateChanged, - this.onMicrophoneCaptureStateChanged, - }) { + HeadlessInAppWebView( + {this.initialSize = const Size(-1, -1), + this.windowId, + this.initialUrlRequest, + this.initialFile, + this.initialData, + @Deprecated('Use initialSettings instead') + this.initialOptions, + this.initialSettings, + this.contextMenu, + this.initialUserScripts, + this.pullToRefreshController, + this.findInteractionController, + this.implementation = WebViewImplementation.NATIVE, + this.onWebViewCreated, + this.onLoadStart, + this.onLoadStop, + @Deprecated("Use onReceivedError instead") + this.onLoadError, + this.onReceivedError, + @Deprecated("Use onReceivedHttpError instead") + this.onLoadHttpError, + this.onReceivedHttpError, + this.onProgressChanged, + this.onConsoleMessage, + this.shouldOverrideUrlLoading, + this.onLoadResource, + this.onScrollChanged, + @Deprecated('Use onDownloadStartRequest instead') + this.onDownloadStart, + this.onDownloadStartRequest, + @Deprecated('Use onLoadResourceWithCustomScheme instead') + this.onLoadResourceCustomScheme, + this.onLoadResourceWithCustomScheme, + this.onCreateWindow, + this.onCloseWindow, + this.onJsAlert, + this.onJsConfirm, + this.onJsPrompt, + this.onReceivedHttpAuthRequest, + this.onReceivedServerTrustAuthRequest, + this.onReceivedClientCertRequest, + @Deprecated('Use FindInteractionController.onFindResultReceived instead') + this.onFindResultReceived, + this.shouldInterceptAjaxRequest, + this.onAjaxReadyStateChange, + this.onAjaxProgress, + this.shouldInterceptFetchRequest, + this.onUpdateVisitedHistory, + @Deprecated("Use onPrintRequest instead") + this.onPrint, + this.onPrintRequest, + this.onLongPressHitTestResult, + this.onEnterFullscreen, + this.onExitFullscreen, + this.onPageCommitVisible, + this.onTitleChanged, + this.onWindowFocus, + this.onWindowBlur, + this.onOverScrolled, + @Deprecated('Use onSafeBrowsingHit instead') + this.androidOnSafeBrowsingHit, + this.onSafeBrowsingHit, + @Deprecated('Use onPermissionRequest instead') + this.androidOnPermissionRequest, + this.onPermissionRequest, + @Deprecated('Use onGeolocationPermissionsShowPrompt instead') + this.androidOnGeolocationPermissionsShowPrompt, + this.onGeolocationPermissionsShowPrompt, + @Deprecated('Use onGeolocationPermissionsHidePrompt instead') + this.androidOnGeolocationPermissionsHidePrompt, + this.onGeolocationPermissionsHidePrompt, + @Deprecated('Use shouldInterceptRequest instead') + this.androidShouldInterceptRequest, + this.shouldInterceptRequest, + @Deprecated('Use onRenderProcessGone instead') + this.androidOnRenderProcessGone, + this.onRenderProcessGone, + @Deprecated('Use onRenderProcessResponsive instead') + this.androidOnRenderProcessResponsive, + this.onRenderProcessResponsive, + @Deprecated('Use onRenderProcessUnresponsive instead') + this.androidOnRenderProcessUnresponsive, + this.onRenderProcessUnresponsive, + @Deprecated('Use onFormResubmission instead') + this.androidOnFormResubmission, + this.onFormResubmission, + @Deprecated('Use onZoomScaleChanged instead') + this.androidOnScaleChanged, + @Deprecated('Use onReceivedIcon instead') + this.androidOnReceivedIcon, + this.onReceivedIcon, + @Deprecated('Use onReceivedTouchIconUrl instead') + this.androidOnReceivedTouchIconUrl, + this.onReceivedTouchIconUrl, + @Deprecated('Use onJsBeforeUnload instead') + this.androidOnJsBeforeUnload, + this.onJsBeforeUnload, + @Deprecated('Use onReceivedLoginRequest instead') + this.androidOnReceivedLoginRequest, + this.onReceivedLoginRequest, + this.onPermissionRequestCanceled, + this.onRequestFocus, + @Deprecated('Use onWebContentProcessDidTerminate instead') + this.iosOnWebContentProcessDidTerminate, + this.onWebContentProcessDidTerminate, + @Deprecated('Use onDidReceiveServerRedirectForProvisionalNavigation instead') + this.iosOnDidReceiveServerRedirectForProvisionalNavigation, + this.onDidReceiveServerRedirectForProvisionalNavigation, + @Deprecated('Use onNavigationResponse instead') + this.iosOnNavigationResponse, + this.onNavigationResponse, + @Deprecated('Use shouldAllowDeprecatedTLS instead') + this.iosShouldAllowDeprecatedTLS, + this.shouldAllowDeprecatedTLS, + this.onCameraCaptureStateChanged, + this.onMicrophoneCaptureStateChanged, + this.onContentSizeChanged}) { id = IdGenerator.generate(); webViewController = new InAppWebViewController(id, this); this._channel = @@ -668,6 +679,14 @@ class HeadlessInAppWebView implements WebView, Disposable { void Function(InAppWebViewController controller, LoginRequest loginRequest)? onReceivedLoginRequest; + @override + final void Function(InAppWebViewController controller, + PermissionRequest permissionRequest)? onPermissionRequestCanceled; + + @override + final void Function(InAppWebViewController controller)? + onRequestFocus; + @override void Function( InAppWebViewController controller, WebUri url, bool precomposed)? @@ -719,6 +738,10 @@ class HeadlessInAppWebView implements WebView, Disposable { MediaCaptureState? oldState, MediaCaptureState? newState, )? onMicrophoneCaptureStateChanged; + + @override + final void Function(InAppWebViewController controller, Size oldContentSize, + Size newContentSize)? onContentSizeChanged; } extension InternalHeadlessInAppWebView on HeadlessInAppWebView { diff --git a/lib/src/in_app_webview/in_app_webview.dart b/lib/src/in_app_webview/in_app_webview.dart index ab3d88fe..3c18c693 100755 --- a/lib/src/in_app_webview/in_app_webview.dart +++ b/lib/src/in_app_webview/in_app_webview.dart @@ -149,6 +149,8 @@ class InAppWebView extends StatefulWidget implements WebView { @Deprecated('Use onReceivedLoginRequest instead') this.androidOnReceivedLoginRequest, this.onReceivedLoginRequest, + this.onPermissionRequestCanceled, + this.onRequestFocus, @Deprecated('Use onWebContentProcessDidTerminate instead') this.iosOnWebContentProcessDidTerminate, this.onWebContentProcessDidTerminate, @@ -163,6 +165,7 @@ class InAppWebView extends StatefulWidget implements WebView { this.shouldAllowDeprecatedTLS, this.onCameraCaptureStateChanged, this.onMicrophoneCaptureStateChanged, + this.onContentSizeChanged, this.gestureRecognizers, this.headlessWebView, }) : super(key: key); @@ -550,6 +553,14 @@ class InAppWebView extends StatefulWidget implements WebView { InAppWebViewController controller, LoginRequest loginRequest)? onReceivedLoginRequest; + @override + final void Function(InAppWebViewController controller, + PermissionRequest permissionRequest)? onPermissionRequestCanceled; + + @override + final void Function(InAppWebViewController controller)? + onRequestFocus; + @override final void Function( InAppWebViewController controller, WebUri url, bool precomposed)? @@ -603,6 +614,10 @@ class InAppWebView extends StatefulWidget implements WebView { MediaCaptureState? oldState, MediaCaptureState? newState, )? onMicrophoneCaptureStateChanged; + + @override + final void Function(InAppWebViewController controller, Size oldContentSize, + Size newContentSize)? onContentSizeChanged; } class _InAppWebViewState extends State { diff --git a/lib/src/in_app_webview/in_app_webview_controller.dart b/lib/src/in_app_webview/in_app_webview_controller.dart index 00ba72be..d935365a 100644 --- a/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/lib/src/in_app_webview/in_app_webview_controller.dart @@ -735,6 +735,30 @@ class InAppWebViewController { } } break; + case "onPermissionRequestCanceled": + if ((_webview != null && + _webview!.onPermissionRequestCanceled != null) || + _inAppBrowser != null) { + Map arguments = + call.arguments.cast(); + PermissionRequest permissionRequest = + PermissionRequest.fromMap(arguments)!; + + if (_webview != null && _webview!.onPermissionRequestCanceled != null) + _webview!.onPermissionRequestCanceled!(this, permissionRequest); + else + _inAppBrowser!.onPermissionRequestCanceled(permissionRequest); + } + break; + case "onRequestFocus": + if ((_webview != null && _webview!.onRequestFocus != null) || + _inAppBrowser != null) { + if (_webview != null && _webview!.onRequestFocus != null) + _webview!.onRequestFocus!(this); + else + _inAppBrowser!.onRequestFocus(); + } + break; case "onReceivedHttpAuthRequest": if ((_webview != null && _webview!.onReceivedHttpAuthRequest != null) || _inAppBrowser != null) { @@ -1188,6 +1212,21 @@ class InAppWebViewController { _inAppBrowser!.onMicrophoneCaptureStateChanged(oldState, newState); } break; + case "onContentSizeChanged": + if ((_webview != null && _webview!.onContentSizeChanged != null) || + _inAppBrowser != null) { + var oldContentSize = MapSize.fromMap( + call.arguments["oldContentSize"]?.cast())!; + var newContentSize = MapSize.fromMap( + call.arguments["newContentSize"]?.cast())!; + + if (_webview != null && _webview!.onContentSizeChanged != null) + _webview!.onContentSizeChanged!( + this, oldContentSize, newContentSize); + else + _inAppBrowser!.onContentSizeChanged(oldContentSize, newContentSize); + } + break; case "onCallJsHandler": String handlerName = call.arguments["handlerName"]; // decode args to json @@ -3697,6 +3736,23 @@ class InAppWebViewController { return await _staticChannel.invokeMethod('getVariationsHeader', args); } + ///Returns `true` if WebView is running in multi process mode. + /// + ///In Android O and above, WebView may run in "multiprocess" mode. + ///In multiprocess mode, rendering of web content is performed by a sandboxed + ///renderer process separate to the application process. + ///This renderer process may be shared with other WebViews in the application, + ///but is not shared with other application processes. + /// + ///**NOTE for Android native WebView**: This method should only be called if [WebViewFeature.isFeatureSupported] returns `true` for [WebViewFeature.MULTI_PROCESS]. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebViewCompat.isMultiProcessEnabled](https://developer.android.com/reference/androidx/webkit/WebViewCompat#isMultiProcessEnabled())) + static Future isMultiProcessEnabled() async { + Map args = {}; + return await _staticChannel.invokeMethod('isMultiProcessEnabled', args); + } + ///Returns a Boolean value that indicates whether WebKit natively supports resources with the specified URL scheme. /// ///[urlScheme] represents the URL scheme associated with the resource. diff --git a/lib/src/in_app_webview/in_app_webview_settings.dart b/lib/src/in_app_webview/in_app_webview_settings.dart index b6f665fd..f2719551 100755 --- a/lib/src/in_app_webview/in_app_webview_settings.dart +++ b/lib/src/in_app_webview/in_app_webview_settings.dart @@ -700,8 +700,8 @@ class InAppWebViewSettings_ { ///- Android native WebView RendererPriorityPolicy_? rendererPriorityPolicy; - ///Sets whether the default Android error page should be disabled. - ///The default value is `false`. + ///Sets whether the default Android WebView’s internal error page should be suppressed or displayed for bad navigations. + ///`true` means suppressed (not shown), `false` means it will be displayed. The default value is `false`. /// ///**Supported Platforms/Implementations**: ///- Android native WebView @@ -739,15 +739,6 @@ class InAppWebViewSettings_ { ///- Android native WebView Color? horizontalScrollbarTrackColor; - ///Sets whether the WebView’s internal error page should be suppressed or displayed for bad navigations. - ///`true` means suppressed (not shown), `false` means it will be displayed. The default value is `false`. - /// - ///**NOTE**: available on Android only if [WebViewFeature.SUPPRESS_ERROR_PAGE] feature is supported. - /// - ///**Supported Platforms/Implementations**: - ///- Android native WebView - bool? willSuppressErrorPage; - ///Control whether algorithmic darkening is allowed. /// ///WebView always sets the media query `prefers-color-scheme` according to the app's theme attribute `isLightTheme`, @@ -794,6 +785,15 @@ class InAppWebViewSettings_ { ///- Android native WebView bool? enterpriseAuthenticationAppLinkPolicyEnabled; + ///When not playing, video elements are represented by a 'poster' image. + ///The image to use can be specified by the poster attribute of the video tag in HTML. + ///If the attribute is absent, then a default poster will be used. + ///This property allows the WebView to provide that default image. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + Uint8List? defaultVideoPoster; + ///Set to `true` to disable the bouncing of the WebView when the scrolling has reached an edge of the content. The default value is `false`. /// ///**Supported Platforms/Implementations**: @@ -1358,10 +1358,10 @@ class InAppWebViewSettings_ { this.verticalScrollbarTrackColor, this.horizontalScrollbarThumbColor, this.horizontalScrollbarTrackColor, - this.willSuppressErrorPage = false, this.algorithmicDarkeningAllowed = false, this.requestedWithHeaderMode, this.enterpriseAuthenticationAppLinkPolicyEnabled = true, + this.defaultVideoPoster, this.disallowOverScroll = false, this.enableViewportScale = false, this.suppressesIncrementalRendering = false, diff --git a/lib/src/in_app_webview/in_app_webview_settings.g.dart b/lib/src/in_app_webview/in_app_webview_settings.g.dart index 3945a36b..39821929 100644 --- a/lib/src/in_app_webview/in_app_webview_settings.g.dart +++ b/lib/src/in_app_webview/in_app_webview_settings.g.dart @@ -656,8 +656,8 @@ class InAppWebViewSettings { ///- Android native WebView RendererPriorityPolicy? rendererPriorityPolicy; - ///Sets whether the default Android error page should be disabled. - ///The default value is `false`. + ///Sets whether the default Android WebView’s internal error page should be suppressed or displayed for bad navigations. + ///`true` means suppressed (not shown), `false` means it will be displayed. The default value is `false`. /// ///**Supported Platforms/Implementations**: ///- Android native WebView @@ -695,15 +695,6 @@ class InAppWebViewSettings { ///- Android native WebView Color? horizontalScrollbarTrackColor; - ///Sets whether the WebView’s internal error page should be suppressed or displayed for bad navigations. - ///`true` means suppressed (not shown), `false` means it will be displayed. The default value is `false`. - /// - ///**NOTE**: available on Android only if [WebViewFeature.SUPPRESS_ERROR_PAGE] feature is supported. - /// - ///**Supported Platforms/Implementations**: - ///- Android native WebView - bool? willSuppressErrorPage; - ///Control whether algorithmic darkening is allowed. /// ///WebView always sets the media query `prefers-color-scheme` according to the app's theme attribute `isLightTheme`, @@ -750,6 +741,15 @@ class InAppWebViewSettings { ///- Android native WebView bool? enterpriseAuthenticationAppLinkPolicyEnabled; + ///When not playing, video elements are represented by a 'poster' image. + ///The image to use can be specified by the poster attribute of the video tag in HTML. + ///If the attribute is absent, then a default poster will be used. + ///This property allows the WebView to provide that default image. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + Uint8List? defaultVideoPoster; + ///Set to `true` to disable the bouncing of the WebView when the scrolling has reached an edge of the content. The default value is `false`. /// ///**Supported Platforms/Implementations**: @@ -1312,10 +1312,10 @@ class InAppWebViewSettings { this.verticalScrollbarTrackColor, this.horizontalScrollbarThumbColor, this.horizontalScrollbarTrackColor, - this.willSuppressErrorPage = false, this.algorithmicDarkeningAllowed = false, this.requestedWithHeaderMode, this.enterpriseAuthenticationAppLinkPolicyEnabled = true, + this.defaultVideoPoster, this.disallowOverScroll = false, this.enableViewportScale = false, this.suppressesIncrementalRendering = false, @@ -1428,6 +1428,7 @@ class InAppWebViewSettings { : null, requestedWithHeaderMode: RequestedWithHeaderMode.fromNativeValue( map['requestedWithHeaderMode']), + defaultVideoPoster: map['defaultVideoPoster'], mediaType: map['mediaType'], allowingReadAccessTo: map['allowingReadAccessTo'] != null ? WebUri(map['allowingReadAccessTo']) @@ -1532,7 +1533,6 @@ class InAppWebViewSettings { map['verticalScrollbarPosition']); instance.scrollbarFadingEnabled = map['scrollbarFadingEnabled']; instance.disableDefaultErrorPage = map['disableDefaultErrorPage']; - instance.willSuppressErrorPage = map['willSuppressErrorPage']; instance.algorithmicDarkeningAllowed = map['algorithmicDarkeningAllowed']; instance.enterpriseAuthenticationAppLinkPolicyEnabled = map['enterpriseAuthenticationAppLinkPolicyEnabled']; @@ -1680,11 +1680,11 @@ class InAppWebViewSettings { "verticalScrollbarTrackColor": verticalScrollbarTrackColor?.toHex(), "horizontalScrollbarThumbColor": horizontalScrollbarThumbColor?.toHex(), "horizontalScrollbarTrackColor": horizontalScrollbarTrackColor?.toHex(), - "willSuppressErrorPage": willSuppressErrorPage, "algorithmicDarkeningAllowed": algorithmicDarkeningAllowed, "requestedWithHeaderMode": requestedWithHeaderMode?.toNativeValue(), "enterpriseAuthenticationAppLinkPolicyEnabled": enterpriseAuthenticationAppLinkPolicyEnabled, + "defaultVideoPoster": defaultVideoPoster, "disallowOverScroll": disallowOverScroll, "enableViewportScale": enableViewportScale, "suppressesIncrementalRendering": suppressesIncrementalRendering, @@ -1751,6 +1751,6 @@ class InAppWebViewSettings { @override String toString() { - return 'InAppWebViewSettings{useShouldOverrideUrlLoading: $useShouldOverrideUrlLoading, useOnLoadResource: $useOnLoadResource, useOnDownloadStart: $useOnDownloadStart, clearCache: $clearCache, userAgent: $userAgent, applicationNameForUserAgent: $applicationNameForUserAgent, javaScriptEnabled: $javaScriptEnabled, javaScriptCanOpenWindowsAutomatically: $javaScriptCanOpenWindowsAutomatically, mediaPlaybackRequiresUserGesture: $mediaPlaybackRequiresUserGesture, minimumFontSize: $minimumFontSize, verticalScrollBarEnabled: $verticalScrollBarEnabled, horizontalScrollBarEnabled: $horizontalScrollBarEnabled, resourceCustomSchemes: $resourceCustomSchemes, contentBlockers: $contentBlockers, preferredContentMode: $preferredContentMode, useShouldInterceptAjaxRequest: $useShouldInterceptAjaxRequest, useShouldInterceptFetchRequest: $useShouldInterceptFetchRequest, incognito: $incognito, cacheEnabled: $cacheEnabled, transparentBackground: $transparentBackground, disableVerticalScroll: $disableVerticalScroll, disableHorizontalScroll: $disableHorizontalScroll, disableContextMenu: $disableContextMenu, supportZoom: $supportZoom, allowFileAccessFromFileURLs: $allowFileAccessFromFileURLs, allowUniversalAccessFromFileURLs: $allowUniversalAccessFromFileURLs, allowBackgroundAudioPlaying: $allowBackgroundAudioPlaying, webViewAssetLoader: $webViewAssetLoader, textZoom: $textZoom, clearSessionCache: $clearSessionCache, builtInZoomControls: $builtInZoomControls, displayZoomControls: $displayZoomControls, databaseEnabled: $databaseEnabled, domStorageEnabled: $domStorageEnabled, useWideViewPort: $useWideViewPort, safeBrowsingEnabled: $safeBrowsingEnabled, mixedContentMode: $mixedContentMode, allowContentAccess: $allowContentAccess, allowFileAccess: $allowFileAccess, appCachePath: $appCachePath, blockNetworkImage: $blockNetworkImage, blockNetworkLoads: $blockNetworkLoads, cacheMode: $cacheMode, cursiveFontFamily: $cursiveFontFamily, defaultFixedFontSize: $defaultFixedFontSize, defaultFontSize: $defaultFontSize, defaultTextEncodingName: $defaultTextEncodingName, disabledActionModeMenuItems: $disabledActionModeMenuItems, fantasyFontFamily: $fantasyFontFamily, fixedFontFamily: $fixedFontFamily, forceDark: $forceDark, forceDarkStrategy: $forceDarkStrategy, geolocationEnabled: $geolocationEnabled, layoutAlgorithm: $layoutAlgorithm, loadWithOverviewMode: $loadWithOverviewMode, loadsImagesAutomatically: $loadsImagesAutomatically, minimumLogicalFontSize: $minimumLogicalFontSize, initialScale: $initialScale, needInitialFocus: $needInitialFocus, offscreenPreRaster: $offscreenPreRaster, sansSerifFontFamily: $sansSerifFontFamily, serifFontFamily: $serifFontFamily, standardFontFamily: $standardFontFamily, saveFormData: $saveFormData, thirdPartyCookiesEnabled: $thirdPartyCookiesEnabled, hardwareAcceleration: $hardwareAcceleration, supportMultipleWindows: $supportMultipleWindows, regexToCancelSubFramesLoading: $regexToCancelSubFramesLoading, useHybridComposition: $useHybridComposition, useShouldInterceptRequest: $useShouldInterceptRequest, useOnRenderProcessGone: $useOnRenderProcessGone, overScrollMode: $overScrollMode, networkAvailable: $networkAvailable, scrollBarStyle: $scrollBarStyle, verticalScrollbarPosition: $verticalScrollbarPosition, scrollBarDefaultDelayBeforeFade: $scrollBarDefaultDelayBeforeFade, scrollbarFadingEnabled: $scrollbarFadingEnabled, scrollBarFadeDuration: $scrollBarFadeDuration, rendererPriorityPolicy: $rendererPriorityPolicy, disableDefaultErrorPage: $disableDefaultErrorPage, verticalScrollbarThumbColor: $verticalScrollbarThumbColor, verticalScrollbarTrackColor: $verticalScrollbarTrackColor, horizontalScrollbarThumbColor: $horizontalScrollbarThumbColor, horizontalScrollbarTrackColor: $horizontalScrollbarTrackColor, willSuppressErrorPage: $willSuppressErrorPage, algorithmicDarkeningAllowed: $algorithmicDarkeningAllowed, requestedWithHeaderMode: $requestedWithHeaderMode, enterpriseAuthenticationAppLinkPolicyEnabled: $enterpriseAuthenticationAppLinkPolicyEnabled, disallowOverScroll: $disallowOverScroll, enableViewportScale: $enableViewportScale, suppressesIncrementalRendering: $suppressesIncrementalRendering, allowsAirPlayForMediaPlayback: $allowsAirPlayForMediaPlayback, allowsBackForwardNavigationGestures: $allowsBackForwardNavigationGestures, allowsLinkPreview: $allowsLinkPreview, ignoresViewportScaleLimits: $ignoresViewportScaleLimits, allowsInlineMediaPlayback: $allowsInlineMediaPlayback, allowsPictureInPictureMediaPlayback: $allowsPictureInPictureMediaPlayback, isFraudulentWebsiteWarningEnabled: $isFraudulentWebsiteWarningEnabled, selectionGranularity: $selectionGranularity, dataDetectorTypes: $dataDetectorTypes, sharedCookiesEnabled: $sharedCookiesEnabled, automaticallyAdjustsScrollIndicatorInsets: $automaticallyAdjustsScrollIndicatorInsets, accessibilityIgnoresInvertColors: $accessibilityIgnoresInvertColors, decelerationRate: $decelerationRate, alwaysBounceVertical: $alwaysBounceVertical, alwaysBounceHorizontal: $alwaysBounceHorizontal, scrollsToTop: $scrollsToTop, isPagingEnabled: $isPagingEnabled, maximumZoomScale: $maximumZoomScale, minimumZoomScale: $minimumZoomScale, contentInsetAdjustmentBehavior: $contentInsetAdjustmentBehavior, isDirectionalLockEnabled: $isDirectionalLockEnabled, mediaType: $mediaType, pageZoom: $pageZoom, limitsNavigationsToAppBoundDomains: $limitsNavigationsToAppBoundDomains, useOnNavigationResponse: $useOnNavigationResponse, applePayAPIEnabled: $applePayAPIEnabled, allowingReadAccessTo: $allowingReadAccessTo, disableLongPressContextMenuOnLinks: $disableLongPressContextMenuOnLinks, disableInputAccessoryView: $disableInputAccessoryView, underPageBackgroundColor: $underPageBackgroundColor, isTextInteractionEnabled: $isTextInteractionEnabled, isSiteSpecificQuirksModeEnabled: $isSiteSpecificQuirksModeEnabled, upgradeKnownHostsToHTTPS: $upgradeKnownHostsToHTTPS, isElementFullscreenEnabled: $isElementFullscreenEnabled, isFindInteractionEnabled: $isFindInteractionEnabled, minimumViewportInset: $minimumViewportInset, maximumViewportInset: $maximumViewportInset, iframeAllow: $iframeAllow, iframeAllowFullscreen: $iframeAllowFullscreen, iframeSandbox: $iframeSandbox, iframeReferrerPolicy: $iframeReferrerPolicy, iframeName: $iframeName, iframeCsp: $iframeCsp}'; + return 'InAppWebViewSettings{useShouldOverrideUrlLoading: $useShouldOverrideUrlLoading, useOnLoadResource: $useOnLoadResource, useOnDownloadStart: $useOnDownloadStart, clearCache: $clearCache, userAgent: $userAgent, applicationNameForUserAgent: $applicationNameForUserAgent, javaScriptEnabled: $javaScriptEnabled, javaScriptCanOpenWindowsAutomatically: $javaScriptCanOpenWindowsAutomatically, mediaPlaybackRequiresUserGesture: $mediaPlaybackRequiresUserGesture, minimumFontSize: $minimumFontSize, verticalScrollBarEnabled: $verticalScrollBarEnabled, horizontalScrollBarEnabled: $horizontalScrollBarEnabled, resourceCustomSchemes: $resourceCustomSchemes, contentBlockers: $contentBlockers, preferredContentMode: $preferredContentMode, useShouldInterceptAjaxRequest: $useShouldInterceptAjaxRequest, useShouldInterceptFetchRequest: $useShouldInterceptFetchRequest, incognito: $incognito, cacheEnabled: $cacheEnabled, transparentBackground: $transparentBackground, disableVerticalScroll: $disableVerticalScroll, disableHorizontalScroll: $disableHorizontalScroll, disableContextMenu: $disableContextMenu, supportZoom: $supportZoom, allowFileAccessFromFileURLs: $allowFileAccessFromFileURLs, allowUniversalAccessFromFileURLs: $allowUniversalAccessFromFileURLs, allowBackgroundAudioPlaying: $allowBackgroundAudioPlaying, webViewAssetLoader: $webViewAssetLoader, textZoom: $textZoom, clearSessionCache: $clearSessionCache, builtInZoomControls: $builtInZoomControls, displayZoomControls: $displayZoomControls, databaseEnabled: $databaseEnabled, domStorageEnabled: $domStorageEnabled, useWideViewPort: $useWideViewPort, safeBrowsingEnabled: $safeBrowsingEnabled, mixedContentMode: $mixedContentMode, allowContentAccess: $allowContentAccess, allowFileAccess: $allowFileAccess, appCachePath: $appCachePath, blockNetworkImage: $blockNetworkImage, blockNetworkLoads: $blockNetworkLoads, cacheMode: $cacheMode, cursiveFontFamily: $cursiveFontFamily, defaultFixedFontSize: $defaultFixedFontSize, defaultFontSize: $defaultFontSize, defaultTextEncodingName: $defaultTextEncodingName, disabledActionModeMenuItems: $disabledActionModeMenuItems, fantasyFontFamily: $fantasyFontFamily, fixedFontFamily: $fixedFontFamily, forceDark: $forceDark, forceDarkStrategy: $forceDarkStrategy, geolocationEnabled: $geolocationEnabled, layoutAlgorithm: $layoutAlgorithm, loadWithOverviewMode: $loadWithOverviewMode, loadsImagesAutomatically: $loadsImagesAutomatically, minimumLogicalFontSize: $minimumLogicalFontSize, initialScale: $initialScale, needInitialFocus: $needInitialFocus, offscreenPreRaster: $offscreenPreRaster, sansSerifFontFamily: $sansSerifFontFamily, serifFontFamily: $serifFontFamily, standardFontFamily: $standardFontFamily, saveFormData: $saveFormData, thirdPartyCookiesEnabled: $thirdPartyCookiesEnabled, hardwareAcceleration: $hardwareAcceleration, supportMultipleWindows: $supportMultipleWindows, regexToCancelSubFramesLoading: $regexToCancelSubFramesLoading, useHybridComposition: $useHybridComposition, useShouldInterceptRequest: $useShouldInterceptRequest, useOnRenderProcessGone: $useOnRenderProcessGone, overScrollMode: $overScrollMode, networkAvailable: $networkAvailable, scrollBarStyle: $scrollBarStyle, verticalScrollbarPosition: $verticalScrollbarPosition, scrollBarDefaultDelayBeforeFade: $scrollBarDefaultDelayBeforeFade, scrollbarFadingEnabled: $scrollbarFadingEnabled, scrollBarFadeDuration: $scrollBarFadeDuration, rendererPriorityPolicy: $rendererPriorityPolicy, disableDefaultErrorPage: $disableDefaultErrorPage, verticalScrollbarThumbColor: $verticalScrollbarThumbColor, verticalScrollbarTrackColor: $verticalScrollbarTrackColor, horizontalScrollbarThumbColor: $horizontalScrollbarThumbColor, horizontalScrollbarTrackColor: $horizontalScrollbarTrackColor, algorithmicDarkeningAllowed: $algorithmicDarkeningAllowed, requestedWithHeaderMode: $requestedWithHeaderMode, enterpriseAuthenticationAppLinkPolicyEnabled: $enterpriseAuthenticationAppLinkPolicyEnabled, defaultVideoPoster: $defaultVideoPoster, disallowOverScroll: $disallowOverScroll, enableViewportScale: $enableViewportScale, suppressesIncrementalRendering: $suppressesIncrementalRendering, allowsAirPlayForMediaPlayback: $allowsAirPlayForMediaPlayback, allowsBackForwardNavigationGestures: $allowsBackForwardNavigationGestures, allowsLinkPreview: $allowsLinkPreview, ignoresViewportScaleLimits: $ignoresViewportScaleLimits, allowsInlineMediaPlayback: $allowsInlineMediaPlayback, allowsPictureInPictureMediaPlayback: $allowsPictureInPictureMediaPlayback, isFraudulentWebsiteWarningEnabled: $isFraudulentWebsiteWarningEnabled, selectionGranularity: $selectionGranularity, dataDetectorTypes: $dataDetectorTypes, sharedCookiesEnabled: $sharedCookiesEnabled, automaticallyAdjustsScrollIndicatorInsets: $automaticallyAdjustsScrollIndicatorInsets, accessibilityIgnoresInvertColors: $accessibilityIgnoresInvertColors, decelerationRate: $decelerationRate, alwaysBounceVertical: $alwaysBounceVertical, alwaysBounceHorizontal: $alwaysBounceHorizontal, scrollsToTop: $scrollsToTop, isPagingEnabled: $isPagingEnabled, maximumZoomScale: $maximumZoomScale, minimumZoomScale: $minimumZoomScale, contentInsetAdjustmentBehavior: $contentInsetAdjustmentBehavior, isDirectionalLockEnabled: $isDirectionalLockEnabled, mediaType: $mediaType, pageZoom: $pageZoom, limitsNavigationsToAppBoundDomains: $limitsNavigationsToAppBoundDomains, useOnNavigationResponse: $useOnNavigationResponse, applePayAPIEnabled: $applePayAPIEnabled, allowingReadAccessTo: $allowingReadAccessTo, disableLongPressContextMenuOnLinks: $disableLongPressContextMenuOnLinks, disableInputAccessoryView: $disableInputAccessoryView, underPageBackgroundColor: $underPageBackgroundColor, isTextInteractionEnabled: $isTextInteractionEnabled, isSiteSpecificQuirksModeEnabled: $isSiteSpecificQuirksModeEnabled, upgradeKnownHostsToHTTPS: $upgradeKnownHostsToHTTPS, isElementFullscreenEnabled: $isElementFullscreenEnabled, isFindInteractionEnabled: $isFindInteractionEnabled, minimumViewportInset: $minimumViewportInset, maximumViewportInset: $maximumViewportInset, iframeAllow: $iframeAllow, iframeAllowFullscreen: $iframeAllowFullscreen, iframeSandbox: $iframeSandbox, iframeReferrerPolicy: $iframeReferrerPolicy, iframeName: $iframeName, iframeCsp: $iframeCsp}'; } } diff --git a/lib/src/in_app_webview/webview.dart b/lib/src/in_app_webview/webview.dart index c969859e..41a5d4f3 100644 --- a/lib/src/in_app_webview/webview.dart +++ b/lib/src/in_app_webview/webview.dart @@ -1,5 +1,6 @@ import 'dart:collection'; import 'dart:typed_data'; +import 'dart:ui'; import '../find_interaction/find_interaction_controller.dart'; import '../pull_to_refresh/pull_to_refresh_controller.dart'; @@ -612,9 +613,8 @@ abstract class WebView { ///Event fired when the WebView is requesting permission to access the specified resources and the permission currently isn't granted or denied. /// - ///[origin] represents the origin of the web page which is trying to access the restricted resources. - /// - ///[resources] represents the array of resources the web content wants to access. + ///[permissionRequest] represents the permission request with an array of resources the web content wants to access + ///and the origin of the web page which is trying to access the restricted resources. /// ///**NOTE for Android**: available only on Android 23+. /// @@ -845,6 +845,27 @@ abstract class WebView { InAppWebViewController controller, LoginRequest loginRequest)? onReceivedLoginRequest; + ///Notify the host application that the given permission request has been canceled. Any related UI should therefore be hidden. + /// + ///[permissionRequest] represents the permission request that needs be canceled + ///with an array of resources the web content wants to access + ///and the origin of the web page which is trying to access the restricted resources. + /// + ///**NOTE for Android**: available only on Android 21+. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebChromeClient.onPermissionRequestCanceled](https://developer.android.com/reference/android/webkit/WebChromeClient#onPermissionRequestCanceled(android.webkit.PermissionRequest))) + final void Function(InAppWebViewController controller, + PermissionRequest permissionRequest)? onPermissionRequestCanceled; + + ///Request display and focus for this WebView. + ///This may happen due to another WebView opening a link in this WebView and requesting that this WebView be displayed. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebChromeClient.onRequestFocus](https://developer.android.com/reference/android/webkit/WebChromeClient#onRequestFocus(android.webkit.WebView))) + final void Function(InAppWebViewController controller)? + onRequestFocus; + ///Use [onWebContentProcessDidTerminate] instead. @Deprecated('Use onWebContentProcessDidTerminate instead') final void Function(InAppWebViewController controller)? @@ -941,6 +962,17 @@ abstract class WebView { MediaCaptureState? newState, )? onMicrophoneCaptureStateChanged; + ///Event fired when the content size of the [WebView] changes. + /// + ///[oldContentSize] represents the old content size value. + /// + ///[newContentSize] represents the new content size value. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + final void Function(InAppWebViewController controller, Size oldContentSize, + Size newContentSize)? onContentSizeChanged; + ///Initial url request that will be loaded. /// ///**NOTE for Android**: when loading an URL Request using "POST" method, headers are ignored. @@ -1115,6 +1147,8 @@ abstract class WebView { @Deprecated('Use onReceivedLoginRequest instead') this.androidOnReceivedLoginRequest, this.onReceivedLoginRequest, + this.onPermissionRequestCanceled, + this.onRequestFocus, @Deprecated('Use onWebContentProcessDidTerminate instead') this.iosOnWebContentProcessDidTerminate, this.onWebContentProcessDidTerminate, @@ -1129,6 +1163,7 @@ abstract class WebView { this.shouldAllowDeprecatedTLS, this.onCameraCaptureStateChanged, this.onMicrophoneCaptureStateChanged, + this.onContentSizeChanged, this.initialUrlRequest, this.initialFile, this.initialData, diff --git a/lib/src/types/main.dart b/lib/src/types/main.dart index 6b8343f0..4cad6ba2 100644 --- a/lib/src/types/main.dart +++ b/lib/src/types/main.dart @@ -223,3 +223,5 @@ export 'android_resource.dart' show AndroidResource; export 'ui_image.dart' show UIImage; export 'activity_button.dart' show ActivityButton; export 'ui_event_attribution.dart' show UIEventAttribution; +export 'tracing_mode.dart' show TracingMode; +export 'tracing_category.dart' show TracingCategory; \ No newline at end of file diff --git a/lib/src/types/tracing_category.dart b/lib/src/types/tracing_category.dart new file mode 100644 index 00000000..00cac6ce --- /dev/null +++ b/lib/src/types/tracing_category.dart @@ -0,0 +1,43 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'tracing_category.g.dart'; + +///Constants that describe the results summary the find panel UI includes. +@ExchangeableEnum() +class TracingCategory_ { + // ignore: unused_field + final int _value; + const TracingCategory_._internal(this._value); + + ///Predefined set of categories, includes all categories enabled by default in chromium. + ///Use with caution: this setting may produce large trace output. + static const CATEGORIES_ALL = const TracingCategory_._internal(1); + + ///Predefined set of categories typically useful for analyzing WebViews. + ///Typically includes "android_webview" and "Java" categories. + static const CATEGORIES_ANDROID_WEBVIEW = const TracingCategory_._internal(2); + + ///Predefined set of categories for studying difficult rendering performance problems. + ///Typically includes "blink", "compositor", "gpu", "renderer.scheduler", "v8" + ///and some other compositor categories which are disabled by default. + static const CATEGORIES_FRAME_VIEWER = const TracingCategory_._internal(64); + + ///Predefined set of categories for analyzing input latency issues. + ///Typically includes "input", "renderer.scheduler" categories. + static const CATEGORIES_INPUT_LATENCY = const TracingCategory_._internal(8); + + ///Predefined set of categories for analyzing javascript and rendering issues. + ///Typically includes "blink", "compositor", "gpu", "renderer.scheduler" and "v8" categories. + static const CATEGORIES_JAVASCRIPT_AND_RENDERING = const TracingCategory_._internal(32); + + ///Indicates that there are no predefined categories. + static const CATEGORIES_NONE = const TracingCategory_._internal(0); + + ///Predefined set of categories for analyzing rendering issues. + ///Typically includes "blink", "compositor" and "gpu" categories. + static const CATEGORIES_RENDERING = const TracingCategory_._internal(16); + + ///Predefined set of categories typically useful for web developers. + ///Typically includes "blink", "compositor", "renderer.scheduler" and "v8" categories. + static const CATEGORIES_WEB_DEVELOPER = const TracingCategory_._internal(4); +} diff --git a/lib/src/types/tracing_category.g.dart b/lib/src/types/tracing_category.g.dart new file mode 100644 index 00000000..3487a184 --- /dev/null +++ b/lib/src/types/tracing_category.g.dart @@ -0,0 +1,124 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'tracing_category.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///Constants that describe the results summary the find panel UI includes. +class TracingCategory { + final int _value; + final int _nativeValue; + const TracingCategory._internal(this._value, this._nativeValue); +// ignore: unused_element + factory TracingCategory._internalMultiPlatform( + int value, Function nativeValue) => + TracingCategory._internal(value, nativeValue()); + + ///Predefined set of categories, includes all categories enabled by default in chromium. + ///Use with caution: this setting may produce large trace output. + static const CATEGORIES_ALL = TracingCategory._internal(1, 1); + + ///Predefined set of categories typically useful for analyzing WebViews. + ///Typically includes "android_webview" and "Java" categories. + static const CATEGORIES_ANDROID_WEBVIEW = TracingCategory._internal(2, 2); + + ///Predefined set of categories for studying difficult rendering performance problems. + ///Typically includes "blink", "compositor", "gpu", "renderer.scheduler", "v8" + ///and some other compositor categories which are disabled by default. + static const CATEGORIES_FRAME_VIEWER = TracingCategory._internal(64, 64); + + ///Predefined set of categories for analyzing input latency issues. + ///Typically includes "input", "renderer.scheduler" categories. + static const CATEGORIES_INPUT_LATENCY = TracingCategory._internal(8, 8); + + ///Predefined set of categories for analyzing javascript and rendering issues. + ///Typically includes "blink", "compositor", "gpu", "renderer.scheduler" and "v8" categories. + static const CATEGORIES_JAVASCRIPT_AND_RENDERING = + TracingCategory._internal(32, 32); + + ///Indicates that there are no predefined categories. + static const CATEGORIES_NONE = TracingCategory._internal(0, 0); + + ///Predefined set of categories for analyzing rendering issues. + ///Typically includes "blink", "compositor" and "gpu" categories. + static const CATEGORIES_RENDERING = TracingCategory._internal(16, 16); + + ///Predefined set of categories typically useful for web developers. + ///Typically includes "blink", "compositor", "renderer.scheduler" and "v8" categories. + static const CATEGORIES_WEB_DEVELOPER = TracingCategory._internal(4, 4); + + ///Set of all values of [TracingCategory]. + static final Set values = [ + TracingCategory.CATEGORIES_ALL, + TracingCategory.CATEGORIES_ANDROID_WEBVIEW, + TracingCategory.CATEGORIES_FRAME_VIEWER, + TracingCategory.CATEGORIES_INPUT_LATENCY, + TracingCategory.CATEGORIES_JAVASCRIPT_AND_RENDERING, + TracingCategory.CATEGORIES_NONE, + TracingCategory.CATEGORIES_RENDERING, + TracingCategory.CATEGORIES_WEB_DEVELOPER, + ].toSet(); + + ///Gets a possible [TracingCategory] instance from [int] value. + static TracingCategory? fromValue(int? value) { + if (value != null) { + try { + return TracingCategory.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets a possible [TracingCategory] instance from a native value. + static TracingCategory? fromNativeValue(int? value) { + if (value != null) { + try { + return TracingCategory.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets [int] value. + int toValue() => _value; + + ///Gets [int] native value. + int toNativeValue() => _nativeValue; + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + @override + String toString() { + switch (_value) { + case 1: + return 'CATEGORIES_ALL'; + case 2: + return 'CATEGORIES_ANDROID_WEBVIEW'; + case 64: + return 'CATEGORIES_FRAME_VIEWER'; + case 8: + return 'CATEGORIES_INPUT_LATENCY'; + case 32: + return 'CATEGORIES_JAVASCRIPT_AND_RENDERING'; + case 0: + return 'CATEGORIES_NONE'; + case 16: + return 'CATEGORIES_RENDERING'; + case 4: + return 'CATEGORIES_WEB_DEVELOPER'; + } + return _value.toString(); + } +} diff --git a/lib/src/types/tracing_mode.dart b/lib/src/types/tracing_mode.dart new file mode 100644 index 00000000..f29e01a3 --- /dev/null +++ b/lib/src/types/tracing_mode.dart @@ -0,0 +1,23 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'tracing_mode.g.dart'; + +///Constants that describe the results summary the find panel UI includes. +@ExchangeableEnum() +class TracingMode_ { + // ignore: unused_field + final int _value; + const TracingMode_._internal(this._value); + + ///Record trace events until the internal tracing buffer is full. + ///Typically the buffer memory usage is larger than [RECORD_CONTINUOUSLY]. + ///Depending on the implementation typically allows up to 256k events to be stored. + static const RECORD_UNTIL_FULL = const TracingMode_._internal(0); + + ///Record trace events continuously using an internal ring buffer. + ///Default tracing mode. + ///Overwrites old events if they exceed buffer capacity. + ///Uses less memory than the [RECORD_UNTIL_FULL] mode. + ///Depending on the implementation typically allows up to 64k events to be stored. + static const RECORD_CONTINUOUSLY = const TracingMode_._internal(1); +} diff --git a/lib/src/types/tracing_mode.g.dart b/lib/src/types/tracing_mode.g.dart new file mode 100644 index 00000000..a6fcb504 --- /dev/null +++ b/lib/src/types/tracing_mode.g.dart @@ -0,0 +1,84 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'tracing_mode.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///Constants that describe the results summary the find panel UI includes. +class TracingMode { + final int _value; + final int _nativeValue; + const TracingMode._internal(this._value, this._nativeValue); +// ignore: unused_element + factory TracingMode._internalMultiPlatform(int value, Function nativeValue) => + TracingMode._internal(value, nativeValue()); + + ///Record trace events until the internal tracing buffer is full. + ///Typically the buffer memory usage is larger than [RECORD_CONTINUOUSLY]. + ///Depending on the implementation typically allows up to 256k events to be stored. + static const RECORD_UNTIL_FULL = TracingMode._internal(0, 0); + + ///Record trace events continuously using an internal ring buffer. + ///Default tracing mode. + ///Overwrites old events if they exceed buffer capacity. + ///Uses less memory than the [RECORD_UNTIL_FULL] mode. + ///Depending on the implementation typically allows up to 64k events to be stored. + static const RECORD_CONTINUOUSLY = TracingMode._internal(1, 1); + + ///Set of all values of [TracingMode]. + static final Set values = [ + TracingMode.RECORD_UNTIL_FULL, + TracingMode.RECORD_CONTINUOUSLY, + ].toSet(); + + ///Gets a possible [TracingMode] instance from [int] value. + static TracingMode? fromValue(int? value) { + if (value != null) { + try { + return TracingMode.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets a possible [TracingMode] instance from a native value. + static TracingMode? fromNativeValue(int? value) { + if (value != null) { + try { + return TracingMode.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets [int] value. + int toValue() => _value; + + ///Gets [int] native value. + int toNativeValue() => _nativeValue; + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + @override + String toString() { + switch (_value) { + case 0: + return 'RECORD_UNTIL_FULL'; + case 1: + return 'RECORD_CONTINUOUSLY'; + } + return _value.toString(); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 31bcbd45..5678ea76 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. -version: 6.0.0-beta.11 +version: 6.0.0-beta.12 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues