Removed willSuppressErrorPage WebView Android setting in favor of disableDefaultErrorPage, Added isMultiProcessEnabled static method on InAppWebViewController for Android, Added onContentSizeChanged WebView event for iOS, Added onPermissionRequestCanceled and onRequestFocus WebView events for Android, Added defaultVideoPoster WebView setting for Android, Added TracingController for Android WebViews
This commit is contained in:
parent
9ad20bd13a
commit
06668703c4
15
CHANGELOG.md
15
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
|
||||
|
|
|
@ -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<Uri> filePathCallbackLegacy;
|
||||
@Nullable
|
||||
public static ValueCallback<Uri[]> 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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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<String, Object> settingsMap = (Map<String, Object>) 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<TracingController> {
|
||||
|
||||
public static final String LOG_TAG = "TracingSettings";
|
||||
|
||||
@NonNull
|
||||
public List<Object> categories = new ArrayList<>();
|
||||
@Nullable
|
||||
public Integer tracingMode;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TracingSettings parse(@NonNull Map<String, Object> settings) {
|
||||
for (Map.Entry<String, Object> pair : settings.entrySet()) {
|
||||
String key = pair.getKey();
|
||||
Object value = pair.getValue();
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case "categories":
|
||||
categories = (List<Object>) value;
|
||||
break;
|
||||
case "tracingMode":
|
||||
tracingMode = (Integer) value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> settings = new HashMap<>();
|
||||
settings.put("categories", categories);
|
||||
settings.put("tracingMode", tracingMode);
|
||||
return settings;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Map<String, Object> getRealSettings(@NonNull TracingController tracingController) {
|
||||
Map<String, Object> realSettings = toMap();
|
||||
return realSettings;
|
||||
}
|
||||
}
|
|
@ -952,6 +952,15 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
|||
channel.invokeMethod("onPermissionRequest", obj, callback);
|
||||
}
|
||||
|
||||
public void onPermissionRequestCanceled(String origin, List<String> resources) {
|
||||
MethodChannel channel = getChannel();
|
||||
if (channel == null) return;
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("origin", origin);
|
||||
obj.put("resources", resources);
|
||||
channel.invokeMethod("onPermissionRequestCanceled", obj);
|
||||
}
|
||||
|
||||
public static class ShouldOverrideUrlLoadingCallback extends BaseCallbackResultImpl<NavigationActionPolicy> {
|
||||
@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<String, Object> obj = new HashMap<>();
|
||||
channel.invokeMethod("onRequestFocus", obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
|
|
@ -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) &&
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -114,13 +114,14 @@ public class InAppWebViewSettings implements ISettings<InAppWebViewInterface> {
|
|||
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<String, Object> webViewAssetLoader;
|
||||
@Nullable
|
||||
public byte[] defaultVideoPoster;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
|
@ -379,9 +380,6 @@ public class InAppWebViewSettings implements ISettings<InAppWebViewInterface> {
|
|||
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<InAppWebViewInterface> {
|
|||
case "webViewAssetLoader":
|
||||
webViewAssetLoader = (Map<String, Object>) value;
|
||||
break;
|
||||
case "defaultVideoPoster":
|
||||
defaultVideoPoster = (byte[]) value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,11 +490,11 @@ public class InAppWebViewSettings implements ISettings<InAppWebViewInterface> {
|
|||
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<InAppWebViewInterface> {
|
|||
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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<void> onContentSizeChangedCompleter =
|
||||
Completer<void>();
|
||||
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);
|
||||
}
|
|
@ -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<InAppWebViewController> 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<InAppWebViewController> controllerCompleter =
|
||||
Completer<InAppWebViewController>();
|
||||
final Completer<void> pageLoaded = Completer<void>();
|
||||
final Completer<List<PermissionResourceType>> onPermissionRequestCompleter =
|
||||
Completer<List<PermissionResourceType>>();
|
||||
final Completer<List<PermissionResourceType>>
|
||||
onPermissionRequestCancelCompleter =
|
||||
Completer<List<PermissionResourceType>>();
|
||||
|
||||
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<PermissionResourceType> resources =
|
||||
await onPermissionRequestCompleter.future;
|
||||
expect(listEquals(resources, expectedValue), true);
|
||||
|
||||
controller.reload();
|
||||
|
||||
final List<PermissionResourceType> canceledResources =
|
||||
await onPermissionRequestCancelCompleter.future;
|
||||
expect(listEquals(canceledResources, expectedValue), true);
|
||||
}, skip: shouldSkip2);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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<void> pageLoaded = Completer<void>();
|
||||
|
||||
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);
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
]
|
||||
}
|
||||
}
|
|
@ -8,3 +8,4 @@ export 'webview_asset_loader.dart'
|
|||
AssetsPathHandler,
|
||||
ResourcesPathHandler,
|
||||
InternalStoragePathHandler;
|
||||
export 'tracing_controller.dart' show TracingController, TracingSettings;
|
||||
|
|
|
@ -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<dynamic> _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<void> start({required TracingSettings settings}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
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<bool> stop({String? filePath}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
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<bool> isTracing() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('isTracing', args);
|
||||
}
|
||||
}
|
||||
|
||||
List<dynamic> _deserializeCategories(List<dynamic> categories) {
|
||||
List<dynamic> 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<dynamic> _serializeCategories(List<dynamic> categories) {
|
||||
List<dynamic> 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<dynamic> 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");
|
||||
}
|
||||
}
|
|
@ -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<dynamic> 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<String, dynamic>? 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<String, dynamic> toMap() {
|
||||
return {
|
||||
"categories": _serializeCategories(categories),
|
||||
"tracingMode": tracingMode?.toNativeValue(),
|
||||
};
|
||||
}
|
||||
|
||||
///Converts instance to a map.
|
||||
Map<String, dynamic> toJson() {
|
||||
return toMap();
|
||||
}
|
||||
|
||||
///Returns a copy of TracingSettings.
|
||||
TracingSettings copy() {
|
||||
return TracingSettings.fromMap(toMap()) ?? TracingSettings();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TracingSettings{categories: $categories, tracingMode: $tracingMode}';
|
||||
}
|
||||
}
|
|
@ -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([
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<InAppWebView> {
|
||||
|
|
|
@ -735,6 +735,30 @@ class InAppWebViewController {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case "onPermissionRequestCanceled":
|
||||
if ((_webview != null &&
|
||||
_webview!.onPermissionRequestCanceled != null) ||
|
||||
_inAppBrowser != null) {
|
||||
Map<String, dynamic> arguments =
|
||||
call.arguments.cast<String, dynamic>();
|
||||
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<String, dynamic>())!;
|
||||
var newContentSize = MapSize.fromMap(
|
||||
call.arguments["newContentSize"]?.cast<String, dynamic>())!;
|
||||
|
||||
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<bool> isMultiProcessEnabled() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
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.
|
||||
|
|
|
@ -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,
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -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,
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
|
@ -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<TracingCategory> 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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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<TracingMode> 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();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue