Commit 64246d84 authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

Added 'values' property for all the custom Enums, bug fixes

parent b0c06c61
......@@ -3,15 +3,21 @@
- Added `requestFocusNodeHref`, `requestImageRef`, `getMetaTags`, `getMetaThemeColor`, `getScrollX`, `getScrollY`, `getCertificate` webview methods
- Added `WebStorage`, `LocalStorage` and `SessionStorage` class to manage `window.localStorage` and `window.sessionStorage` JavaScript [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API)
- Added `supportZoom` webview option also on iOS
- Added `HttpOnly`, `SameSite` set cookie options
- Added `HttpOnly`, `SameSite` cookie options
- Updated `Cookie` class
- Added `animated` option to `scrollTo` and `scrollBy` webview methods
- Added error and message to the `ServerTrustChallenge` class for iOS (class used by the `onReceivedServerTrustAuthRequest` event)
- Added `contentInsetAdjustmentBehavior` webview iOS-specific option
- Added `copy` and `copyWithValue` methods for webview class options
- Added `copy` methods for webview class options
- Added `SslCertificate` class and `X509Certificate` class and parser
- Added `values` property for all the custom Enums
- Updated Android workaround to hide the Keyboard when the user click outside on something not focusable such as input or a textarea.
- Fixed `zoomBy`, `setOptions` webview methods on Android
- Fixed `databaseEnabled` android webview option default value to `true`
- Fixed `verticalScrollBarEnabled` and `horizontalScrollBarEnabled` on Android
- Fixed error caused by `pauseTimers` on iOS when the WebView has been disposed
- Fixed `ignoresViewportScaleLimits`, `dataDetectorTypes`, `suppressesIncrementalRendering`, `selectionGranularity` iOS-specific option when used in `initialOptions`
- Fixed `getFavicons` method
### BREAKING CHANGES
......
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
import android.content.Context;
import android.content.MutableContextWrapper;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Handler;
......@@ -64,6 +65,11 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
"- See the official wiki here: https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects\n\n\n");
}
// MutableContextWrapper mMutableContext = new MutableContextWrapper(Shared.activity);
// webView = new InAppWebView(mMutableContext, this, id, options, contextMenu, containerView);
// displayListenerProxy.onPostWebViewInitialization(displayManager);
// mMutableContext.setBaseContext(context);
webView = new InAppWebView(Shared.activity, this, id, options, contextMenu, containerView);
displayListenerProxy.onPostWebViewInitialization(displayManager);
......
......@@ -28,6 +28,9 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.webkit.CookieManager;
import android.webkit.DownloadListener;
import android.webkit.ValueCallback;
......@@ -70,6 +73,7 @@ import java.util.regex.Pattern;
import io.flutter.plugin.common.MethodChannel;
import okhttp3.OkHttpClient;
import static android.content.Context.INPUT_METHOD_SERVICE;
import static com.pichillilorenzo.flutter_inappwebview.InAppWebView.PreferredContentModeOptionType.fromValue;
final public class InAppWebView extends InputAwareWebView {
......@@ -204,7 +208,7 @@ final public class InAppWebView extends InputAwareWebView {
" };" +
" function handleEvent(e) {" +
" var self = this;" +
" if (window." + variableForShouldInterceptAjaxRequestJS + " == null || window." + variableForShouldInterceptAjaxRequestJS + " == true) {" +
" if (" + variableForShouldInterceptAjaxRequestJS + " == null || " + variableForShouldInterceptAjaxRequestJS + " == true) {" +
" var headers = this.getAllResponseHeaders();" +
" var responseHeaders = {};" +
" if (headers != null) {" +
......@@ -255,12 +259,12 @@ final public class InAppWebView extends InputAwareWebView {
" };" +
" ajax.prototype.send = function(data) {" +
" var self = this;" +
" if (window." + variableForShouldInterceptAjaxRequestJS + " == null || window." + variableForShouldInterceptAjaxRequestJS + " == true) {" +
" if (" + variableForShouldInterceptAjaxRequestJS + " == null || " + variableForShouldInterceptAjaxRequestJS + " == true) {" +
" if (!this._flutter_inappwebview_already_onreadystatechange_wrapped) {" +
" this._flutter_inappwebview_already_onreadystatechange_wrapped = true;" +
" var onreadystatechange = this.onreadystatechange;" +
" this.onreadystatechange = function() {" +
" if (window." + variableForShouldInterceptAjaxRequestJS + " == null || window." + variableForShouldInterceptAjaxRequestJS + " == true) {" +
" if (" + variableForShouldInterceptAjaxRequestJS + " == null || " + variableForShouldInterceptAjaxRequestJS + " == true) {" +
" var headers = this.getAllResponseHeaders();" +
" var responseHeaders = {};" +
" if (headers != null) {" +
......@@ -588,26 +592,6 @@ final public class InAppWebView extends InputAwareWebView {
" });" +
"})();";
// android Workaround to hide the Keyboard when the user click outside
// on something not focusable such as input or a textarea.
static final String androidKeyboardWorkaroundFocusoutEventJS = "(function(){" +
" var isFocusin = false;" +
" document.addEventListener('focusin', function(e) {" +
" var nodeName = e.target.nodeName.toLowerCase();" +
" var isInputButton = nodeName === 'input' && e.target.type != null && e.target.type === 'button';" +
" isFocusin = (['a', 'area', 'button', 'details', 'iframe', 'select', 'summary'].indexOf(nodeName) >= 0 || isInputButton) ? false : true;" +
" });" +
" document.addEventListener('focusout', function(e) {" +
" isFocusin = false;" +
" setTimeout(function() {" +
isActiveElementInputEditableJS +
" if (!isFocusin && !isActiveElementEditable) {" +
" window." + JavaScriptBridgeInterface.name + ".callHandler('androidKeyboardWorkaroundFocusoutEvent');" +
" }" +
" }, 300);" +
" });" +
"})();";
public InAppWebView(Context context) {
super(context);
}
......@@ -705,8 +689,9 @@ final public class InAppWebView extends InputAwareWebView {
settings.setUseWideViewPort(options.useWideViewPort);
settings.setSupportZoom(options.supportZoom);
settings.setTextZoom(options.textZoom);
setVerticalScrollBarEnabled(options.verticalScrollBarEnabled);
setHorizontalScrollBarEnabled(options.horizontalScrollBarEnabled);
setVerticalScrollBarEnabled(!options.disableVerticalScroll && options.verticalScrollBarEnabled);
setHorizontalScrollBarEnabled(!options.disableHorizontalScroll && options.horizontalScrollBarEnabled);
if (options.transparentBackground)
setBackgroundColor(Color.TRANSPARENT);
......@@ -780,8 +765,6 @@ final public class InAppWebView extends InputAwareWebView {
options.scrollBarFadeDuration = getScrollBarFadeDuration();
}
setVerticalScrollbarPosition(options.verticalScrollbarPosition);
setVerticalScrollBarEnabled(!options.disableVerticalScroll);
setHorizontalScrollBarEnabled(!options.disableHorizontalScroll);
setOverScrollMode(options.overScrollMode);
if (options.networkAvailable != null) {
setNetworkAvailable(options.networkAvailable);
......@@ -1065,29 +1048,41 @@ final public class InAppWebView extends InputAwareWebView {
headlessHandler.post(new Runnable() {
@Override
public void run() {
int height = (int) (getContentHeight() * scale + 0.5);
Bitmap b = Bitmap.createBitmap( getWidth(),
height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
draw(c);
int scrollOffset = (getScrollY() + getMeasuredHeight() > b.getHeight())
? b.getHeight() : getScrollY();
Bitmap resized = Bitmap.createBitmap(
b, 0, scrollOffset, b.getWidth(), getMeasuredHeight());
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
resized.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
try {
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
Log.e(LOG_TAG, e.getMessage());
int height = (int) (getContentHeight() * scale + 0.5);
Bitmap b = Bitmap.createBitmap(getWidth(),
height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
draw(c);
int scrollOffset = (getScrollY() + getMeasuredHeight() > b.getHeight())
? b.getHeight() : getScrollY();
Bitmap resized = Bitmap.createBitmap(
b, 0, scrollOffset, b.getWidth(), getMeasuredHeight());
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
resized.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
try {
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
String errorMessage = e.getMessage();
if (errorMessage != null) {
Log.e(LOG_TAG, errorMessage);
}
}
resized.recycle();
result.success(byteArrayOutputStream.toByteArray());
} catch (IllegalArgumentException e) {
String errorMessage = e.getMessage();
if (errorMessage != null) {
Log.e(LOG_TAG, errorMessage);
}
result.success(null);
}
resized.recycle();
result.success(byteArrayOutputStream.toByteArray());
}
});
}
......@@ -1367,10 +1362,10 @@ final public class InAppWebView extends InputAwareWebView {
setVerticalScrollbarPosition(newOptions.verticalScrollbarPosition);
if (newOptionsMap.get("disableVerticalScroll") != null && options.disableVerticalScroll != newOptions.disableVerticalScroll)
setVerticalScrollBarEnabled(!newOptions.disableVerticalScroll);
setVerticalScrollBarEnabled(!newOptions.disableVerticalScroll && newOptions.verticalScrollBarEnabled);
if (newOptionsMap.get("disableHorizontalScroll") != null && options.disableHorizontalScroll != newOptions.disableHorizontalScroll)
setHorizontalScrollBarEnabled(!newOptions.disableHorizontalScroll);
setHorizontalScrollBarEnabled(!newOptions.disableHorizontalScroll && newOptions.horizontalScrollBarEnabled);
if (newOptionsMap.get("overScrollMode") != null && !options.overScrollMode.equals(newOptions.overScrollMode))
setOverScrollMode(newOptions.overScrollMode);
......@@ -1600,6 +1595,31 @@ final public class InAppWebView extends InputAwareWebView {
return super.dispatchTouchEvent(event);
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
InputConnection connection = super.onCreateInputConnection(outAttrs);
if (connection == null && containerView != null) {
// workaround to hide the Keyboard when the user click outside
// on something not focusable such as input or a textarea.
containerView
.getHandler()
.postDelayed(
new Runnable() {
@Override
public void run() {
InputMethodManager imm =
(InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
if (imm != null && !imm.isAcceptingText()) {
imm.hideSoftInputFromWindow(
containerView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
},
128);
}
return connection;
}
@Override
public ActionMode startActionMode(ActionMode.Callback callback) {
return rebuildActionMode(super.startActionMode(callback), callback);
......
......@@ -185,9 +185,6 @@ public class InAppWebViewClient extends WebViewClient {
js += InAppWebView.resourceObserverJS.replaceAll("[\r\n]+", "");
}
js += InAppWebView.checkGlobalKeyDownEventToHideContextMenuJS.replaceAll("[\r\n]+", "");
if (flutterWebView != null) {
js += InAppWebView.androidKeyboardWorkaroundFocusoutEventJS.replaceAll("[\r\n]+", "");
}
js += InAppWebView.printJS.replaceAll("[\r\n]+", "");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
......
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.4.4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.9/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.0+hotfix.6/","dependencies":[]}],"android":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.4.4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.9/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.0+hotfix.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+3/","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"e2e","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos"]},{"name":"path_provider_macos","dependencies":[]},{"name":"permission_handler","dependencies":[]}],"date_created":"2020-06-14 18:36:37.641339","version":"1.17.1"}
\ No newline at end of file
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.4.4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.10/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.1/","dependencies":[]}],"android":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.4.4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.10/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.1/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+3/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.0.1+1/","dependencies":[]}],"windows":[],"web":[]},"dependencyGraph":[{"name":"e2e","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"permission_handler","dependencies":[]}],"date_created":"2020-06-18 15:48:06.962625","version":"1.17.3"}
\ No newline at end of file
......@@ -24,7 +24,6 @@
</header>
<main role="main" class="inner cover">
<input type="text">
<h1 class="cover-heading">Inline WebView</h1>
<img src="images/flutter-logo.svg" alt="flutter logo">
<a href="index.html"><img src="images/flutter-logo.svg" alt="flutter logo"></a>
......
......@@ -2,11 +2,10 @@
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/lorenzopichilli/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example"
export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
export "FLUTTER_FRAMEWORK_DIR=/Users/lorenzopichilli/flutter/bin/cache/artifacts/engine/ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "TRACK_WIDGET_CREATION=true"
......@@ -26,25 +26,25 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
contextMenu = ContextMenu(
menuItems: [
ContextMenuItem(androidId: 1, iosId: "1", title: "Special", action: () async {
print("Menu item Special clicked!");
//print("Menu item Special clicked!");
print(await webView.getSelectedText());
await webView.clearFocus();
})
],
options: ContextMenuOptions(
hideDefaultSystemContextMenuItems: true
hideDefaultSystemContextMenuItems: false
),
onCreateContextMenu: (hitTestResult) async {
print("onCreateContextMenu");
//print("onCreateContextMenu");
print(hitTestResult.extra);
print(await webView.getSelectedText());
},
onHideContextMenu: () {
print("onHideContextMenu");
//print("onHideContextMenu");
},
onContextMenuActionItemClicked: (contextMenuItemClicked) async {
var id = (Platform.isAndroid) ? contextMenuItemClicked.androidId : contextMenuItemClicked.iosId;
print("onContextMenuActionItemClicked: " + id.toString() + " " + contextMenuItemClicked.title);
// print("onContextMenuActionItemClicked: " + id.toString() + " " + contextMenuItemClicked.title);
}
);
}
......@@ -80,8 +80,8 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: InAppWebView(
contextMenu: contextMenu,
initialUrl: "https://github.com/flutter",
// initialFile: "assets/index.html",
// initialUrl: "https://github.com/flutter",
initialFile: "assets/index.html",
initialHeaders: {},
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
......
......@@ -27,6 +27,7 @@
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/build" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/ios/Flutter/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/example/ios/Flutter/App.framework/flutter_assets/packages" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/.pub" />
<excludeFolder url="file://$MODULE_DIR$/flutter_inappbrowser_tests/build" />
......
......@@ -320,7 +320,7 @@ let interceptAjaxRequestsJS = """
};
function handleEvent(e) {
var self = this;
if (window.\(variableForShouldInterceptAjaxRequestJS) == null || window.\(variableForShouldInterceptAjaxRequestJS) == true) {
if (\(variableForShouldInterceptAjaxRequestJS) == null || \(variableForShouldInterceptAjaxRequestJS) == true) {
var headers = this.getAllResponseHeaders();
var responseHeaders = {};
if (headers != null) {
......@@ -371,12 +371,12 @@ let interceptAjaxRequestsJS = """
};
ajax.prototype.send = function(data) {
var self = this;
if (window.\(variableForShouldInterceptAjaxRequestJS) == null || window.\(variableForShouldInterceptAjaxRequestJS) == true) {
if (\(variableForShouldInterceptAjaxRequestJS) == null || \(variableForShouldInterceptAjaxRequestJS) == true) {
if (!this._flutter_inappwebview_already_onreadystatechange_wrapped) {
this._flutter_inappwebview_already_onreadystatechange_wrapped = true;
var onreadystatechange = this.onreadystatechange;
this.onreadystatechange = function() {
if (window.\(variableForShouldInterceptAjaxRequestJS) == null || window.\(variableForShouldInterceptAjaxRequestJS) == true) {
if (\(variableForShouldInterceptAjaxRequestJS) == null || \(variableForShouldInterceptAjaxRequestJS) == true) {
var headers = this.getAllResponseHeaders();
var responseHeaders = {};
if (headers != null) {
......@@ -1029,143 +1029,130 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
configuration.userContentController = WKUserContentController()
configuration.preferences = WKPreferences()
if (options?.transparentBackground)! {
isOpaque = false
backgroundColor = UIColor.clear
scrollView.backgroundColor = UIColor.clear
}
// prevent webView from bouncing
if (options?.disallowOverScroll)! {
if responds(to: #selector(getter: scrollView)) {
scrollView.bounces = false
if let options = options {
if options.transparentBackground {
isOpaque = false
backgroundColor = UIColor.clear
scrollView.backgroundColor = UIColor.clear
}
else {
for subview: UIView in subviews {
if subview is UIScrollView {
(subview as! UIScrollView).bounces = false
// prevent webView from bouncing
if options.disallowOverScroll {
if responds(to: #selector(getter: scrollView)) {
scrollView.bounces = false
}
else {
for subview: UIView in subviews {
if subview is UIScrollView {
(subview as! UIScrollView).bounces = false
}
}
}
}
}
let originalViewPortMetaTagContentJSScript = WKUserScript(source: originalViewPortMetaTagContentJS, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
configuration.userContentController.addUserScript(originalViewPortMetaTagContentJSScript)
if !(options?.supportZoom)! {
let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'); document.getElementsByTagName('head')[0].appendChild(meta);"
let userScript = WKUserScript(source: jscript, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
configuration.userContentController.addUserScript(userScript)
} else if (options?.enableViewportScale)! {
let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);"
let userScript = WKUserScript(source: jscript, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
configuration.userContentController.addUserScript(userScript)
}
let promisePolyfillJSScript = WKUserScript(source: promisePolyfillJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(promisePolyfillJSScript)
let javaScriptBridgeJSScript = WKUserScript(source: javaScriptBridgeJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(javaScriptBridgeJSScript)
configuration.userContentController.add(self, name: "callHandler")
let consoleLogJSScript = WKUserScript(source: consoleLogJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(consoleLogJSScript)
configuration.userContentController.add(self, name: "consoleLog")
configuration.userContentController.add(self, name: "consoleDebug")
configuration.userContentController.add(self, name: "consoleError")
configuration.userContentController.add(self, name: "consoleInfo")
configuration.userContentController.add(self, name: "consoleWarn")
let findElementsAtPointJSScript = WKUserScript(source: findElementsAtPointJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(findElementsAtPointJSScript)
let printJSScript = WKUserScript(source: printJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(printJSScript)
let lastTouchedAnchorOrImageJSScript = WKUserScript(source: lastTouchedAnchorOrImageJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(lastTouchedAnchorOrImageJSScript)
if (options?.useOnLoadResource)! {
let resourceObserverJSScript = WKUserScript(source: resourceObserverJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(resourceObserverJSScript)
}
let findTextHighlightJSScript = WKUserScript(source: findTextHighlightJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(findTextHighlightJSScript)
configuration.userContentController.add(self, name: "onFindResultReceived")
if (options?.useShouldInterceptAjaxRequest)! {
let interceptAjaxRequestsJSScript = WKUserScript(source: interceptAjaxRequestsJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(interceptAjaxRequestsJSScript)
}
if (options?.useShouldInterceptFetchRequest)! {
let interceptFetchRequestsJSScript = WKUserScript(source: interceptFetchRequestsJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(interceptFetchRequestsJSScript)
}
if #available(iOS 11.0, *) {
accessibilityIgnoresInvertColors = (options?.accessibilityIgnoresInvertColors)!
scrollView.contentInsetAdjustmentBehavior =
UIScrollView.ContentInsetAdjustmentBehavior.init(rawValue: (options?.contentInsetAdjustmentBehavior)!)!
}
configuration.suppressesIncrementalRendering = (options?.suppressesIncrementalRendering)!
allowsBackForwardNavigationGestures = (options?.allowsBackForwardNavigationGestures)!
if #available(iOS 9.0, *) {
allowsLinkPreview = (options?.allowsLinkPreview)!
configuration.allowsAirPlayForMediaPlayback = (options?.allowsAirPlayForMediaPlayback)!
configuration.allowsPictureInPictureMediaPlayback = (options?.allowsPictureInPictureMediaPlayback)!
if (options?.applicationNameForUserAgent != nil && (options?.applicationNameForUserAgent)! != "") {
configuration.applicationNameForUserAgent = (options?.applicationNameForUserAgent)!
let originalViewPortMetaTagContentJSScript = WKUserScript(source: originalViewPortMetaTagContentJS, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
configuration.userContentController.addUserScript(originalViewPortMetaTagContentJSScript)
if !options.supportZoom {
let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'); document.getElementsByTagName('head')[0].appendChild(meta);"
let userScript = WKUserScript(source: jscript, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
configuration.userContentController.addUserScript(userScript)
} else if options.enableViewportScale {
let jscript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);"
let userScript = WKUserScript(source: jscript, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
configuration.userContentController.addUserScript(userScript)
}
if (options?.userAgent != nil && (options?.userAgent)! != "") {
customUserAgent = (options?.userAgent)!
let promisePolyfillJSScript = WKUserScript(source: promisePolyfillJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(promisePolyfillJSScript)
let javaScriptBridgeJSScript = WKUserScript(source: javaScriptBridgeJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(javaScriptBridgeJSScript)
configuration.userContentController.add(self, name: "callHandler")
let consoleLogJSScript = WKUserScript(source: consoleLogJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(consoleLogJSScript)
configuration.userContentController.add(self, name: "consoleLog")
configuration.userContentController.add(self, name: "consoleDebug")
configuration.userContentController.add(self, name: "consoleError")
configuration.userContentController.add(self, name: "consoleInfo")
configuration.userContentController.add(self, name: "consoleWarn")
let findElementsAtPointJSScript = WKUserScript(source: findElementsAtPointJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(findElementsAtPointJSScript)
let printJSScript = WKUserScript(source: printJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(printJSScript)
let lastTouchedAnchorOrImageJSScript = WKUserScript(source: lastTouchedAnchorOrImageJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(lastTouchedAnchorOrImageJSScript)
if options.useOnLoadResource {
let resourceObserverJSScript = WKUserScript(source: resourceObserverJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(resourceObserverJSScript)
}
}
configuration.preferences.javaScriptCanOpenWindowsAutomatically = (options?.javaScriptCanOpenWindowsAutomatically)!
configuration.preferences.javaScriptEnabled = (options?.javaScriptEnabled)!
configuration.preferences.minimumFontSize = CGFloat((options?.minimumFontSize)!)
configuration.selectionGranularity = WKSelectionGranularity.init(rawValue: (options?.selectionGranularity)!)!
if #available(iOS 10.0, *) {
configuration.ignoresViewportScaleLimits = (options?.ignoresViewportScaleLimits)!
var dataDetectorTypes = WKDataDetectorTypes.init(rawValue: 0)
for type in options?.dataDetectorTypes ?? [] {
let dataDetectorType = InAppWebView.getDataDetectorType(type: type)
dataDetectorTypes = WKDataDetectorTypes(rawValue: dataDetectorTypes.rawValue | dataDetectorType.rawValue)
let findTextHighlightJSScript = WKUserScript(source: findTextHighlightJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(findTextHighlightJSScript)
configuration.userContentController.add(self, name: "onFindResultReceived")
if options.useShouldInterceptAjaxRequest {
let interceptAjaxRequestsJSScript = WKUserScript(source: interceptAjaxRequestsJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(interceptAjaxRequestsJSScript)
}
configuration.dataDetectorTypes = dataDetectorTypes
}
if #available(iOS 13.0, *) {
configuration.preferences.isFraudulentWebsiteWarningEnabled = (options?.isFraudulentWebsiteWarningEnabled)!
if options?.preferredContentMode != nil {
configuration.defaultWebpagePreferences.preferredContentMode = WKWebpagePreferences.ContentMode(rawValue: (options?.preferredContentMode)!)!
if options.useShouldInterceptFetchRequest {
let interceptFetchRequestsJSScript = WKUserScript(source: interceptFetchRequestsJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(interceptFetchRequestsJSScript)
}
scrollView.automaticallyAdjustsScrollIndicatorInsets = (options?.automaticallyAdjustsScrollIndicatorInsets)!
}
scrollView.showsVerticalScrollIndicator = !(options?.disableVerticalScroll)!
scrollView.showsHorizontalScrollIndicator = !(options?.disableHorizontalScroll)!
scrollView.showsVerticalScrollIndicator = (options?.verticalScrollBarEnabled)!
scrollView.showsHorizontalScrollIndicator = (options?.horizontalScrollBarEnabled)!
if #available(iOS 11.0, *) {
accessibilityIgnoresInvertColors = options.accessibilityIgnoresInvertColors
scrollView.contentInsetAdjustmentBehavior =
UIScrollView.ContentInsetAdjustmentBehavior.init(rawValue: options.contentInsetAdjustmentBehavior)!
}
allowsBackForwardNavigationGestures = options.allowsBackForwardNavigationGestures
if #available(iOS 9.0, *) {
allowsLinkPreview = options.allowsLinkPreview
configuration.allowsAirPlayForMediaPlayback = options.allowsAirPlayForMediaPlayback
configuration.allowsPictureInPictureMediaPlayback = options.allowsPictureInPictureMediaPlayback
if !options.applicationNameForUserAgent.isEmpty {
configuration.applicationNameForUserAgent = options.applicationNameForUserAgent
}
if !options.userAgent.isEmpty {
customUserAgent = options.userAgent
}
}
configuration.preferences.javaScriptCanOpenWindowsAutomatically = options.javaScriptCanOpenWindowsAutomatically
configuration.preferences.javaScriptEnabled = options.javaScriptEnabled
configuration.preferences.minimumFontSize = CGFloat(options.minimumFontSize)
if #available(iOS 13.0, *) {
configuration.preferences.isFraudulentWebsiteWarningEnabled = options.isFraudulentWebsiteWarningEnabled
configuration.defaultWebpagePreferences.preferredContentMode = WKWebpagePreferences.ContentMode(rawValue: options.preferredContentMode)!
scrollView.automaticallyAdjustsScrollIndicatorInsets = options.automaticallyAdjustsScrollIndicatorInsets
}
scrollView.showsVerticalScrollIndicator = !options.disableVerticalScroll
scrollView.showsHorizontalScrollIndicator = !options.disableHorizontalScroll
scrollView.showsVerticalScrollIndicator = options.verticalScrollBarEnabled
scrollView.showsHorizontalScrollIndicator = options.horizontalScrollBarEnabled
scrollView.decelerationRate = InAppWebView.getDecelerationRate(type: (options?.decelerationRate)!)
scrollView.alwaysBounceVertical = (options?.alwaysBounceVertical)!
scrollView.alwaysBounceHorizontal = (options?.alwaysBounceHorizontal)!
scrollView.scrollsToTop = (options?.scrollsToTop)!
scrollView.isPagingEnabled = (options?.isPagingEnabled)!
scrollView.maximumZoomScale = CGFloat((options?.maximumZoomScale)!)
scrollView.minimumZoomScale = CGFloat((options?.minimumZoomScale)!)
// options.debuggingEnabled is always enabled for iOS.
if (options?.clearCache)! {
clearCache()
scrollView.decelerationRate = InAppWebView.getDecelerationRate(type: options.decelerationRate)
scrollView.alwaysBounceVertical = options.alwaysBounceVertical
scrollView.alwaysBounceHorizontal = options.alwaysBounceHorizontal
scrollView.scrollsToTop = options.scrollsToTop
scrollView.isPagingEnabled = options.isPagingEnabled
scrollView.maximumZoomScale = CGFloat(options.maximumZoomScale)
scrollView.minimumZoomScale = CGFloat(options.minimumZoomScale)
// options.debuggingEnabled is always enabled for iOS.
if options.clearCache {
clearCache()
}
}
}
......@@ -1261,43 +1248,51 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
configuration.processPool = WKProcessPoolManager.sharedProcessPool
if #available(iOS 10.0, *) {
configuration.mediaTypesRequiringUserActionForPlayback = ((options?.mediaPlaybackRequiresUserGesture)!) ? .all : []
} else {
// Fallback on earlier versions
configuration.mediaPlaybackRequiresUserAction = (options?.mediaPlaybackRequiresUserGesture)!
}
configuration.allowsInlineMediaPlayback = (options?.allowsInlineMediaPlayback)!
if #available(iOS 11.0, *) {
if let schemes = options?.resourceCustomSchemes {
for scheme in schemes {
configuration.setURLSchemeHandler(CustomeSchemeHandler(), forURLScheme: scheme)
if let options = options {
configuration.allowsInlineMediaPlayback = options.allowsInlineMediaPlayback
configuration.suppressesIncrementalRendering = options.suppressesIncrementalRendering
configuration.selectionGranularity = WKSelectionGranularity.init(rawValue: options.selectionGranularity)!
if #available(iOS 9.0, *) {
if options.incognito {
configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent()
} else if options.cacheEnabled {
configuration.websiteDataStore = WKWebsiteDataStore.default()
}
}
}
if #available(iOS 9.0, *) {
if ((options?.incognito)!) {
configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent()
} else if ((options?.cacheEnabled)!) {
configuration.websiteDataStore = WKWebsiteDataStore.default()
if #available(iOS 10.0, *) {
configuration.ignoresViewportScaleLimits = options.ignoresViewportScaleLimits
var dataDetectorTypes = WKDataDetectorTypes.init(rawValue: 0)
for type in options.dataDetectorTypes {
let dataDetectorType = InAppWebView.getDataDetectorType(type: type)
dataDetectorTypes = WKDataDetectorTypes(rawValue: dataDetectorTypes.rawValue | dataDetectorType.rawValue)
}
configuration.dataDetectorTypes = dataDetectorTypes
configuration.mediaTypesRequiringUserActionForPlayback = options.mediaPlaybackRequiresUserGesture ? .all : []
} else {
// Fallback on earlier versions
configuration.mediaPlaybackRequiresUserAction = options.mediaPlaybackRequiresUserGesture
}
}
if #available(iOS 11.0, *) {
if((options?.sharedCookiesEnabled)!) {
// More info to sending cookies with WKWebView
// https://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview/26577303#26577303
// Set Cookies in iOS 11 and above, initialize websiteDataStore before setting cookies
// See also https://forums.developer.apple.com/thread/97194
// check if websiteDataStore has not been initialized before
if(!(options?.incognito)! && !(options?.cacheEnabled)!) {
configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent()
if #available(iOS 11.0, *) {
for scheme in options.resourceCustomSchemes {
configuration.setURLSchemeHandler(CustomeSchemeHandler(), forURLScheme: scheme)
}
for cookie in HTTPCookieStorage.shared.cookies ?? [] {
configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
if options.sharedCookiesEnabled {
// More info to sending cookies with WKWebView
// https://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview/26577303#26577303
// Set Cookies in iOS 11 and above, initialize websiteDataStore before setting cookies
// See also https://forums.developer.apple.com/thread/97194
// check if websiteDataStore has not been initialized before
if(!options.incognito && options.cacheEnabled) {
configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent()
}
for cookie in HTTPCookieStorage.shared.cookies ?? [] {
configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
}
}
}
......@@ -2804,17 +2799,21 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
public func pauseTimers() {
isPausedTimers = true
let script = "alert();";
self.evaluateJavaScript(script, completionHandler: nil)
if !isPausedTimers {
isPausedTimers = true
let script = "alert();";
self.evaluateJavaScript(script, completionHandler: nil)
}
}
public func resumeTimers() {
if let completionHandler = isPausedTimersCompletionHandler {
completionHandler()
isPausedTimersCompletionHandler = nil
if isPausedTimers {
if let completionHandler = isPausedTimersCompletionHandler {
self.isPausedTimersCompletionHandler = nil
completionHandler()
}
isPausedTimers = false
}
isPausedTimers = false
}
public func printCurrentPage(printCompletionHandler: ((_ completed: Bool, _ error: Error?) -> Void)?) {
......@@ -2925,6 +2924,10 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
}
public func dispose() {
if isPausedTimers, let completionHandler = isPausedTimersCompletionHandler {
isPausedTimersCompletionHandler = nil
completionHandler()
}
stopLoading()
configuration.userContentController.removeScriptMessageHandler(forName: "consoleLog")
configuration.userContentController.removeScriptMessageHandler(forName: "consoleDebug")
......
......@@ -4,7 +4,7 @@ class ASN1DistinguishedNames {
const ASN1DistinguishedNames._internal(this._oid, this._representation);
static List<ASN1DistinguishedNames> values = [
static final Set<ASN1DistinguishedNames> values = [
ASN1DistinguishedNames.COMMON_NAME,
ASN1DistinguishedNames.DN_QUALIFIER,
ASN1DistinguishedNames.SERIAL_NUMBER,
......@@ -17,10 +17,12 @@ class ASN1DistinguishedNames {
ASN1DistinguishedNames.STATE_OR_PROVINCE_NAME,
ASN1DistinguishedNames.COUNTRY_NAME,
ASN1DistinguishedNames.EMAIL,
];
].toSet();
static ASN1DistinguishedNames fromValue(String oid) {
return ASN1DistinguishedNames.values.firstWhere((element) => element.oid() == oid, orElse: () => null);
if (oid != null)
return ASN1DistinguishedNames.values.firstWhere((element) => element.oid() == oid, orElse: () => null);
return null;
}
String oid() => _oid;
......
......@@ -3,12 +3,12 @@ class ASN1IdentifierClass {
const ASN1IdentifierClass._internal(this._value);
static List<ASN1IdentifierClass> values = [
static final Set<ASN1IdentifierClass> values = [
ASN1IdentifierClass.UNIVERSAL,
ASN1IdentifierClass.APPLICATION,
ASN1IdentifierClass.CONTEXT_SPECIFIC,
ASN1IdentifierClass.PRIVATE,
];
].toSet();
static ASN1IdentifierClass fromValue(int value) {
if (value != null)
......@@ -47,7 +47,7 @@ class ASN1IdentifierTagNumber {
const ASN1IdentifierTagNumber._internal(this._value);
static List<ASN1IdentifierTagNumber> values = [
static final Set<ASN1IdentifierTagNumber> values = [
ASN1IdentifierTagNumber.END_OF_CONTENT,
ASN1IdentifierTagNumber.BOOLEAN,
ASN1IdentifierTagNumber.INTEGER,
......@@ -77,7 +77,7 @@ class ASN1IdentifierTagNumber {
ASN1IdentifierTagNumber.UNIVERSAL_STRING,
ASN1IdentifierTagNumber.CHARACTER_STRING,
ASN1IdentifierTagNumber.BMP_STRING,
];
].toSet();
static ASN1IdentifierTagNumber fromValue(int value) {
if (value != null)
......
......@@ -3,7 +3,7 @@ class KeyUsage {
const KeyUsage._internal(this._value);
static List<KeyUsage> values = [
static final Set<KeyUsage> values = [
KeyUsage.digitalSignature,
KeyUsage.nonRepudiation,
KeyUsage.keyEncipherment,
......@@ -13,7 +13,7 @@ class KeyUsage {
KeyUsage.cRLSign,
KeyUsage.encipherOnly,
KeyUsage.decipherOnly,
];
].toSet();
static KeyUsage fromIndex(int value) {
return KeyUsage.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
......
......@@ -3,7 +3,7 @@ class OID {
const OID._internal(this._value);
static List<OID> values = [
static final Set<OID> values = [
OID.etsiQcsCompliance,
OID.etsiQcsRetentionPeriod,
OID.etsiQcsQcSSCD,
......@@ -100,7 +100,7 @@ class OID {
OID.codeSigning,
OID.emailProtection,
OID.timeStamping,
];
].toSet();
static OID fromValue(String value) {
return OID.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
......
......@@ -287,10 +287,18 @@ class _InAppWebViewState extends State<InAppWebView> {
@override
Widget build(BuildContext context) {
if (defaultTargetPlatform == TargetPlatform.android) {
var gestureRecognizers = widget.gestureRecognizers;
if (gestureRecognizers == null) {
gestureRecognizers = <Factory<OneSequenceGestureRecognizer>>[
Factory<OneSequenceGestureRecognizer>(
() => EagerGestureRecognizer(),
),
].toSet();
}
return AndroidView(
viewType: 'com.pichillilorenzo/flutter_inappwebview',
onPlatformViewCreated: _onPlatformViewCreated,
gestureRecognizers: widget.gestureRecognizers,
gestureRecognizers: gestureRecognizers,
layoutDirection: TextDirection.rtl,
creationParams: <String, dynamic>{
'initialUrl': '${Uri.parse(widget.initialUrl)}',
......
import 'dart:developer';
import 'dart:io';
import 'dart:async';
import 'dart:collection';
......@@ -13,8 +12,6 @@ import 'package:flutter/widgets.dart';
import 'X509Certificate/asn1_distinguished_names.dart';
import 'X509Certificate/x509_certificate.dart';
import 'package:html/parser.dart' show parse;
import 'context_menu.dart';
import 'types.dart';
import 'in_app_browser.dart';
......@@ -586,11 +583,6 @@ class InAppWebViewController {
List<dynamic> args = jsonDecode(call.arguments["args"]);
switch (handlerName) {
case "androidKeyboardWorkaroundFocusoutEvent":
// android Workaround to hide the Keyboard when the user click outside
// on something not focusable such as input or a textarea.
SystemChannels.textInput.invokeMethod("TextInput.hide");
break;
case "onLoadResource":
Map<dynamic, dynamic> argMap = args[0];
String initiatorType = argMap["initiatorType"];
......@@ -883,7 +875,6 @@ class InAppWebViewController {
if (html == null || (html != null && html.isEmpty)) {
return favicons;
}
var assetPathBase;
if (webviewUrl.startsWith("file:///")) {
......@@ -891,29 +882,53 @@ class InAppWebViewController {
assetPathBase = assetPathSplitted[0] + "/flutter_assets/";
}
// 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);
InAppWebViewGroupOptions options = await getOptions();
if (options != null && options.crossPlatform.javaScriptEnabled == true) {
List<Map<dynamic, dynamic>> links = (await evaluateJavascript(
source: """
(function() {
var linkNodes = document.head.getElementsByTagName("link");
var links = [];
for (var i = 0; i < linkNodes.length; i++) {
var linkNode = linkNodes[i];
if (linkNode.rel === 'manifest') {
links.push(
{
rel: linkNode.rel,
href: linkNode.href,
sizes: null
}
);
} else if (linkNode.rel != null && linkNode.rel.indexOf('icon') >= 0) {
links.push(
{
rel: linkNode.rel,
href: linkNode.href,
sizes: linkNode.sizes != null && linkNode.sizes.value != "" ? linkNode.sizes.value : null
}
);
}
}
return links;
})();
"""))?.cast<Map<dynamic, dynamic>>() ?? [];
for (var link in links) {
if (link["rel"] == "manifest") {
manifestUrl = link["href"];
if (!_isUrlAbsolute(manifestUrl)) {
if (manifestUrl.startsWith("/")) {
manifestUrl = manifestUrl.substring(1);
}
manifestUrl = ((assetPathBase == null)
? url.scheme + "://" + url.host + "/"
: assetPathBase) +
manifestUrl;
}
manifestUrl = ((assetPathBase == null)
? url.scheme + "://" + url.host + "/"
: assetPathBase) +
manifestUrl;
continue;
}
continue;
favicons.addAll(_createFavicons(url, assetPathBase, link["href"],
link["rel"], link["sizes"], false));
}
if (!attributes["rel"].contains("icon")) {
continue;
}
favicons.addAll(_createFavicons(url, assetPathBase, attributes["href"],
attributes["rel"], attributes["sizes"], false));
}
// try to get /favicon.ico
......@@ -923,7 +938,7 @@ class InAppWebViewController {
favicons.add(Favicon(url: faviconUrl, rel: "shortcut icon"));
} catch (e, stacktrace) {
print("/favicon.ico file not found: " + e.toString());
print(stacktrace);
// print(stacktrace);
}
// try to get the manifest file
......@@ -940,7 +955,7 @@ class InAppWebViewController {
manifestResponse.headers.contentType?.mimeType == "application/json";
} catch (e, stacktrace) {
print("Manifest file not found: " + e.toString());
print(stacktrace);
// print(stacktrace);
}
if (manifestFound) {
......@@ -1181,6 +1196,11 @@ class InAppWebViewController {
///Evaluates JavaScript code into the WebView and returns the result of the evaluation.
///
///**NOTE**: This method shouldn't be called in the [WebView.onWebViewCreated] or [WebView.onLoadStart] events,
///because, in these events, the [WebView] is not ready to handle it yet.
///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events
///where you know the page is ready "enough".
///
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#evaluateJavascript(java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.String%3E)
///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1415017-evaluatejavascript
Future<dynamic> evaluateJavascript({@required String source}) async {
......@@ -1192,6 +1212,11 @@ class InAppWebViewController {
}
///Injects an external JavaScript file into the WebView from a defined url.
///
///**NOTE**: This method shouldn't be called in the [WebView.onWebViewCreated] or [WebView.onLoadStart] events,
///because, in these events, the [WebView] is not ready to handle it yet.
///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events
///where you know the page is ready "enough".
Future<void> injectJavascriptFileFromUrl({@required String urlFile}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('urlFile', () => urlFile);
......@@ -1199,6 +1224,11 @@ class InAppWebViewController {
}
///Injects a JavaScript file into the WebView from the flutter assets directory.
///
///**NOTE**: This method shouldn't be called in the [WebView.onWebViewCreated] or [WebView.onLoadStart] events,
///because, in these events, the [WebView] is not ready to handle it yet.
///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events
///where you know the page is ready "enough".
Future<void> injectJavascriptFileFromAsset(
{@required String assetFilePath}) async {
String source = await rootBundle.loadString(assetFilePath);
......@@ -1206,6 +1236,11 @@ class InAppWebViewController {
}
///Injects CSS into the WebView.
///
///**NOTE**: This method shouldn't be called in the [WebView.onWebViewCreated] or [WebView.onLoadStart] events,
///because, in these events, the [WebView] is not ready to handle it yet.
///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events
///where you know the page is ready "enough".
Future<void> injectCSSCode({@required String source}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('source', () => source);
......@@ -1213,6 +1248,11 @@ class InAppWebViewController {
}
///Injects an external CSS file into the WebView from a defined url.
///
///**NOTE**: This method shouldn't be called in the [WebView.onWebViewCreated] or [WebView.onLoadStart] events,
///because, in these events, the [WebView] is not ready to handle it yet.
///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events
///where you know the page is ready "enough".
Future<void> injectCSSFileFromUrl({@required String urlFile}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('urlFile', () => urlFile);
......@@ -1220,6 +1260,11 @@ class InAppWebViewController {
}
///Injects a CSS file into the WebView from the flutter assets directory.
///
///**NOTE**: This method shouldn't be called in the [WebView.onWebViewCreated] or [WebView.onLoadStart] events,
///because, in these events, the [WebView] is not ready to handle it yet.
///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events
///where you know the page is ready "enough".
Future<void> injectCSSFileFromAsset({@required String assetFilePath}) async {
String source = await rootBundle.loadString(assetFilePath);
await injectCSSCode(source: source);
......@@ -1271,6 +1316,10 @@ class InAppWebViewController {
///```
///
///Forbidden names for JavaScript handlers are defined in [javaScriptHandlerForbiddenNames].
///
///**NOTE**: This method should be called, for example, in the [WebView.onWebViewCreated] or [WebView.onLoadStart] events or, at least,
///before you know that your JavaScript code will call the `window.flutter_inappwebview.callHandler` method,
///otherwise you won't be able to intercept the JavaScript message.
void addJavaScriptHandler(
{@required String handlerName,
@required JavaScriptHandlerCallback callback}) {
......
......@@ -36,9 +36,17 @@ class ConsoleMessageLevel {
const ConsoleMessageLevel._internal(this._value);
static final Set<ConsoleMessageLevel> values = [
ConsoleMessageLevel.TIP,
ConsoleMessageLevel.LOG,
ConsoleMessageLevel.WARNING,
ConsoleMessageLevel.ERROR,
ConsoleMessageLevel.DEBUG,
].toSet();
static ConsoleMessageLevel fromValue(int value) {
if (value != null && value >= 0 && value <= 4)
return ConsoleMessageLevel._internal(value);
if (value != null)
return ConsoleMessageLevel.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -126,12 +134,11 @@ class InAppWebViewInitialData {
///The URL to use as the history entry. The default value is `about:blank`. If non-null, this must be a valid URL. This parameter is used only on Android.
String historyUrl;
InAppWebViewInitialData(
{@required this.data,
this.mimeType = "text/html",
this.encoding = "utf8",
this.baseUrl = "about:blank",
this.historyUrl = "about:blank"});
InAppWebViewInitialData({@required this.data,
this.mimeType = "text/html",
this.encoding = "utf8",
this.baseUrl = "about:blank",
this.historyUrl = "about:blank"});
Map<String, String> toMap() {
return {
......@@ -189,13 +196,12 @@ class WebResourceRequest {
///**NOTE**: Available on Android 21+. For Android < 21 it will be always `false`.
bool isRedirect;
WebResourceRequest(
{@required this.url,
this.headers,
this.method,
this.hasGesture,
this.isForMainFrame,
this.isRedirect});
WebResourceRequest({@required this.url,
this.headers,
this.method,
this.hasGesture,
this.isForMainFrame,
this.isRedirect});
Map<String, dynamic> toMap() {
return {
......@@ -249,13 +255,12 @@ class WebResourceResponse {
///**NOTE**: Available on Android 21+. For Android < 21 it won't be used.
String reasonPhrase;
WebResourceResponse(
{this.contentType = "",
this.contentEncoding = "utf-8",
this.data = null,
this.headers,
this.statusCode,
this.reasonPhrase});
WebResourceResponse({this.contentType = "",
this.contentEncoding = "utf-8",
this.data,
this.headers,
this.statusCode,
this.reasonPhrase});
Map<String, dynamic> toMap() {
return {
......@@ -289,10 +294,9 @@ class CustomSchemeResponse {
///Content-Enconding of the data, such as `utf-8`.
String contentEnconding;
CustomSchemeResponse(
{@required this.data,
@required this.contentType,
this.contentEnconding = 'utf-8'});
CustomSchemeResponse({@required this.data,
@required this.contentType,
this.contentEnconding = 'utf-8'});
Map<String, dynamic> toMap() {
return {
......@@ -459,11 +463,10 @@ class JsAlertResponse {
///Action used to confirm that the user hit confirm button.
JsAlertResponseAction action;
JsAlertResponse(
{this.message = "",
this.handledByClient = false,
this.confirmButtonTitle = "",
this.action = JsAlertResponseAction.CONFIRM});
JsAlertResponse({this.message = "",
this.handledByClient = false,
this.confirmButtonTitle = "",
this.action = JsAlertResponseAction.CONFIRM});
Map<String, dynamic> toMap() {
return {
......@@ -518,12 +521,11 @@ class JsConfirmResponse {
///Action used to confirm that the user hit confirm or cancel button.
JsConfirmResponseAction action;
JsConfirmResponse(
{this.message = "",
this.handledByClient = false,
this.confirmButtonTitle = "",
this.cancelButtonTitle = "",
this.action = JsConfirmResponseAction.CANCEL});
JsConfirmResponse({this.message = "",
this.handledByClient = false,
this.confirmButtonTitle = "",
this.cancelButtonTitle = "",
this.action = JsConfirmResponseAction.CANCEL});
Map<String, dynamic> toMap() {
return {
......@@ -585,14 +587,13 @@ class JsPromptResponse {
///Action used to confirm that the user hit confirm or cancel button.
JsPromptResponseAction action;
JsPromptResponse(
{this.message = "",
this.defaultValue = "",
this.handledByClient = false,
this.confirmButtonTitle = "",
this.cancelButtonTitle = "",
this.value,
this.action = JsPromptResponseAction.CANCEL});
JsPromptResponse({this.message = "",
this.defaultValue = "",
this.handledByClient = false,
this.confirmButtonTitle = "",
this.cancelButtonTitle = "",
this.value,
this.action = JsPromptResponseAction.CANCEL});
Map<String, dynamic> toMap() {
return {
......@@ -622,9 +623,17 @@ class SafeBrowsingThreat {
const SafeBrowsingThreat._internal(this._value);
static final Set<SafeBrowsingThreat> values = [
SafeBrowsingThreat.SAFE_BROWSING_THREAT_UNKNOWN,
SafeBrowsingThreat.SAFE_BROWSING_THREAT_MALWARE,
SafeBrowsingThreat.SAFE_BROWSING_THREAT_PHISHING,
SafeBrowsingThreat.SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE,
SafeBrowsingThreat.SAFE_BROWSING_THREAT_BILLING,
].toSet();
static SafeBrowsingThreat fromValue(int value) {
if (value != null && value >= 0 && value <= 4)
return SafeBrowsingThreat._internal(value);
if (value != null)
return SafeBrowsingThreat.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -647,15 +656,15 @@ class SafeBrowsingThreat {
}
static const SAFE_BROWSING_THREAT_UNKNOWN =
const SafeBrowsingThreat._internal(0);
const SafeBrowsingThreat._internal(0);
static const SAFE_BROWSING_THREAT_MALWARE =
const SafeBrowsingThreat._internal(1);
const SafeBrowsingThreat._internal(1);
static const SAFE_BROWSING_THREAT_PHISHING =
const SafeBrowsingThreat._internal(2);
const SafeBrowsingThreat._internal(2);
static const SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE =
const SafeBrowsingThreat._internal(3);
const SafeBrowsingThreat._internal(3);
static const SAFE_BROWSING_THREAT_BILLING =
const SafeBrowsingThreat._internal(4);
const SafeBrowsingThreat._internal(4);
bool operator ==(value) => value == _value;
......@@ -679,7 +688,7 @@ class SafeBrowsingResponseAction {
///Display the default interstitial.
static const SHOW_INTERSTITIAL =
const SafeBrowsingResponseAction._internal(2);
const SafeBrowsingResponseAction._internal(2);
bool operator ==(value) => value == _value;
......@@ -696,9 +705,8 @@ class SafeBrowsingResponse {
///Indicate the [SafeBrowsingResponseAction] to take when hitting a malicious URL.
SafeBrowsingResponseAction action;
SafeBrowsingResponse(
{this.report = true,
this.action = SafeBrowsingResponseAction.SHOW_INTERSTITIAL});
SafeBrowsingResponse({this.report = true,
this.action = SafeBrowsingResponseAction.SHOW_INTERSTITIAL});
Map<String, dynamic> toMap() {
return {"report": report, "action": action?.toValue()};
......@@ -730,7 +738,7 @@ class HttpAuthResponseAction {
///Uses the credentials stored for the current host.
static const USE_SAVED_HTTP_AUTH_CREDENTIALS =
const HttpAuthResponseAction._internal(2);
const HttpAuthResponseAction._internal(2);
bool operator ==(value) => value == _value;
......@@ -752,11 +760,10 @@ class HttpAuthResponse {
///Indicate the [HttpAuthResponseAction] to take in response of the authentication challenge.
HttpAuthResponseAction action;
HttpAuthResponse(
{this.username = "",
this.password = "",
this.permanentPersistence = false,
this.action = HttpAuthResponseAction.CANCEL});
HttpAuthResponse({this.username = "",
this.password = "",
this.permanentPersistence = false,
this.action = HttpAuthResponseAction.CANCEL});
Map<String, dynamic> toMap() {
return {
......@@ -928,12 +935,11 @@ class ServerTrustChallenge {
///The SSL certificate used for this challenge.
SslCertificate sslCertificate;
ServerTrustChallenge(
{@required this.protectionSpace,
this.androidError,
this.iosError,
this.message,
this.sslCertificate})
ServerTrustChallenge({@required this.protectionSpace,
this.androidError,
this.iosError,
this.message,
this.sslCertificate})
: assert(protectionSpace != null);
Map<String, dynamic> toMap() {
......@@ -993,11 +999,10 @@ class ClientCertResponse {
///Indicate the [ClientCertResponseAction] to take in response of the client certificate challenge.
ClientCertResponseAction action;
ClientCertResponse(
{this.certificatePath,
this.certificatePassword = "",
this.androidKeyStoreType = "PKCS12",
this.action = ClientCertResponseAction.CANCEL}) {
ClientCertResponse({this.certificatePath,
this.certificatePassword = "",
this.androidKeyStoreType = "PKCS12",
this.action = ClientCertResponseAction.CANCEL}) {
if (this.action == ClientCertResponseAction.PROCEED)
assert(certificatePath != null && certificatePath.isNotEmpty);
}
......@@ -1081,9 +1086,16 @@ class AndroidCacheMode {
const AndroidCacheMode._internal(this._value);
static final Set<AndroidCacheMode> values = [
AndroidCacheMode.LOAD_DEFAULT,
AndroidCacheMode.LOAD_CACHE_ELSE_NETWORK,
AndroidCacheMode.LOAD_NO_CACHE,
AndroidCacheMode.LOAD_CACHE_ONLY,
].toSet();
static AndroidCacheMode fromValue(int value) {
if (value != null && value >= 0 && value <= 3)
return AndroidCacheMode._internal(value);
if (value != null)
return AndroidCacheMode.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -1131,9 +1143,16 @@ class AndroidActionModeMenuItem {
const AndroidActionModeMenuItem._internal(this._value);
static final Set<AndroidActionModeMenuItem> values = [
AndroidActionModeMenuItem.MENU_ITEM_NONE,
AndroidActionModeMenuItem.MENU_ITEM_SHARE,
AndroidActionModeMenuItem.MENU_ITEM_WEB_SEARCH,
AndroidActionModeMenuItem.MENU_ITEM_PROCESS_TEXT,
].toSet();
static AndroidActionModeMenuItem fromValue(int value) {
if (value != null && value != 3 && value >= 0 && value <= 4)
return AndroidActionModeMenuItem._internal(value);
if (value != null)
return AndroidActionModeMenuItem.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -1162,11 +1181,11 @@ class AndroidActionModeMenuItem {
///Disable menu item "Web Search".
static const MENU_ITEM_WEB_SEARCH =
const AndroidActionModeMenuItem._internal(2);
const AndroidActionModeMenuItem._internal(2);
///Disable all the action mode menu items for text processing.
static const MENU_ITEM_PROCESS_TEXT =
const AndroidActionModeMenuItem._internal(4);
const AndroidActionModeMenuItem._internal(4);
bool operator ==(value) => value == _value;
......@@ -1182,9 +1201,15 @@ class AndroidForceDark {
const AndroidForceDark._internal(this._value);
static final Set<AndroidForceDark> values = [
AndroidForceDark.FORCE_DARK_OFF,
AndroidForceDark.FORCE_DARK_AUTO,
AndroidForceDark.FORCE_DARK_ON,
].toSet();
static AndroidForceDark fromValue(int value) {
if (value != null && value >= 0 && value <= 2)
return AndroidForceDark._internal(value);
if (value != null)
return AndroidForceDark.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -1225,10 +1250,16 @@ class AndroidLayoutAlgorithm {
const AndroidLayoutAlgorithm._internal(this._value);
static final Set<AndroidLayoutAlgorithm> values = [
AndroidLayoutAlgorithm.NORMAL,
AndroidLayoutAlgorithm.TEXT_AUTOSIZING,
AndroidLayoutAlgorithm.NARROW_COLUMNS,
].toSet();
static AndroidLayoutAlgorithm fromValue(String value) {
return (["NORMAL", "TEXT_AUTOSIZING", "NARROW_COLUMNS"].contains(value))
? AndroidLayoutAlgorithm._internal(value)
: null;
if (value != null)
return AndroidLayoutAlgorithm.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
String toValue() => _value;
......@@ -1244,11 +1275,11 @@ class AndroidLayoutAlgorithm {
///
///**NOTE**: available on Android 19+.
static const TEXT_AUTOSIZING =
const AndroidLayoutAlgorithm._internal("TEXT_AUTOSIZING");
const AndroidLayoutAlgorithm._internal("TEXT_AUTOSIZING");
///NARROW_COLUMNS makes all columns no wider than the screen if possible. Only use this for API levels prior to `Build.VERSION_CODES.KITKAT`.
static const NARROW_COLUMNS =
const AndroidLayoutAlgorithm._internal("NARROW_COLUMNS");
const AndroidLayoutAlgorithm._internal("NARROW_COLUMNS");
bool operator ==(value) => value == _value;
......@@ -1264,9 +1295,15 @@ class AndroidMixedContentMode {
const AndroidMixedContentMode._internal(this._value);
static final Set<AndroidMixedContentMode> values = [
AndroidMixedContentMode.MIXED_CONTENT_ALWAYS_ALLOW,
AndroidMixedContentMode.MIXED_CONTENT_NEVER_ALLOW,
AndroidMixedContentMode.MIXED_CONTENT_COMPATIBILITY_MODE,
].toSet();
static AndroidMixedContentMode fromValue(int value) {
if (value != null && value >= 0 && value <= 2)
return AndroidMixedContentMode._internal(value);
if (value != null)
return AndroidMixedContentMode.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -1288,12 +1325,12 @@ class AndroidMixedContentMode {
///In this mode, the WebView will allow a secure origin to load content from any other origin, even if that origin is insecure.
///This is the least secure mode of operation for the WebView, and where possible apps should not set this mode.
static const MIXED_CONTENT_ALWAYS_ALLOW =
const AndroidMixedContentMode._internal(0);
const AndroidMixedContentMode._internal(0);
///In this mode, the WebView will not allow a secure origin to load content from an insecure origin.
///This is the preferred and most secure mode of operation for the WebView and apps are strongly advised to use this mode.
static const MIXED_CONTENT_NEVER_ALLOW =
const AndroidMixedContentMode._internal(1);
const AndroidMixedContentMode._internal(1);
///In this mode, the WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content.
///Some insecure content may be allowed to be loaded by a secure origin and other types of content will be blocked.
......@@ -1301,7 +1338,7 @@ class AndroidMixedContentMode {
///This mode is intended to be used by apps that are not in control of the content that they render but desire to operate in a reasonably secure environment.
///For highest security, apps are recommended to use [AndroidMixedContentMode.MIXED_CONTENT_NEVER_ALLOW].
static const MIXED_CONTENT_COMPATIBILITY_MODE =
const AndroidMixedContentMode._internal(2);
const AndroidMixedContentMode._internal(2);
bool operator ==(value) => value == _value;
......@@ -1315,9 +1352,14 @@ class IOSWKSelectionGranularity {
const IOSWKSelectionGranularity._internal(this._value);
static final Set<IOSWKSelectionGranularity> values = [
IOSWKSelectionGranularity.DYNAMIC,
IOSWKSelectionGranularity.CHARACTER,
].toSet();
static IOSWKSelectionGranularity fromValue(int value) {
if (value != null && value >= 0 && value <= 1)
return IOSWKSelectionGranularity._internal(value);
if (value != null)
return IOSWKSelectionGranularity.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -1354,22 +1396,23 @@ class IOSWKDataDetectorTypes {
const IOSWKDataDetectorTypes._internal(this._value);
static final Set<IOSWKDataDetectorTypes> values = [
IOSWKDataDetectorTypes.NONE,
IOSWKDataDetectorTypes.PHONE_NUMBER,
IOSWKDataDetectorTypes.LINK,
IOSWKDataDetectorTypes.ADDRESS,
IOSWKDataDetectorTypes.CALENDAR_EVENT,
IOSWKDataDetectorTypes.TRACKING_NUMBER,
IOSWKDataDetectorTypes.FLIGHT_NUMBER,
IOSWKDataDetectorTypes.LOOKUP_SUGGESTION,
IOSWKDataDetectorTypes.SPOTLIGHT_SUGGESTION,
IOSWKDataDetectorTypes.ALL,
].toSet();
static IOSWKDataDetectorTypes fromValue(String value) {
return ([
"NONE",
"PHONE_NUMBER",
"LINK",
"ADDRESS",
"CALENDAR_EVENT",
"TRACKING_NUMBER",
"TRACKING_NUMBER",
"FLIGHT_NUMBER",
"LOOKUP_SUGGESTION",
"SPOTLIGHT_SUGGESTION",
"ALL"
].contains(value))
? IOSWKDataDetectorTypes._internal(value)
: null;
if (value != null)
return IOSWKDataDetectorTypes.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
String toValue() => _value;
......@@ -1382,7 +1425,7 @@ class IOSWKDataDetectorTypes {
///Phone numbers are detected and turned into links.
static const PHONE_NUMBER =
const IOSWKDataDetectorTypes._internal("PHONE_NUMBER");
const IOSWKDataDetectorTypes._internal("PHONE_NUMBER");
///URLs in text are detected and turned into links.
static const LINK = const IOSWKDataDetectorTypes._internal("LINK");
......@@ -1392,23 +1435,23 @@ class IOSWKDataDetectorTypes {
///Dates and times that are in the future are detected and turned into links.
static const CALENDAR_EVENT =
const IOSWKDataDetectorTypes._internal("CALENDAR_EVENT");
const IOSWKDataDetectorTypes._internal("CALENDAR_EVENT");
///Tracking numbers are detected and turned into links.
static const TRACKING_NUMBER =
const IOSWKDataDetectorTypes._internal("TRACKING_NUMBER");
const IOSWKDataDetectorTypes._internal("TRACKING_NUMBER");
///Flight numbers are detected and turned into links.
static const FLIGHT_NUMBER =
const IOSWKDataDetectorTypes._internal("FLIGHT_NUMBER");
const IOSWKDataDetectorTypes._internal("FLIGHT_NUMBER");
///Lookup suggestions are detected and turned into links.
static const LOOKUP_SUGGESTION =
const IOSWKDataDetectorTypes._internal("LOOKUP_SUGGESTION");
const IOSWKDataDetectorTypes._internal("LOOKUP_SUGGESTION");
///Spotlight suggestions are detected and turned into links.
static const SPOTLIGHT_SUGGESTION =
const IOSWKDataDetectorTypes._internal("SPOTLIGHT_SUGGESTION");
const IOSWKDataDetectorTypes._internal("SPOTLIGHT_SUGGESTION");
///All of the above data types are turned into links when detected. Choosing this value will automatically include any new detection type that is added.
static const ALL = const IOSWKDataDetectorTypes._internal("ALL");
......@@ -1425,10 +1468,15 @@ class IOSUIScrollViewDecelerationRate {
const IOSUIScrollViewDecelerationRate._internal(this._value);
static final Set<IOSUIScrollViewDecelerationRate> values = [
IOSUIScrollViewDecelerationRate.NORMAL,
IOSUIScrollViewDecelerationRate.FAST,
].toSet();
static IOSUIScrollViewDecelerationRate fromValue(String value) {
return (["NORMAL", "FAST"].contains(value))
? IOSUIScrollViewDecelerationRate._internal(value)
: null;
if (value != null)
return IOSUIScrollViewDecelerationRate.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
String toValue() => _value;
......@@ -1438,7 +1486,7 @@ class IOSUIScrollViewDecelerationRate {
///The default deceleration rate for a scroll view: `0.998`.
static const NORMAL =
const IOSUIScrollViewDecelerationRate._internal("NORMAL");
const IOSUIScrollViewDecelerationRate._internal("NORMAL");
///A fast deceleration rate for a scroll view: `0.99`.
static const FAST = const IOSUIScrollViewDecelerationRate._internal("FAST");
......@@ -1455,9 +1503,15 @@ class UserPreferredContentMode {
const UserPreferredContentMode._internal(this._value);
static final Set<UserPreferredContentMode> values = [
UserPreferredContentMode.RECOMMENDED,
UserPreferredContentMode.MOBILE,
UserPreferredContentMode.DESKTOP,
].toSet();
static UserPreferredContentMode fromValue(int value) {
if (value != null && value >= 0 && value <= 2)
return UserPreferredContentMode._internal(value);
if (value != null)
return UserPreferredContentMode.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -1497,9 +1551,22 @@ class IOSUIModalPresentationStyle {
const IOSUIModalPresentationStyle._internal(this._value);
static final Set<IOSUIModalPresentationStyle> values = [
IOSUIModalPresentationStyle.FULL_SCREEN,
IOSUIModalPresentationStyle.PAGE_SHEET,
IOSUIModalPresentationStyle.FORM_SHEET,
IOSUIModalPresentationStyle.CURRENT_CONTEXT,
IOSUIModalPresentationStyle.CUSTOM,
IOSUIModalPresentationStyle.OVER_FULL_SCREEN,
IOSUIModalPresentationStyle.OVER_CURRENT_CONTEXT,
IOSUIModalPresentationStyle.POPOVER,
IOSUIModalPresentationStyle.NONE,
IOSUIModalPresentationStyle.AUTOMATIC,
].toSet();
static IOSUIModalPresentationStyle fromValue(int value) {
if (value != null && value >= 0 && value <= 9)
return IOSUIModalPresentationStyle._internal(value);
if (value != null)
return IOSUIModalPresentationStyle.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -1549,11 +1616,11 @@ class IOSUIModalPresentationStyle {
///A view presentation style in which the presented view covers the screen.
static const OVER_FULL_SCREEN =
const IOSUIModalPresentationStyle._internal(5);
const IOSUIModalPresentationStyle._internal(5);
///A presentation style where the content is displayed over another view controller’s content.
static const OVER_CURRENT_CONTEXT =
const IOSUIModalPresentationStyle._internal(6);
const IOSUIModalPresentationStyle._internal(6);
///A presentation style where the content is displayed in a popover view.
static const POPOVER = const IOSUIModalPresentationStyle._internal(7);
......@@ -1578,9 +1645,16 @@ class IOSUIModalTransitionStyle {
const IOSUIModalTransitionStyle._internal(this._value);
static final Set<IOSUIModalTransitionStyle> values = [
IOSUIModalTransitionStyle.COVER_VERTICAL,
IOSUIModalTransitionStyle.FLIP_HORIZONTAL,
IOSUIModalTransitionStyle.CROSS_DISSOLVE,
IOSUIModalTransitionStyle.PARTIAL_CURL,
].toSet();
static IOSUIModalTransitionStyle fromValue(int value) {
if (value != null && value >= 0 && value <= 3)
return IOSUIModalTransitionStyle._internal(value);
if (value != null)
return IOSUIModalTransitionStyle.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -1633,9 +1707,15 @@ class IOSSafariDismissButtonStyle {
const IOSSafariDismissButtonStyle._internal(this._value);
static final Set<IOSSafariDismissButtonStyle> values = [
IOSSafariDismissButtonStyle.DONE,
IOSSafariDismissButtonStyle.CLOSE,
IOSSafariDismissButtonStyle.CANCEL,
].toSet();
static IOSSafariDismissButtonStyle fromValue(int value) {
if (value != null && value >= 0 && value <= 2)
return IOSSafariDismissButtonStyle._internal(value);
if (value != null)
return IOSSafariDismissButtonStyle.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -1680,7 +1760,13 @@ class InAppWebViewGroupOptions {
///iOS-specific options.
IOSInAppWebViewOptions ios;
InAppWebViewGroupOptions({this.crossPlatform, this.android, this.ios});
InAppWebViewGroupOptions({this.crossPlatform,
this.android,
this.ios}) {
this.crossPlatform = this.crossPlatform ?? InAppWebViewOptions();
this.android = this.android ?? AndroidInAppWebViewOptions();
this.ios = this.ios ?? IOSInAppWebViewOptions();
}
Map<String, dynamic> toMap() {
Map<String, dynamic> options = {};
......@@ -1695,9 +1781,11 @@ class InAppWebViewGroupOptions {
static InAppWebViewGroupOptions fromMap(Map<String, dynamic> options) {
InAppWebViewGroupOptions inAppWebViewGroupOptions = InAppWebViewGroupOptions();
inAppWebViewGroupOptions.crossPlatform = InAppWebViewOptions.fromMap(options);
inAppWebViewGroupOptions.crossPlatform =
InAppWebViewOptions.fromMap(options);
if (Platform.isAndroid)
inAppWebViewGroupOptions.android = AndroidInAppWebViewOptions.fromMap(options);
inAppWebViewGroupOptions.android =
AndroidInAppWebViewOptions.fromMap(options);
else if (Platform.isIOS)
inAppWebViewGroupOptions.ios = IOSInAppWebViewOptions.fromMap(options);
......@@ -1716,12 +1804,6 @@ class InAppWebViewGroupOptions {
InAppWebViewGroupOptions copy() {
return InAppWebViewGroupOptions.fromMap(this.toMap());
}
InAppWebViewGroupOptions copyWithValue(InAppWebViewGroupOptions webViewOptions) {
var mergedMap = this.toMap();
mergedMap.addAll(webViewOptions.toMap());
return InAppWebViewGroupOptions.fromMap(mergedMap);
}
}
///Class that represents the options that can be used for an [InAppBrowser] WebView.
......@@ -1738,11 +1820,16 @@ class InAppBrowserClassOptions {
///WebView options.
InAppWebViewGroupOptions inAppWebViewGroupOptions;
InAppBrowserClassOptions(
{this.crossPlatform,
this.android,
this.ios,
this.inAppWebViewGroupOptions});
InAppBrowserClassOptions({this.crossPlatform,
this.android,
this.ios,
this.inAppWebViewGroupOptions}) {
this.crossPlatform = this.crossPlatform ?? InAppBrowserOptions();
this.android = this.android ?? AndroidInAppBrowserOptions();
this.ios = this.ios ?? IOSInAppBrowserOptions();
this.inAppWebViewGroupOptions =
this.inAppWebViewGroupOptions ?? InAppWebViewGroupOptions();
}
Map<String, dynamic> toMap() {
Map<String, dynamic> options = {};
......@@ -1795,12 +1882,6 @@ class InAppBrowserClassOptions {
InAppBrowserClassOptions copy() {
return InAppBrowserClassOptions.fromMap(this.toMap());
}
InAppBrowserClassOptions copyWithValue(InAppBrowserClassOptions webViewOptions) {
var mergedMap = this.toMap();
mergedMap.addAll(webViewOptions.toMap());
return InAppBrowserClassOptions.fromMap(mergedMap);
}
}
///Class that represents the options that can be used for an [ChromeSafariBrowser] window.
......@@ -1811,7 +1892,13 @@ class ChromeSafariBrowserClassOptions {
///iOS-specific options.
IOSSafariOptions ios;
ChromeSafariBrowserClassOptions({this.android, this.ios});
ChromeSafariBrowserClassOptions({
this.android,
this.ios
}) {
this.android = this.android ?? AndroidChromeCustomTabsOptions();
this.ios = this.ios ?? IOSSafariOptions();
}
Map<String, dynamic> toMap() {
Map<String, dynamic> options = {};
......@@ -1873,11 +1960,20 @@ class AjaxRequestEventType {
const AjaxRequestEventType._internal(this._value);
static final Set<AjaxRequestEventType> values = [
AjaxRequestEventType.LOADSTART,
AjaxRequestEventType.LOAD,
AjaxRequestEventType.LOADEND,
AjaxRequestEventType.PROGRESS,
AjaxRequestEventType.ERROR,
AjaxRequestEventType.ABORT,
AjaxRequestEventType.TIMEOUT,
].toSet();
static AjaxRequestEventType fromValue(String value) {
return (["loadstart", "load", "loadend", "progress", "error", "abort"]
.contains(value))
? AjaxRequestEventType._internal(value)
: null;
if (value != null)
return AjaxRequestEventType.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
String toValue() => _value;
......@@ -1939,9 +2035,17 @@ class AjaxRequestReadyState {
const AjaxRequestReadyState._internal(this._value);
static final Set<AjaxRequestReadyState> values = [
AjaxRequestReadyState.UNSENT,
AjaxRequestReadyState.OPENED,
AjaxRequestReadyState.HEADERS_RECEIVED,
AjaxRequestReadyState.LOADING,
AjaxRequestReadyState.DONE,
].toSet();
static AjaxRequestReadyState fromValue(int value) {
if (value != null && value >= 0 && value <= 4)
return AjaxRequestReadyState._internal(value);
if (value != null)
return AjaxRequestReadyState.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -2079,26 +2183,25 @@ class AjaxRequest {
///Indicates the [AjaxRequestAction] that can be used to control the `XMLHttpRequest` request.
AjaxRequestAction action;
AjaxRequest(
{this.data,
this.method,
this.url,
this.isAsync,
this.user,
this.password,
this.withCredentials,
this.headers,
this.readyState,
this.status,
this.responseURL,
this.responseType,
this.response,
this.responseText,
this.responseXML,
this.statusText,
this.responseHeaders,
this.event,
this.action = AjaxRequestAction.PROCEED});
AjaxRequest({this.data,
this.method,
this.url,
this.isAsync,
this.user,
this.password,
this.withCredentials,
this.headers,
this.readyState,
this.status,
this.responseURL,
this.responseType,
this.response,
this.responseText,
this.responseXML,
this.statusText,
this.responseHeaders,
this.event,
this.action = AjaxRequestAction.PROCEED});
Map<String, dynamic> toMap() {
return {
......@@ -2319,20 +2422,19 @@ class FetchRequest {
///Indicates the [FetchRequestAction] that can be used to control the request.
FetchRequestAction action;
FetchRequest(
{this.url,
this.method,
this.headers,
this.body,
this.mode,
this.credentials,
this.cache,
this.redirect,
this.referrer,
this.referrerPolicy,
this.integrity,
this.keepalive,
this.action = FetchRequestAction.PROCEED});
FetchRequest({this.url,
this.method,
this.headers,
this.body,
this.mode,
this.credentials,
this.cache,
this.redirect,
this.referrer,
this.referrerPolicy,
this.integrity,
this.keepalive,
this.action = FetchRequestAction.PROCEED});
Map<String, dynamic> toMap() {
return {
......@@ -2393,19 +2495,21 @@ class ContentBlockerTriggerResourceType {
const ContentBlockerTriggerResourceType._internal(this._value);
static final Set<ContentBlockerTriggerResourceType> values = [
ContentBlockerTriggerResourceType.DOCUMENT,
ContentBlockerTriggerResourceType.IMAGE,
ContentBlockerTriggerResourceType.STYLE_SHEET,
ContentBlockerTriggerResourceType.SCRIPT,
ContentBlockerTriggerResourceType.FONT,
ContentBlockerTriggerResourceType.MEDIA,
ContentBlockerTriggerResourceType.SVG_DOCUMENT,
ContentBlockerTriggerResourceType.RAW,
].toSet();
static ContentBlockerTriggerResourceType fromValue(String value) {
return ([
"document",
"image",
"style-sheet",
"script",
"font",
"media",
"svg-document",
"raw"
].contains(value))
? ContentBlockerTriggerResourceType._internal(value)
: null;
if (value != null)
return ContentBlockerTriggerResourceType.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
String toValue() => _value;
......@@ -2414,18 +2518,18 @@ class ContentBlockerTriggerResourceType {
String toString() => _value;
static const DOCUMENT =
const ContentBlockerTriggerResourceType._internal('document');
const ContentBlockerTriggerResourceType._internal('document');
static const IMAGE =
const ContentBlockerTriggerResourceType._internal('image');
const ContentBlockerTriggerResourceType._internal('image');
static const STYLE_SHEET =
const ContentBlockerTriggerResourceType._internal('style-sheet');
const ContentBlockerTriggerResourceType._internal('style-sheet');
static const SCRIPT =
const ContentBlockerTriggerResourceType._internal('script');
const ContentBlockerTriggerResourceType._internal('script');
static const FONT = const ContentBlockerTriggerResourceType._internal('font');
static const MEDIA =
const ContentBlockerTriggerResourceType._internal('media');
const ContentBlockerTriggerResourceType._internal('media');
static const SVG_DOCUMENT =
const ContentBlockerTriggerResourceType._internal('svg-document');
const ContentBlockerTriggerResourceType._internal('svg-document');
///Any untyped load
static const RAW = const ContentBlockerTriggerResourceType._internal('raw');
......@@ -2442,10 +2546,15 @@ class ContentBlockerTriggerLoadType {
const ContentBlockerTriggerLoadType._internal(this._value);
static final Set<ContentBlockerTriggerLoadType> values = [
ContentBlockerTriggerLoadType.FIRST_PARTY,
ContentBlockerTriggerLoadType.THIRD_PARTY,
].toSet();
static ContentBlockerTriggerLoadType fromValue(String value) {
return (["first-party", "third-party"].contains(value))
? ContentBlockerTriggerLoadType._internal(value)
: null;
if (value != null)
return ContentBlockerTriggerLoadType.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
String toValue() => _value;
......@@ -2455,11 +2564,11 @@ class ContentBlockerTriggerLoadType {
///FIRST_PARTY is triggered only if the resource has the same scheme, domain, and port as the main page resource.
static const FIRST_PARTY =
const ContentBlockerTriggerLoadType._internal('first-party');
const ContentBlockerTriggerLoadType._internal('first-party');
///THIRD_PARTY is triggered if the resource is not from the same domain as the main page resource.
static const THIRD_PARTY =
const ContentBlockerTriggerLoadType._internal('third-party');
const ContentBlockerTriggerLoadType._internal('third-party');
bool operator ==(value) => value == _value;
......@@ -2473,10 +2582,16 @@ class ContentBlockerActionType {
const ContentBlockerActionType._internal(this._value);
static final Set<ContentBlockerActionType> values = [
ContentBlockerActionType.BLOCK,
ContentBlockerActionType.CSS_DISPLAY_NONE,
ContentBlockerActionType.MAKE_HTTPS,
].toSet();
static ContentBlockerActionType fromValue(String value) {
return (["block", "css-display-none", "make-https"].contains(value))
? ContentBlockerActionType._internal(value)
: null;
if (value != null)
return ContentBlockerActionType.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
String toValue() => _value;
......@@ -2491,11 +2606,11 @@ class ContentBlockerActionType {
///
///**NOTE**: on Android, JavaScript must be enabled.
static const CSS_DISPLAY_NONE =
const ContentBlockerActionType._internal('css-display-none');
const ContentBlockerActionType._internal('css-display-none');
///Changes a URL from http to https. URLs with a specified (nondefault) port and links using other protocols are unaffected.
static const MAKE_HTTPS =
const ContentBlockerActionType._internal('make-https');
const ContentBlockerActionType._internal('make-https');
bool operator ==(value) => value == _value;
......@@ -2546,16 +2661,15 @@ class Cookie {
///**NOTE**: on Android it will be always `null`.
String path;
Cookie(
{@required this.name,
@required this.value,
this.expiresDate,
this.isSessionOnly,
this.domain,
this.sameSite,
this.isSecure,
this.isHttpOnly,
this.path});
Cookie({@required this.name,
@required this.value,
this.expiresDate,
this.isSessionOnly,
this.domain,
this.sameSite,
this.isSecure,
this.isHttpOnly,
this.path});
Map<String, dynamic> toMap() {
return {
......@@ -2609,9 +2723,8 @@ class PermissionRequestResponse {
///Indicate the [PermissionRequestResponseAction] to take in response of a permission request.
PermissionRequestResponseAction action;
PermissionRequestResponse(
{this.resources = const [],
this.action = PermissionRequestResponseAction.DENY});
PermissionRequestResponse({this.resources = const [],
this.action = PermissionRequestResponseAction.DENY});
Map<String, dynamic> toMap() {
return {"resources": resources, "action": action?.toValue()};
......@@ -2660,14 +2773,23 @@ class IOSWKNavigationType {
const IOSWKNavigationType._internal(this._value);
int toValue() => _value;
static final Set<IOSWKNavigationType> values = [
IOSWKNavigationType.LINK_ACTIVATED,
IOSWKNavigationType.FORM_SUBMITTED,
IOSWKNavigationType.BACK_FORWARD,
IOSWKNavigationType.RELOAD,
IOSWKNavigationType.FORM_RESUBMITTED,
IOSWKNavigationType.OTHER,
].toSet();
static IOSWKNavigationType fromValue(int value) {
if (value != null && ((value >= 0 && value <= 4) || value == -1))
return IOSWKNavigationType._internal(value);
if (value != null)
return IOSWKNavigationType.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
int toValue() => _value;
///A link with an href attribute was activated by the user.
static const LINK_ACTIVATED = const IOSWKNavigationType._internal(0);
......@@ -2720,14 +2842,13 @@ class ShouldOverrideUrlLoadingRequest {
///The type of action triggering the navigation. Available only on iOS.
IOSWKNavigationType iosWKNavigationType;
ShouldOverrideUrlLoadingRequest(
{this.url,
this.method,
this.headers,
this.isForMainFrame,
this.androidHasGesture,
this.androidIsRedirect,
this.iosWKNavigationType});
ShouldOverrideUrlLoadingRequest({this.url,
this.method,
this.headers,
this.isForMainFrame,
this.androidHasGesture,
this.androidIsRedirect,
this.iosWKNavigationType});
Map<String, dynamic> toMap() {
return {
......@@ -2765,11 +2886,10 @@ class OnCreateWindowRequest {
///The type of action triggering the navigation. Available only on iOS.
IOSWKNavigationType iosWKNavigationType;
OnCreateWindowRequest(
{this.url,
this.androidIsDialog,
this.androidIsUserGesture,
this.iosWKNavigationType});
OnCreateWindowRequest({this.url,
this.androidIsDialog,
this.androidIsUserGesture,
this.iosWKNavigationType});
Map<String, dynamic> toMap() {
return {
......@@ -2826,21 +2946,23 @@ class IOSWKWebsiteDataType {
const IOSWKWebsiteDataType._internal(this._value);
static final Set<IOSWKWebsiteDataType> values = [
IOSWKWebsiteDataType.WKWebsiteDataTypeFetchCache,
IOSWKWebsiteDataType.WKWebsiteDataTypeDiskCache,
IOSWKWebsiteDataType.WKWebsiteDataTypeMemoryCache,
IOSWKWebsiteDataType.WKWebsiteDataTypeOfflineWebApplicationCache,
IOSWKWebsiteDataType.WKWebsiteDataTypeCookies,
IOSWKWebsiteDataType.WKWebsiteDataTypeSessionStorage,
IOSWKWebsiteDataType.WKWebsiteDataTypeLocalStorage,
IOSWKWebsiteDataType.WKWebsiteDataTypeWebSQLDatabases,
IOSWKWebsiteDataType.WKWebsiteDataTypeIndexedDBDatabases,
IOSWKWebsiteDataType.WKWebsiteDataTypeServiceWorkerRegistrations,
].toSet();
static IOSWKWebsiteDataType fromValue(String value) {
return ([
"WKWebsiteDataTypeFetchCache",
"WKWebsiteDataTypeDiskCache",
"WKWebsiteDataTypeMemoryCache",
"WKWebsiteDataTypeOfflineWebApplicationCache",
"WKWebsiteDataTypeCookies",
"WKWebsiteDataTypeSessionStorage",
"WKWebsiteDataTypeLocalStorage",
"WKWebsiteDataTypeWebSQLDatabases",
"WKWebsiteDataTypeIndexedDBDatabases",
"WKWebsiteDataTypeServiceWorkerRegistrations"
].contains(value))
? IOSWKWebsiteDataType._internal(value)
: null;
if (value != null)
return IOSWKWebsiteDataType.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
String toValue() => _value;
......@@ -2852,50 +2974,51 @@ class IOSWKWebsiteDataType {
///
///**NOTE**: available on iOS 11.3+.
static const WKWebsiteDataTypeFetchCache =
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeFetchCache");
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeFetchCache");
///On-disk caches.
static const WKWebsiteDataTypeDiskCache =
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeDiskCache");
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeDiskCache");
///In-memory caches.
static const WKWebsiteDataTypeMemoryCache =
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeMemoryCache");
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeMemoryCache");
///HTML offline web application caches.
static const WKWebsiteDataTypeOfflineWebApplicationCache =
const IOSWKWebsiteDataType._internal(
"WKWebsiteDataTypeOfflineWebApplicationCache");
const IOSWKWebsiteDataType._internal(
"WKWebsiteDataTypeOfflineWebApplicationCache");
///Cookies.
static const WKWebsiteDataTypeCookies =
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeCookies");
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeCookies");
///HTML session storage.
static const WKWebsiteDataTypeSessionStorage =
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeSessionStorage");
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeSessionStorage");
///HTML local storage.
static const WKWebsiteDataTypeLocalStorage =
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeLocalStorage");
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeLocalStorage");
///WebSQL databases.
static const WKWebsiteDataTypeWebSQLDatabases =
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeWebSQLDatabases");
const IOSWKWebsiteDataType._internal("WKWebsiteDataTypeWebSQLDatabases");
///IndexedDB databases.
static const WKWebsiteDataTypeIndexedDBDatabases =
const IOSWKWebsiteDataType._internal(
"WKWebsiteDataTypeIndexedDBDatabases");
const IOSWKWebsiteDataType._internal(
"WKWebsiteDataTypeIndexedDBDatabases");
///Service worker registrations.
///
///**NOTE**: available on iOS 11.3+.
static const WKWebsiteDataTypeServiceWorkerRegistrations =
const IOSWKWebsiteDataType._internal(
"WKWebsiteDataTypeServiceWorkerRegistrations");
const IOSWKWebsiteDataType._internal(
"WKWebsiteDataTypeServiceWorkerRegistrations");
///Returns a set of all available website data types.
// ignore: non_constant_identifier_names
static final Set<IOSWKWebsiteDataType> ALL = [
IOSWKWebsiteDataType.WKWebsiteDataTypeFetchCache,
IOSWKWebsiteDataType.WKWebsiteDataTypeDiskCache,
......@@ -2952,9 +3075,20 @@ class InAppWebViewHitTestResultType {
const InAppWebViewHitTestResultType._internal(this._value);
static final Set<InAppWebViewHitTestResultType> values = [
InAppWebViewHitTestResultType.UNKNOWN_TYPE,
InAppWebViewHitTestResultType.PHONE_TYPE,
InAppWebViewHitTestResultType.GEO_TYPE,
InAppWebViewHitTestResultType.EMAIL_TYPE,
InAppWebViewHitTestResultType.IMAGE_TYPE,
InAppWebViewHitTestResultType.SRC_ANCHOR_TYPE,
InAppWebViewHitTestResultType.SRC_IMAGE_ANCHOR_TYPE,
InAppWebViewHitTestResultType.EDIT_TEXT_TYPE,
].toSet();
static InAppWebViewHitTestResultType fromValue(int value) {
if (value != null && [0, 2, 3, 4, 5, 7, 8, 9].contains(value))
return InAppWebViewHitTestResultType._internal(value);
if (value != null)
return InAppWebViewHitTestResultType.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -3000,15 +3134,15 @@ class InAppWebViewHitTestResultType {
///[InAppWebViewHitTestResult] for hitting a HTML::a tag with src=http.
static const SRC_ANCHOR_TYPE =
const InAppWebViewHitTestResultType._internal(7);
const InAppWebViewHitTestResultType._internal(7);
///[InAppWebViewHitTestResult] for hitting a HTML::a tag with src=http + HTML::img.
static const SRC_IMAGE_ANCHOR_TYPE =
const InAppWebViewHitTestResultType._internal(8);
const InAppWebViewHitTestResultType._internal(8);
///[InAppWebViewHitTestResult] for hitting an edit text area.
static const EDIT_TEXT_TYPE =
const InAppWebViewHitTestResultType._internal(9);
const InAppWebViewHitTestResultType._internal(9);
bool operator ==(value) => value == _value;
......@@ -3099,9 +3233,15 @@ class RendererPriority {
const RendererPriority._internal(this._value);
static final Set<RendererPriority> values = [
RendererPriority.RENDERER_PRIORITY_WAIVED,
RendererPriority.RENDERER_PRIORITY_BOUND,
RendererPriority.RENDERER_PRIORITY_IMPORTANT,
].toSet();
static RendererPriority fromValue(int value) {
if (value != null && value >= 0 && value <= 2)
return RendererPriority._internal(value);
if (value != null)
return RendererPriority.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -3129,7 +3269,7 @@ class RendererPriority {
///The renderer associated with this WebView is bound with Android `Context#BIND_IMPORTANT`.
static const RENDERER_PRIORITY_IMPORTANT =
const RendererPriority._internal(2);
const RendererPriority._internal(2);
bool operator ==(value) => value == _value;
......@@ -3150,9 +3290,8 @@ class RendererPriorityPolicy {
///If true, this flag specifies that when this WebView is not visible, it will be treated as if it had requested a priority of [RendererPriority.RENDERER_PRIORITY_WAIVED].
bool waivedWhenNotVisible;
RendererPriorityPolicy(
{@required this.rendererRequestedPriority,
@required this.waivedWhenNotVisible});
RendererPriorityPolicy({@required this.rendererRequestedPriority,
@required this.waivedWhenNotVisible});
Map<String, dynamic> toMap() {
return {
......@@ -3173,9 +3312,9 @@ class RendererPriorityPolicy {
static RendererPriorityPolicy fromMap(Map<String, dynamic> map) {
return map != null
? RendererPriorityPolicy(
rendererRequestedPriority:
RendererPriority.fromValue(map["rendererRequestedPriority"]),
waivedWhenNotVisible: map["waivedWhenNotVisible"])
rendererRequestedPriority:
RendererPriority.fromValue(map["rendererRequestedPriority"]),
waivedWhenNotVisible: map["waivedWhenNotVisible"])
: null;
}
}
......@@ -3220,9 +3359,15 @@ class AndroidOverScrollMode {
const AndroidOverScrollMode._internal(this._value);
static final Set<AndroidOverScrollMode> values = [
AndroidOverScrollMode.OVER_SCROLL_ALWAYS,
AndroidOverScrollMode.OVER_SCROLL_IF_CONTENT_SCROLLS,
AndroidOverScrollMode.OVER_SCROLL_NEVER,
].toSet();
static AndroidOverScrollMode fromValue(int value) {
if (value != null && value >= 0 && value <= 2)
return AndroidOverScrollMode._internal(value);
if (value != null)
return AndroidOverScrollMode.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -3246,7 +3391,7 @@ class AndroidOverScrollMode {
///Allow a user to over-scroll this view only if the content is large enough to meaningfully scroll, provided it is a view that can scroll.
static const OVER_SCROLL_IF_CONTENT_SCROLLS =
const AndroidOverScrollMode._internal(1);
const AndroidOverScrollMode._internal(1);
///Never allow a user to over-scroll this view.
static const OVER_SCROLL_NEVER = const AndroidOverScrollMode._internal(2);
......@@ -3269,9 +3414,16 @@ class AndroidScrollBarStyle {
const AndroidScrollBarStyle._internal(this._value);
static final Set<AndroidScrollBarStyle> values = [
AndroidScrollBarStyle.SCROLLBARS_INSIDE_OVERLAY,
AndroidScrollBarStyle.SCROLLBARS_INSIDE_INSET,
AndroidScrollBarStyle.SCROLLBARS_OUTSIDE_OVERLAY,
AndroidScrollBarStyle.SCROLLBARS_OUTSIDE_INSET,
].toSet();
static AndroidScrollBarStyle fromValue(int value) {
if (value != null && [0, 16777216, 33554432, 50331648].contains(value))
return AndroidScrollBarStyle._internal(value);
if (value != null)
return AndroidScrollBarStyle.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -3295,22 +3447,22 @@ class AndroidScrollBarStyle {
///The scrollbar style to display the scrollbars inside the content area, without increasing the padding.
///The scrollbars will be overlaid with translucency on the view's content.
static const SCROLLBARS_INSIDE_OVERLAY =
const AndroidScrollBarStyle._internal(0);
const AndroidScrollBarStyle._internal(0);
///The scrollbar style to display the scrollbars inside the padded area, increasing the padding of the view.
///The scrollbars will not overlap the content area of the view.
static const SCROLLBARS_INSIDE_INSET =
const AndroidScrollBarStyle._internal(16777216);
const AndroidScrollBarStyle._internal(16777216);
///The scrollbar style to display the scrollbars at the edge of the view, without increasing the padding.
///The scrollbars will be overlaid with translucency.
static const SCROLLBARS_OUTSIDE_OVERLAY =
const AndroidScrollBarStyle._internal(33554432);
const AndroidScrollBarStyle._internal(33554432);
///The scrollbar style to display the scrollbars at the edge of the view, increasing the padding of the view.
///The scrollbars will only overlap the background, if any.
static const SCROLLBARS_OUTSIDE_INSET =
const AndroidScrollBarStyle._internal(50331648);
const AndroidScrollBarStyle._internal(50331648);
bool operator ==(value) => value == _value;
......@@ -3324,9 +3476,15 @@ class AndroidVerticalScrollbarPosition {
const AndroidVerticalScrollbarPosition._internal(this._value);
static final Set<AndroidVerticalScrollbarPosition> values = [
AndroidVerticalScrollbarPosition.SCROLLBAR_POSITION_DEFAULT,
AndroidVerticalScrollbarPosition.SCROLLBAR_POSITION_LEFT,
AndroidVerticalScrollbarPosition.SCROLLBAR_POSITION_RIGHT,
].toSet();
static AndroidVerticalScrollbarPosition fromValue(int value) {
if (value != null && value >= 0 && value <= 2)
return AndroidVerticalScrollbarPosition._internal(value);
if (value != null)
return AndroidVerticalScrollbarPosition.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -3347,15 +3505,15 @@ class AndroidVerticalScrollbarPosition {
///Position the scroll bar at the default position as determined by the system.
static const SCROLLBAR_POSITION_DEFAULT =
const AndroidVerticalScrollbarPosition._internal(0);
const AndroidVerticalScrollbarPosition._internal(0);
///Position the scroll bar along the left edge.
static const SCROLLBAR_POSITION_LEFT =
const AndroidVerticalScrollbarPosition._internal(1);
const AndroidVerticalScrollbarPosition._internal(1);
///Position the scroll bar along the right edge.
static const SCROLLBAR_POSITION_RIGHT =
const AndroidVerticalScrollbarPosition._internal(2);
const AndroidVerticalScrollbarPosition._internal(2);
bool operator ==(value) => value == _value;
......@@ -3376,7 +3534,7 @@ class AndroidWebViewPackageInfo {
static AndroidWebViewPackageInfo fromMap(Map<String, dynamic> map) {
return map != null
? AndroidWebViewPackageInfo(
versionName: map["versionName"], packageName: map["packageName"])
versionName: map["versionName"], packageName: map["packageName"])
: null;
}
......@@ -3505,13 +3663,15 @@ class WebStorageType {
const WebStorageType._internal(this._value);
static final Set<WebStorageType> values = [
WebStorageType.LOCAL_STORAGE,
WebStorageType.SESSION_STORAGE,
].toSet();
static WebStorageType fromValue(String value) {
return ([
"localStorage",
"sessionStorage",
].contains(value))
? WebStorageType._internal(value)
: null;
if (value != null)
return WebStorageType.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
String toValue() => _value;
......@@ -3525,7 +3685,7 @@ class WebStorageType {
///`window.sessionStorage`: maintains a separate storage area for each given origin that's available for the duration
///of the page session (as long as the browser is open, including page reloads and restores).
static const SESSION_STORAGE =
const WebStorageType._internal("sessionStorage");
const WebStorageType._internal("sessionStorage");
bool operator ==(value) => value == _value;
......@@ -3539,14 +3699,16 @@ class HTTPCookieSameSitePolicy {
const HTTPCookieSameSitePolicy._internal(this._value);
static final Set<HTTPCookieSameSitePolicy> values = [
HTTPCookieSameSitePolicy.LAX,
HTTPCookieSameSitePolicy.STRICT,
HTTPCookieSameSitePolicy.NONE,
].toSet();
static HTTPCookieSameSitePolicy fromValue(String value) {
return ([
"Lax",
"Strict",
"None",
].contains(value))
? HTTPCookieSameSitePolicy._internal(value)
: null;
if (value != null)
return HTTPCookieSameSitePolicy.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
String toValue() => _value;
......@@ -3584,9 +3746,18 @@ class AndroidSslError {
const AndroidSslError._internal(this._value);
static final Set<AndroidSslError> values = [
AndroidSslError.SSL_NOTYETVALID,
AndroidSslError.SSL_EXPIRED,
AndroidSslError.SSL_IDMISMATCH,
AndroidSslError.SSL_UNTRUSTED,
AndroidSslError.SSL_DATE_INVALID,
AndroidSslError.SSL_INVALID,
].toSet();
static AndroidSslError fromValue(int value) {
if (value != null && value >= 0 && value <= 5)
return AndroidSslError._internal(value);
if (value != null)
return AndroidSslError.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -3642,9 +3813,18 @@ class IOSSslError {
const IOSSslError._internal(this._value);
static final Set<IOSSslError> values = [
IOSSslError.INVALID,
IOSSslError.DENY,
IOSSslError.UNSPECIFIED,
IOSSslError.RECOVERABLE_TRUST_FAILURE,
IOSSslError.FATAL_TRUST_FAILURE,
IOSSslError.OTHER_ERROR,
].toSet();
static IOSSslError fromValue(int value) {
if (value != null && [0, 3, 4, 5, 6, 7].contains(value))
return IOSSslError._internal(value);
if (value != null)
return IOSSslError.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -3701,9 +3881,16 @@ class IOSUIScrollViewContentInsetAdjustmentBehavior {
const IOSUIScrollViewContentInsetAdjustmentBehavior._internal(this._value);
static final Set<IOSUIScrollViewContentInsetAdjustmentBehavior> values = [
IOSUIScrollViewContentInsetAdjustmentBehavior.AUTOMATIC,
IOSUIScrollViewContentInsetAdjustmentBehavior.SCROLLABLE_AXES,
IOSUIScrollViewContentInsetAdjustmentBehavior.NEVER,
IOSUIScrollViewContentInsetAdjustmentBehavior.ALWAYS,
].toSet();
static IOSUIScrollViewContentInsetAdjustmentBehavior fromValue(int value) {
if (value != null && value >= 0 && value <= 3)
return IOSUIScrollViewContentInsetAdjustmentBehavior._internal(value);
if (value != null)
return IOSUIScrollViewContentInsetAdjustmentBehavior.values.firstWhere((element) => element.toValue() == value, orElse: () => null);
return null;
}
......@@ -3725,16 +3912,20 @@ class IOSUIScrollViewContentInsetAdjustmentBehavior {
}
///Automatically adjust the scroll view insets.
static const AUTOMATIC = const IOSUIScrollViewContentInsetAdjustmentBehavior._internal(0);
static const AUTOMATIC = const IOSUIScrollViewContentInsetAdjustmentBehavior
._internal(0);
///Adjust the insets only in the scrollable directions.
static const SCROLLABLE_AXES = const IOSUIScrollViewContentInsetAdjustmentBehavior._internal(1);
static const SCROLLABLE_AXES = const IOSUIScrollViewContentInsetAdjustmentBehavior
._internal(1);
///Do not adjust the scroll view insets.
static const NEVER = const IOSUIScrollViewContentInsetAdjustmentBehavior._internal(2);
static const NEVER = const IOSUIScrollViewContentInsetAdjustmentBehavior
._internal(2);
///Always include the safe area insets in the content adjustment.
static const ALWAYS = const IOSUIScrollViewContentInsetAdjustmentBehavior._internal(3);
static const ALWAYS = const IOSUIScrollViewContentInsetAdjustmentBehavior
._internal(3);
bool operator ==(value) => value == _value;
......@@ -3778,10 +3969,14 @@ class SslCertificate {
}
return map != null ? SslCertificate(
issuedBy: SslCertificateDName.fromMap(map["issuedBy"]?.cast<String, dynamic>()),
issuedTo: SslCertificateDName.fromMap(map["issuedTo"]?.cast<String, dynamic>()),
validNotAfterDate: DateTime.fromMillisecondsSinceEpoch(map["validNotAfterDate"]),
validNotBeforeDate: DateTime.fromMillisecondsSinceEpoch(map["validNotBeforeDate"]),
issuedBy: SslCertificateDName.fromMap(
map["issuedBy"]?.cast<String, dynamic>()),
issuedTo: SslCertificateDName.fromMap(
map["issuedTo"]?.cast<String, dynamic>()),
validNotAfterDate: DateTime.fromMillisecondsSinceEpoch(
map["validNotAfterDate"]),
validNotBeforeDate: DateTime.fromMillisecondsSinceEpoch(
map["validNotBeforeDate"]),
x509Certificate: x509Certificate,
) : null;
}
......@@ -3811,18 +4006,22 @@ class SslCertificateDName {
///Common-name (CN) component of the name
// ignore: non_constant_identifier_names
String CName;
///Distinguished name (normally includes CN, O, and OU names)
// ignore: non_constant_identifier_names
String DName;
///Organization (O) component of the name
// ignore: non_constant_identifier_names
String OName;
///Organizational Unit (OU) component of the name
// ignore: non_constant_identifier_names
String UName;
// ignore: non_constant_identifier_names
SslCertificateDName({this.CName = "", this.DName = "", this.OName = "", this.UName = ""});
SslCertificateDName(
// ignore: non_constant_identifier_names
{this.CName = "", this.DName = "", this.OName = "", this.UName = ""});
static SslCertificateDName fromMap(Map<String, dynamic> map) {
return map != null ? SslCertificateDName(
......
......@@ -301,12 +301,6 @@ class InAppWebViewOptions
InAppWebViewOptions copy() {
return InAppWebViewOptions.fromMap(this.toMap());
}
InAppWebViewOptions copyWithValue(InAppWebViewOptions webViewOptions) {
var mergedMap = this.toMap();
mergedMap.addAll(webViewOptions.toMap());
return InAppWebViewOptions.fromMap(mergedMap);
}
}
///This class represents all the Android-only WebView options available.
......@@ -709,12 +703,6 @@ class AndroidInAppWebViewOptions
AndroidInAppWebViewOptions copy() {
return AndroidInAppWebViewOptions.fromMap(this.toMap());
}
AndroidInAppWebViewOptions copyWithValue(AndroidInAppWebViewOptions webViewOptions) {
var mergedMap = this.toMap();
mergedMap.addAll(webViewOptions.toMap());
return AndroidInAppWebViewOptions.fromMap(mergedMap);
}
}
///This class represents all the iOS-only WebView options available.
......@@ -783,7 +771,7 @@ class IOSInAppWebViewOptions
///**NOTE**: available on iOS 13.0+.
bool automaticallyAdjustsScrollIndicatorInsets;
///A Boolean value indicating whether the view ignores an accessibility request to invert its colors.
///A Boolean value indicating whether the WebView ignores an accessibility request to invert its colors.
///The default value is `false`.
///
///**NOTE**: available on iOS 11.0+.
......@@ -949,12 +937,6 @@ class IOSInAppWebViewOptions
IOSInAppWebViewOptions copy() {
return IOSInAppWebViewOptions.fromMap(this.toMap());
}
IOSInAppWebViewOptions copyWithValue(IOSInAppWebViewOptions webViewOptions) {
var mergedMap = this.toMap();
mergedMap.addAll(webViewOptions.toMap());
return IOSInAppWebViewOptions.fromMap(mergedMap);
}
}
///This class represents all the cross-platform [InAppBrowser] options available.
......@@ -1012,12 +994,6 @@ class InAppBrowserOptions
InAppBrowserOptions copy() {
return InAppBrowserOptions.fromMap(this.toMap());
}
InAppBrowserOptions copyWithValue(InAppBrowserOptions webViewOptions) {
var mergedMap = this.toMap();
mergedMap.addAll(webViewOptions.toMap());
return InAppBrowserOptions.fromMap(mergedMap);
}
}
///This class represents all the Android-only [InAppBrowser] options available.
......@@ -1073,12 +1049,6 @@ class AndroidInAppBrowserOptions implements BrowserOptions, AndroidOptions {
AndroidInAppBrowserOptions copy() {
return AndroidInAppBrowserOptions.fromMap(this.toMap());
}
AndroidInAppBrowserOptions copyWithValue(AndroidInAppBrowserOptions webViewOptions) {
var mergedMap = this.toMap();
mergedMap.addAll(webViewOptions.toMap());
return AndroidInAppBrowserOptions.fromMap(mergedMap);
}
}
///This class represents all the iOS-only [InAppBrowser] options available.
......@@ -1160,12 +1130,6 @@ class IOSInAppBrowserOptions implements BrowserOptions, IosOptions {
IOSInAppBrowserOptions copy() {
return IOSInAppBrowserOptions.fromMap(this.toMap());
}
IOSInAppBrowserOptions copyWithValue(IOSInAppBrowserOptions webViewOptions) {
var mergedMap = this.toMap();
mergedMap.addAll(webViewOptions.toMap());
return IOSInAppBrowserOptions.fromMap(mergedMap);
}
}
///This class represents all the Android-only [ChromeSafariBrowser] options available.
......@@ -1245,12 +1209,6 @@ class AndroidChromeCustomTabsOptions
AndroidChromeCustomTabsOptions copy() {
return AndroidChromeCustomTabsOptions.fromMap(this.toMap());
}
AndroidChromeCustomTabsOptions copyWithValue(AndroidChromeCustomTabsOptions webViewOptions) {
var mergedMap = this.toMap();
mergedMap.addAll(webViewOptions.toMap());
return AndroidChromeCustomTabsOptions.fromMap(mergedMap);
}
}
///This class represents all the iOS-only [ChromeSafariBrowser] options available.
......@@ -1333,10 +1291,4 @@ class IOSSafariOptions implements ChromeSafariBrowserOptions, IosOptions {
IOSSafariOptions copy() {
return IOSSafariOptions.fromMap(this.toMap());
}
IOSSafariOptions copyWithValue(IOSSafariOptions webViewOptions) {
var mergedMap = this.toMap();
mergedMap.addAll(webViewOptions.toMap());
return IOSSafariOptions.fromMap(mergedMap);
}
}
......@@ -12,7 +12,6 @@ dependencies:
sdk: flutter
uuid: ^2.0.0
mime: ^0.9.6+2
html: ^0.14.0+3
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment