| // 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/services.dart' show BinaryMessenger; |
| |
| import 'package:flutter/widgets.dart' show WidgetsFlutterBinding; |
| |
| import 'android_webview.g.dart'; |
| import 'android_webview_api_impls.dart'; |
| import 'instance_manager.dart'; |
| |
| export 'android_webview_api_impls.dart' show FileChooserMode; |
| |
| /// Root of the Java class hierarchy. |
| /// |
| /// See https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html. |
| class JavaObject with Copyable { |
| /// Constructs a [JavaObject] without creating the associated Java object. |
| /// |
| /// This should only be used by subclasses created by this library or to |
| /// create copies. |
| @protected |
| JavaObject.detached({ |
| BinaryMessenger? binaryMessenger, |
| InstanceManager? instanceManager, |
| }) : _api = JavaObjectHostApiImpl( |
| binaryMessenger: binaryMessenger, |
| instanceManager: instanceManager, |
| ); |
| |
| /// Global instance of [InstanceManager]. |
| static final InstanceManager globalInstanceManager = _initInstanceManager(); |
| |
| static InstanceManager _initInstanceManager() { |
| WidgetsFlutterBinding.ensureInitialized(); |
| // Clears the native `InstanceManager` on initial use of the Dart one. |
| InstanceManagerHostApi().clear(); |
| return InstanceManager( |
| onWeakReferenceRemoved: (int identifier) { |
| JavaObjectHostApiImpl().dispose(identifier); |
| }, |
| ); |
| } |
| |
| /// Pigeon Host Api implementation for [JavaObject]. |
| final JavaObjectHostApiImpl _api; |
| |
| /// Release the reference to a native Java instance. |
| static void dispose(JavaObject instance) { |
| instance._api.instanceManager.removeWeakReference(instance); |
| } |
| |
| @override |
| JavaObject copy() { |
| return JavaObject.detached(); |
| } |
| } |
| |
| /// 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 extends JavaObject { |
| /// Constructs a new WebView. |
| /// |
| /// Due to changes in Flutter 3.0 the [useHybridComposition] doesn't have |
| /// any effect and should not be exposed publicly. More info here: |
| /// https://github.com/flutter/flutter/issues/108106 |
| WebView({ |
| @visibleForTesting super.binaryMessenger, |
| @visibleForTesting super.instanceManager, |
| }) : super.detached() { |
| api.createFromInstance(this); |
| } |
| |
| /// Constructs a [WebView] without creating the associated Java object. |
| /// |
| /// This should only be used by subclasses created by this library or to |
| /// create copies. |
| @protected |
| WebView.detached({ |
| super.binaryMessenger, |
| super.instanceManager, |
| }) : super.detached(); |
| |
| /// Pigeon Host Api implementation for [WebView]. |
| @visibleForTesting |
| static WebViewHostApiImpl api = WebViewHostApiImpl(); |
| |
| /// 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); |
| } |
| |
| /// Returns the X and Y scroll position of this view. |
| Future<Offset> getScrollPosition() { |
| return api.getScrollPositionFromInstance(this); |
| } |
| |
| /// Sets the [WebViewClient] that will receive various notifications and requests. |
| /// |
| /// This will replace the current handler. |
| Future<void> setWebViewClient(WebViewClient 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) { |
| return 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) { |
| return api.setWebChromeClientFromInstance(this, client); |
| } |
| |
| /// Sets the background color of this WebView. |
| Future<void> setBackgroundColor(Color color) { |
| return api.setBackgroundColorFromInstance(this, color.value); |
| } |
| |
| @override |
| WebView copy() { |
| return WebView.detached( |
| binaryMessenger: _api.binaryMessenger, |
| instanceManager: _api.instanceManager, |
| ); |
| } |
| } |
| |
| /// 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 extends JavaObject { |
| /// Constructs a [WebSettings]. |
| /// |
| /// This constructor is only used for testing. An instance should be obtained |
| /// with [WebView.settings]. |
| @visibleForTesting |
| WebSettings( |
| WebView webView, { |
| @visibleForTesting super.binaryMessenger, |
| @visibleForTesting super.instanceManager, |
| }) : super.detached() { |
| api.createFromInstance(this, webView); |
| } |
| |
| /// Constructs a [WebSettings] without creating the associated Java object. |
| /// |
| /// This should only be used by subclasses created by this library or to |
| /// create copies. |
| @protected |
| WebSettings.detached({ |
| super.binaryMessenger, |
| super.instanceManager, |
| }) : super.detached(); |
| |
| /// 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); |
| } |
| |
| /// Sets the text zoom of the page in percent. |
| /// |
| /// The default is 100. See https://developer.android.com/reference/android/webkit/WebSettings#setTextZoom(int) |
| Future<void> setTextZoom(int textZoom) { |
| return api.setSetTextZoomFromInstance(this, textZoom); |
| } |
| |
| @override |
| WebSettings copy() { |
| return WebSettings.detached( |
| binaryMessenger: _api.binaryMessenger, |
| instanceManager: _api.instanceManager, |
| ); |
| } |
| } |
| |
| /// Exposes a channel to receive calls from javaScript. |
| /// |
| /// See [WebView.addJavaScriptChannel]. |
| class JavaScriptChannel extends JavaObject { |
| /// Constructs a [JavaScriptChannel]. |
| JavaScriptChannel( |
| this.channelName, { |
| required this.postMessage, |
| @visibleForTesting super.binaryMessenger, |
| @visibleForTesting super.instanceManager, |
| }) : super.detached() { |
| AndroidWebViewFlutterApis.instance.ensureSetUp(); |
| api.createFromInstance(this); |
| } |
| |
| /// Constructs a [JavaScriptChannel] without creating the associated Java |
| /// object. |
| /// |
| /// This should only be used by subclasses created by this library or to |
| /// create copies. |
| @protected |
| JavaScriptChannel.detached( |
| this.channelName, { |
| required this.postMessage, |
| super.binaryMessenger, |
| super.instanceManager, |
| }) : super.detached(); |
| |
| /// 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. |
| final void Function(String message) postMessage; |
| |
| @override |
| JavaScriptChannel copy() { |
| return JavaScriptChannel.detached( |
| channelName, |
| postMessage: postMessage, |
| binaryMessenger: _api.binaryMessenger, |
| instanceManager: _api.instanceManager, |
| ); |
| } |
| } |
| |
| /// Receive various notifications and requests for [WebView]. |
| class WebViewClient extends JavaObject { |
| /// Constructs a [WebViewClient]. |
| WebViewClient({ |
| this.onPageStarted, |
| this.onPageFinished, |
| this.onReceivedRequestError, |
| @Deprecated('Only called on Android version < 23.') this.onReceivedError, |
| this.requestLoading, |
| this.urlLoading, |
| this.doUpdateVisitedHistory, |
| @visibleForTesting super.binaryMessenger, |
| @visibleForTesting super.instanceManager, |
| }) : super.detached() { |
| AndroidWebViewFlutterApis.instance.ensureSetUp(); |
| api.createFromInstance(this); |
| } |
| |
| /// Constructs a [WebViewClient] without creating the associated Java object. |
| /// |
| /// This should only be used by subclasses created by this library or to |
| /// create copies. |
| @protected |
| WebViewClient.detached({ |
| this.onPageStarted, |
| this.onPageFinished, |
| this.onReceivedRequestError, |
| @Deprecated('Only called on Android version < 23.') this.onReceivedError, |
| this.requestLoading, |
| this.urlLoading, |
| this.doUpdateVisitedHistory, |
| super.binaryMessenger, |
| super.instanceManager, |
| }) : super.detached(); |
| |
| /// 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(); |
| |
| /// 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). |
| final void Function(WebView webView, String url)? onPageStarted; |
| |
| // 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. |
| final void Function(WebView webView, String url)? onPageFinished; |
| |
| /// 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. |
| final void Function( |
| WebView webView, |
| WebResourceRequest request, |
| WebResourceError error, |
| )? onReceivedRequestError; |
| |
| /// 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.') |
| final void Function( |
| WebView webView, |
| int errorCode, |
| String description, |
| String failingUrl, |
| )? onReceivedError; |
| |
| /// When the current [WebView] wants to load a URL. |
| /// |
| /// The value set by [setSynchronousReturnValueForShouldOverrideUrlLoading] |
| /// indicates whether the [WebView] loaded the request. |
| final void Function(WebView webView, WebResourceRequest request)? |
| requestLoading; |
| |
| /// When the current [WebView] wants to load a URL. |
| /// |
| /// The value set by [setSynchronousReturnValueForShouldOverrideUrlLoading] |
| /// indicates whether the [WebView] loaded the URL. |
| final void Function(WebView webView, String url)? urlLoading; |
| |
| /// Notify the host application to update its visited links database. |
| final void Function(WebView webView, String url, bool isReload)? |
| doUpdateVisitedHistory; |
| |
| /// Sets the required synchronous return value for the Java method, |
| /// `WebViewClient.shouldOverrideUrlLoading(...)`. |
| /// |
| /// The Java method, `WebViewClient.shouldOverrideUrlLoading(...)`, requires |
| /// a boolean to be returned and this method sets the returned value for all |
| /// calls to the Java method. |
| /// |
| /// Setting this to true causes the current [WebView] to abort loading any URL |
| /// received by [requestLoading] or [urlLoading], while setting this to false |
| /// causes the [WebView] to continue loading a URL as usual. |
| /// |
| /// Defaults to false. |
| Future<void> setSynchronousReturnValueForShouldOverrideUrlLoading( |
| bool value, |
| ) { |
| return api.setShouldOverrideUrlLoadingReturnValueFromInstance(this, value); |
| } |
| |
| @override |
| WebViewClient copy() { |
| return WebViewClient.detached( |
| onPageStarted: onPageStarted, |
| onPageFinished: onPageFinished, |
| onReceivedRequestError: onReceivedRequestError, |
| onReceivedError: onReceivedError, |
| requestLoading: requestLoading, |
| urlLoading: urlLoading, |
| doUpdateVisitedHistory: doUpdateVisitedHistory, |
| binaryMessenger: _api.binaryMessenger, |
| instanceManager: _api.instanceManager, |
| ); |
| } |
| } |
| |
| /// The interface to be used when content can not be handled by the rendering |
| /// engine for [WebView], and should be downloaded instead. |
| class DownloadListener extends JavaObject { |
| /// Constructs a [DownloadListener]. |
| DownloadListener({ |
| required this.onDownloadStart, |
| @visibleForTesting super.binaryMessenger, |
| @visibleForTesting super.instanceManager, |
| }) : super.detached() { |
| AndroidWebViewFlutterApis.instance.ensureSetUp(); |
| api.createFromInstance(this); |
| } |
| |
| /// Constructs a [DownloadListener] without creating the associated Java |
| /// object. |
| /// |
| /// This should only be used by subclasses created by this library or to |
| /// create copies. |
| @protected |
| DownloadListener.detached({ |
| required this.onDownloadStart, |
| super.binaryMessenger, |
| super.instanceManager, |
| }) : super.detached(); |
| |
| /// Pigeon Host Api implementation for [DownloadListener]. |
| @visibleForTesting |
| static DownloadListenerHostApiImpl api = DownloadListenerHostApiImpl(); |
| |
| /// Notify the host application that a file should be downloaded. |
| final void Function( |
| String url, |
| String userAgent, |
| String contentDisposition, |
| String mimetype, |
| int contentLength, |
| ) onDownloadStart; |
| |
| @override |
| DownloadListener copy() { |
| return DownloadListener.detached( |
| onDownloadStart: onDownloadStart, |
| binaryMessenger: _api.binaryMessenger, |
| instanceManager: _api.instanceManager, |
| ); |
| } |
| } |
| |
| /// Handles JavaScript dialogs, favicons, titles, and the progress for [WebView]. |
| class WebChromeClient extends JavaObject { |
| /// Constructs a [WebChromeClient]. |
| WebChromeClient({ |
| this.onProgressChanged, |
| this.onShowFileChooser, |
| @visibleForTesting super.binaryMessenger, |
| @visibleForTesting super.instanceManager, |
| }) : super.detached() { |
| AndroidWebViewFlutterApis.instance.ensureSetUp(); |
| api.createFromInstance(this); |
| } |
| |
| /// Constructs a [WebChromeClient] without creating the associated Java |
| /// object. |
| /// |
| /// This should only be used by subclasses created by this library or to |
| /// create copies. |
| @protected |
| WebChromeClient.detached({ |
| this.onProgressChanged, |
| this.onShowFileChooser, |
| super.binaryMessenger, |
| super.instanceManager, |
| }) : super.detached(); |
| |
| /// Pigeon Host Api implementation for [WebChromeClient]. |
| @visibleForTesting |
| static WebChromeClientHostApiImpl api = WebChromeClientHostApiImpl(); |
| |
| /// Notify the host application that a file should be downloaded. |
| final void Function(WebView webView, int progress)? onProgressChanged; |
| |
| /// Indicates the client should show a file chooser. |
| /// |
| /// To handle the request for a file chooser with this callback, passing true |
| /// to [setSynchronousReturnValueForOnShowFileChooser] is required. Otherwise, |
| /// the returned list of strings will be ignored and the client will use the |
| /// default handling of a file chooser request. |
| /// |
| /// Only invoked on Android versions 21+. |
| final Future<List<String>> Function( |
| WebView webView, |
| FileChooserParams params, |
| )? onShowFileChooser; |
| |
| /// Sets the required synchronous return value for the Java method, |
| /// `WebChromeClient.onShowFileChooser(...)`. |
| /// |
| /// The Java method, `WebChromeClient.onShowFileChooser(...)`, requires |
| /// a boolean to be returned and this method sets the returned value for all |
| /// calls to the Java method. |
| /// |
| /// Setting this to true indicates that all file chooser requests should be |
| /// handled by [onShowFileChooser] and the returned list of Strings will be |
| /// returned to the WebView. Otherwise, the client will use the default |
| /// handling and the returned value in [onShowFileChooser] will be ignored. |
| /// |
| /// Requires [onShowFileChooser] to be nonnull. |
| /// |
| /// Defaults to false. |
| Future<void> setSynchronousReturnValueForOnShowFileChooser( |
| bool value, |
| ) { |
| if (value && onShowFileChooser == null) { |
| throw StateError( |
| 'Setting this to true requires `onShowFileChooser` to be nonnull.', |
| ); |
| } |
| return api.setSynchronousReturnValueForOnShowFileChooserFromInstance( |
| this, |
| value, |
| ); |
| } |
| |
| @override |
| WebChromeClient copy() { |
| return WebChromeClient.detached( |
| onProgressChanged: onProgressChanged, |
| onShowFileChooser: onShowFileChooser, |
| binaryMessenger: _api.binaryMessenger, |
| instanceManager: _api.instanceManager, |
| ); |
| } |
| } |
| |
| /// Parameters received when a [WebChromeClient] should show a file chooser. |
| /// |
| /// See https://developer.android.com/reference/android/webkit/WebChromeClient.FileChooserParams. |
| class FileChooserParams extends JavaObject { |
| /// Constructs a [FileChooserParams] without creating the associated Java |
| /// object. |
| /// |
| /// This should only be used by subclasses created by this library or to |
| /// create copies. |
| @protected |
| FileChooserParams.detached({ |
| required this.isCaptureEnabled, |
| required this.acceptTypes, |
| required this.filenameHint, |
| required this.mode, |
| super.binaryMessenger, |
| super.instanceManager, |
| }) : super.detached(); |
| |
| /// Preference for a live media captured value (e.g. Camera, Microphone). |
| final bool isCaptureEnabled; |
| |
| /// A list of acceptable MIME types. |
| final List<String> acceptTypes; |
| |
| /// The file name of a default selection if specified, or null. |
| final String? filenameHint; |
| |
| /// Mode of how to select files for a file chooser. |
| final FileChooserMode mode; |
| |
| @override |
| FileChooserParams copy() { |
| return FileChooserParams.detached( |
| isCaptureEnabled: isCaptureEnabled, |
| acceptTypes: acceptTypes, |
| filenameHint: filenameHint, |
| mode: mode, |
| binaryMessenger: _api.binaryMessenger, |
| instanceManager: _api.instanceManager, |
| ); |
| } |
| } |
| |
| /// 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 extends JavaObject { |
| /// Constructs a [WebStorage]. |
| /// |
| /// This constructor is only used for testing. An instance should be obtained |
| /// with [WebStorage.instance]. |
| @visibleForTesting |
| WebStorage({ |
| @visibleForTesting super.binaryMessenger, |
| @visibleForTesting super.instanceManager, |
| }) : super.detached() { |
| AndroidWebViewFlutterApis.instance.ensureSetUp(); |
| api.createFromInstance(this); |
| } |
| |
| /// Constructs a [WebStorage] without creating the associated Java object. |
| /// |
| /// This should only be used by subclasses created by this library or to |
| /// create copies. |
| @protected |
| WebStorage.detached({ |
| super.binaryMessenger, |
| super.instanceManager, |
| }) : super.detached(); |
| |
| /// 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); |
| } |
| |
| @override |
| WebStorage copy() { |
| return WebStorage.detached( |
| binaryMessenger: _api.binaryMessenger, |
| instanceManager: _api.instanceManager, |
| ); |
| } |
| } |