blob: 7fdcf4b2871f0e9f717f6bd42fea9073af49b1d7 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#104231)
// ignore: unnecessary_import
import 'dart:typed_data';
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart' show AndroidViewSurface;
import 'android_webview.pigeon.dart';
import 'android_webview_api_impls.dart';
/// An Android View that displays web pages.
///
/// **Basic usage**
/// In most cases, we recommend using a standard web browser, like Chrome, to
/// deliver content to the user. To learn more about web browsers, read the
/// guide on invoking a browser with
/// [url_launcher](https://pub.dev/packages/url_launcher).
///
/// WebView objects allow you to display web content as part of your widget
/// layout, but lack some of the features of fully-developed browsers. A WebView
/// is useful when you need increased control over the UI and advanced
/// configuration options that will allow you to embed web pages in a
/// specially-designed environment for your app.
///
/// To learn more about WebView and alternatives for serving web content, read
/// the documentation on
/// [Web-based content](https://developer.android.com/guide/webapps).
///
/// When a [WebView] is no longer needed [release] must be called.
class WebView {
/// Constructs a new WebView.
WebView({this.useHybridComposition = false}) {
api.createFromInstance(this);
}
/// Pigeon Host Api implementation for [WebView].
@visibleForTesting
static WebViewHostApiImpl api = WebViewHostApiImpl();
WebViewClient? _currentWebViewClient;
/// Whether the [WebView] will be rendered with an [AndroidViewSurface].
///
/// This implementation uses hybrid composition to render the WebView Widget.
/// This comes at the cost of some performance on Android versions below 10.
/// See
/// https://flutter.dev/docs/development/platform-integration/platform-views#performance
/// for more information.
///
/// Defaults to false.
final bool useHybridComposition;
/// The [WebSettings] object used to control the settings for this WebView.
late final WebSettings settings = WebSettings(this);
/// Enables debugging of web contents (HTML / CSS / JavaScript) loaded into any WebViews of this application.
///
/// This flag can be enabled in order to facilitate debugging of web layouts
/// and JavaScript code running inside WebViews. Please refer to [WebView]
/// documentation for the debugging guide. The default is false.
static Future<void> setWebContentsDebuggingEnabled(bool enabled) {
return api.setWebContentsDebuggingEnabled(enabled);
}
/// Loads the given data into this WebView using a 'data' scheme URL.
///
/// Note that JavaScript's same origin policy means that script running in a
/// page loaded using this method will be unable to access content loaded
/// using any scheme other than 'data', including 'http(s)'. To avoid this
/// restriction, use [loadDataWithBaseURL()] with an appropriate base URL.
///
/// The [encoding] parameter specifies whether the data is base64 or URL
/// encoded. If the data is base64 encoded, the value of the encoding
/// parameter must be `'base64'`. HTML can be encoded with
/// `base64.encode(bytes)` like so:
/// ```dart
/// import 'dart:convert';
///
/// final unencodedHtml = '''
/// <html><body>'%28' is the code for '('</body></html>
/// ''';
/// final encodedHtml = base64.encode(utf8.encode(unencodedHtml));
/// print(encodedHtml);
/// ```
///
/// The [mimeType] parameter specifies the format of the data. If WebView
/// can't handle the specified MIME type, it will download the data. If
/// `null`, defaults to 'text/html'.
Future<void> loadData({
required String data,
String? mimeType,
String? encoding,
}) {
return api.loadDataFromInstance(
this,
data,
mimeType,
encoding,
);
}
/// Loads the given data into this WebView.
///
/// The [baseUrl] is used as base URL for the content. It is used both to
/// resolve relative URLs and when applying JavaScript's same origin policy.
///
/// The [historyUrl] is used for the history entry.
///
/// The [mimeType] parameter specifies the format of the data. If WebView
/// can't handle the specified MIME type, it will download the data. If
/// `null`, defaults to 'text/html'.
///
/// Note that content specified in this way can access local device files (via
/// 'file' scheme URLs) only if baseUrl specifies a scheme other than 'http',
/// 'https', 'ftp', 'ftps', 'about' or 'javascript'.
///
/// If the base URL uses the data scheme, this method is equivalent to calling
/// [loadData] and the [historyUrl] is ignored, and the data will be treated
/// as part of a data: URL, including the requirement that the content be
/// URL-encoded or base64 encoded. If the base URL uses any other scheme, then
/// the data will be loaded into the WebView as a plain string (i.e. not part
/// of a data URL) and any URL-encoded entities in the string will not be
/// decoded.
///
/// Note that the [baseUrl] is sent in the 'Referer' HTTP header when
/// requesting subresources (images, etc.) of the page loaded using this
/// method.
///
/// If a valid HTTP or HTTPS base URL is not specified in [baseUrl], then
/// content loaded using this method will have a `window.origin` value of
/// `"null"`. This must not be considered to be a trusted origin by the
/// application or by any JavaScript code running inside the WebView (for
/// example, event sources in DOM event handlers or web messages), because
/// malicious content can also create frames with a null origin. If you need
/// to identify the main frame's origin in a trustworthy way, you should use a
/// valid HTTP or HTTPS base URL to set the origin.
Future<void> loadDataWithBaseUrl({
String? baseUrl,
required String data,
String? mimeType,
String? encoding,
String? historyUrl,
}) {
return api.loadDataWithBaseUrlFromInstance(
this,
baseUrl,
data,
mimeType,
encoding,
historyUrl,
);
}
/// Loads the given URL with additional HTTP headers, specified as a map from name to value.
///
/// Note that if this map contains any of the headers that are set by default
/// by this WebView, such as those controlling caching, accept types or the
/// User-Agent, their values may be overridden by this WebView's defaults.
///
/// Also see compatibility note on [evaluateJavascript].
Future<void> loadUrl(String url, Map<String, String> headers) {
return api.loadUrlFromInstance(this, url, headers);
}
/// Loads the URL with postData using "POST" method into this WebView.
///
/// If url is not a network URL, it will be loaded with [loadUrl] instead, ignoring the postData param.
Future<void> postUrl(String url, Uint8List data) {
return api.postUrlFromInstance(this, url, data);
}
/// Gets the URL for the current page.
///
/// This is not always the same as the URL passed to
/// [WebViewClient.onPageStarted] because although the load for that URL has
/// begun, the current page may not have changed.
///
/// Returns null if no page has been loaded.
Future<String?> getUrl() {
return api.getUrlFromInstance(this);
}
/// Whether this WebView has a back history item.
Future<bool> canGoBack() {
return api.canGoBackFromInstance(this);
}
/// Whether this WebView has a forward history item.
Future<bool> canGoForward() {
return api.canGoForwardFromInstance(this);
}
/// Goes back in the history of this WebView.
Future<void> goBack() {
return api.goBackFromInstance(this);
}
/// Goes forward in the history of this WebView.
Future<void> goForward() {
return api.goForwardFromInstance(this);
}
/// Reloads the current URL.
Future<void> reload() {
return api.reloadFromInstance(this);
}
/// Clears the resource cache.
///
/// Note that the cache is per-application, so this will clear the cache for
/// all WebViews used.
Future<void> clearCache(bool includeDiskFiles) {
return api.clearCacheFromInstance(this, includeDiskFiles);
}
// TODO(bparrishMines): Update documentation once addJavascriptInterface is added.
/// Asynchronously evaluates JavaScript in the context of the currently displayed page.
///
/// If non-null, the returned value will be any result returned from that
/// execution.
///
/// Compatibility note. Applications targeting Android versions N or later,
/// JavaScript state from an empty WebView is no longer persisted across
/// navigations like [loadUrl]. For example, global variables and functions
/// defined before calling [loadUrl]) will not exist in the loaded page.
Future<String?> evaluateJavascript(String javascriptString) {
return api.evaluateJavascriptFromInstance(
this,
javascriptString,
);
}
// TODO(bparrishMines): Update documentation when WebViewClient.onReceivedTitle is added.
/// Gets the title for the current page.
///
/// Returns null if no page has been loaded.
Future<String?> getTitle() {
return api.getTitleFromInstance(this);
}
// TODO(bparrishMines): Update documentation when onScrollChanged is added.
/// Set the scrolled position of your view.
Future<void> scrollTo(int x, int y) {
return api.scrollToFromInstance(this, x, y);
}
// TODO(bparrishMines): Update documentation when onScrollChanged is added.
/// Move the scrolled position of your view.
Future<void> scrollBy(int x, int y) {
return api.scrollByFromInstance(this, x, y);
}
/// Return the scrolled left position of this view.
///
/// This is the left edge of the displayed part of your view. You do not
/// need to draw any pixels farther left, since those are outside of the frame
/// of your view on screen.
Future<int> getScrollX() {
return api.getScrollXFromInstance(this);
}
/// Return the scrolled top position of this view.
///
/// This is the top edge of the displayed part of your view. You do not need
/// to draw any pixels above it, since those are outside of the frame of your
/// view on screen.
Future<int> getScrollY() {
return api.getScrollYFromInstance(this);
}
/// Sets the [WebViewClient] that will receive various notifications and requests.
///
/// This will replace the current handler.
Future<void> setWebViewClient(WebViewClient webViewClient) {
_currentWebViewClient = webViewClient;
WebViewClient.api.createFromInstance(webViewClient);
return api.setWebViewClientFromInstance(this, webViewClient);
}
/// Injects the supplied [JavascriptChannel] into this WebView.
///
/// The object is injected into all frames of the web page, including all the
/// iframes, using the supplied name. This allows the object's methods to
/// be accessed from JavaScript.
///
/// Note that injected objects will not appear in JavaScript until the page is
/// next (re)loaded. JavaScript should be enabled before injecting the object.
/// For example:
///
/// ```dart
/// webview.settings.setJavaScriptEnabled(true);
/// webView.addJavascriptChannel(JavScriptChannel("injectedObject"));
/// webView.loadUrl("about:blank", <String, String>{});
/// webView.loadUrl("javascript:injectedObject.postMessage("Hello, World!")", <String, String>{});
/// ```
///
/// **Important**
/// * Because the object is exposed to all the frames, any frame could obtain
/// the object name and call methods on it. There is no way to tell the
/// calling frame's origin from the app side, so the app must not assume that
/// the caller is trustworthy unless the app can guarantee that no third party
/// content is ever loaded into the WebView even inside an iframe.
Future<void> addJavaScriptChannel(JavaScriptChannel javaScriptChannel) {
JavaScriptChannel.api.createFromInstance(javaScriptChannel);
return api.addJavaScriptChannelFromInstance(this, javaScriptChannel);
}
/// Removes a previously injected [JavaScriptChannel] from this WebView.
///
/// Note that the removal will not be reflected in JavaScript until the page
/// is next (re)loaded. See [addJavaScriptChannel].
Future<void> removeJavaScriptChannel(JavaScriptChannel javaScriptChannel) {
JavaScriptChannel.api.createFromInstance(javaScriptChannel);
return api.removeJavaScriptChannelFromInstance(this, javaScriptChannel);
}
/// Registers the interface to be used when content can not be handled by the rendering engine, and should be downloaded instead.
///
/// This will replace the current handler.
Future<void> setDownloadListener(DownloadListener? listener) async {
await Future.wait(<Future<void>>[
if (listener != null) DownloadListener.api.createFromInstance(listener),
api.setDownloadListenerFromInstance(this, listener)
]);
}
/// Sets the chrome handler.
///
/// This is an implementation of [WebChromeClient] for use in handling
/// JavaScript dialogs, favicons, titles, and the progress. This will replace
/// the current handler.
Future<void> setWebChromeClient(WebChromeClient? client) async {
// WebView requires a WebViewClient because of a bug fix that makes
// calls to WebViewClient.requestLoading/WebViewClient.urlLoading when a new
// window is opened. This is to make sure a url opened by `Window.open` has
// a secure url.
assert(
_currentWebViewClient != null,
"Can't set a WebChromeClient without setting a WebViewClient first.",
);
await Future.wait(<Future<void>>[
if (client != null)
WebChromeClient.api.createFromInstance(client, _currentWebViewClient!),
api.setWebChromeClientFromInstance(this, client),
]);
}
/// Sets the background color of this WebView.
Future<void> setBackgroundColor(Color color) {
return api.setBackgroundColorFromInstance(this, color.value);
}
/// Releases all resources used by the [WebView].
///
/// Any methods called after [release] will throw an exception.
Future<void> release() {
_currentWebViewClient = null;
WebSettings.api.disposeFromInstance(settings);
return api.disposeFromInstance(this);
}
}
/// Manages cookies globally for all webviews.
class CookieManager {
CookieManager._();
static CookieManager? _instance;
/// Gets the globally set CookieManager instance.
static CookieManager get instance => _instance ??= CookieManager._();
/// Setter for the singleton value, for testing purposes only.
@visibleForTesting
static set instance(CookieManager value) => _instance = value;
/// Pigeon Host Api implementation for [CookieManager].
@visibleForTesting
static CookieManagerHostApi api = CookieManagerHostApi();
/// Sets a single cookie (key-value pair) for the given URL. Any existing
/// cookie with the same host, path and name will be replaced with the new
/// cookie. The cookie being set will be ignored if it is expired. To set
/// multiple cookies, your application should invoke this method multiple
/// times.
///
/// The value parameter must follow the format of the Set-Cookie HTTP
/// response header defined by RFC6265bis. This is a key-value pair of the
/// form "key=value", optionally followed by a list of cookie attributes
/// delimited with semicolons (ex. "key=value; Max-Age=123"). Please consult
/// the RFC specification for a list of valid attributes.
///
/// Note: if specifying a value containing the "Secure" attribute, url must
/// use the "https://" scheme.
///
/// Params:
/// url – the URL for which the cookie is to be set
/// value – the cookie as a string, using the format of the 'Set-Cookie' HTTP response header
Future<void> setCookie(String url, String value) => api.setCookie(url, value);
/// Removes all cookies.
///
/// The returned future resolves to true if any cookies were removed.
Future<bool> clearCookies() => api.clearCookies();
}
/// Manages settings state for a [WebView].
///
/// When a WebView is first created, it obtains a set of default settings. These
/// default settings will be returned from any getter call. A WebSettings object
/// obtained from [WebView.settings] is tied to the life of the WebView. If a
/// WebView has been destroyed, any method call on [WebSettings] will throw an
/// Exception.
class WebSettings {
/// Constructs a [WebSettings].
///
/// This constructor is only used for testing. An instance should be obtained
/// with [WebView.settings].
@visibleForTesting
WebSettings(WebView webView) {
api.createFromInstance(this, webView);
}
/// Pigeon Host Api implementation for [WebSettings].
@visibleForTesting
static WebSettingsHostApiImpl api = WebSettingsHostApiImpl();
/// Sets whether the DOM storage API is enabled.
///
/// The default value is false.
Future<void> setDomStorageEnabled(bool flag) {
return api.setDomStorageEnabledFromInstance(this, flag);
}
/// Tells JavaScript to open windows automatically.
///
/// This applies to the JavaScript function `window.open()`. The default is
/// false.
Future<void> setJavaScriptCanOpenWindowsAutomatically(bool flag) {
return api.setJavaScriptCanOpenWindowsAutomaticallyFromInstance(
this,
flag,
);
}
// TODO(bparrishMines): Update documentation when WebChromeClient.onCreateWindow is added.
/// Sets whether the WebView should supports multiple windows.
///
/// The default is false.
Future<void> setSupportMultipleWindows(bool support) {
return api.setSupportMultipleWindowsFromInstance(this, support);
}
/// Tells the WebView to enable JavaScript execution.
///
/// The default is false.
Future<void> setJavaScriptEnabled(bool flag) {
return api.setJavaScriptEnabledFromInstance(this, flag);
}
/// Sets the WebView's user-agent string.
///
/// If the string is empty, the system default value will be used. Note that
/// starting from KITKAT Android version, changing the user-agent while
/// loading a web page causes WebView to initiate loading once again.
Future<void> setUserAgentString(String? userAgentString) {
return api.setUserAgentStringFromInstance(this, userAgentString);
}
/// Sets whether the WebView requires a user gesture to play media.
///
/// The default is true.
Future<void> setMediaPlaybackRequiresUserGesture(bool require) {
return api.setMediaPlaybackRequiresUserGestureFromInstance(this, require);
}
// TODO(bparrishMines): Update documentation when WebView.zoomIn and WebView.zoomOut are added.
/// Sets whether the WebView should support zooming using its on-screen zoom controls and gestures.
///
/// The particular zoom mechanisms that should be used can be set with
/// [setBuiltInZoomControls].
///
/// The default is true.
Future<void> setSupportZoom(bool support) {
return api.setSupportZoomFromInstance(this, support);
}
/// Sets whether the WebView loads pages in overview mode, that is, zooms out the content to fit on screen by width.
///
/// This setting is taken into account when the content width is greater than
/// the width of the WebView control, for example, when [setUseWideViewPort]
/// is enabled.
///
/// The default is false.
Future<void> setLoadWithOverviewMode(bool overview) {
return api.setLoadWithOverviewModeFromInstance(this, overview);
}
/// Sets whether the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport.
///
/// When the value of the setting is false, the layout width is always set to
/// the width of the WebView control in device-independent (CSS) pixels. When
/// the value is true and the page contains the viewport meta tag, the value
/// of the width specified in the tag is used. If the page does not contain
/// the tag or does not provide a width, then a wide viewport will be used.
Future<void> setUseWideViewPort(bool use) {
return api.setUseWideViewPortFromInstance(this, use);
}
// TODO(bparrishMines): Update documentation when ZoomButtonsController is added.
/// Sets whether the WebView should display on-screen zoom controls when using the built-in zoom mechanisms.
///
/// See [setBuiltInZoomControls]. The default is true. However, on-screen zoom
/// controls are deprecated in Android so it's recommended to set this to
/// false.
Future<void> setDisplayZoomControls(bool enabled) {
return api.setDisplayZoomControlsFromInstance(this, enabled);
}
// TODO(bparrishMines): Update documentation when ZoomButtonsController is added.
/// Sets whether the WebView should use its built-in zoom mechanisms.
///
/// The built-in zoom mechanisms comprise on-screen zoom controls, which are
/// displayed over the WebView's content, and the use of a pinch gesture to
/// control zooming. Whether or not these on-screen controls are displayed can
/// be set with [setDisplayZoomControls]. The default is false.
///
/// The built-in mechanisms are the only currently supported zoom mechanisms,
/// so it is recommended that this setting is always enabled. However,
/// on-screen zoom controls are deprecated in Android so it's recommended to
/// disable [setDisplayZoomControls].
Future<void> setBuiltInZoomControls(bool enabled) {
return api.setBuiltInZoomControlsFromInstance(this, enabled);
}
/// Enables or disables file access within WebView.
///
/// This enables or disables file system access only. Assets and resources are
/// still accessible using file:///android_asset and file:///android_res. The
/// default value is true for apps targeting Build.VERSION_CODES.Q and below,
/// and false when targeting Build.VERSION_CODES.R and above.
Future<void> setAllowFileAccess(bool enabled) {
return api.setAllowFileAccessFromInstance(this, enabled);
}
}
/// Exposes a channel to receive calls from javaScript.
///
/// See [WebView.addJavaScriptChannel].
abstract class JavaScriptChannel {
/// Constructs a [JavaScriptChannel].
JavaScriptChannel(this.channelName) {
AndroidWebViewFlutterApis.instance.ensureSetUp();
}
/// Pigeon Host Api implementation for [JavaScriptChannel].
@visibleForTesting
static JavaScriptChannelHostApiImpl api = JavaScriptChannelHostApiImpl();
/// Used to identify this object to receive messages from javaScript.
final String channelName;
/// Callback method when javaScript calls `postMessage` on the object instance passed.
void postMessage(String message);
}
/// Receive various notifications and requests for [WebView].
abstract class WebViewClient {
/// Constructs a [WebViewClient].
WebViewClient({this.shouldOverrideUrlLoading = true}) {
AndroidWebViewFlutterApis.instance.ensureSetUp();
}
/// User authentication failed on server.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_AUTHENTICATION
static const int errorAuthentication = -4;
/// Malformed URL.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_BAD_URL
static const int errorBadUrl = -12;
/// Failed to connect to the server.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_CONNECT
static const int errorConnect = -6;
/// Failed to perform SSL handshake.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_FAILED_SSL_HANDSHAKE
static const int errorFailedSslHandshake = -11;
/// Generic file error.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_FILE
static const int errorFile = -13;
/// File not found.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_FILE_NOT_FOUND
static const int errorFileNotFound = -14;
/// Server or proxy hostname lookup failed.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_HOST_LOOKUP
static const int errorHostLookup = -2;
/// Failed to read or write to the server.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_IO
static const int errorIO = -7;
/// User authentication failed on proxy.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_PROXY_AUTHENTICATION
static const int errorProxyAuthentication = -5;
/// Too many redirects.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_REDIRECT_LOOP
static const int errorRedirectLoop = -9;
/// Connection timed out.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_TIMEOUT
static const int errorTimeout = -8;
/// Too many requests during this load.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_TOO_MANY_REQUESTS
static const int errorTooManyRequests = -15;
/// Generic error.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNKNOWN
static const int errorUnknown = -1;
/// Resource load was canceled by Safe Browsing.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNSAFE_RESOURCE
static const int errorUnsafeResource = -16;
/// Unsupported authentication scheme (not basic or digest).
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNSUPPORTED_AUTH_SCHEME
static const int errorUnsupportedAuthScheme = -3;
/// Unsupported URI scheme.
///
/// See https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNSUPPORTED_SCHEME
static const int errorUnsupportedScheme = -10;
/// Pigeon Host Api implementation for [WebViewClient].
@visibleForTesting
static WebViewClientHostApiImpl api = WebViewClientHostApiImpl();
/// Whether loading a url should be overridden.
///
/// In Java, `shouldOverrideUrlLoading()` and `shouldOverrideRequestLoading()`
/// callbacks must synchronously return a boolean. This sets the default
/// return value.
///
/// Setting [shouldOverrideUrlLoading] to true causes the current [WebView] to
/// abort loading the URL, while returning false causes the [WebView] to
/// continue loading the URL as usual. [requestLoading] or [urlLoading] will
/// still be called either way.
///
/// Defaults to true.
final bool shouldOverrideUrlLoading;
/// Notify the host application that a page has started loading.
///
/// This method is called once for each main frame load so a page with iframes
/// or framesets will call onPageStarted one time for the main frame. This
/// also means that [onPageStarted] will not be called when the contents of an
/// embedded frame changes, i.e. clicking a link whose target is an iframe, it
/// will also not be called for fragment navigations (navigations to
/// #fragment_id).
void onPageStarted(WebView webView, String url) {}
// TODO(bparrishMines): Update documentation when WebView.postVisualStateCallback is added.
/// Notify the host application that a page has finished loading.
///
/// This method is called only for main frame. Receiving an [onPageFinished]
/// callback does not guarantee that the next frame drawn by WebView will
/// reflect the state of the DOM at this point.
void onPageFinished(WebView webView, String url) {}
/// Report web resource loading error to the host application.
///
/// These errors usually indicate inability to connect to the server. Note
/// that unlike the deprecated version of the callback, the new version will
/// be called for any resource (iframe, image, etc.), not just for the main
/// page. Thus, it is recommended to perform minimum required work in this
/// callback.
void onReceivedRequestError(
WebView webView,
WebResourceRequest request,
WebResourceError error,
) {}
/// Report an error to the host application.
///
/// These errors are unrecoverable (i.e. the main resource is unavailable).
/// The errorCode parameter corresponds to one of the error* constants.
@Deprecated('Only called on Android version < 23.')
void onReceivedError(
WebView webView,
int errorCode,
String description,
String failingUrl,
) {}
// TODO(bparrishMines): Update documentation once synchronous url handling is supported.
/// When a URL is about to be loaded in the current [WebView].
///
/// If a [WebViewClient] is not provided, by default [WebView] will ask
/// Activity Manager to choose the proper handler for the URL. If a
/// [WebViewClient] is provided, setting [shouldOverrideUrlLoading] to true
/// causes the current [WebView] to abort loading the URL, while returning
/// false causes the [WebView] to continue loading the URL as usual.
void requestLoading(WebView webView, WebResourceRequest request) {}
// TODO(bparrishMines): Update documentation once synchronous url handling is supported.
/// When a URL is about to be loaded in the current [WebView].
///
/// If a [WebViewClient] is not provided, by default [WebView] will ask
/// Activity Manager to choose the proper handler for the URL. If a
/// [WebViewClient] is provided, setting [shouldOverrideUrlLoading] to true
/// causes the current [WebView] to abort loading the URL, while returning
/// false causes the [WebView] to continue loading the URL as usual.
void urlLoading(WebView webView, String url) {}
}
/// The interface to be used when content can not be handled by the rendering engine for [WebView], and should be downloaded instead.
abstract class DownloadListener {
/// Constructs a [DownloadListener].
DownloadListener() {
AndroidWebViewFlutterApis.instance.ensureSetUp();
}
/// Pigeon Host Api implementation for [DownloadListener].
@visibleForTesting
static DownloadListenerHostApiImpl api = DownloadListenerHostApiImpl();
/// Notify the host application that a file should be downloaded.
void onDownloadStart(
String url,
String userAgent,
String contentDisposition,
String mimetype,
int contentLength,
);
}
/// Handles JavaScript dialogs, favicons, titles, and the progress for [WebView].
abstract class WebChromeClient {
/// Constructs a [WebChromeClient].
WebChromeClient() {
AndroidWebViewFlutterApis.instance.ensureSetUp();
}
/// Pigeon Host Api implementation for [WebChromeClient].
@visibleForTesting
static WebChromeClientHostApiImpl api = WebChromeClientHostApiImpl();
/// Notify the host application that a file should be downloaded.
void onProgressChanged(WebView webView, int progress) {}
}
/// Encompasses parameters to the [WebViewClient.requestLoading] method.
class WebResourceRequest {
/// Constructs a [WebResourceRequest].
WebResourceRequest({
required this.url,
required this.isForMainFrame,
required this.isRedirect,
required this.hasGesture,
required this.method,
required this.requestHeaders,
});
/// The URL for which the resource request was made.
final String url;
/// Whether the request was made in order to fetch the main frame's document.
final bool isForMainFrame;
/// Whether the request was a result of a server-side redirect.
///
/// Only supported on Android version >= 24.
final bool? isRedirect;
/// Whether a gesture (such as a click) was associated with the request.
final bool hasGesture;
/// The method associated with the request, for example "GET".
final String method;
/// The headers associated with the request.
final Map<String, String> requestHeaders;
}
/// Encapsulates information about errors occurred during loading of web resources.
///
/// See [WebViewClient.onReceivedRequestError].
class WebResourceError {
/// Constructs a [WebResourceError].
WebResourceError({
required this.errorCode,
required this.description,
});
/// The integer code of the error (e.g. [WebViewClient.errorAuthentication].
final int errorCode;
/// Describes the error.
final String description;
}
/// Manages Flutter assets that are part of Android's app bundle.
class FlutterAssetManager {
/// Constructs the [FlutterAssetManager].
const FlutterAssetManager();
/// Pigeon Host Api implementation for [FlutterAssetManager].
@visibleForTesting
static FlutterAssetManagerHostApi api = FlutterAssetManagerHostApi();
/// Lists all assets at the given path.
///
/// The assets are returned as a `List<String>`. The `List<String>` only
/// contains files which are direct childs
Future<List<String?>> list(String path) => api.list(path);
/// Gets the relative file path to the Flutter asset with the given name.
Future<String> getAssetFilePathByName(String name) =>
api.getAssetFilePathByName(name);
}
/// Manages the JavaScript storage APIs provided by the [WebView].
///
/// Wraps [WebStorage](https://developer.android.com/reference/android/webkit/WebStorage).
class WebStorage {
/// Constructs a [WebStorage].
///
/// This constructor is only used for testing. An instance should be obtained
/// with [WebStorage.instance].
@visibleForTesting
WebStorage() {
AndroidWebViewFlutterApis.instance.ensureSetUp();
api.createFromInstance(this);
}
/// Pigeon Host Api implementation for [WebStorage].
@visibleForTesting
static WebStorageHostApiImpl api = WebStorageHostApiImpl();
/// The singleton instance of this class.
static WebStorage instance = WebStorage();
/// Clears all storage currently being used by the JavaScript storage APIs.
Future<void> deleteAllData() {
return api.deleteAllDataFromInstance(this);
}
}