2019-11-02 03:16:47 +00:00
import ' dart:io ' ;
import ' dart:async ' ;
import ' dart:collection ' ;
import ' dart:typed_data ' ;
import ' dart:convert ' ;
import ' package:flutter/foundation.dart ' ;
import ' package:flutter/material.dart ' ;
import ' package:flutter/services.dart ' ;
import ' package:flutter/widgets.dart ' ;
import ' package:flutter/gestures.dart ' ;
2019-11-02 18:58:01 +00:00
import ' package:html/parser.dart ' show parse ;
2019-11-02 03:16:47 +00:00
import ' types.dart ' ;
import ' in_app_browser.dart ' ;
import ' webview_options.dart ' ;
2019-11-05 23:37:36 +00:00
const javaScriptHandlerForbiddenNames = [ " onLoadResource " , " shouldInterceptAjaxRequest " , " onAjaxReadyStateChange " , " onAjaxProgress " , " shouldInterceptFetchRequest " ] ;
2019-11-02 03:16:47 +00:00
///InAppWebView Widget class.
///
///Flutter Widget for adding an **inline native WebView** integrated in the flutter widget tree.
class InAppWebView extends StatefulWidget {
///Event fires when the [InAppWebView] is created.
final void Function ( InAppWebViewController controller ) onWebViewCreated ;
///Event fires when the [InAppWebView] starts to load an [url].
final void Function ( InAppWebViewController controller , String url ) onLoadStart ;
///Event fires when the [InAppWebView] finishes loading an [url].
final void Function ( InAppWebViewController controller , String url ) onLoadStop ;
///Event fires when the [InAppWebView] encounters an error loading an [url].
final void Function ( InAppWebViewController controller , String url , int code , String message ) onLoadError ;
///Event fires when the current [progress] of loading a page is changed.
final void Function ( InAppWebViewController controller , int progress ) onProgressChanged ;
///Event fires when the [InAppWebView] receives a [ConsoleMessage].
final void Function ( InAppWebViewController controller , ConsoleMessage consoleMessage ) onConsoleMessage ;
///Give the host application a chance to take control when a URL is about to be loaded in the current WebView.
///
2019-11-08 18:12:21 +00:00
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldOverrideUrlLoading] option to `true`.
2019-11-02 03:16:47 +00:00
final void Function ( InAppWebViewController controller , String url ) shouldOverrideUrlLoading ;
///Event fires when the [InAppWebView] loads a resource.
///
2019-11-08 18:12:21 +00:00
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnLoadResource] and [InAppWebViewOptions.javaScriptEnabled] options to `true`.
2019-11-04 00:39:23 +00:00
final void Function ( InAppWebViewController controller , LoadedResource resource ) onLoadResource ;
2019-11-02 03:16:47 +00:00
///Event fires when the [InAppWebView] scrolls.
///
///[x] represents the current horizontal scroll origin in pixels.
///
///[y] represents the current vertical scroll origin in pixels.
final void Function ( InAppWebViewController controller , int x , int y ) onScrollChanged ;
///Event fires when [InAppWebView] recognizes and starts a downloadable file.
///
///[url] represents the url of the file.
2019-11-08 18:12:21 +00:00
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnDownloadStart] option to `true`.
2019-11-02 03:16:47 +00:00
final void Function ( InAppWebViewController controller , String url ) onDownloadStart ;
///Event fires when the [InAppWebView] finds the `custom-scheme` while loading a resource. Here you can handle the url request and return a [CustomSchemeResponse] to load a specific resource encoded to `base64`.
///
///[scheme] represents the scheme of the url.
///
///[url] represents the url of the request.
final Future < CustomSchemeResponse > Function ( InAppWebViewController controller , String scheme , String url ) onLoadResourceCustomScheme ;
///Event fires when the [InAppWebView] tries to open a link with `target="_blank"`.
///
///[url] represents the url of the link.
2019-11-08 18:12:21 +00:00
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnTargetBlank] option to `true`.
2019-11-02 03:16:47 +00:00
final void Function ( InAppWebViewController controller , String url ) onTargetBlank ;
///Event that notifies the host application that web content from the specified origin is attempting to use the Geolocation API, but no permission state is currently set for that origin.
///Note that for applications targeting Android N and later SDKs (API level > `Build.VERSION_CODES.M`) this method is only called for requests originating from secure origins such as https.
///On non-secure origins geolocation requests are automatically denied.
///
///[origin] represents the origin of the web content attempting to use the Geolocation API.
///
///**NOTE**: available only for Android.
final Future < GeolocationPermissionShowPromptResponse > Function ( InAppWebViewController controller , String origin ) onGeolocationPermissionsShowPrompt ;
///Event fires when javascript calls the `alert()` method to display an alert dialog.
///If [JsAlertResponse.handledByClient] is `true`, the webview will assume that the client will handle the dialog.
///
///[message] represents the message to be displayed in the alert dialog.
final Future < JsAlertResponse > Function ( InAppWebViewController controller , String message ) onJsAlert ;
///Event fires when javascript calls the `confirm()` method to display a confirm dialog.
///If [JsConfirmResponse.handledByClient] is `true`, the webview will assume that the client will handle the dialog.
///
///[message] represents the message to be displayed in the alert dialog.
final Future < JsConfirmResponse > Function ( InAppWebViewController controller , String message ) onJsConfirm ;
///Event fires when javascript calls the `prompt()` method to display a prompt dialog.
///If [JsPromptResponse.handledByClient] is `true`, the webview will assume that the client will handle the dialog.
///
///[message] represents the message to be displayed in the alert dialog.
///
///[defaultValue] represents the default value displayed in the prompt dialog.
final Future < JsPromptResponse > Function ( InAppWebViewController controller , String message , String defaultValue ) onJsPrompt ;
///Event fires when the webview notifies that a loading URL has been flagged by Safe Browsing.
///The default behavior is to show an interstitial to the user, with the reporting checkbox visible.
///
///[url] represents the url of the request.
///
///[threatType] represents the reason the resource was caught by Safe Browsing, corresponding to a [SafeBrowsingThreat].
///
///**NOTE**: available only for Android.
final Future < SafeBrowsingResponse > Function ( InAppWebViewController controller , String url , SafeBrowsingThreat threatType ) onSafeBrowsingHit ;
2019-11-08 18:12:21 +00:00
///Event fires when the WebView received an HTTP authentication request. The default behavior is to cancel the request.
2019-11-02 03:16:47 +00:00
///
2019-11-08 18:12:21 +00:00
///[challenge] contains data about host, port, protocol, realm, etc. as specified in the [HttpAuthChallenge].
2019-11-02 03:16:47 +00:00
final Future < HttpAuthResponse > Function ( InAppWebViewController controller , HttpAuthChallenge challenge ) onReceivedHttpAuthRequest ;
2019-11-08 18:12:21 +00:00
///Event fires when the WebView need to perform server trust authentication (certificate validation).
2019-11-09 22:35:18 +00:00
///The host application must return either [ServerTrustAuthResponse] instance with [ServerTrustAuthResponseAction.CANCEL] or [ServerTrustAuthResponseAction.PROCEED].
2019-11-02 03:16:47 +00:00
///
2019-11-08 18:12:21 +00:00
///[challenge] contains data about host, port, protocol, realm, etc. as specified in the [ServerTrustChallenge].
2019-11-02 03:16:47 +00:00
final Future < ServerTrustAuthResponse > Function ( InAppWebViewController controller , ServerTrustChallenge challenge ) onReceivedServerTrustAuthRequest ;
2019-11-08 18:12:21 +00:00
///Notify the host application to handle a SSL client certificate request.
///Webview stores the response in memory (for the life of the application) if [ClientCertResponseAction.PROCEED] or [ClientCertResponseAction.CANCEL]
///is called and does not call [onReceivedClientCertRequest] again for the same host and port pair.
///Note that, multiple layers in chromium network stack might be caching the responses.
2019-11-02 03:16:47 +00:00
///
2019-11-08 18:12:21 +00:00
///[challenge] contains data about host, port, protocol, realm, etc. as specified in the [ClientCertChallenge].
2019-11-02 03:16:47 +00:00
final Future < ClientCertResponse > Function ( InAppWebViewController controller , ClientCertChallenge challenge ) onReceivedClientCertRequest ;
///Event fired as find-on-page operations progress.
///The listener may be notified multiple times while the operation is underway, and the numberOfMatches value should not be considered final unless [isDoneCounting] is true.
///
///[activeMatchOrdinal] represents the zero-based ordinal of the currently selected match.
///
///[numberOfMatches] represents how many matches have been found.
///
///[isDoneCounting] whether the find operation has actually completed.
final void Function ( InAppWebViewController controller , int activeMatchOrdinal , int numberOfMatches , bool isDoneCounting ) onFindResultReceived ;
2019-11-08 18:12:21 +00:00
///Event fired when an `XMLHttpRequest` is sent to a server.
///It gives the host application a chance to take control over the request before sending it.
///
///[ajaxRequest] represents the `XMLHttpRequest`.
2019-11-05 02:44:22 +00:00
///
2019-11-08 18:12:21 +00:00
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`.
2019-11-16 11:41:30 +00:00
///Also, unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
2019-11-16 12:10:00 +00:00
///Inside the `window.addEventListener("flutterInAppBrowserPlatformReady")` event, the ajax requests will be intercept for sure.
2019-11-05 02:44:22 +00:00
final Future < AjaxRequest > Function ( InAppWebViewController controller , AjaxRequest ajaxRequest ) shouldInterceptAjaxRequest ;
2019-11-08 18:12:21 +00:00
///Event fired whenever the `readyState` attribute of an `XMLHttpRequest` changes.
///It gives the host application a chance to abort the request.
2019-11-05 02:44:22 +00:00
///
2019-11-08 18:12:21 +00:00
///[ajaxRequest] represents the [XMLHttpRequest].
///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`.
2019-11-16 11:41:30 +00:00
///Also, unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
2019-11-16 12:10:00 +00:00
///Inside the `window.addEventListener("flutterInAppBrowserPlatformReady")` event, the ajax requests will be intercept for sure.
2019-11-05 23:23:24 +00:00
final Future < AjaxRequestAction > Function ( InAppWebViewController controller , AjaxRequest ajaxRequest ) onAjaxReadyStateChange ;
2019-11-05 02:44:22 +00:00
2019-11-08 18:12:21 +00:00
///Event fired as an `XMLHttpRequest` progress.
///It gives the host application a chance to abort the request.
///
///[ajaxRequest] represents the [XMLHttpRequest].
2019-11-05 02:44:22 +00:00
///
2019-11-08 18:12:21 +00:00
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptAjaxRequest] option to `true`.
2019-11-16 11:41:30 +00:00
///Also, unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept ajax requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
2019-11-16 12:10:00 +00:00
///Inside the `window.addEventListener("flutterInAppBrowserPlatformReady")` event, the ajax requests will be intercept for sure.
2019-11-05 23:23:24 +00:00
final Future < AjaxRequestAction > Function ( InAppWebViewController controller , AjaxRequest ajaxRequest ) onAjaxProgress ;
2019-11-05 02:44:22 +00:00
2019-11-08 18:12:21 +00:00
///Event fired when an request is sent to a server through [Fetch API](https://developer.mozilla.org/it/docs/Web/API/Fetch_API).
///It gives the host application a chance to take control over the request before sending it.
///
///[fetchRequest] represents a resource request.
2019-11-05 02:44:22 +00:00
///
2019-11-08 18:12:21 +00:00
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useShouldInterceptFetchRequest] option to `true`.
2019-11-16 11:41:30 +00:00
///Also, unlike iOS that has [WKUserScript](https://developer.apple.com/documentation/webkit/wkuserscript) that
///can inject javascript code right after the document element is created but before any other content is loaded, in Android the javascript code
///used to intercept fetch requests is loaded as soon as possible so it won't be instantaneous as iOS but just after some milliseconds (< ~100ms).
///Inside the `window.addEventListener("flutterInAppBrowserPlatformReady")` event, the fetch requests will be intercept for sure.
2019-11-05 02:44:22 +00:00
final Future < FetchRequest > Function ( InAppWebViewController controller , FetchRequest fetchRequest ) shouldInterceptFetchRequest ;
2019-11-05 23:23:24 +00:00
///Event fired when the navigation state of the [InAppWebView] changes throught the usage of
///javascript **[History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API)** functions (`pushState()`, `replaceState()`) and `onpopstate` event.
///
///Also, the event is fired when the javascript `window.location` changes without reloading the webview (for example appending or modifying an hash to the url).
///
///[url] represents the new url.
final void Function ( InAppWebViewController controller , String url ) onNavigationStateChange ;
2019-11-02 03:16:47 +00:00
///Initial url that will be loaded.
final String initialUrl ;
///Initial asset file that will be loaded. See [InAppWebView.loadFile()] for explanation.
final String initialFile ;
///Initial [InAppWebViewInitialData] that will be loaded.
final InAppWebViewInitialData initialData ;
///Initial headers that will be used.
final Map < String , String > initialHeaders ;
///Initial options that will be used.
2019-11-04 00:39:23 +00:00
final InAppWebViewWidgetOptions initialOptions ;
2019-11-02 03:16:47 +00:00
/// `gestureRecognizers` specifies which gestures should be consumed by the web view.
/// It is possible for other gesture recognizers to be competing with the web view on pointer
/// events, e.g if the web view is inside a [ListView] the [ListView] will want to handle
/// vertical drags. The web view will claim gestures that are recognized by any of the
/// recognizers on this list.
/// When `gestureRecognizers` is empty or null, the web view will only handle pointer events for gestures that
/// were not claimed by any other gesture recognizer.
final Set < Factory < OneSequenceGestureRecognizer > > gestureRecognizers ;
const InAppWebView ( {
Key key ,
this . initialUrl = " about:blank " ,
this . initialFile ,
this . initialData ,
this . initialHeaders = const { } ,
2019-11-04 00:39:23 +00:00
this . initialOptions ,
2019-11-02 03:16:47 +00:00
this . onWebViewCreated ,
this . onLoadStart ,
this . onLoadStop ,
this . onLoadError ,
this . onConsoleMessage ,
this . onProgressChanged ,
this . shouldOverrideUrlLoading ,
this . onLoadResource ,
this . onScrollChanged ,
this . onDownloadStart ,
this . onLoadResourceCustomScheme ,
this . onTargetBlank ,
this . onGeolocationPermissionsShowPrompt ,
this . onJsAlert ,
this . onJsConfirm ,
this . onJsPrompt ,
this . onSafeBrowsingHit ,
this . onReceivedHttpAuthRequest ,
this . onReceivedServerTrustAuthRequest ,
this . onReceivedClientCertRequest ,
this . onFindResultReceived ,
2019-11-05 02:44:22 +00:00
this . shouldInterceptAjaxRequest ,
this . onAjaxReadyStateChange ,
2019-11-05 23:23:24 +00:00
this . onAjaxProgress ,
2019-11-05 02:44:22 +00:00
this . shouldInterceptFetchRequest ,
2019-11-05 23:23:24 +00:00
this . onNavigationStateChange ,
2019-11-02 03:16:47 +00:00
this . gestureRecognizers ,
} ) : super ( key: key ) ;
@ override
_InAppWebViewState createState ( ) = > _InAppWebViewState ( ) ;
}
class _InAppWebViewState extends State < InAppWebView > {
InAppWebViewController _controller ;
@ override
Widget build ( BuildContext context ) {
Map < String , dynamic > initialOptions = { } ;
2019-11-04 00:39:23 +00:00
initialOptions . addAll ( widget . initialOptions . inAppWebViewOptions ? . toMap ( ) ? ? { } ) ;
if ( Platform . isAndroid )
initialOptions . addAll ( widget . initialOptions . androidInAppWebViewOptions ? . toMap ( ) ? ? { } ) ;
else if ( Platform . isIOS )
initialOptions . addAll ( widget . initialOptions . iosInAppWebViewOptions ? . toMap ( ) ? ? { } ) ;
2019-11-02 03:16:47 +00:00
if ( defaultTargetPlatform = = TargetPlatform . android ) {
2019-11-02 18:58:01 +00:00
return AndroidView (
viewType: ' com.pichillilorenzo/flutter_inappwebview ' ,
onPlatformViewCreated: _onPlatformViewCreated ,
gestureRecognizers: widget . gestureRecognizers ,
layoutDirection: TextDirection . rtl ,
creationParams: < String , dynamic > {
' initialUrl ' : widget . initialUrl ,
' initialFile ' : widget . initialFile ,
' initialData ' : widget . initialData ? . toMap ( ) ,
' initialHeaders ' : widget . initialHeaders ,
' initialOptions ' : initialOptions
} ,
creationParamsCodec: const StandardMessageCodec ( ) ,
) ;
// onLongPress issue: https://github.com/flutter/plugins/blob/f31d16a6ca0c4bd6849cff925a00b6823973696b/packages/webview_flutter/lib/src/webview_android.dart#L31
/ * return GestureDetector (
2019-11-02 03:16:47 +00:00
onLongPress: ( ) { } ,
excludeFromSemantics: true ,
child: AndroidView (
viewType: ' com.pichillilorenzo/flutter_inappwebview ' ,
onPlatformViewCreated: _onPlatformViewCreated ,
gestureRecognizers: widget . gestureRecognizers ,
layoutDirection: TextDirection . rtl ,
creationParams: < String , dynamic > {
' initialUrl ' : widget . initialUrl ,
' initialFile ' : widget . initialFile ,
' initialData ' : widget . initialData ? . toMap ( ) ,
' initialHeaders ' : widget . initialHeaders ,
' initialOptions ' : initialOptions
} ,
creationParamsCodec: const StandardMessageCodec ( ) ,
) ,
2019-11-02 18:58:01 +00:00
) ; * /
2019-11-02 03:16:47 +00:00
} else if ( defaultTargetPlatform = = TargetPlatform . iOS ) {
return UiKitView (
viewType: ' com.pichillilorenzo/flutter_inappwebview ' ,
onPlatformViewCreated: _onPlatformViewCreated ,
gestureRecognizers: widget . gestureRecognizers ,
creationParams: < String , dynamic > {
' initialUrl ' : widget . initialUrl ,
' initialFile ' : widget . initialFile ,
' initialData ' : widget . initialData ? . toMap ( ) ,
' initialHeaders ' : widget . initialHeaders ,
' initialOptions ' : initialOptions
} ,
creationParamsCodec: const StandardMessageCodec ( ) ,
) ;
}
return Text (
' $ defaultTargetPlatform is not yet supported by the flutter_inappbrowser plugin ' ) ;
}
@ override
void didUpdateWidget ( InAppWebView oldWidget ) {
super . didUpdateWidget ( oldWidget ) ;
}
2019-11-07 23:32:29 +00:00
@ override
void dispose ( ) {
super . dispose ( ) ;
if ( Platform . isIOS )
_controller . _channel . invokeMethod ( ' removeFromSuperview ' ) ;
}
2019-11-02 03:16:47 +00:00
void _onPlatformViewCreated ( int id ) {
_controller = InAppWebViewController ( id , widget ) ;
if ( widget . onWebViewCreated ! = null ) {
widget . onWebViewCreated ( _controller ) ;
}
}
}
/// Controls an [InAppWebView] widget instance.
///
/// An [InAppWebViewController] instance can be obtained by setting the [InAppWebView.onWebViewCreated]
/// callback for an [InAppWebView] widget.
class InAppWebViewController {
InAppWebView _widget ;
MethodChannel _channel ;
Map < String , JavaScriptHandlerCallback > javaScriptHandlersMap = HashMap < String , JavaScriptHandlerCallback > ( ) ;
2019-11-10 13:11:30 +00:00
// ignore: unused_field
2019-11-02 03:16:47 +00:00
bool _isOpened = false ;
// ignore: unused_field
int _id ;
String _inAppBrowserUuid ;
InAppBrowser _inAppBrowser ;
InAppWebViewController ( int id , InAppWebView widget ) {
this . _id = id ;
this . _channel = MethodChannel ( ' com.pichillilorenzo/flutter_inappwebview_ $ id ' ) ;
this . _channel . setMethodCallHandler ( handleMethod ) ;
this . _widget = widget ;
}
InAppWebViewController . fromInAppBrowser ( String uuid , MethodChannel channel , InAppBrowser inAppBrowser ) {
this . _inAppBrowserUuid = uuid ;
this . _channel = channel ;
this . _inAppBrowser = inAppBrowser ;
}
Future < dynamic > handleMethod ( MethodCall call ) async {
switch ( call . method ) {
case " onLoadStart " :
String url = call . arguments [ " url " ] ;
if ( _widget ! = null & & _widget . onLoadStart ! = null )
_widget . onLoadStart ( this , url ) ;
else if ( _inAppBrowser ! = null )
_inAppBrowser . onLoadStart ( url ) ;
break ;
case " onLoadStop " :
String url = call . arguments [ " url " ] ;
if ( _widget ! = null & & _widget . onLoadStop ! = null )
_widget . onLoadStop ( this , url ) ;
else if ( _inAppBrowser ! = null )
_inAppBrowser . onLoadStop ( url ) ;
break ;
case " onLoadError " :
String url = call . arguments [ " url " ] ;
int code = call . arguments [ " code " ] ;
String message = call . arguments [ " message " ] ;
if ( _widget ! = null & & _widget . onLoadError ! = null )
_widget . onLoadError ( this , url , code , message ) ;
else if ( _inAppBrowser ! = null )
_inAppBrowser . onLoadError ( url , code , message ) ;
break ;
case " onProgressChanged " :
int progress = call . arguments [ " progress " ] ;
if ( _widget ! = null & & _widget . onProgressChanged ! = null )
_widget . onProgressChanged ( this , progress ) ;
else if ( _inAppBrowser ! = null )
_inAppBrowser . onProgressChanged ( progress ) ;
break ;
case " shouldOverrideUrlLoading " :
String url = call . arguments [ " url " ] ;
if ( _widget ! = null & & _widget . shouldOverrideUrlLoading ! = null )
_widget . shouldOverrideUrlLoading ( this , url ) ;
else if ( _inAppBrowser ! = null )
_inAppBrowser . shouldOverrideUrlLoading ( url ) ;
break ;
case " onConsoleMessage " :
String message = call . arguments [ " message " ] ;
ConsoleMessageLevel messageLevel = ConsoleMessageLevel . fromValue ( call . arguments [ " messageLevel " ] ) ;
2019-11-17 17:31:31 +00:00
ConsoleMessage consoleMessage = ConsoleMessage ( message: message , messageLevel: messageLevel ) ;
2019-11-02 03:16:47 +00:00
if ( _widget ! = null & & _widget . onConsoleMessage ! = null )
2019-11-10 13:11:30 +00:00
_widget . onConsoleMessage ( this , consoleMessage ) ;
2019-11-02 03:16:47 +00:00
else if ( _inAppBrowser ! = null )
2019-11-10 13:11:30 +00:00
_inAppBrowser . onConsoleMessage ( consoleMessage ) ;
2019-11-02 03:16:47 +00:00
break ;
case " onScrollChanged " :
int x = call . arguments [ " x " ] ;
int y = call . arguments [ " y " ] ;
if ( _widget ! = null & & _widget . onScrollChanged ! = null )
_widget . onScrollChanged ( this , x , y ) ;
else if ( _inAppBrowser ! = null )
_inAppBrowser . onScrollChanged ( x , y ) ;
break ;
case " onDownloadStart " :
String url = call . arguments [ " url " ] ;
if ( _widget ! = null & & _widget . onDownloadStart ! = null )
_widget . onDownloadStart ( this , url ) ;
else if ( _inAppBrowser ! = null )
_inAppBrowser . onDownloadStart ( url ) ;
break ;
case " onLoadResourceCustomScheme " :
String scheme = call . arguments [ " scheme " ] ;
String url = call . arguments [ " url " ] ;
if ( _widget ! = null & & _widget . onLoadResourceCustomScheme ! = null ) {
try {
var response = await _widget . onLoadResourceCustomScheme ( this , scheme , url ) ;
return ( response ! = null ) ? response . toJson ( ) : null ;
} catch ( error ) {
print ( error ) ;
return null ;
}
} else if ( _inAppBrowser ! = null ) {
try {
var response = await _inAppBrowser . onLoadResourceCustomScheme ( scheme , url ) ;
return ( response ! = null ) ? response . toJson ( ) : null ;
} catch ( error ) {
print ( error ) ;
return null ;
}
}
break ;
case " onTargetBlank " :
String url = call . arguments [ " url " ] ;
if ( _widget ! = null & & _widget . onTargetBlank ! = null )
_widget . onTargetBlank ( this , url ) ;
else if ( _inAppBrowser ! = null )
_inAppBrowser . onTargetBlank ( url ) ;
break ;
case " onGeolocationPermissionsShowPrompt " :
String origin = call . arguments [ " origin " ] ;
if ( _widget ! = null & & _widget . onGeolocationPermissionsShowPrompt ! = null )
return ( await _widget . onGeolocationPermissionsShowPrompt ( this , origin ) ) ? . toMap ( ) ;
else if ( _inAppBrowser ! = null )
return ( await _inAppBrowser . onGeolocationPermissionsShowPrompt ( origin ) ) ? . toMap ( ) ;
break ;
case " onJsAlert " :
String message = call . arguments [ " message " ] ;
if ( _widget ! = null & & _widget . onJsAlert ! = null )
return ( await _widget . onJsAlert ( this , message ) ) ? . toMap ( ) ;
else if ( _inAppBrowser ! = null )
return ( await _inAppBrowser . onJsAlert ( message ) ) ? . toMap ( ) ;
break ;
case " onJsConfirm " :
String message = call . arguments [ " message " ] ;
if ( _widget ! = null & & _widget . onJsConfirm ! = null )
return ( await _widget . onJsConfirm ( this , message ) ) ? . toMap ( ) ;
else if ( _inAppBrowser ! = null )
return ( await _inAppBrowser . onJsConfirm ( message ) ) ? . toMap ( ) ;
break ;
case " onJsPrompt " :
String message = call . arguments [ " message " ] ;
String defaultValue = call . arguments [ " defaultValue " ] ;
if ( _widget ! = null & & _widget . onJsPrompt ! = null )
return ( await _widget . onJsPrompt ( this , message , defaultValue ) ) ? . toMap ( ) ;
else if ( _inAppBrowser ! = null )
return ( await _inAppBrowser . onJsPrompt ( message , defaultValue ) ) ? . toMap ( ) ;
break ;
case " onSafeBrowsingHit " :
String url = call . arguments [ " url " ] ;
SafeBrowsingThreat threatType = SafeBrowsingThreat . fromValue ( call . arguments [ " threatType " ] ) ;
if ( _widget ! = null & & _widget . onJsPrompt ! = null )
return ( await _widget . onSafeBrowsingHit ( this , url , threatType ) ) ? . toMap ( ) ;
else if ( _inAppBrowser ! = null )
return ( await _inAppBrowser . onSafeBrowsingHit ( url , threatType ) ) ? . toMap ( ) ;
break ;
case " onReceivedHttpAuthRequest " :
String host = call . arguments [ " host " ] ;
String protocol = call . arguments [ " protocol " ] ;
String realm = call . arguments [ " realm " ] ;
int port = call . arguments [ " port " ] ;
int previousFailureCount = call . arguments [ " previousFailureCount " ] ;
var protectionSpace = ProtectionSpace ( host: host , protocol: protocol , realm: realm , port: port ) ;
var challenge = HttpAuthChallenge ( previousFailureCount: previousFailureCount , protectionSpace: protectionSpace ) ;
if ( _widget ! = null & & _widget . onReceivedHttpAuthRequest ! = null )
return ( await _widget . onReceivedHttpAuthRequest ( this , challenge ) ) ? . toMap ( ) ;
else if ( _inAppBrowser ! = null )
return ( await _inAppBrowser . onReceivedHttpAuthRequest ( challenge ) ) ? . toMap ( ) ;
break ;
case " onReceivedServerTrustAuthRequest " :
String host = call . arguments [ " host " ] ;
String protocol = call . arguments [ " protocol " ] ;
String realm = call . arguments [ " realm " ] ;
int port = call . arguments [ " port " ] ;
int error = call . arguments [ " error " ] ;
String message = call . arguments [ " message " ] ;
Uint8List serverCertificate = call . arguments [ " serverCertificate " ] ;
var protectionSpace = ProtectionSpace ( host: host , protocol: protocol , realm: realm , port: port ) ;
var challenge = ServerTrustChallenge ( protectionSpace: protectionSpace , error: error , message: message , serverCertificate: serverCertificate ) ;
if ( _widget ! = null & & _widget . onReceivedServerTrustAuthRequest ! = null )
return ( await _widget . onReceivedServerTrustAuthRequest ( this , challenge ) ) ? . toMap ( ) ;
else if ( _inAppBrowser ! = null )
return ( await _inAppBrowser . onReceivedServerTrustAuthRequest ( challenge ) ) ? . toMap ( ) ;
break ;
case " onReceivedClientCertRequest " :
String host = call . arguments [ " host " ] ;
String protocol = call . arguments [ " protocol " ] ;
String realm = call . arguments [ " realm " ] ;
int port = call . arguments [ " port " ] ;
var protectionSpace = ProtectionSpace ( host: host , protocol: protocol , realm: realm , port: port ) ;
var challenge = ClientCertChallenge ( protectionSpace: protectionSpace ) ;
if ( _widget ! = null & & _widget . onReceivedClientCertRequest ! = null )
return ( await _widget . onReceivedClientCertRequest ( this , challenge ) ) ? . toMap ( ) ;
else if ( _inAppBrowser ! = null )
return ( await _inAppBrowser . onReceivedClientCertRequest ( challenge ) ) ? . toMap ( ) ;
break ;
case " onFindResultReceived " :
int activeMatchOrdinal = call . arguments [ " activeMatchOrdinal " ] ;
int numberOfMatches = call . arguments [ " numberOfMatches " ] ;
bool isDoneCounting = call . arguments [ " isDoneCounting " ] ;
if ( _widget ! = null & & _widget . onReceivedClientCertRequest ! = null )
_widget . onFindResultReceived ( this , activeMatchOrdinal , numberOfMatches , isDoneCounting ) ;
else if ( _inAppBrowser ! = null )
_inAppBrowser . onFindResultReceived ( activeMatchOrdinal , numberOfMatches , isDoneCounting ) ;
break ;
2019-11-05 23:23:24 +00:00
case " onNavigationStateChange " :
String url = call . arguments [ " url " ] ;
if ( _widget ! = null & & _widget . onNavigationStateChange ! = null )
_widget . onNavigationStateChange ( this , url ) ;
else if ( _inAppBrowser ! = null )
_inAppBrowser . onNavigationStateChange ( url ) ;
break ;
2019-11-02 03:16:47 +00:00
case " onCallJsHandler " :
String handlerName = call . arguments [ " handlerName " ] ;
// decode args to json
List < dynamic > args = jsonDecode ( call . arguments [ " args " ] ) ;
2019-11-05 02:44:22 +00:00
switch ( handlerName ) {
case " onLoadResource " :
Map < dynamic , dynamic > argMap = args [ 0 ] ;
String initiatorType = argMap [ " initiatorType " ] ;
String url = argMap [ " name " ] ;
double startTime = argMap [ " startTime " ] is int ? argMap [ " startTime " ] . toDouble ( ) : argMap [ " startTime " ] ;
double duration = argMap [ " duration " ] is int ? argMap [ " duration " ] . toDouble ( ) : argMap [ " duration " ] ;
2019-11-10 13:11:30 +00:00
var response = new LoadedResource ( initiatorType: initiatorType , url: url , startTime: startTime , duration: duration ) ;
2019-11-05 02:44:22 +00:00
if ( _widget ! = null & & _widget . onLoadResource ! = null )
_widget . onLoadResource ( this , response ) ;
else if ( _inAppBrowser ! = null )
_inAppBrowser . onLoadResource ( response ) ;
return null ;
case " shouldInterceptAjaxRequest " :
Map < dynamic , dynamic > argMap = args [ 0 ] ;
dynamic data = argMap [ " data " ] ;
String method = argMap [ " method " ] ;
String url = argMap [ " url " ] ;
bool isAsync = argMap [ " isAsync " ] ;
String user = argMap [ " user " ] ;
String password = argMap [ " password " ] ;
bool withCredentials = argMap [ " withCredentials " ] ;
Map < dynamic , dynamic > headers = argMap [ " headers " ] ;
2019-11-10 23:16:38 +00:00
String responseType = argMap [ " responseType " ] ;
2019-11-05 02:44:22 +00:00
2019-11-10 23:16:38 +00:00
var request = new AjaxRequest ( data: data , method: method , url: url , isAsync: isAsync , user: user , password: password , withCredentials: withCredentials , headers: headers , responseType: responseType ) ;
2019-11-05 02:44:22 +00:00
if ( _widget ! = null & & _widget . shouldInterceptAjaxRequest ! = null )
return jsonEncode ( await _widget . shouldInterceptAjaxRequest ( this , request ) ) ;
2019-11-05 23:23:24 +00:00
else if ( _inAppBrowser ! = null )
return jsonEncode ( await _inAppBrowser . shouldInterceptAjaxRequest ( request ) ) ;
2019-11-05 02:44:22 +00:00
return null ;
case " onAjaxReadyStateChange " :
Map < dynamic , dynamic > argMap = args [ 0 ] ;
dynamic data = argMap [ " data " ] ;
String method = argMap [ " method " ] ;
String url = argMap [ " url " ] ;
bool isAsync = argMap [ " isAsync " ] ;
String user = argMap [ " user " ] ;
String password = argMap [ " password " ] ;
bool withCredentials = argMap [ " withCredentials " ] ;
Map < dynamic , dynamic > headers = argMap [ " headers " ] ;
int readyState = argMap [ " readyState " ] ;
int status = argMap [ " status " ] ;
String responseURL = argMap [ " responseURL " ] ;
String responseType = argMap [ " responseType " ] ;
2019-11-10 23:16:38 +00:00
dynamic response = argMap [ " response " ] ;
2019-11-05 02:44:22 +00:00
String responseText = argMap [ " responseText " ] ;
2019-11-10 23:16:38 +00:00
String responseXML = argMap [ " responseXML " ] ;
2019-11-05 02:44:22 +00:00
String statusText = argMap [ " statusText " ] ;
Map < dynamic , dynamic > responseHeaders = argMap [ " responseHeaders " ] ;
var request = new AjaxRequest ( data: data , method: method , url: url , isAsync: isAsync , user: user , password: password ,
withCredentials: withCredentials , headers: headers , readyState: AjaxRequestReadyState . fromValue ( readyState ) , status: status , responseURL: responseURL ,
2019-11-10 23:16:38 +00:00
responseType: responseType , response: response , responseText: responseText , responseXML: responseXML , statusText: statusText , responseHeaders: responseHeaders ) ;
2019-11-05 02:44:22 +00:00
if ( _widget ! = null & & _widget . onAjaxReadyStateChange ! = null )
return jsonEncode ( await _widget . onAjaxReadyStateChange ( this , request ) ) ;
2019-11-05 23:23:24 +00:00
else if ( _inAppBrowser ! = null )
return jsonEncode ( await _inAppBrowser . onAjaxReadyStateChange ( request ) ) ;
2019-11-05 02:44:22 +00:00
return null ;
2019-11-05 23:23:24 +00:00
case " onAjaxProgress " :
2019-11-05 02:44:22 +00:00
Map < dynamic , dynamic > argMap = args [ 0 ] ;
dynamic data = argMap [ " data " ] ;
String method = argMap [ " method " ] ;
String url = argMap [ " url " ] ;
bool isAsync = argMap [ " isAsync " ] ;
String user = argMap [ " user " ] ;
String password = argMap [ " password " ] ;
bool withCredentials = argMap [ " withCredentials " ] ;
Map < dynamic , dynamic > headers = argMap [ " headers " ] ;
int readyState = argMap [ " readyState " ] ;
int status = argMap [ " status " ] ;
String responseURL = argMap [ " responseURL " ] ;
String responseType = argMap [ " responseType " ] ;
2019-11-10 23:16:38 +00:00
dynamic response = argMap [ " response " ] ;
2019-11-05 02:44:22 +00:00
String responseText = argMap [ " responseText " ] ;
2019-11-10 23:16:38 +00:00
String responseXML = argMap [ " responseXML " ] ;
2019-11-05 02:44:22 +00:00
String statusText = argMap [ " statusText " ] ;
Map < dynamic , dynamic > responseHeaders = argMap [ " responseHeaders " ] ;
Map < dynamic , dynamic > eventMap = argMap [ " event " ] ;
2019-11-09 22:35:18 +00:00
AjaxRequestEvent event = AjaxRequestEvent ( lengthComputable: eventMap [ " lengthComputable " ] , loaded: eventMap [ " loaded " ] , total: eventMap [ " total " ] , type: AjaxRequestEventType . fromValue ( eventMap [ " type " ] ) ) ;
2019-11-05 02:44:22 +00:00
var request = new AjaxRequest ( data: data , method: method , url: url , isAsync: isAsync , user: user , password: password ,
withCredentials: withCredentials , headers: headers , readyState: AjaxRequestReadyState . fromValue ( readyState ) , status: status , responseURL: responseURL ,
2019-11-10 23:16:38 +00:00
responseType: responseType , response: response , responseText: responseText , responseXML: responseXML , statusText: statusText , responseHeaders: responseHeaders , event: event ) ;
2019-11-05 02:44:22 +00:00
2019-11-05 23:23:24 +00:00
if ( _widget ! = null & & _widget . onAjaxProgress ! = null )
return jsonEncode ( await _widget . onAjaxProgress ( this , request ) ) ;
else if ( _inAppBrowser ! = null )
return jsonEncode ( await _inAppBrowser . onAjaxProgress ( request ) ) ;
2019-11-05 02:44:22 +00:00
return null ;
case " shouldInterceptFetchRequest " :
Map < dynamic , dynamic > argMap = args [ 0 ] ;
String url = argMap [ " url " ] ;
String method = argMap [ " method " ] ;
Map < dynamic , dynamic > headers = argMap [ " headers " ] ;
2019-11-06 21:55:54 +00:00
Uint8List body = Uint8List . fromList ( argMap [ " body " ] . cast < int > ( ) ) ;
2019-11-05 02:44:22 +00:00
String mode = argMap [ " mode " ] ;
2019-11-06 21:55:54 +00:00
FetchRequestCredential credentials = FetchRequest . createFetchRequestCredentialFromMap ( argMap [ " credentials " ] ) ;
2019-11-05 02:44:22 +00:00
String cache = argMap [ " cache " ] ;
String redirect = argMap [ " redirect " ] ;
String referrer = argMap [ " referrer " ] ;
String referrerPolicy = argMap [ " referrerPolicy " ] ;
String integrity = argMap [ " integrity " ] ;
bool keepalive = argMap [ " keepalive " ] ;
var request = new FetchRequest ( url: url , method: method , headers: headers , body: body , mode: mode , credentials: credentials ,
cache: cache , redirect: redirect , referrer: referrer , referrerPolicy: referrerPolicy , integrity: integrity , keepalive: keepalive ) ;
if ( _widget ! = null & & _widget . shouldInterceptFetchRequest ! = null )
return jsonEncode ( await _widget . shouldInterceptFetchRequest ( this , request ) ) ;
2019-11-05 23:23:24 +00:00
else if ( _inAppBrowser ! = null )
return jsonEncode ( await _inAppBrowser . shouldInterceptFetchRequest ( request ) ) ;
2019-11-05 02:44:22 +00:00
return null ;
}
2019-11-02 03:16:47 +00:00
if ( javaScriptHandlersMap . containsKey ( handlerName ) ) {
// convert result to json
try {
return jsonEncode ( await javaScriptHandlersMap [ handlerName ] ( args ) ) ;
} catch ( error ) {
print ( error ) ;
return null ;
}
}
break ;
default :
throw UnimplementedError ( " Unimplemented ${ call . method } method " ) ;
}
}
///Gets the URL for the current page.
///This is not always the same as the URL passed to [InAppWebView.onLoadStarted] because although the load for that URL has begun, the current page may not have changed.
Future < String > getUrl ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
return await _channel . invokeMethod ( ' getUrl ' , args ) ;
}
///Gets the title for the current page.
Future < String > getTitle ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
return await _channel . invokeMethod ( ' getTitle ' , args ) ;
}
///Gets the progress for the current page. The progress value is between 0 and 100.
Future < int > getProgress ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
return await _channel . invokeMethod ( ' getProgress ' , args ) ;
}
2019-11-02 18:58:01 +00:00
///Gets the content html of the page. It first tries to get the content through javascript.
///If this doesn't work, it tries to get the content reading the file:
///- checking if it is an asset (`file:///`) or
///- downloading it using an `HttpClient` through the WebView's current url.
Future < String > getHtml ( ) async {
var html = " " ;
2019-11-04 00:39:23 +00:00
InAppWebViewWidgetOptions options = await getOptions ( ) ;
if ( options ! = null & & options . inAppWebViewOptions . javaScriptEnabled = = true ) {
2019-11-10 13:11:30 +00:00
html = await evaluateJavascript ( source : " window.document.getElementsByTagName('html')[0].outerHTML; " ) ;
2019-11-17 17:31:31 +00:00
if ( html ! = null & & html . isNotEmpty )
2019-11-02 18:58:01 +00:00
return html ;
}
var webviewUrl = await getUrl ( ) ;
if ( webviewUrl . startsWith ( " file:/// " ) ) {
var assetPathSplitted = webviewUrl . split ( " /flutter_assets/ " ) ;
var assetPath = assetPathSplitted [ assetPathSplitted . length - 1 ] ;
var bytes = await rootBundle . load ( assetPath ) ;
html = utf8 . decode ( bytes . buffer . asUint8List ( ) ) ;
}
else {
HttpClient client = new HttpClient ( ) ;
var url = Uri . parse ( webviewUrl ) ;
try {
var htmlRequest = await client . getUrl ( url ) ;
html = await ( await htmlRequest . close ( ) ) . transform ( Utf8Decoder ( ) ) . join ( ) ;
} catch ( e ) {
print ( e ) ;
}
}
return html ;
}
///Gets the list of all favicons for the current page.
Future < List < Favicon > > getFavicons ( ) async {
2019-11-02 03:16:47 +00:00
List < Favicon > favicons = [ ] ;
2019-11-02 18:58:01 +00:00
2019-11-02 03:16:47 +00:00
HttpClient client = new HttpClient ( ) ;
2019-11-02 18:58:01 +00:00
var webviewUrl = await getUrl ( ) ;
var url = ( webviewUrl . startsWith ( " file:/// " ) ) ? Uri . file ( webviewUrl ) : Uri . parse ( webviewUrl ) ;
String manifestUrl ;
2019-11-02 03:16:47 +00:00
2019-11-02 18:58:01 +00:00
var html = await getHtml ( ) ;
if ( html . isEmpty ) {
return favicons ;
}
2019-11-02 03:16:47 +00:00
2019-11-02 18:58:01 +00:00
var assetPathBase ;
if ( webviewUrl . startsWith ( " file:/// " ) ) {
var assetPathSplitted = webviewUrl . split ( " /flutter_assets/ " ) ;
assetPathBase = assetPathSplitted [ 0 ] + " /flutter_assets/ " ;
2019-11-02 03:16:47 +00:00
}
2019-11-02 18:58:01 +00:00
// get all link html elements
var document = parse ( html ) ;
var links = document . getElementsByTagName ( ' link ' ) ;
for ( var link in links ) {
var attributes = link . attributes ;
if ( attributes [ " rel " ] = = " manifest " ) {
manifestUrl = attributes [ " href " ] ;
if ( ! _isUrlAbsolute ( manifestUrl ) ) {
if ( manifestUrl . startsWith ( " / " ) ) {
manifestUrl = manifestUrl . substring ( 1 ) ;
2019-11-02 03:16:47 +00:00
}
2019-11-02 18:58:01 +00:00
manifestUrl = ( ( assetPathBase = = null ) ? url . scheme + " :// " + url . host + " / " : assetPathBase ) + manifestUrl ;
2019-11-02 03:16:47 +00:00
}
2019-11-02 18:58:01 +00:00
continue ;
2019-11-02 03:16:47 +00:00
}
2019-11-02 18:58:01 +00:00
if ( ! attributes [ " rel " ] . contains ( " icon " ) ) {
continue ;
}
favicons . addAll ( _createFavicons ( url , assetPathBase , attributes [ " href " ] , attributes [ " rel " ] , attributes [ " sizes " ] , false ) ) ;
}
2019-11-02 03:16:47 +00:00
2019-11-02 18:58:01 +00:00
// try to get /favicon.ico
2019-11-02 03:16:47 +00:00
try {
var faviconUrl = url . scheme + " :// " + url . host + " /favicon.ico " ;
await client . headUrl ( Uri . parse ( faviconUrl ) ) ;
favicons . add ( Favicon ( url: faviconUrl , rel: " shortcut icon " ) ) ;
2019-11-02 18:58:01 +00:00
} catch ( e ) {
print ( " /favicon.ico file not found: " + e . toString ( ) ) ;
}
2019-11-02 03:16:47 +00:00
2019-11-02 18:58:01 +00:00
// try to get the manifest file
HttpClientRequest manifestRequest ;
HttpClientResponse manifestResponse ;
bool manifestFound = false ;
if ( manifestUrl = = null ) {
manifestUrl = url . scheme + " :// " + url . host + " /manifest.json " ;
}
2019-11-02 03:16:47 +00:00
try {
2019-11-02 18:58:01 +00:00
manifestRequest = await client . getUrl ( Uri . parse ( manifestUrl ) ) ;
manifestResponse = await manifestRequest . close ( ) ;
manifestFound = manifestResponse . statusCode = = 200 & & manifestResponse . headers . contentType ? . mimeType = = " application/json " ;
2019-11-02 03:16:47 +00:00
} catch ( e ) {
2019-11-02 18:58:01 +00:00
print ( " Manifest file not found: " + e . toString ( ) ) ;
2019-11-02 03:16:47 +00:00
}
2019-11-02 18:58:01 +00:00
if ( manifestFound ) {
Map < String , dynamic > manifest = json . decode ( await manifestResponse . transform ( Utf8Decoder ( ) ) . join ( ) ) ;
2019-11-02 03:16:47 +00:00
if ( manifest . containsKey ( " icons " ) ) {
for ( Map < String , dynamic > icon in manifest [ " icons " ] ) {
2019-11-02 18:58:01 +00:00
favicons . addAll ( _createFavicons ( url , assetPathBase , icon [ " src " ] , icon [ " rel " ] , icon [ " sizes " ] , true ) ) ;
2019-11-02 03:16:47 +00:00
}
}
}
2019-11-02 18:58:01 +00:00
return favicons ;
}
bool _isUrlAbsolute ( String url ) {
return url . startsWith ( " http:// " ) | | url . startsWith ( " https:// " ) ;
}
List < Favicon > _createFavicons ( Uri url , String assetPathBase , String urlIcon , String rel , String sizes , bool isManifest ) {
List < Favicon > favicons = [ ] ;
List < String > urlSplitted = urlIcon . split ( " / " ) ;
if ( ! _isUrlAbsolute ( urlIcon ) ) {
if ( urlIcon . startsWith ( " / " ) ) {
urlIcon = urlIcon . substring ( 1 ) ;
}
urlIcon = ( ( assetPathBase = = null ) ? url . scheme + " :// " + url . host + " / " : assetPathBase ) + urlIcon ;
}
if ( isManifest ) {
rel = ( sizes ! = null ) ? urlSplitted [ urlSplitted . length - 1 ] . replaceFirst ( " - " + sizes , " " ) . split ( " " ) [ 0 ] . split ( " . " ) [ 0 ] : null ;
}
if ( sizes ! = null & & sizes . isNotEmpty & & sizes ! = " any " ) {
List < String > sizesSplitted = sizes . split ( " " ) ;
for ( String size in sizesSplitted ) {
int width = int . parse ( size . split ( " x " ) [ 0 ] ) ;
int height = int . parse ( size . split ( " x " ) [ 1 ] ) ;
favicons . add ( Favicon ( url: urlIcon , rel: rel , width: width , height: height ) ) ;
}
} else {
favicons . add ( Favicon ( url: urlIcon , rel: rel , width: null , height: null ) ) ;
}
return favicons ;
2019-11-02 03:16:47 +00:00
}
///Loads the given [url] with optional [headers] specified as a map from name to value.
2019-11-10 13:11:30 +00:00
Future < void > loadUrl ( { @ required String url , Map < String , String > headers = const { } } ) async {
2019-11-02 03:16:47 +00:00
assert ( url ! = null & & url . isNotEmpty ) ;
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( message: ' Cannot laod $ url ! ' ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' url ' , ( ) = > url ) ;
args . putIfAbsent ( ' headers ' , ( ) = > headers ) ;
await _channel . invokeMethod ( ' loadUrl ' , args ) ;
}
///Loads the given [url] with [postData] using `POST` method into this WebView.
2019-11-10 13:11:30 +00:00
Future < void > postUrl ( { @ required String url , @ required Uint8List postData } ) async {
2019-11-02 03:16:47 +00:00
assert ( url ! = null & & url . isNotEmpty ) ;
assert ( postData ! = null ) ;
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( message: ' Cannot laod $ url ! ' ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' url ' , ( ) = > url ) ;
args . putIfAbsent ( ' postData ' , ( ) = > postData ) ;
await _channel . invokeMethod ( ' postUrl ' , args ) ;
}
///Loads the given [data] into this WebView, using [baseUrl] as the base URL for the content.
///The [mimeType] parameter specifies the format of the data.
///The [encoding] parameter specifies the encoding of the data.
2019-11-10 13:11:30 +00:00
Future < void > loadData ( { @ required String data , String mimeType = " text/html " , String encoding = " utf8 " , String baseUrl = " about:blank " } ) async {
2019-11-02 03:16:47 +00:00
assert ( data ! = null ) ;
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' data ' , ( ) = > data ) ;
args . putIfAbsent ( ' mimeType ' , ( ) = > mimeType ) ;
args . putIfAbsent ( ' encoding ' , ( ) = > encoding ) ;
args . putIfAbsent ( ' baseUrl ' , ( ) = > baseUrl ) ;
await _channel . invokeMethod ( ' loadData ' , args ) ;
}
///Loads the given [assetFilePath] with optional [headers] specified as a map from name to value.
///
///To be able to load your local files (assets, js, css, etc.), you need to add them in the `assets` section of the `pubspec.yaml` file, otherwise they cannot be found!
///
///Example of a `pubspec.yaml` file:
///```yaml
///...
///
///# The following section is specific to Flutter.
///flutter:
///
/// # The following line ensures that the Material Icons font is
/// # included with your application, so that you can use the icons in
/// # the material Icons class.
/// uses-material-design: true
///
/// assets:
2019-11-16 11:41:30 +00:00
/// - assets/index.html
2019-11-02 03:16:47 +00:00
/// - assets/css/
/// - assets/images/
///
///...
///```
///Example of a `main.dart` file:
///```dart
///...
2019-11-16 11:41:30 +00:00
///inAppBrowser.loadFile("assets/index.html");
2019-11-02 03:16:47 +00:00
///...
///```
2019-11-10 13:11:30 +00:00
Future < void > loadFile ( { @ required String assetFilePath , Map < String , String > headers = const { } } ) async {
2019-11-02 03:16:47 +00:00
assert ( assetFilePath ! = null & & assetFilePath . isNotEmpty ) ;
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( message: ' Cannot laod $ assetFilePath ! ' ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' url ' , ( ) = > assetFilePath ) ;
args . putIfAbsent ( ' headers ' , ( ) = > headers ) ;
await _channel . invokeMethod ( ' loadFile ' , args ) ;
}
2019-11-05 02:44:22 +00:00
///Reloads the [InAppWebView].
2019-11-02 03:16:47 +00:00
Future < void > reload ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
await _channel . invokeMethod ( ' reload ' , args ) ;
}
2019-11-05 02:44:22 +00:00
///Goes back in the history of the [InAppWebView].
2019-11-02 03:16:47 +00:00
Future < void > goBack ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
await _channel . invokeMethod ( ' goBack ' , args ) ;
}
///Returns a boolean value indicating whether the [InAppWebView] can move backward.
Future < bool > canGoBack ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
return await _channel . invokeMethod ( ' canGoBack ' , args ) ;
}
2019-11-05 02:44:22 +00:00
///Goes forward in the history of the [InAppWebView].
2019-11-02 03:16:47 +00:00
Future < void > goForward ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
await _channel . invokeMethod ( ' goForward ' , args ) ;
}
///Returns a boolean value indicating whether the [InAppWebView] can move forward.
Future < bool > canGoForward ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
return await _channel . invokeMethod ( ' canGoForward ' , args ) ;
}
///Goes to the history item that is the number of steps away from the current item. Steps is negative if backward and positive if forward.
2019-11-10 13:11:30 +00:00
Future < void > goBackOrForward ( { @ required int steps } ) async {
2019-11-02 03:16:47 +00:00
assert ( steps ! = null ) ;
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' steps ' , ( ) = > steps ) ;
await _channel . invokeMethod ( ' goBackOrForward ' , args ) ;
}
2019-11-10 13:11:30 +00:00
///Returns a boolean value indicating whether the WebView can go back or forward the given number of steps. Steps is negative if backward and positive if forward.
Future < bool > canGoBackOrForward ( { @ required int steps } ) async {
2019-11-02 03:16:47 +00:00
assert ( steps ! = null ) ;
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' steps ' , ( ) = > steps ) ;
return await _channel . invokeMethod ( ' canGoBackOrForward ' , args ) ;
}
///Navigates to a [WebHistoryItem] from the back-forward [WebHistory.list] and sets it as the current item.
2019-11-10 13:11:30 +00:00
Future < void > goTo ( { @ required WebHistoryItem historyItem } ) async {
await goBackOrForward ( steps: historyItem . offset ) ;
2019-11-02 03:16:47 +00:00
}
2019-11-10 13:11:30 +00:00
///Check if the WebView instance is in a loading state.
2019-11-02 03:16:47 +00:00
Future < bool > isLoading ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
return await _channel . invokeMethod ( ' isLoading ' , args ) ;
}
2019-11-10 13:11:30 +00:00
///Stops the WebView from loading.
2019-11-02 03:16:47 +00:00
Future < void > stopLoading ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
await _channel . invokeMethod ( ' stopLoading ' , args ) ;
}
2019-11-10 13:11:30 +00:00
///Evaluates JavaScript code into the WebView and returns the result of the evaluation.
2019-11-17 17:31:31 +00:00
Future < dynamic > evaluateJavascript ( { @ required String source } ) async {
2019-11-02 03:16:47 +00:00
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' source ' , ( ) = > source ) ;
2019-11-17 17:31:31 +00:00
var data = await _channel . invokeMethod ( ' evaluateJavascript ' , args ) ;
if ( data ! = null & & Platform . isAndroid )
data = json . decode ( data ) ;
return data ;
2019-11-02 03:16:47 +00:00
}
2019-11-10 13:11:30 +00:00
///Injects an external JavaScript file into the WebView from a defined url.
Future < void > injectJavascriptFileFromUrl ( { @ required String urlFile } ) async {
2019-11-02 03:16:47 +00:00
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' urlFile ' , ( ) = > urlFile ) ;
2019-11-05 02:44:22 +00:00
await _channel . invokeMethod ( ' injectJavascriptFileFromUrl ' , args ) ;
}
2019-11-10 13:11:30 +00:00
///Injects a JavaScript file into the WebView from the flutter assets directory.
Future < void > injectJavascriptFileFromAsset ( { @ required String assetFilePath } ) async {
2019-11-05 02:44:22 +00:00
String source = await rootBundle . loadString ( assetFilePath ) ;
2019-11-10 13:11:30 +00:00
await evaluateJavascript ( source : source ) ;
2019-11-02 03:16:47 +00:00
}
2019-11-10 13:11:30 +00:00
///Injects CSS into the WebView.
Future < void > injectCSSCode ( { @ required String source } ) async {
2019-11-02 03:16:47 +00:00
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' source ' , ( ) = > source ) ;
2019-11-05 02:44:22 +00:00
await _channel . invokeMethod ( ' injectCSSCode ' , args ) ;
2019-11-02 03:16:47 +00:00
}
2019-11-10 13:11:30 +00:00
///Injects an external CSS file into the WebView from a defined url.
Future < void > injectCSSFileFromUrl ( { @ required String urlFile } ) async {
2019-11-02 03:16:47 +00:00
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' urlFile ' , ( ) = > urlFile ) ;
await _channel . invokeMethod ( ' injectStyleFile ' , args ) ;
}
2019-11-10 13:11:30 +00:00
///Injects a CSS file into the WebView from the flutter assets directory.
Future < void > injectCSSFileFromAsset ( { @ required String assetFilePath } ) async {
2019-11-05 02:44:22 +00:00
String source = await rootBundle . loadString ( assetFilePath ) ;
2019-11-10 13:11:30 +00:00
await injectCSSCode ( source : source ) ;
2019-11-05 02:44:22 +00:00
}
2019-11-02 03:16:47 +00:00
///Adds a JavaScript message handler [callback] ([JavaScriptHandlerCallback]) that listen to post messages sent from JavaScript by the handler with name [handlerName].
///
///The Android implementation uses [addJavascriptInterface](https://developer.android.com/reference/android/webkit/WebView#addJavascriptInterface(java.lang.Object,%20java.lang.String)).
///The iOS implementation uses [addScriptMessageHandler](https://developer.apple.com/documentation/webkit/wkusercontentcontroller/1537172-addscriptmessagehandler?language=objc)
///
///The JavaScript function that can be used to call the handler is `window.flutter_inappbrowser.callHandler(handlerName <String>, ...args)`, where `args` are [rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters).
///The `args` will be stringified automatically using `JSON.stringify(args)` method and then they will be decoded on the Dart side.
///
2019-11-16 11:41:30 +00:00
///In order to call `window.flutter_inappbrowser.callHandler(handlerName <String>, ...args)` properly, you need to wait and listen the JavaScript event `flutterInAppBrowserPlatformReady`.
///This event will be dispatch as soon as the platform (Android or iOS) is ready to handle the `callHandler` method.
///```javascript
/// window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
/// console.log("ready");
/// });
///```
///
2019-11-02 03:16:47 +00:00
///`window.flutter_inappbrowser.callHandler` returns a JavaScript [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
///that can be used to get the json result returned by [JavaScriptHandlerCallback].
///In this case, simply return data that you want to send and it will be automatically json encoded using [jsonEncode] from the `dart:convert` library.
///
///So, on the JavaScript side, to get data coming from the Dart side, you will use:
///```html
///<script>
2019-11-16 11:41:30 +00:00
/// window.addEventListener("flutterInAppBrowserPlatformReady", function(event) {
2019-11-02 03:16:47 +00:00
/// window.flutter_inappbrowser.callHandler('handlerFoo').then(function(result) {
/// console.log(result, typeof result);
/// console.log(JSON.stringify(result));
/// });
///
/// window.flutter_inappbrowser.callHandler('handlerFooWithArgs', 1, true, ['bar', 5], {foo: 'baz'}).then(function(result) {
/// console.log(result, typeof result);
/// console.log(JSON.stringify(result));
/// });
2019-11-16 11:41:30 +00:00
/// });
2019-11-02 03:16:47 +00:00
///</script>
///```
2019-11-16 11:41:30 +00:00
///
///Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
///```dart
/// // Inject JavaScript that will receive data back from Flutter
/// inAppWebViewController.evaluateJavascript(source: """
/// window.flutter_inappbrowser.callHandler('test', 'Text from Javascript').then(function(result) {
/// console.log(result);
/// });
/// """);
///```
2019-11-10 13:11:30 +00:00
void addJavaScriptHandler ( { @ required String handlerName , @ required JavaScriptHandlerCallback callback } ) {
2019-11-05 23:37:36 +00:00
assert ( ! javaScriptHandlerForbiddenNames . contains ( handlerName ) ) ;
2019-11-02 03:16:47 +00:00
this . javaScriptHandlersMap [ handlerName ] = ( callback ) ;
}
///Removes a JavaScript message handler previously added with the [addJavaScriptHandler()] associated to [handlerName] key.
///Returns the value associated with [handlerName] before it was removed.
///Returns `null` if [handlerName] was not found.
2019-11-10 13:11:30 +00:00
JavaScriptHandlerCallback removeJavaScriptHandler ( { @ required String handlerName } ) {
2019-11-02 03:16:47 +00:00
return this . javaScriptHandlersMap . remove ( handlerName ) ;
}
///Takes a screenshot (in PNG format) of the WebView's visible viewport and returns a `Uint8List`. Returns `null` if it wasn't be able to take it.
///
///**NOTE for iOS**: available from iOS 11.0+.
Future < Uint8List > takeScreenshot ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
return await _channel . invokeMethod ( ' takeScreenshot ' , args ) ;
}
2019-11-10 13:11:30 +00:00
///Sets the WebView options with the new [options] and evaluates them.
Future < void > setOptions ( { @ required InAppWebViewWidgetOptions options } ) async {
2019-11-02 03:16:47 +00:00
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
2019-11-04 00:39:23 +00:00
Map < String , dynamic > optionsMap = { } ;
optionsMap . addAll ( options . inAppWebViewOptions ? . toMap ( ) ? ? { } ) ;
if ( Platform . isAndroid )
optionsMap . addAll ( options . androidInAppWebViewOptions ? . toMap ( ) ? ? { } ) ;
else if ( Platform . isIOS )
optionsMap . addAll ( options . iosInAppWebViewOptions ? . toMap ( ) ? ? { } ) ;
args . putIfAbsent ( ' options ' , ( ) = > optionsMap ) ;
2019-11-02 03:16:47 +00:00
await _channel . invokeMethod ( ' setOptions ' , args ) ;
}
2019-11-10 13:11:30 +00:00
///Gets the current WebView options. Returns the options with `null` value if they are not set yet.
2019-11-04 00:39:23 +00:00
Future < InAppWebViewWidgetOptions > getOptions ( ) async {
2019-11-02 03:16:47 +00:00
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
2019-11-04 00:39:23 +00:00
InAppWebViewWidgetOptions inAppWebViewWidgetOptions = InAppWebViewWidgetOptions ( ) ;
2019-11-02 18:58:01 +00:00
Map < dynamic , dynamic > options = await _channel . invokeMethod ( ' getOptions ' , args ) ;
2019-11-04 00:39:23 +00:00
if ( options ! = null ) {
2019-11-02 18:58:01 +00:00
options = options . cast < String , dynamic > ( ) ;
2019-11-04 00:39:23 +00:00
inAppWebViewWidgetOptions . inAppWebViewOptions = InAppWebViewOptions . fromMap ( options ) ;
if ( Platform . isAndroid )
inAppWebViewWidgetOptions . androidInAppWebViewOptions = AndroidInAppWebViewOptions . fromMap ( options ) ;
else if ( Platform . isIOS )
inAppWebViewWidgetOptions . iosInAppWebViewOptions = IosInAppWebViewOptions . fromMap ( options ) ;
}
return inAppWebViewWidgetOptions ;
2019-11-02 03:16:47 +00:00
}
///Gets the WebHistory for this WebView. This contains the back/forward list for use in querying each item in the history stack.
///This contains only a snapshot of the current state.
///Multiple calls to this method may return different objects.
///The object returned from this method will not be updated to reflect any new state.
Future < WebHistory > getCopyBackForwardList ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
Map < dynamic , dynamic > result = await _channel . invokeMethod ( ' getCopyBackForwardList ' , args ) ;
result = result . cast < String , dynamic > ( ) ;
List < dynamic > historyListMap = result [ " history " ] ;
historyListMap = historyListMap . cast < LinkedHashMap < dynamic , dynamic > > ( ) ;
int currentIndex = result [ " currentIndex " ] ;
List < WebHistoryItem > historyList = List ( ) ;
for ( var i = 0 ; i < historyListMap . length ; i + + ) {
LinkedHashMap < dynamic , dynamic > historyItem = historyListMap [ i ] ;
2019-11-10 13:11:30 +00:00
historyList . add ( WebHistoryItem ( originalUrl: historyItem [ " originalUrl " ] , title: historyItem [ " title " ] , url: historyItem [ " url " ] , index: i , offset: i - currentIndex ) ) ;
2019-11-02 03:16:47 +00:00
}
2019-11-10 13:11:30 +00:00
return WebHistory ( list: historyList , currentIndex: currentIndex ) ;
2019-11-02 03:16:47 +00:00
}
///Starts Safe Browsing initialization.
///
///URL loads are not guaranteed to be protected by Safe Browsing until after the this method returns true.
///Safe Browsing is not fully supported on all devices. For those devices this method will returns false.
///
///This should not be called if Safe Browsing has been disabled by manifest tag
///or [AndroidInAppWebViewOptions.safeBrowsingEnabled]. This prepares resources used for Safe Browsing.
///
///**NOTE**: available only for Android.
Future < bool > startSafeBrowsing ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
return await _channel . invokeMethod ( ' startSafeBrowsing ' , args ) ;
}
///Sets the list of hosts (domain names/IP addresses) that are exempt from SafeBrowsing checks. The list is global for all the WebViews.
///
/// Each rule should take one of these:
///| Rule | Example | Matches Subdomain |
///| -- | -- | -- |
///| HOSTNAME | example.com | Yes |
///| .HOSTNAME | .example.com | No |
///| IPV4_LITERAL | 192.168.1.1 | No |
///| IPV6_LITERAL_WITH_BRACKETS | [10:20:30:40:50:60:70:80] | No |
///
///All other rules, including wildcards, are invalid. The correct syntax for hosts is defined by [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3.2.2).
///
///[hosts] represents the list of hosts. This value must never be null.
///
///**NOTE**: available only for Android.
2019-11-10 13:11:30 +00:00
Future < bool > setSafeBrowsingWhitelist ( { @ required List < String > hosts } ) async {
2019-11-02 03:16:47 +00:00
assert ( hosts ! = null ) ;
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' hosts ' , ( ) = > hosts ) ;
return await _channel . invokeMethod ( ' setSafeBrowsingWhitelist ' , args ) ;
}
///Returns a URL pointing to the privacy policy for Safe Browsing reporting. This value will never be `null`.
///
///**NOTE**: available only for Android.
Future < String > getSafeBrowsingPrivacyPolicyUrl ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
return await _channel . invokeMethod ( ' getSafeBrowsingPrivacyPolicyUrl ' , args ) ;
}
///Clears all the webview's cache
Future < void > clearCache ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
await _channel . invokeMethod ( ' clearCache ' , args ) ;
}
///Clears the SSL preferences table stored in response to proceeding with SSL certificate errors.
///
///**NOTE**: available only for Android.
Future < void > clearSslPreferences ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
await _channel . invokeMethod ( ' clearSslPreferences ' , args ) ;
}
///Clears the client certificate preferences stored in response to proceeding/cancelling client cert requests.
///Note that WebView automatically clears these preferences when the system keychain is updated.
///The preferences are shared by all the WebViews that are created by the embedder application.
///
///**NOTE**: On iOS certificate-based credentials are never stored permanently.
///
///**NOTE**: available only for Android.
Future < void > clearClientCertPreferences ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
await _channel . invokeMethod ( ' clearClientCertPreferences ' , args ) ;
}
///Finds all instances of find on the page and highlights them. Notifies [onFindResultReceived] listener.
///
///[find] represents the string to find.
///
///**NOTE**: on Android, it finds all instances asynchronously. Successive calls to this will cancel any pending searches.
///
///**NOTE**: on iOS, this is implemented using CSS and Javascript.
2019-11-10 13:11:30 +00:00
Future < void > findAllAsync ( { @ required String find } ) async {
2019-11-02 03:16:47 +00:00
assert ( find ! = null ) ;
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' find ' , ( ) = > find ) ;
await _channel . invokeMethod ( ' findAllAsync ' , args ) ;
}
///Highlights and scrolls to the next match found by [findAllAsync()]. Notifies [onFindResultReceived] listener.
///
///[forward] represents the direction to search.
///
///**NOTE**: on iOS, this is implemented using CSS and Javascript.
2019-11-10 13:11:30 +00:00
Future < void > findNext ( { @ required bool forward } ) async {
2019-11-02 03:16:47 +00:00
assert ( forward ! = null ) ;
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
args . putIfAbsent ( ' forward ' , ( ) = > forward ) ;
await _channel . invokeMethod ( ' findNext ' , args ) ;
}
///Clears the highlighting surrounding text matches created by [findAllAsync()].
///
///**NOTE**: on iOS, this is implemented using CSS and Javascript.
Future < void > clearMatches ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
if ( _inAppBrowserUuid ! = null & & _inAppBrowser ! = null ) {
_inAppBrowser . throwIsNotOpened ( ) ;
args . putIfAbsent ( ' uuid ' , ( ) = > _inAppBrowserUuid ) ;
}
await _channel . invokeMethod ( ' clearMatches ' , args ) ;
}
2019-11-04 00:39:23 +00:00
///Gets the html (with javascript) of the Chromium's t-rex runner game. Used in combination with [getTRexRunnerCss()].
Future < String > getTRexRunnerHtml ( ) async {
return await rootBundle . loadString ( " packages/flutter_inappbrowser/t_rex_runner/t-rex.html " ) ;
}
///Gets the css of the Chromium's t-rex runner game. Used in combination with [getTRexRunnerHtml()].
Future < String > getTRexRunnerCss ( ) async {
return await rootBundle . loadString ( " packages/flutter_inappbrowser/t_rex_runner/t-rex.css " ) ;
}
2019-11-02 03:16:47 +00:00
}