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