Commit 6a7963e4 authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

fixed android zoom, added new ios webview options, added

>  onLongPressHitTestResult event, updated test cases, fixed Promise polyfill, fixed android options
parent 7d9f9f56
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
## 3.0.0
- Added `Promise` javascript [polyfill](https://github.com/taylorhakes/promise-polyfill/blob/master/src/index.js) for webviews that doesn't support it for `window.flutter_inappwebview.callHandler`
- Added `Promise` javascript [polyfill](https://github.com/tildeio/rsvp.js) for webviews that doesn't support it for `window.flutter_inappwebview.callHandler`
- Added `getDefaultUserAgent` static method to `InAppWebViewController`
- Added `onUpdateVisitedHistory`, `onPrint` event
- Added `onGeolocationPermissionsHidePrompt` event for Android
- Added `onUpdateVisitedHistory`, `onPrint`, `onLongPressHitTestResult` event
- Added `androidOnGeolocationPermissionsHidePrompt` event for Android webview
- Added `iosOnWebContentProcessDidTerminate`, `iosOnDidCommit`, `iosOnDidReceiveServerRedirectForProvisionalNavigation` events for iOS webview
- Added `supportMultipleWindows` webview option for Android
- Added `regexToCancelSubFramesLoading` webview option for Android to cancel subframe requests on `shouldOverrideUrlLoading` event based on a Regular Expression
- Added `getContentHeight`, `zoomBy`, `printCurrentPage`, `getScale` methods
- Added `getOriginalUrl` webview method for Android
- Added `reloadFromOrigin` webview method for iOS
- Added `automaticallyAdjustsScrollIndicatorInsets` webview options for iOS
- Added `reloadFromOrigin`, `hasOnlySecureContent` webview methods for iOS
- Added `automaticallyAdjustsScrollIndicatorInsets`, `accessibilityIgnoresInvertColors`, `decelerationRate`, `alwaysBounceVertical`, `alwaysBounceHorizontal`, `scrollsToTop`, `isPagingEnabled`, `maximumZoomScale`, `minimumZoomScale` webview options for iOS
- Added `WebStorageManager` class which manages the web storage used by WebView instances
- Added `packageName` [#229](https://github.com/pichillilorenzo/flutter_inappwebview/issues/229) and `keepAliveEnabled` ChromeCustomTab options for Android
- Updated for Flutter 1.12 new Java Embedding API (Android)
......@@ -17,10 +18,16 @@
- Updated default value for `domStorageEnabled` and `databaseEnabled` options to `true` for Android
- Merge "Fixes null error when calling getOptions for InAppBrowser class" [#214](https://github.com/pichillilorenzo/flutter_inappwebview/pull/214) (thanks to [panndoraBoo](https://github.com/panndoraBoo))
- Merge "Fixes crash onConsoleMessage iOS forced unwrapping" [#228](https://github.com/pichillilorenzo/flutter_inappwebview/pull/228) (thanks to [tokonu](https://github.com/tokonu))
- Merge "Fix HTTPCookie.secure" [#311](https://github.com/pichillilorenzo/flutter_inappwebview/pull/311) (thanks to [xtyxtyx](https://github.com/xtyxtyx))
- Merge "Fix config options for Android release builds" [#295](https://github.com/pichillilorenzo/flutter_inappwebview/pull/295) (thanks to [wwwdata](https://github.com/wwwdata))
- Merge "fix scrollbar on iOS always show if not disable scroll" [#256](https://github.com/pichillilorenzo/flutter_inappwebview/pull/256) (thanks to [phamnhuvu-dev](https://github.com/phamnhuvu-dev))
- Merge "Fix crash on nil/invalid URL (iOS)" [#262](https://github.com/pichillilorenzo/flutter_inappwebview/pull/262) (thanks to [AlexVincent525](https://github.com/AlexVincent525))
- Merge "Fix crash when `prompt` was called on Android Q." [#262](https://github.com/pichillilorenzo/flutter_inappwebview/pull/263) (thanks to [AlexVincent525](https://github.com/AlexVincent525))
- Fix for Android and iOS `InAppBrowser` for some controller methods not exposed.
- Fixed "App Crashes after clicking on dropdown (Using inappwebview)" [#182](https://github.com/pichillilorenzo/flutter_inappwebview/issues/182)
- Fixed "webview can not be released when in ios" [#225](https://github.com/pichillilorenzo/flutter_inappwebview/issues/225). Now the iOS WebView is released from memory when it is disposed from Flutter.
- Fixed "Setting of presentationStyle not working on iOS" [#213](https://github.com/pichillilorenzo/flutter_inappwebview/issues/213)
- Fixed "Android zoom issues" [#270](https://github.com/pichillilorenzo/flutter_inappwebview/issues/270)
### BREAKING CHANGES
......
File mode changed from 100644 to 100755
......@@ -11,8 +11,8 @@ A Flutter plugin that allows you to add an inline webview or open an in-app brow
### Requirements
- Dart sdk: ">=2.0.0-dev.68.0 <3.0.0"
- Flutter: ">=1.9.1+hotfix.5 <2.0.0"
- Dart sdk: ">=2.7.0 <3.0.0"
- Flutter: ">=1.12.13+hotfix.5"
- Android: `minSdkVersion 17` and add support for `androidx` (see [AndroidX Migration](https://flutter.dev/docs/development/androidx-migration) to migrate an existing app)
- iOS: `--ios-language swift`, Xcode version `>= 11`
......@@ -448,6 +448,15 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly:
* `selectionGranularity`: The level of granularity with which the user can interactively select content in the web view.
* `dataDetectorTypes`: Specifying a dataDetectoryTypes value adds interactivity to web content that matches the value.
* `sharedCookiesEnabled`: Set `true` if shared cookies from `HTTPCookieStorage.shared` should used for every load request in the WebView.
* `automaticallyAdjustsScrollIndicatorInsets`: Configures whether the scroll indicator insets are automatically adjusted by the system. The default value is `false`.
* `accessibilityIgnoresInvertColors`: A Boolean value indicating whether the view ignores an accessibility request to invert its colors. The default value is `false`.
* `decelerationRate`: A `IOSUIScrollViewDecelerationRate` value that determines the rate of deceleration after the user lifts their finger. The default value is `IOSUIScrollViewDecelerationRate.NORMAL`.
* `alwaysBounceVertical`: A Boolean value that determines whether bouncing always occurs when vertical scrolling reaches the end of the content. The default value is `false`.
* `alwaysBounceHorizontal`: A Boolean value that determines whether bouncing always occurs when horizontal scrolling reaches the end of the content view. The default value is `false`.
* `scrollsToTop`: A Boolean value that controls whether the scroll-to-top gesture is enabled. The default value is `true`.
* `isPagingEnabled`: A Boolean value that determines whether paging is enabled for the scroll view. The default value is `false`.
* `maximumZoomScale`: A floating-point value that specifies the maximum scale factor that can be applied to the scroll view's content. The default value is `1.0`.
* `minimumZoomScale`: A floating-point value that specifies the minimum scale factor that can be applied to the scroll view's content. The default value is `1.0`.
#### `InAppWebView` Events
......@@ -479,10 +488,14 @@ Event names that starts with `android` or `ios` are events platform-specific.
* `onAjaxProgress`: Event fired as an `XMLHttpRequest` progress (to use this event, the `useShouldInterceptAjaxRequest` option must be `true`).
* `shouldInterceptFetchRequest`: Event fired when a request is sent to a server through [Fetch API](https://developer.mozilla.org/it/docs/Web/API/Fetch_API) (to use this event, the `useShouldInterceptFetchRequest` option must be `true`).
* `onPrint`: Event fired when `window.print()` is called from JavaScript side.
* `onLongPressHitTestResult`: Event fired when an HTML element of the webview has been clicked and held.
* `androidOnSafeBrowsingHit`: Event fired when the webview notifies that a loading URL has been flagged by Safe Browsing (available only on Android).
* `androidOnPermissionRequest`: Event fired when the webview is requesting permission to access the specified resources and the permission currently isn't granted or denied (available only on Android).
* `androidOnGeolocationPermissionsShowPrompt`: Event that notifies the host application that web content from the specified origin is attempting to use the Geolocation API, but no permission state is currently set for that origin (available only on Android).
* `androidOnGeolocationPermissionsHidePrompt`: Notify the host application that a request for Geolocation permissions, made with a previous call to `androidOnGeolocationPermissionsShowPrompt` has been canceled. (available only on Android).
* `iosOnWebContentProcessDidTerminate`: Invoked when the web view's web content process is terminated (available only on iOS).
* `iosOnDidCommit`: Called when the web view begins to receive web content (available only on iOS).
* `iosOnDidReceiveServerRedirectForProvisionalNavigation`: Called when a web view receives a server redirect (available only on iOS).
### `InAppBrowser` class
......@@ -553,7 +566,12 @@ class MyInAppBrowser extends InAppBrowser {
}
}
void main() => runApp(new MyApp());
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(
new MyApp(),
);
}
class MyApp extends StatefulWidget {
final MyInAppBrowser browser = new MyInAppBrowser();
......@@ -707,7 +725,12 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser {
}
}
void main() => runApp(new MyApp());
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(
new MyApp(),
);
}
class MyApp extends StatefulWidget {
final ChromeSafariBrowser browser = new MyChromeSafariBrowser(new MyInAppBrowser());
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -2,7 +2,10 @@ package com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs;
import com.pichillilorenzo.flutter_inappwebview.Options;
public class ChromeCustomTabsOptions extends Options {
import java.util.HashMap;
import java.util.Map;
public class ChromeCustomTabsOptions implements Options {
final static String LOG_TAG = "ChromeCustomTabsOptions";
......@@ -14,4 +17,53 @@ public class ChromeCustomTabsOptions extends Options {
public String packageName;
public Boolean keepAliveEnabled = false;
@Override
public ChromeCustomTabsOptions parse(HashMap<String, Object> options) {
for (Map.Entry<String, Object> pair : options.entrySet()) {
String key = pair.getKey();
Object value = pair.getValue();
if (value == null) {
continue;
}
switch (key) {
case "addDefaultShareMenuItem":
addDefaultShareMenuItem = (boolean) value;
break;
case "showTitle":
showTitle = (boolean) value;
break;
case "toolbarBackgroundColor":
toolbarBackgroundColor = (String) value;
break;
case "enableUrlBarHiding":
enableUrlBarHiding = (boolean) value;
break;
case "instantAppsEnabled":
instantAppsEnabled = (boolean) value;
break;
case "packageName":
packageName = (String) value;
break;
case "keepAliveEnabled":
keepAliveEnabled = (boolean) value;
break;
}
}
return this;
}
@Override
public HashMap<String, Object> getHashMap() {
HashMap<String, Object> options = new HashMap<>();
options.put("addDefaultShareMenuItem", addDefaultShareMenuItem);
options.put("showTitle", showTitle);
options.put("toolbarBackgroundColor", toolbarBackgroundColor);
options.put("enableUrlBarHiding", enableUrlBarHiding);
options.put("instantAppsEnabled", instantAppsEnabled);
options.put("packageName", packageName);
options.put("keepAliveEnabled", keepAliveEnabled);
return options;
}
}
package com.pichillilorenzo.flutter_inappwebview;
public class InAppBrowserOptions extends Options {
import java.util.HashMap;
import java.util.Map;
public class InAppBrowserOptions implements Options {
public static final String LOG_TAG = "InAppBrowserOptions";
......@@ -13,4 +16,58 @@ public class InAppBrowserOptions extends Options {
public Boolean hideTitleBar = false;
public Boolean closeOnCannotGoBack = true;
public Boolean progressBar = true;
@Override
public InAppBrowserOptions parse(HashMap<String, Object> options) {
for (Map.Entry<String, Object> pair : options.entrySet()) {
String key = pair.getKey();
Object value = pair.getValue();
if (value == null) {
continue;
}
switch (key) {
case "hidden":
hidden = (boolean) value;
break;
case "toolbarTop":
toolbarTop = (boolean) value;
break;
case "toolbarTopBackgroundColor":
toolbarTopBackgroundColor = (String) value;
break;
case "toolbarTopFixedTitle":
toolbarTopFixedTitle = (String) value;
break;
case "hideUrlBar":
hideUrlBar = (boolean) value;
break;
case "hideTitleBar":
hideTitleBar = (boolean) value;
break;
case "closeOnCannotGoBack":
closeOnCannotGoBack = (boolean) value;
break;
case "progressBar":
progressBar = (boolean) value;
break;
}
}
return this;
}
@Override
public HashMap<String, Object> getHashMap() {
HashMap<String, Object> options = new HashMap<>();
options.put("hidden", hidden);
options.put("toolbarTop", toolbarTop);
options.put("toolbarTopBackgroundColor", toolbarTopBackgroundColor);
options.put("toolbarTopFixedTitle", toolbarTopFixedTitle);
options.put("hideUrlBar", hideUrlBar);
options.put("hideTitleBar", hideTitleBar);
options.put("closeOnCannotGoBack", closeOnCannotGoBack);
options.put("progressBar", progressBar);
return options;
}
}
......@@ -4,14 +4,20 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.print.PrintManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
import android.webkit.CookieManager;
import android.webkit.DownloadListener;
import android.webkit.ValueCallback;
......@@ -21,6 +27,10 @@ import android.webkit.WebSettings;
import android.webkit.WebStorage;
import androidx.annotation.RequiresApi;
import androidx.appcompat.widget.PopupMenu;
import android.view.ActionMode;
import android.webkit.WebView;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlocker;
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerAction;
......@@ -28,7 +38,6 @@ import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerHan
import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerTrigger;
import com.pichillilorenzo.flutter_inappwebview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.JavaScriptBridgeInterface;
import com.pichillilorenzo.flutter_inappwebview.Shared;
import com.pichillilorenzo.flutter_inappwebview.Util;
......@@ -115,7 +124,7 @@ final public class InAppWebView extends InputAwareWebView {
static final String interceptAjaxRequestsJS = "(function(ajax) {" +
" var send = ajax.prototype.send;" +
" var openUrl = ajax.prototype.openUrl;" +
" var open = ajax.prototype.open;" +
" var setRequestHeader = ajax.prototype.setRequestHeader;" +
" ajax.prototype._flutter_inappwebview_url = null;" +
" ajax.prototype._flutter_inappwebview_method = null;" +
......@@ -148,7 +157,7 @@ final public class InAppWebView extends InputAwareWebView {
" }" +
" callback(null);" +
" };" +
" ajax.prototype.openUrl = function(method, url, isAsync, user, password) {" +
" ajax.prototype.open = function(method, url, isAsync, user, password) {" +
" isAsync = (isAsync != null) ? isAsync : true;" +
" this._flutter_inappwebview_url = url;" +
" this._flutter_inappwebview_method = method;" +
......@@ -156,7 +165,7 @@ final public class InAppWebView extends InputAwareWebView {
" this._flutter_inappwebview_user = user;" +
" this._flutter_inappwebview_password = password;" +
" this._flutter_inappwebview_request_headers = {};" +
" openUrl.call(this, method, url, isAsync, user, password);" +
" open.call(this, method, url, isAsync, user, password);" +
" };" +
" ajax.prototype.setRequestHeader = function(header, value) {" +
" this._flutter_inappwebview_request_headers[header] = value;" +
......@@ -311,7 +320,7 @@ final public class InAppWebView extends InputAwareWebView {
" };" +
" if ((self._flutter_inappwebview_method != result.method && result.method != null) || (self._flutter_inappwebview_url != result.url && result.url != null)) {" +
" self.abort();" +
" self.openUrl(result.method, result.url, result.isAsync, result.user, result.password);" +
" self.open(result.method, result.url, result.isAsync, result.user, result.password);" +
" return;" +
" }" +
" }" +
......@@ -527,6 +536,7 @@ final public class InAppWebView extends InputAwareWebView {
this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel;
this.id = id;
this.options = options;
//Shared.activity.registerForContextMenu(this);
}
@Override
......@@ -643,16 +653,9 @@ final public class InAppWebView extends InputAwareWebView {
settings.setSansSerifFontFamily(options.sansSerifFontFamily);
settings.setSerifFontFamily(options.serifFontFamily);
settings.setStandardFontFamily(options.standardFontFamily);
if (options.preferredContentMode != null) {
switch (fromValue(options.preferredContentMode)) {
case DESKTOP:
if (options.preferredContentMode != null &&
options.preferredContentMode == PreferredContentModeOptionType.DESKTOP.toValue()) {
setDesktopMode(true);
break;
case MOBILE:
case RECOMMENDED:
setDesktopMode(false);
break;
}
}
settings.setSaveFormData(options.saveFormData);
if (options.incognito)
......@@ -688,18 +691,13 @@ final public class InAppWebView extends InputAwareWebView {
setVerticalScrollBarEnabled(!options.disableVerticalScroll);
setHorizontalScrollBarEnabled(!options.disableHorizontalScroll);
setOnTouchListener(new View.OnTouchListener() {
float m_downX;
float m_downY;
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getPointerCount() > 1) {
//Multi touch detected
return true;
}
if (options.disableHorizontalScroll && options.disableVerticalScroll) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
......@@ -729,6 +727,31 @@ final public class InAppWebView extends InputAwareWebView {
return false;
}
});
setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
HitTestResult hitTestResult = getHitTestResult();
Map<String, Object> hitTestResultMap = new HashMap<>();
hitTestResultMap.put("type", hitTestResult.getType());
hitTestResultMap.put("extra", hitTestResult.getExtra());
Map<String, Object> obj = new HashMap<>();
if (inAppBrowserActivity != null)
obj.put("uuid", inAppBrowserActivity.uuid);
obj.put("hitTestResult", hitTestResultMap);
channel.invokeMethod("onLongPressHitTestResult", obj);
return false;
}
});
}
private Point lastTouch;
@Override
public boolean onTouchEvent(MotionEvent ev) {
lastTouch = new Point((int) ev.getX(), (int) ev.getY()) ;
return super.onTouchEvent(ev);
}
public void setIncognito(boolean enabled) {
......@@ -1334,7 +1357,69 @@ final public class InAppWebView extends InputAwareWebView {
public Float getUpdatedScale() {
return scale;
}
/*
@Override
public void onCreateContextMenu(ContextMenu menu) {
Log.d(LOG_TAG, getHitTestResult().getType() + "");
String extra = getHitTestResult().getExtra();
//if (getHitTestResult().getType() == 7 || getHitTestResult().getType() == 5)
if (extra != null)
Log.d(LOG_TAG, extra);
Log.d(LOG_TAG, "\n\nonCreateContextMenu\n\n");
for(int i = 0; i < menu.size(); i++) {
Log.d(LOG_TAG, menu.getItem(i).toString());
}
}
private Integer mActionMode;
private CustomActionModeCallback mActionModeCallback;
@Override
public ActionMode startActionMode(ActionMode.Callback callback, int mode) {
Log.d(LOG_TAG, "startActionMode");
ViewParent parent = getParent();
if (parent == null || mActionMode != null) {
return null;
}
mActionModeCallback = new CustomActionModeCallback();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mActionMode = ActionMode.TYPE_FLOATING;
//return Shared.activity.getWindow().getDecorView().startActionMode(mActionModeCallback, mActionMode);
return parent.startActionModeForChild(this, mActionModeCallback, mActionMode);
} else {
return parent.startActionModeForChild(this, mActionModeCallback);
}
}
private class CustomActionModeCallback implements ActionMode.Callback {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
menu.add("ciao");
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
mode.finish();
return true;
}
// Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
clearFocus();
}
}
*/
@Override
public void dispose() {
super.dispose();
......
......@@ -4,16 +4,18 @@ import android.os.Build;
import android.util.Log;
import android.webkit.WebSettings;
import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ChromeCustomTabsOptions;
import com.pichillilorenzo.flutter_inappwebview.Options;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static android.webkit.WebSettings.LayoutAlgorithm.NORMAL;
public class InAppWebViewOptions extends Options {
public class InAppWebViewOptions implements Options {
public static final String LOG_TAG = "InAppWebViewOptions";
......@@ -85,47 +87,316 @@ public class InAppWebViewOptions extends Options {
public String regexToCancelSubFramesLoading;
@Override
public Object onParse(Map.Entry<String, Object> pair) {
if (pair.getKey().equals("layoutAlgorithm")) {
String value = (String) pair.getValue();
public InAppWebViewOptions parse(HashMap<String, Object> options) {
for (Map.Entry<String, Object> pair : options.entrySet()) {
String key = pair.getKey();
Object value = pair.getValue();
if (value == null) {
continue;
}
switch (key) {
case "useShouldOverrideUrlLoading":
useShouldOverrideUrlLoading = (Boolean) value;
break;
case "useOnLoadResource":
useOnLoadResource = (Boolean) value;
break;
case "useOnDownloadStart":
useOnDownloadStart = (Boolean) value;
break;
case "clearCache":
clearCache = (Boolean) value;
break;
case "userAgent":
userAgent = (String) value;
break;
case "applicationNameForUserAgent":
applicationNameForUserAgent = (String) value;
break;
case "javaScriptEnabled":
javaScriptEnabled = (Boolean) value;
break;
case "debuggingEnabled":
debuggingEnabled = (Boolean) value;
break;
case "javaScriptCanOpenWindowsAutomatically":
javaScriptCanOpenWindowsAutomatically = (Boolean) value;
break;
case "mediaPlaybackRequiresUserGesture":
mediaPlaybackRequiresUserGesture = (Boolean) value;
break;
case "minimumFontSize":
minimumFontSize = (Integer) value;
break;
case "verticalScrollBarEnabled":
verticalScrollBarEnabled = (Boolean) value;
break;
case "horizontalScrollBarEnabled":
horizontalScrollBarEnabled = (Boolean) value;
break;
case "resourceCustomSchemes":
resourceCustomSchemes = (List<String>) value;
break;
case "contentBlockers":
contentBlockers = (List<Map<String, Map<String, Object>>>) value;
break;
case "preferredContentMode":
preferredContentMode = (Integer) value;
break;
case "useShouldInterceptAjaxRequest":
useShouldInterceptAjaxRequest = (Boolean) value;
break;
case "useShouldInterceptFetchRequest":
useShouldInterceptFetchRequest = (Boolean) value;
break;
case "incognito":
incognito = (Boolean) value;
break;
case "cacheEnabled":
cacheEnabled = (Boolean) value;
break;
case "transparentBackground":
transparentBackground = (Boolean) value;
break;
case "disableVerticalScroll":
disableVerticalScroll = (Boolean) value;
break;
case "disableHorizontalScroll":
disableHorizontalScroll = (Boolean) value;
break;
case "textZoom":
textZoom = (Integer) value;
break;
case "clearSessionCache":
clearSessionCache = (Boolean) value;
break;
case "builtInZoomControls":
builtInZoomControls = (Boolean) value;
break;
case "displayZoomControls":
displayZoomControls = (Boolean) value;
break;
case "supportZoom":
supportZoom = (Boolean) value;
break;
case "databaseEnabled":
databaseEnabled = (Boolean) value;
break;
case "domStorageEnabled":
domStorageEnabled = (Boolean) value;
break;
case "useWideViewPort":
useWideViewPort = (Boolean) value;
break;
case "safeBrowsingEnabled":
safeBrowsingEnabled = (Boolean) value;
break;
case "mixedContentMode":
mixedContentMode = (Integer) value;
break;
case "allowContentAccess":
allowContentAccess = (Boolean) value;
break;
case "allowFileAccess":
allowFileAccess = (Boolean) value;
break;
case "allowFileAccessFromFileURLs":
allowFileAccessFromFileURLs = (Boolean) value;
break;
case "allowUniversalAccessFromFileURLs":
allowUniversalAccessFromFileURLs = (Boolean) value;
break;
case "appCachePath":
appCachePath = (String) value;
break;
case "blockNetworkImage":
blockNetworkImage = (Boolean) value;
break;
case "blockNetworkLoads":
blockNetworkLoads = (Boolean) value;
break;
case "cacheMode":
cacheMode = (Integer) value;
break;
case "cursiveFontFamily":
cursiveFontFamily = (String) value;
break;
case "defaultFixedFontSize":
defaultFixedFontSize = (Integer) value;
break;
case "defaultFontSize":
defaultFontSize = (Integer) value;
break;
case "defaultTextEncodingName":
defaultTextEncodingName = (String) value;
break;
case "disabledActionModeMenuItems":
disabledActionModeMenuItems = (Integer) value;
break;
case "fantasyFontFamily":
fantasyFontFamily = (String) value;
break;
case "fixedFontFamily":
fixedFontFamily = (String) value;
break;
case "forceDark":
forceDark = (Integer) value;
break;
case "geolocationEnabled":
geolocationEnabled = (Boolean) value;
break;
case "layoutAlgorithm":
setLayoutAlgorithm((String) value);
break;
case "loadWithOverviewMode":
loadWithOverviewMode = (Boolean) value;
break;
case "loadsImagesAutomatically":
loadsImagesAutomatically = (Boolean) value;
break;
case "minimumLogicalFontSize":
minimumLogicalFontSize = (Integer) value;
break;
case "initialScale":
initialScale = (Integer) value;
break;
case "needInitialFocus":
needInitialFocus = (Boolean) value;
break;
case "offscreenPreRaster":
offscreenPreRaster = (Boolean) value;
break;
case "sansSerifFontFamily":
sansSerifFontFamily = (String) value;
break;
case "serifFontFamily":
serifFontFamily = (String) value;
break;
case "standardFontFamily":
standardFontFamily = (String) value;
break;
case "saveFormData":
saveFormData = (Boolean) value;
break;
case "thirdPartyCookiesEnabled":
thirdPartyCookiesEnabled = (Boolean) value;
break;
case "hardwareAcceleration":
hardwareAcceleration = (Boolean) value;
break;
case "supportMultipleWindows":
supportMultipleWindows = (Boolean) value;
break;
case "regexToCancelSubFramesLoading":
regexToCancelSubFramesLoading = (String) value;
break;
}
}
return this;
}
@Override
public HashMap<String, Object> getHashMap() {
HashMap<String, Object> options = new HashMap<>();
options.put("useShouldOverrideUrlLoading", useShouldOverrideUrlLoading);
options.put("useOnLoadResource", useOnLoadResource);
options.put("useOnDownloadStart", useOnDownloadStart);
options.put("clearCache", clearCache);
options.put("userAgent", userAgent);
options.put("applicationNameForUserAgent", applicationNameForUserAgent);
options.put("javaScriptEnabled", javaScriptEnabled);
options.put("debuggingEnabled", debuggingEnabled);
options.put("javaScriptCanOpenWindowsAutomatically", javaScriptCanOpenWindowsAutomatically);
options.put("mediaPlaybackRequiresUserGesture", mediaPlaybackRequiresUserGesture);
options.put("minimumFontSize", minimumFontSize);
options.put("verticalScrollBarEnabled", verticalScrollBarEnabled);
options.put("horizontalScrollBarEnabled", horizontalScrollBarEnabled);
options.put("resourceCustomSchemes", resourceCustomSchemes);
options.put("contentBlockers", contentBlockers);
options.put("preferredContentMode", preferredContentMode);
options.put("useShouldInterceptAjaxRequest", useShouldInterceptAjaxRequest);
options.put("useShouldInterceptFetchRequest", useShouldInterceptFetchRequest);
options.put("incognito", incognito);
options.put("cacheEnabled", cacheEnabled);
options.put("transparentBackground", transparentBackground);
options.put("disableVerticalScroll", disableVerticalScroll);
options.put("disableHorizontalScroll", disableHorizontalScroll);
options.put("textZoom", textZoom);
options.put("clearSessionCache", clearSessionCache);
options.put("builtInZoomControls", builtInZoomControls);
options.put("displayZoomControls", displayZoomControls);
options.put("supportZoom", supportZoom);
options.put("databaseEnabled", databaseEnabled);
options.put("domStorageEnabled", domStorageEnabled);
options.put("useWideViewPort", useWideViewPort);
options.put("safeBrowsingEnabled", safeBrowsingEnabled);
options.put("mixedContentMode", mixedContentMode);
options.put("allowContentAccess", allowContentAccess);
options.put("allowFileAccess", allowFileAccess);
options.put("allowFileAccessFromFileURLs", allowFileAccessFromFileURLs);
options.put("allowUniversalAccessFromFileURLs", allowUniversalAccessFromFileURLs);
options.put("appCachePath", appCachePath);
options.put("blockNetworkImage", blockNetworkImage);
options.put("blockNetworkLoads", blockNetworkLoads);
options.put("cacheMode", cacheMode);
options.put("cursiveFontFamily", cursiveFontFamily);
options.put("defaultFixedFontSize", defaultFixedFontSize);
options.put("defaultFontSize", defaultFontSize);
options.put("defaultTextEncodingName", defaultTextEncodingName);
options.put("disabledActionModeMenuItems", disabledActionModeMenuItems);
options.put("fantasyFontFamily", fantasyFontFamily);
options.put("fixedFontFamily", fixedFontFamily);
options.put("forceDark", forceDark);
options.put("geolocationEnabled", geolocationEnabled);
options.put("layoutAlgorithm", getLayoutAlgorithm());
options.put("loadWithOverviewMode", loadWithOverviewMode);
options.put("loadsImagesAutomatically", loadsImagesAutomatically);
options.put("minimumLogicalFontSize", minimumLogicalFontSize);
options.put("initialScale", initialScale);
options.put("needInitialFocus", needInitialFocus);
options.put("offscreenPreRaster", offscreenPreRaster);
options.put("sansSerifFontFamily", sansSerifFontFamily);
options.put("serifFontFamily", serifFontFamily);
options.put("standardFontFamily", standardFontFamily);
options.put("saveFormData", saveFormData);
options.put("thirdPartyCookiesEnabled", thirdPartyCookiesEnabled);
options.put("hardwareAcceleration", hardwareAcceleration);
options.put("supportMultipleWindows", supportMultipleWindows);
options.put("regexToCancelSubFramesLoading", regexToCancelSubFramesLoading);
return options;
}
private void setLayoutAlgorithm(String value) {
if (value != null) {
switch (value) {
case "NORMAL":
pair.setValue(NORMAL);
return pair;
layoutAlgorithm = NORMAL;
case "TEXT_AUTOSIZING":
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
return pair.setValue(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING;
} else {
pair.setValue(NORMAL);
}
return pair;
layoutAlgorithm = NORMAL;
}
break;
}
}
return super.onParse(pair);
}
@Override
public Object onGetHashMap(Field field) {
if (field.getName().equals("layoutAlgorithm")) {
try {
WebSettings.LayoutAlgorithm value = (WebSettings.LayoutAlgorithm) field.get(this);
if (value != null) {
switch (value) {
private String getLayoutAlgorithm() {
if (layoutAlgorithm != null) {
switch (layoutAlgorithm) {
case NORMAL:
return "NORMAL";
default:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && value.equals(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING)) {
case TEXT_AUTOSIZING:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
return "TEXT_AUTOSIZING";
}
} else {
return "NORMAL";
}
}
} catch (IllegalAccessException e) {
Log.d(LOG_TAG, e.getMessage());
}
}
return super.onGetHashMap(field);
return null;
}
}
......@@ -3,11 +3,14 @@ package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
import static android.content.Context.INPUT_METHOD_SERVICE;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
import android.widget.ListPopupWindow;
/**
* A WebView subclass that mirrors the same implementation hacks that the system WebView does in
......@@ -190,8 +193,53 @@ public class InputAwareWebView extends WebView {
// onCreateInputConnection() on targetView on the same thread as
// targetView.getHandler(). It will also call subsequent InputConnection methods on this
// thread. This is the IME thread in cases where targetView is our proxyAdapterView.
// TODO (ALexVincent525): Currently only prompt has been tested, still needs more test cases.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
imm.isActive(containerView);
}
}
});
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
// This works around a crash when old (<67.0.3367.0) Chromium versions are used.
// Prior to Chromium 67.0.3367 the following sequence happens when a select drop down is shown
// on tablets:
//
// - WebView is calling ListPopupWindow#show
// - buildDropDown is invoked, which sets mDropDownList to a DropDownListView.
// - showAsDropDown is invoked - resulting in mDropDownList being added to the window and is
// also synchronously performing the following sequence:
// - WebView's focus change listener is loosing focus (as mDropDownList got it)
// - WebView is hiding all popups (as it lost focus)
// - WebView's SelectPopupDropDown#hide is invoked.
// - DropDownPopupWindow#dismiss is invoked setting mDropDownList to null.
// - mDropDownList#setSelection is invoked and is throwing a NullPointerException (as we just set mDropDownList to null).
//
// To workaround this, we drop the problematic focus lost call.
// See more details on: https://github.com/flutter/flutter/issues/54164
//
// We don't do this after Android P as it shipped with a new enough WebView version, and it's
// better to not do this on all future Android versions in case DropDownListView's code changes.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P
&& isCalledFromListPopupWindowShow()
&& !focused) {
return;
}
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
private boolean isCalledFromListPopupWindowShow() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for (int i = 0; i < stackTraceElements.length; i++) {
if (stackTraceElements[i].getClassName().equals(ListPopupWindow.class.getCanonicalName())
&& stackTraceElements[i].getMethodName().equals("show")) {
return true;
}
}
return false;
}
}
\ No newline at end of file
......@@ -21,219 +21,9 @@ public class JavaScriptBridgeInterface {
private InAppBrowserActivity inAppBrowserActivity;
public MethodChannel channel;
// https://github.com/taylorhakes/promise-polyfill/blob/master/src/index.js
// https://github.com/tildeio/rsvp.js
public static final String promisePolyfillJS = "if (window.Promise == null) {" +
" var setTimeoutFunc = setTimeout;" +
" function isArray(x) {" +
" return Boolean(x && typeof x.length !== \"undefined\");" +
" };" +
" function noop() {}" +
" function bind(fn, thisArg) {" +
" return function() {" +
" fn.apply(thisArg, arguments);" +
" };" +
" };" +
" function Promise(fn) {" +
" if (!(this instanceof Promise))" +
" throw new TypeError(\"Promises must be constructed via new\");" +
" if (typeof fn !== \"function\") throw new TypeError(\"not a function\");" +
" this._state = 0;" +
" this._handled = false;" +
" this._value = undefined;" +
" this._deferreds = [];" +
" doResolve(fn, this);" +
" };" +
" function handle(self, deferred) {" +
" while (self._state === 3) {" +
" self = self._value;" +
" }" +
" if (self._state === 0) {" +
" self._deferreds.push(deferred);" +
" return;" +
" }" +
" self._handled = true;" +
" Promise._immediateFn(function() {" +
" var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;" +
" if (cb === null) {" +
" (self._state === 1 ? resolve : reject)(deferred.promise, self._value);" +
" return;" +
" }" +
" var ret;" +
" try {" +
" ret = cb(self._value);" +
" } catch (e) {" +
" reject(deferred.promise, e);" +
" return;" +
" }" +
" resolve(deferred.promise, ret);" +
" });" +
" };" +
" function resolve(self, newValue) {" +
" try {" +
" if (newValue === self)" +
" throw new TypeError(\"A promise cannot be resolved with itself.\");" +
" if (" +
" newValue &&" +
" (typeof newValue === \"object\" || typeof newValue === \"function\")" +
" ) {" +
" var then = newValue.then;" +
" if (newValue instanceof Promise) {" +
" self._state = 3;" +
" self._value = newValue;" +
" finale(self);" +
" return;" +
" } else if (typeof then === \"function\") {" +
" doResolve(bind(then, newValue), self);" +
" return;" +
" }" +
" }" +
" self._state = 1;" +
" self._value = newValue;" +
" finale(self);" +
" } catch (e) {" +
" reject(self, e);" +
" }" +
" };" +
" function reject(self, newValue) {" +
" self._state = 2;" +
" self._value = newValue;" +
" finale(self);" +
" };" +
" function finale(self) {" +
" if (self._state === 2 && self._deferreds.length === 0) {" +
" Promise._immediateFn(function() {" +
" if (!self._handled) {" +
" Promise._unhandledRejectionFn(self._value);" +
" }" +
" });" +
" }" +
" for (var i = 0, len = self._deferreds.length; i < len; i++) {" +
" handle(self, self._deferreds[i]);" +
" }" +
" self._deferreds = null;" +
" };" +
" function Handler(onFulfilled, onRejected, promise) {" +
" this.onFulfilled = typeof onFulfilled === \"function\" ? onFulfilled : null;" +
" this.onRejected = typeof onRejected === \"function\" ? onRejected : null;" +
" this.promise = promise;" +
" };" +
" function doResolve(fn, self) {" +
" var done = false;" +
" try {" +
" fn(" +
" function(value) {" +
" if (done) return;" +
" done = true;" +
" resolve(self, value);" +
" }," +
" function(reason) {" +
" if (done) return;" +
" done = true;" +
" reject(self, reason);" +
" }" +
" );" +
" } catch (ex) {" +
" if (done) return;" +
" done = true;" +
" reject(self, ex);" +
" }" +
" };" +
" Promise.prototype[\"catch\"] = function(onRejected) {" +
" return this.then(null, onRejected);" +
" };" +
" Promise.prototype.then = function(onFulfilled, onRejected) {" +
" var prom = new this.constructor(noop);" +
" handle(this, new Handler(onFulfilled, onRejected, prom));" +
" return prom;" +
" };" +
" Promise.prototype[\"finally\"] = function finallyConstructor(callback) {" +
" var constructor = this.constructor;" +
" return this.then(" +
" function(value) {" +
" return constructor.resolve(callback()).then(function() {" +
" return value;" +
" });" +
" }," +
" function(reason) {" +
" return constructor.resolve(callback()).then(function() {" +
" return constructor.reject(reason);" +
" });" +
" }" +
" );" +
" };" +
" Promise.all = function(arr) {" +
" return new Promise(function(resolve, reject) {" +
" if (!isArray(arr)) {" +
" return reject(new TypeError(\"Promise.all accepts an array\"));" +
" }" +
" var args = Array.prototype.slice.call(arr);" +
" if (args.length === 0) return resolve([]);" +
" var remaining = args.length;" +
" function res(i, val) {" +
" try {" +
" if (val && (typeof val === \"object\" || typeof val === \"function\")) {" +
" var then = val.then;" +
" if (typeof then === \"function\") {" +
" then.call(" +
" val," +
" function(val) {" +
" res(i, val);" +
" }," +
" reject" +
" );" +
" return;" +
" }" +
" }" +
" args[i] = val;" +
" if (--remaining === 0) {" +
" resolve(args);" +
" }" +
" } catch (ex) {" +
" reject(ex);" +
" }" +
" }" +
" for (var i = 0; i < args.length; i++) {" +
" res(i, args[i]);" +
" }" +
" });" +
" };" +
" Promise.resolve = function(value) {" +
" if (value && typeof value === \"object\" && value.constructor === Promise) {" +
" return value;" +
" }" +
"" +
" return new Promise(function(resolve) {" +
" resolve(value);" +
" });" +
" };" +
" Promise.reject = function(value) {" +
" return new Promise(function(resolve, reject) {" +
" reject(value);" +
" });" +
" };" +
" Promise.race = function(arr) {" +
" return new Promise(function(resolve, reject) {" +
" if (!isArray(arr)) {" +
" return reject(new TypeError(\"Promise.race accepts an array\"));" +
" }" +
" for (var i = 0, len = arr.length; i < len; i++) {" +
" Promise.resolve(arr[i]).then(resolve, reject);" +
" }" +
" });" +
" };" +
" Promise._immediateFn =" +
" (typeof setImmediate === \"function\" &&" +
" function(fn) {" +
" setImmediate(fn);" +
" }) ||" +
" function(fn) {" +
" setTimeoutFunc(fn, 0);" +
" };" +
" Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {" +
" if (typeof console !== \"undefined\" && console) {" +
" console.warn(\"Possible Unhandled Promise Rejection:\", err);" +
" }" +
" };" +
" !function(t,e){\"object\"==typeof exports&&\"undefined\"!=typeof module?e(exports):\"function\"==typeof define&&define.amd?define([\"exports\"],e):e(t.RSVP={})}(this,function(t){\"use strict\";function e(t){var e=t._promiseCallbacks;return e||(e=t._promiseCallbacks={}),e}var r={mixin:function(t){return t.on=this.on,t.off=this.off,t.trigger=this.trigger,t._promiseCallbacks=void 0,t},on:function(t,r){if(\"function\"!=typeof r)throw new TypeError(\"Callback must be a function\");var n=e(this),o=n[t];o||(o=n[t]=[]),-1===o.indexOf(r)&&o.push(r)},off:function(t,r){var n=e(this);if(r){var o=n[t],i=o.indexOf(r);-1!==i&&o.splice(i,1)}else n[t]=[]},trigger:function(t,r,n){var o=e(this)[t];if(o)for(var i=0;i<o.length;i++)(0,o[i])(r,n)}},n={instrument:!1};function o(t,e){if(2!==arguments.length)return n[t];n[t]=e}r.mixin(n);var i=[];function s(t,e,r){1===i.push({name:t,payload:{key:e._guidKey,id:e._id,eventName:t,detail:e._result,childId:r&&r._id,label:e._label,timeStamp:Date.now(),error:n[\"instrument-with-stack\"]?new Error(e._label):null}})&&setTimeout(function(){for(var t=0;t<i.length;t++){var e=i[t],r=e.payload;r.guid=r.key+r.id,r.childGuid=r.key+r.childId,r.error&&(r.stack=r.error.stack),n.trigger(e.name,e.payload)}i.length=0},50)}function u(t,e){if(t&&\"object\"==typeof t&&t.constructor===this)return t;var r=new this(c,e);return m(r,t),r}function c(){}var a=void 0,f=1,l=2,h={error:null};function p(t){try{return t.then}catch(t){return h.error=t,h}}var y=void 0;function _(){try{var t=y;return y=null,t.apply(this,arguments)}catch(t){return h.error=t,h}}function v(t){return y=t,_}function d(t,e,r){if(e.constructor===t.constructor&&r===A&&t.constructor.resolve===u)!function(t,e){e._state===f?b(t,e._result):e._state===l?(e._onError=null,g(t,e._result)):j(e,void 0,function(r){e===r?b(t,r):m(t,r)},function(e){return g(t,e)})}(t,e);else if(r===h){var o=h.error;h.error=null,g(t,o)}else\"function\"==typeof r?function(t,e,r){n.async(function(t){var n=!1,o=v(r).call(e,function(r){n||(n=!0,e===r?b(t,r):m(t,r))},function(e){n||(n=!0,g(t,e))},\"Settle: \"+(t._label||\" unknown promise\"));if(!n&&o===h){n=!0;var i=h.error;h.error=null,g(t,i)}},t)}(t,e,r):b(t,e)}function m(t,e){var r,n;t===e?b(t,e):(n=typeof(r=e),null===r||\"object\"!==n&&\"function\"!==n?b(t,e):d(t,e,p(e)))}function w(t){t._onError&&t._onError(t._result),O(t)}function b(t,e){t._state===a&&(t._result=e,t._state=f,0===t._subscribers.length?n.instrument&&s(\"fulfilled\",t):n.async(O,t))}function g(t,e){t._state===a&&(t._state=l,t._result=e,n.async(w,t))}function j(t,e,r,o){var i=t._subscribers,s=i.length;t._onError=null,i[s]=e,i[s+f]=r,i[s+l]=o,0===s&&t._state&&n.async(O,t)}function O(t){var e=t._subscribers,r=t._state;if(n.instrument&&s(r===f?\"fulfilled\":\"rejected\",t),0!==e.length){for(var o=void 0,i=void 0,u=t._result,c=0;c<e.length;c+=3)o=e[c],i=e[c+r],o?E(r,o,i,u):i(u);t._subscribers.length=0}}function E(t,e,r,n){var o=\"function\"==typeof r,i=void 0;if(i=o?v(r)(n):n,e._state!==a);else if(i===e)g(e,new TypeError(\"A promises callback cannot return that same promise.\"));else if(i===h){var s=h.error;h.error=null,g(e,s)}else o?m(e,i):t===f?b(e,i):t===l&&g(e,i)}function A(t,e,r){var o=this._state;if(o===f&&!t||o===l&&!e)return n.instrument&&s(\"chained\",this,this),this;this._onError=null;var i=new this.constructor(c,r),u=this._result;if(n.instrument&&s(\"chained\",this,i),o===a)j(this,i,t,e);else{var h=o===f?t:e;n.async(function(){return E(o,i,h,u)})}return i}var T=function(){function t(t,e,r,n){this._instanceConstructor=t,this.promise=new t(c,n),this._abortOnReject=r,this._isUsingOwnPromise=t===k,this._isUsingOwnResolve=t.resolve===u,this._init.apply(this,arguments)}return t.prototype._init=function(t,e){var r=e.length||0;this.length=r,this._remaining=r,this._result=new Array(r),this._enumerate(e)},t.prototype._enumerate=function(t){for(var e=this.length,r=this.promise,n=0;r._state===a&&n<e;n++)this._eachEntry(t[n],n,!0);this._checkFullfillment()},t.prototype._checkFullfillment=function(){if(0===this._remaining){var t=this._result;b(this.promise,t),this._result=null}},t.prototype._settleMaybeThenable=function(t,e,r){var n=this._instanceConstructor;if(this._isUsingOwnResolve){var o=p(t);if(o===A&&t._state!==a)t._onError=null,this._settledAt(t._state,e,t._result,r);else if(\"function\"!=typeof o)this._settledAt(f,e,t,r);else if(this._isUsingOwnPromise){var i=new n(c);d(i,t,o),this._willSettleAt(i,e,r)}else this._willSettleAt(new n(function(e){return e(t)}),e,r)}else this._willSettleAt(n.resolve(t),e,r)},t.prototype._eachEntry=function(t,e,r){null!==t&&\"object\"==typeof t?this._settleMaybeThenable(t,e,r):this._setResultAt(f,e,t,r)},t.prototype._settledAt=function(t,e,r,n){var o=this.promise;o._state===a&&(this._abortOnReject&&t===l?g(o,r):(this._setResultAt(t,e,r,n),this._checkFullfillment()))},t.prototype._setResultAt=function(t,e,r,n){this._remaining--,this._result[e]=r},t.prototype._willSettleAt=function(t,e,r){var n=this;j(t,void 0,function(t){return n._settledAt(f,e,t,r)},function(t){return n._settledAt(l,e,t,r)})},t}();function P(t,e,r){this._remaining--,this._result[e]=t===f?{state:\"fulfilled\",value:r}:{state:\"rejected\",reason:r}}var S=\"rsvp_\"+Date.now()+\"-\",R=0;var k=function(){function t(e,r){this._id=R++,this._label=r,this._state=void 0,this._result=void 0,this._subscribers=[],n.instrument&&s(\"created\",this),c!==e&&(\"function\"!=typeof e&&function(){throw new TypeError(\"You must pass a resolver function as the first argument to the promise constructor\")}(),this instanceof t?function(t,e){var r=!1;try{e(function(e){r||(r=!0,m(t,e))},function(e){r||(r=!0,g(t,e))})}catch(e){g(t,e)}}(this,e):function(){throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\")}())}return t.prototype._onError=function(t){var e=this;n.after(function(){e._onError&&n.trigger(\"error\",t,e._label)})},t.prototype.catch=function(t,e){return this.then(void 0,t,e)},t.prototype.finally=function(t,e){var r=this.constructor;return\"function\"==typeof t?this.then(function(e){return r.resolve(t()).then(function(){return e})},function(e){return r.resolve(t()).then(function(){throw e})}):this.then(t,t)},t}();function x(t,e){return{then:function(r,n){return t.call(e,r,n)}}}function M(t,e){var r=function(){for(var r=arguments.length,n=new Array(r+1),o=!1,i=0;i<r;++i){var s=arguments[i];if(!o){if((o=F(s))===h){var u=h.error;h.error=null;var a=new k(c);return g(a,u),a}o&&!0!==o&&(s=x(o,s))}n[i]=s}var f=new k(c);return n[r]=function(t,r){t?g(f,t):void 0===e?m(f,r):!0===e?m(f,function(t){for(var e=t.length,r=new Array(e-1),n=1;n<e;n++)r[n-1]=t[n];return r}(arguments)):Array.isArray(e)?m(f,function(t,e){for(var r={},n=t.length,o=new Array(n),i=0;i<n;i++)o[i]=t[i];for(var s=0;s<e.length;s++)r[e[s]]=o[s+1];return r}(arguments,e)):m(f,r)},o?function(t,e,r,n){return k.all(e).then(function(e){return C(t,e,r,n)})}(f,n,t,this):C(f,n,t,this)};return r.__proto__=t,r}function C(t,e,r,n){if(v(r).apply(n,e)===h){var o=h.error;h.error=null,g(t,o)}return t}function F(t){return null!==t&&\"object\"==typeof t&&(t.constructor===k||p(t))}function I(t,e){return k.all(t,e)}k.cast=u,k.all=function(t,e){return Array.isArray(t)?new T(this,t,!0,e).promise:this.reject(new TypeError(\"Promise.all must be called with an array\"),e)},k.race=function(t,e){var r=new this(c,e);if(!Array.isArray(t))return g(r,new TypeError(\"Promise.race must be called with an array\")),r;for(var n=0;r._state===a&&n<t.length;n++)j(this.resolve(t[n]),void 0,function(t){return m(r,t)},function(t){return g(r,t)});return r},k.resolve=u,k.reject=function(t,e){var r=new this(c,e);return g(r,t),r},k.prototype._guidKey=S,k.prototype.then=A;var N=function(t){function e(e,r,n){return function(t,e){if(!t)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return!e||\"object\"!=typeof e&&\"function\"!=typeof e?t:e}(this,t.call(this,e,r,!1,n))}return function(t,e){if(\"function\"!=typeof e&&null!==e)throw new TypeError(\"Super expression must either be null or a function, not \"+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e}(T);function U(t,e){return Array.isArray(t)?new N(k,t,e).promise:k.reject(new TypeError(\"Promise.allSettled must be called with an array\"),e)}function D(t,e){return k.race(t,e)}N.prototype._setResultAt=P;var K=function(t){function e(e,r){var n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],o=arguments[3];return function(t,e){if(!t)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return!e||\"object\"!=typeof e&&\"function\"!=typeof e?t:e}(this,t.call(this,e,r,n,o))}return function(t,e){if(\"function\"!=typeof e&&null!==e)throw new TypeError(\"Super expression must either be null or a function, not \"+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e.prototype._init=function(t,e){this._result={},this._enumerate(e)},e.prototype._enumerate=function(t){var e=Object.keys(t),r=e.length,n=this.promise;this._remaining=r;for(var o=void 0,i=void 0,s=0;n._state===a&&s<r;s++)i=t[o=e[s]],this._eachEntry(i,o,!0);this._checkFullfillment()},e}(T);function q(t,e){return k.resolve(t,e).then(function(t){if(null===t||\"object\"!=typeof t)throw new TypeError(\"Promise.hash must be called with an object\");return new K(k,t,e).promise})}var G=function(t){function e(e,r,n){return function(t,e){if(!t)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return!e||\"object\"!=typeof e&&\"function\"!=typeof e?t:e}(this,t.call(this,e,r,!1,n))}return function(t,e){if(\"function\"!=typeof e&&null!==e)throw new TypeError(\"Super expression must either be null or a function, not \"+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e}(K);function L(t,e){return k.resolve(t,e).then(function(t){if(null===t||\"object\"!=typeof t)throw new TypeError(\"hashSettled must be called with an object\");return new G(k,t,!1,e).promise})}function V(t){throw setTimeout(function(){throw t}),t}function W(t){var e={resolve:void 0,reject:void 0};return e.promise=new k(function(t,r){e.resolve=t,e.reject=r},t),e}G.prototype._setResultAt=P;var Y=function(t){function e(e,r,n,o){return function(t,e){if(!t)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return!e||\"object\"!=typeof e&&\"function\"!=typeof e?t:e}(this,t.call(this,e,r,!0,o,n))}return function(t,e){if(\"function\"!=typeof e&&null!==e)throw new TypeError(\"Super expression must either be null or a function, not \"+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e.prototype._init=function(t,e,r,n,o){var i=e.length||0;this.length=i,this._remaining=i,this._result=new Array(i),this._mapFn=o,this._enumerate(e)},e.prototype._setResultAt=function(t,e,r,n){if(n){var o=v(this._mapFn)(r,e);o===h?this._settledAt(l,e,o.error,!1):this._eachEntry(o,e,!1)}else this._remaining--,this._result[e]=r},e}(T);function $(t,e,r){return\"function\"!=typeof e?k.reject(new TypeError(\"map expects a function as a second argument\"),r):k.resolve(t,r).then(function(t){if(!Array.isArray(t))throw new TypeError(\"map must be called with an array\");return new Y(k,t,e,r).promise})}function z(t,e){return k.resolve(t,e)}function B(t,e){return k.reject(t,e)}var H={},J=function(t){function e(){return function(t,e){if(!t)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return!e||\"object\"!=typeof e&&\"function\"!=typeof e?t:e}(this,t.apply(this,arguments))}return function(t,e){if(\"function\"!=typeof e&&null!==e)throw new TypeError(\"Super expression must either be null or a function, not \"+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e.prototype._checkFullfillment=function(){if(0===this._remaining&&null!==this._result){var t=this._result.filter(function(t){return t!==H});b(this.promise,t),this._result=null}},e.prototype._setResultAt=function(t,e,r,n){if(n){this._result[e]=r;var o=v(this._mapFn)(r,e);o===h?this._settledAt(l,e,o.error,!1):this._eachEntry(o,e,!1)}else this._remaining--,r||(this._result[e]=H)},e}(Y);function Q(t,e,r){return\"function\"!=typeof e?k.reject(new TypeError(\"filter expects function as a second argument\"),r):k.resolve(t,r).then(function(t){if(!Array.isArray(t))throw new TypeError(\"filter must be called with an array\");return new J(k,t,e,r).promise})}var X=0,Z=void 0;function tt(t,e){ut[X]=t,ut[X+1]=e,2===(X+=2)&&_t()}var et=\"undefined\"!=typeof window?window:void 0,rt=et||{},nt=rt.MutationObserver||rt.WebKitMutationObserver,ot=\"undefined\"==typeof self&&\"undefined\"!=typeof process&&\"[object process]\"==={}.toString.call(process),it=\"undefined\"!=typeof Uint8ClampedArray&&\"undefined\"!=typeof importScripts&&\"undefined\"!=typeof MessageChannel;function st(){return function(){return setTimeout(ct,1)}}var ut=new Array(1e3);function ct(){for(var t=0;t<X;t+=2){(0,ut[t])(ut[t+1]),ut[t]=void 0,ut[t+1]=void 0}X=0}var at,ft,lt,ht,pt,yt,_t=void 0;ot?(pt=process.nextTick,yt=process.versions.node.match(/^(?:(\\\\d+)\\\\.)?(?:(\\\\d+)\\\\.)?(\\\\*|\\\\d+)$/),Array.isArray(yt)&&\"0\"===yt[1]&&\"10\"===yt[2]&&(pt=setImmediate),_t=function(){return pt(ct)}):nt?(ft=0,lt=new nt(ct),ht=document.createTextNode(\"\"),lt.observe(ht,{characterData:!0}),_t=function(){return ht.data=ft=++ft%2}):it?((at=new MessageChannel).port1.onmessage=ct,_t=function(){return at.port2.postMessage(0)}):_t=void 0===et&&\"function\"==typeof require?function(){try{var t=Function(\"return this\")().require(\"vertx\");return void 0!==(Z=t.runOnLoop||t.runOnContext)?function(){Z(ct)}:st()}catch(t){return st()}}():st(),n.async=tt,n.after=function(t){return setTimeout(t,0)};var vt=z,dt=function(t,e){return n.async(t,e)};function mt(){n.on.apply(n,arguments)}function wt(){n.off.apply(n,arguments)}if(\"undefined\"!=typeof window&&\"object\"==typeof window.__PROMISE_INSTRUMENTATION__){var bt=window.__PROMISE_INSTRUMENTATION__;for(var gt in o(\"instrument\",!0),bt)bt.hasOwnProperty(gt)&&mt(gt,bt[gt])}var jt={asap:tt,cast:vt,Promise:k,EventTarget:r,all:I,allSettled:U,race:D,hash:q,hashSettled:L,rethrow:V,defer:W,denodeify:M,configure:o,on:mt,off:wt,resolve:z,reject:B,map:$,async:dt,filter:Q};t.default=jt,t.asap=tt,t.cast=vt,t.Promise=k,t.EventTarget=r,t.all=I,t.allSettled=U,t.race=D,t.hash=q,t.hashSettled=L,t.rethrow=V,t.defer=W,t.denodeify=M,t.configure=o,t.on=mt,t.off=wt,t.resolve=z,t.reject=B,t.map=$,t.async=dt,t.filter=Q,Object.defineProperty(t,\"__esModule\",{value:!0})});" +
"}";
public static final String flutterInAppBroserJSClass = promisePolyfillJS + " " + "window." + name + ".callHandler = function() {" +
......
package com.pichillilorenzo.flutter_inappwebview;
import android.util.Log;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
public class Options {
public interface Options {
static String LOG_TAG = "Options";
public Options parse(HashMap<String, Object> options) {
Iterator it = options.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Object> pair = (Map.Entry<String, Object>) it.next();
Object value = this.onParse(pair);
try {
this.getClass().getDeclaredField(pair.getKey()).set(this, value);
} catch (NoSuchFieldException e) {
Log.d(LOG_TAG, e.getMessage());
} catch (IllegalAccessException e) {
Log.d(LOG_TAG, e.getMessage());
}
}
return this;
}
public Object onParse(Map.Entry<String, Object> pair) {
return pair.getValue();
}
public HashMap<String, Object> getHashMap() {
HashMap<String, Object> options = new HashMap<>();
for (Field field : this.getClass().getDeclaredFields()) {
options.put(field.getName(), onGetHashMap(field));
}
return options;
}
public Object onGetHashMap(Field field) {
try {
return field.get(this);
} catch (IllegalAccessException e) {
Log.d(LOG_TAG, e.getMessage());
}
return null;
}
public Options parse(HashMap<String, Object> options);
public HashMap<String, Object> getHashMap();
}
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
{"_info":"// This is a generated file; do not edit or check into version control.","dependencyGraph":[{"name":"connectivity","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"permission_handler","dependencies":[]}]}
\ No newline at end of file
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity-0.4.8+5/","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.7/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-3.3.0/","dependencies":[]}],"android":[{"name":"connectivity","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity-0.4.8+5/","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.7/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-3.3.0/","dependencies":[]}],"macos":[{"name":"connectivity_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_macos-0.1.0+3/","dependencies":[]},{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+2/","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"connectivity","dependencies":["connectivity_macos"]},{"name":"connectivity_macos","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-05-09 04:31:57.281568","version":"1.17.0"}
\ No newline at end of file
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
package com.pichillilorenzo.flutterwebviewexample;
import android.os.Bundle;
import android.view.ActionMode;
import android.view.Menu;
import io.flutter.Log;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<!-- <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> -->
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Flutter InAppWebView</title>
<link rel="stylesheet" href="https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css">
......@@ -26,6 +26,7 @@
<main role="main" class="inner cover">
<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>
<p class="lead">Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.</p>
</main>
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -2,9 +2,11 @@
# 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=lib/main.dart"
export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/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"
# Uncomment this line to define a global platform for your project
platform :ios, '8.0'
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_ary = []
generated_key_values = {}
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
File.foreach(file_abs_path) do |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath});
generated_key_values[podname] = podpath
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_ary
end
generated_key_values
end
target 'Runner' do
use_frameworks!
use_modular_headers!
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
# Flutter Pod
copied_flutter_dir = File.join(__dir__, 'Flutter')
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
unless File.exist?(generated_xcode_build_settings_path)
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
# Flutter Pods
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
if generated_xcode_build_settings.empty?
puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
unless File.exist?(copied_framework_path)
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
end
generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join('.symlinks', 'flutter')
File.symlink(File.dirname(p[:path]), symlink)
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
unless File.exist?(copied_podspec_path)
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
end
}
end
# Keep pod path relative so it can be checked into Podfile.lock.
pod 'Flutter', :path => 'Flutter'
# Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p|
symlink = File.join('.symlinks', 'plugins', p[:name])
File.symlink(p[:path], symlink)
pod p[:name], :path => File.join(symlink, 'ios')
}
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.each do |name, path|
symlink = File.join('.symlinks', 'plugins', name)
File.symlink(path, symlink)
pod name, :path => File.join(symlink, 'ios')
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
config.build_settings['SWIFT_VERSION'] = '5.0'
end
end
end
......@@ -10,12 +10,8 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
25A517508F43E58C47090625 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8D91E403808A7540F18B75D /* Pods_Runner.framework */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
61FF730023634CA10069C557 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 61FF72FF23634CA10069C557 /* libsqlite3.tbd */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
EDC1147F21735BC200D2247A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
......@@ -28,8 +24,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
......@@ -40,7 +34,6 @@
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
61FF72FF23634CA10069C557 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
61FF730123634DD10069C557 /* flutter_downloader.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = flutter_downloader.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
......@@ -48,7 +41,6 @@
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
......@@ -65,8 +57,6 @@
buildActionMask = 2147483647;
files = (
61FF730023634CA10069C557 /* libsqlite3.tbd in Frameworks */,
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
25A517508F43E58C47090625 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
......@@ -96,9 +86,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
......@@ -239,7 +227,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
3F62E6580DEAFBE72C090A85 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
......@@ -266,7 +254,7 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
"${PODS_ROOT}/../Flutter/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework",
"${BUILT_PRODUCTS_DIR}/connectivity/connectivity.framework",
"${BUILT_PRODUCTS_DIR}/flutter_downloader/flutter_downloader.framework",
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -50,12 +50,12 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: InAppWebView(
initialUrl: "https://flutter.dev/",
//initialFile: "assets/index.html",
// initialFile: "assets/index.html",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
)
),
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
......
......@@ -10,6 +10,7 @@ import 'package:flutter_inappwebview_example/in_app_browser_example.screen.dart'
// InAppLocalhostServer localhostServer = new InAppLocalhostServer();
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
// await localhostServer.start();
runApp(new MyApp());
}
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -8,7 +8,7 @@ import '.env.dart';
void main() {
group('Flutter InAppBrowser', () {
group('Flutter InAppWebView', () {
FlutterDriver driver;
// Connect to the Flutter driver before running any tests.
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -53,7 +53,7 @@ setTimeout(function() {
}, 100);
""");
},
onNavigationStateChange: (InAppWebViewController controller, String url) async {
onUpdateVisitedHistory: (InAppWebViewController controller, String url, bool androidIsReload) async {
if (url.endsWith("second-push")) {
setState(() {
appBarTitle += " " + url;
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
import 'package:flutter/material.dart';
import 'dart:io' show Platform;
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'custom_widget_test.dart';
......@@ -51,8 +51,11 @@ class InAppWebViewShouldOverrideUrlLoadingTestState extends WidgetTestState {
}
},
shouldOverrideUrlLoading: (InAppWebViewController controller, ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
controller.loadUrl(url: "https://flutter.dev/");
if (Platform.isAndroid || shouldOverrideUrlLoadingRequest.iosWKNavigationType == IOSWKNavigationType.LINK_ACTIVATED) {
await controller.loadUrl(url: "https://flutter.dev/");
return ShouldOverrideUrlLoadingAction.CANCEL;
}
return ShouldOverrideUrlLoadingAction.ALLOW;
},
),
),
......
File mode changed from 100644 to 100755
......@@ -121,6 +121,7 @@ Drawer myDrawer({@required context}) {
}
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(new MyApp());
}
......
......@@ -26,7 +26,6 @@
<excludeFolder url="file://$MODULE_DIR$/example/ios/.symlinks/plugins/flutter_inappwebview/example/.dart_tool" />
<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" />
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -40,6 +40,8 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
webView = InAppWebView(frame: myView!.bounds, configuration: preWebviewConfiguration, IABController: nil, channel: channel!)
webView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
myView!.autoresizesSubviews = true
myView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
myView!.addSubview(webView!)
webView!.options = options
......@@ -104,8 +106,8 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
let baseUrl = initialData!["baseUrl"]!
webView!.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
}
else {
webView!.loadUrl(url: URL(string: initialUrl!)!, headers: initialHeaders)
else if let url = URL(string: initialUrl!) {
webView!.loadUrl(url: url, headers: initialHeaders)
}
}
......@@ -374,6 +376,9 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
case "getScale":
result( (webView != nil) ? webView!.getScale() : nil )
break
case "hasOnlySecureContent":
result( (webView != nil) ? webView!.hasOnlySecureContent : nil )
break
default:
result(FlutterMethodNotImplemented)
break
......
File mode changed from 100644 to 100755
......@@ -278,6 +278,9 @@ public class InAppBrowserWebViewController: UIViewController, FlutterPlugin, UIS
case "getScale":
result(webView.getScale())
break
case "hasOnlySecureContent":
result(webView.hasOnlySecureContent)
break
default:
result(FlutterMethodNotImplemented)
break
......
......@@ -41,220 +41,11 @@ func JSONStringify(value: Any, prettyPrinted: Bool = false) -> String {
let JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview"
// https://github.com/taylorhakes/promise-polyfill/blob/master/src/index.js
// https://github.com/tildeio/rsvp.js
let promisePolyfillJS = """
if (window.Promise == null) {
var setTimeoutFunc = setTimeout;
function isArray(x) {
return Boolean(x && typeof x.length !== "undefined");
};
function noop() {}
function bind(fn, thisArg) {
return function() {
fn.apply(thisArg, arguments);
};
};
function Promise(fn) {
if (!(this instanceof Promise))
throw new TypeError("Promises must be constructed via new");
if (typeof fn !== "function") throw new TypeError("not a function");
this._state = 0;
this._handled = false;
this._value = undefined;
this._deferreds = [];
doResolve(fn, this);
};
function handle(self, deferred) {
while (self._state === 3) {
self = self._value;
}
if (self._state === 0) {
self._deferreds.push(deferred);
return;
}
self._handled = true;
Promise._immediateFn(function() {
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
if (cb === null) {
(self._state === 1 ? resolve : reject)(deferred.promise, self._value);
return;
}
var ret;
try {
ret = cb(self._value);
} catch (e) {
reject(deferred.promise, e);
return;
}
resolve(deferred.promise, ret);
});
};
function resolve(self, newValue) {
try {
if (newValue === self)
throw new TypeError("A promise cannot be resolved with itself.");
if (
newValue &&
(typeof newValue === "object" || typeof newValue === "function")
) {
var then = newValue.then;
if (newValue instanceof Promise) {
self._state = 3;
self._value = newValue;
finale(self);
return;
} else if (typeof then === "function") {
doResolve(bind(then, newValue), self);
return;
}
}
self._state = 1;
self._value = newValue;
finale(self);
} catch (e) {
reject(self, e);
}
};
function reject(self, newValue) {
self._state = 2;
self._value = newValue;
finale(self);
};
function finale(self) {
if (self._state === 2 && self._deferreds.length === 0) {
Promise._immediateFn(function() {
if (!self._handled) {
Promise._unhandledRejectionFn(self._value);
}
});
}
for (var i = 0, len = self._deferreds.length; i < len; i++) {
handle(self, self._deferreds[i]);
}
self._deferreds = null;
};
function Handler(onFulfilled, onRejected, promise) {
this.onFulfilled = typeof onFulfilled === "function" ? onFulfilled : null;
this.onRejected = typeof onRejected === "function" ? onRejected : null;
this.promise = promise;
};
function doResolve(fn, self) {
var done = false;
try {
fn(
function(value) {
if (done) return;
done = true;
resolve(self, value);
},
function(reason) {
if (done) return;
done = true;
reject(self, reason);
}
);
} catch (ex) {
if (done) return;
done = true;
reject(self, ex);
}
};
Promise.prototype["catch"] = function(onRejected) {
return this.then(null, onRejected);
};
Promise.prototype.then = function(onFulfilled, onRejected) {
var prom = new this.constructor(noop);
handle(this, new Handler(onFulfilled, onRejected, prom));
return prom;
};
Promise.prototype["finally"] = function finallyConstructor(callback) {
var constructor = this.constructor;
return this.then(
function(value) {
return constructor.resolve(callback()).then(function() {
return value;
});
},
function(reason) {
return constructor.resolve(callback()).then(function() {
return constructor.reject(reason);
});
}
);
};
Promise.all = function(arr) {
return new Promise(function(resolve, reject) {
if (!isArray(arr)) {
return reject(new TypeError("Promise.all accepts an array"));
}
var args = Array.prototype.slice.call(arr);
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
try {
if (val && (typeof val === "object" || typeof val === "function")) {
var then = val.then;
if (typeof then === "function") {
then.call(
val,
function(val) {
res(i, val);
},
reject
);
return;
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
} catch (ex) {
reject(ex);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
};
Promise.resolve = function(value) {
if (value && typeof value === "object" && value.constructor === Promise) {
return value;
}
return new Promise(function(resolve) {
resolve(value);
});
};
Promise.reject = function(value) {
return new Promise(function(resolve, reject) {
reject(value);
});
};
Promise.race = function(arr) {
return new Promise(function(resolve, reject) {
if (!isArray(arr)) {
return reject(new TypeError("Promise.race accepts an array"));
}
for (var i = 0, len = arr.length; i < len; i++) {
Promise.resolve(arr[i]).then(resolve, reject);
}
});
};
Promise._immediateFn =
(typeof setImmediate === "function" &&
function(fn) {
setImmediate(fn);
}) ||
function(fn) {
setTimeoutFunc(fn, 0);
};
Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
if (typeof console !== "undefined" && console) {
console.warn("Possible Unhandled Promise Rejection:", err);
}
};
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.RSVP={})}(this,function(t){"use strict";function e(t){var e=t._promiseCallbacks;return e||(e=t._promiseCallbacks={}),e}var r={mixin:function(t){return t.on=this.on,t.off=this.off,t.trigger=this.trigger,t._promiseCallbacks=void 0,t},on:function(t,r){if("function"!=typeof r)throw new TypeError("Callback must be a function");var n=e(this),o=n[t];o||(o=n[t]=[]),-1===o.indexOf(r)&&o.push(r)},off:function(t,r){var n=e(this);if(r){var o=n[t],i=o.indexOf(r);-1!==i&&o.splice(i,1)}else n[t]=[]},trigger:function(t,r,n){var o=e(this)[t];if(o)for(var i=0;i<o.length;i++)(0,o[i])(r,n)}},n={instrument:!1};function o(t,e){if(2!==arguments.length)return n[t];n[t]=e}r.mixin(n);var i=[];function s(t,e,r){1===i.push({name:t,payload:{key:e._guidKey,id:e._id,eventName:t,detail:e._result,childId:r&&r._id,label:e._label,timeStamp:Date.now(),error:n["instrument-with-stack"]?new Error(e._label):null}})&&setTimeout(function(){for(var t=0;t<i.length;t++){var e=i[t],r=e.payload;r.guid=r.key+r.id,r.childGuid=r.key+r.childId,r.error&&(r.stack=r.error.stack),n.trigger(e.name,e.payload)}i.length=0},50)}function u(t,e){if(t&&"object"==typeof t&&t.constructor===this)return t;var r=new this(c,e);return m(r,t),r}function c(){}var a=void 0,f=1,l=2,h={error:null};function p(t){try{return t.then}catch(t){return h.error=t,h}}var y=void 0;function _(){try{var t=y;return y=null,t.apply(this,arguments)}catch(t){return h.error=t,h}}function v(t){return y=t,_}function d(t,e,r){if(e.constructor===t.constructor&&r===A&&t.constructor.resolve===u)!function(t,e){e._state===f?b(t,e._result):e._state===l?(e._onError=null,g(t,e._result)):j(e,void 0,function(r){e===r?b(t,r):m(t,r)},function(e){return g(t,e)})}(t,e);else if(r===h){var o=h.error;h.error=null,g(t,o)}else"function"==typeof r?function(t,e,r){n.async(function(t){var n=!1,o=v(r).call(e,function(r){n||(n=!0,e===r?b(t,r):m(t,r))},function(e){n||(n=!0,g(t,e))},"Settle: "+(t._label||" unknown promise"));if(!n&&o===h){n=!0;var i=h.error;h.error=null,g(t,i)}},t)}(t,e,r):b(t,e)}function m(t,e){var r,n;t===e?b(t,e):(n=typeof(r=e),null===r||"object"!==n&&"function"!==n?b(t,e):d(t,e,p(e)))}function w(t){t._onError&&t._onError(t._result),O(t)}function b(t,e){t._state===a&&(t._result=e,t._state=f,0===t._subscribers.length?n.instrument&&s("fulfilled",t):n.async(O,t))}function g(t,e){t._state===a&&(t._state=l,t._result=e,n.async(w,t))}function j(t,e,r,o){var i=t._subscribers,s=i.length;t._onError=null,i[s]=e,i[s+f]=r,i[s+l]=o,0===s&&t._state&&n.async(O,t)}function O(t){var e=t._subscribers,r=t._state;if(n.instrument&&s(r===f?"fulfilled":"rejected",t),0!==e.length){for(var o=void 0,i=void 0,u=t._result,c=0;c<e.length;c+=3)o=e[c],i=e[c+r],o?E(r,o,i,u):i(u);t._subscribers.length=0}}function E(t,e,r,n){var o="function"==typeof r,i=void 0;if(i=o?v(r)(n):n,e._state!==a);else if(i===e)g(e,new TypeError("A promises callback cannot return that same promise."));else if(i===h){var s=h.error;h.error=null,g(e,s)}else o?m(e,i):t===f?b(e,i):t===l&&g(e,i)}function A(t,e,r){var o=this._state;if(o===f&&!t||o===l&&!e)return n.instrument&&s("chained",this,this),this;this._onError=null;var i=new this.constructor(c,r),u=this._result;if(n.instrument&&s("chained",this,i),o===a)j(this,i,t,e);else{var h=o===f?t:e;n.async(function(){return E(o,i,h,u)})}return i}var T=function(){function t(t,e,r,n){this._instanceConstructor=t,this.promise=new t(c,n),this._abortOnReject=r,this._isUsingOwnPromise=t===k,this._isUsingOwnResolve=t.resolve===u,this._init.apply(this,arguments)}return t.prototype._init=function(t,e){var r=e.length||0;this.length=r,this._remaining=r,this._result=new Array(r),this._enumerate(e)},t.prototype._enumerate=function(t){for(var e=this.length,r=this.promise,n=0;r._state===a&&n<e;n++)this._eachEntry(t[n],n,!0);this._checkFullfillment()},t.prototype._checkFullfillment=function(){if(0===this._remaining){var t=this._result;b(this.promise,t),this._result=null}},t.prototype._settleMaybeThenable=function(t,e,r){var n=this._instanceConstructor;if(this._isUsingOwnResolve){var o=p(t);if(o===A&&t._state!==a)t._onError=null,this._settledAt(t._state,e,t._result,r);else if("function"!=typeof o)this._settledAt(f,e,t,r);else if(this._isUsingOwnPromise){var i=new n(c);d(i,t,o),this._willSettleAt(i,e,r)}else this._willSettleAt(new n(function(e){return e(t)}),e,r)}else this._willSettleAt(n.resolve(t),e,r)},t.prototype._eachEntry=function(t,e,r){null!==t&&"object"==typeof t?this._settleMaybeThenable(t,e,r):this._setResultAt(f,e,t,r)},t.prototype._settledAt=function(t,e,r,n){var o=this.promise;o._state===a&&(this._abortOnReject&&t===l?g(o,r):(this._setResultAt(t,e,r,n),this._checkFullfillment()))},t.prototype._setResultAt=function(t,e,r,n){this._remaining--,this._result[e]=r},t.prototype._willSettleAt=function(t,e,r){var n=this;j(t,void 0,function(t){return n._settledAt(f,e,t,r)},function(t){return n._settledAt(l,e,t,r)})},t}();function P(t,e,r){this._remaining--,this._result[e]=t===f?{state:"fulfilled",value:r}:{state:"rejected",reason:r}}var S="rsvp_"+Date.now()+"-",R=0;var k=function(){function t(e,r){this._id=R++,this._label=r,this._state=void 0,this._result=void 0,this._subscribers=[],n.instrument&&s("created",this),c!==e&&("function"!=typeof e&&function(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}(),this instanceof t?function(t,e){var r=!1;try{e(function(e){r||(r=!0,m(t,e))},function(e){r||(r=!0,g(t,e))})}catch(e){g(t,e)}}(this,e):function(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}())}return t.prototype._onError=function(t){var e=this;n.after(function(){e._onError&&n.trigger("error",t,e._label)})},t.prototype.catch=function(t,e){return this.then(void 0,t,e)},t.prototype.finally=function(t,e){var r=this.constructor;return"function"==typeof t?this.then(function(e){return r.resolve(t()).then(function(){return e})},function(e){return r.resolve(t()).then(function(){throw e})}):this.then(t,t)},t}();function x(t,e){return{then:function(r,n){return t.call(e,r,n)}}}function M(t,e){var r=function(){for(var r=arguments.length,n=new Array(r+1),o=!1,i=0;i<r;++i){var s=arguments[i];if(!o){if((o=F(s))===h){var u=h.error;h.error=null;var a=new k(c);return g(a,u),a}o&&!0!==o&&(s=x(o,s))}n[i]=s}var f=new k(c);return n[r]=function(t,r){t?g(f,t):void 0===e?m(f,r):!0===e?m(f,function(t){for(var e=t.length,r=new Array(e-1),n=1;n<e;n++)r[n-1]=t[n];return r}(arguments)):Array.isArray(e)?m(f,function(t,e){for(var r={},n=t.length,o=new Array(n),i=0;i<n;i++)o[i]=t[i];for(var s=0;s<e.length;s++)r[e[s]]=o[s+1];return r}(arguments,e)):m(f,r)},o?function(t,e,r,n){return k.all(e).then(function(e){return C(t,e,r,n)})}(f,n,t,this):C(f,n,t,this)};return r.__proto__=t,r}function C(t,e,r,n){if(v(r).apply(n,e)===h){var o=h.error;h.error=null,g(t,o)}return t}function F(t){return null!==t&&"object"==typeof t&&(t.constructor===k||p(t))}function I(t,e){return k.all(t,e)}k.cast=u,k.all=function(t,e){return Array.isArray(t)?new T(this,t,!0,e).promise:this.reject(new TypeError("Promise.all must be called with an array"),e)},k.race=function(t,e){var r=new this(c,e);if(!Array.isArray(t))return g(r,new TypeError("Promise.race must be called with an array")),r;for(var n=0;r._state===a&&n<t.length;n++)j(this.resolve(t[n]),void 0,function(t){return m(r,t)},function(t){return g(r,t)});return r},k.resolve=u,k.reject=function(t,e){var r=new this(c,e);return g(r,t),r},k.prototype._guidKey=S,k.prototype.then=A;var N=function(t){function e(e,r,n){return function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,t.call(this,e,r,!1,n))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e}(T);function U(t,e){return Array.isArray(t)?new N(k,t,e).promise:k.reject(new TypeError("Promise.allSettled must be called with an array"),e)}function D(t,e){return k.race(t,e)}N.prototype._setResultAt=P;var K=function(t){function e(e,r){var n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],o=arguments[3];return function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,t.call(this,e,r,n,o))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e.prototype._init=function(t,e){this._result={},this._enumerate(e)},e.prototype._enumerate=function(t){var e=Object.keys(t),r=e.length,n=this.promise;this._remaining=r;for(var o=void 0,i=void 0,s=0;n._state===a&&s<r;s++)i=t[o=e[s]],this._eachEntry(i,o,!0);this._checkFullfillment()},e}(T);function q(t,e){return k.resolve(t,e).then(function(t){if(null===t||"object"!=typeof t)throw new TypeError("Promise.hash must be called with an object");return new K(k,t,e).promise})}var G=function(t){function e(e,r,n){return function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,t.call(this,e,r,!1,n))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e}(K);function L(t,e){return k.resolve(t,e).then(function(t){if(null===t||"object"!=typeof t)throw new TypeError("hashSettled must be called with an object");return new G(k,t,!1,e).promise})}function V(t){throw setTimeout(function(){throw t}),t}function W(t){var e={resolve:void 0,reject:void 0};return e.promise=new k(function(t,r){e.resolve=t,e.reject=r},t),e}G.prototype._setResultAt=P;var Y=function(t){function e(e,r,n,o){return function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,t.call(this,e,r,!0,o,n))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e.prototype._init=function(t,e,r,n,o){var i=e.length||0;this.length=i,this._remaining=i,this._result=new Array(i),this._mapFn=o,this._enumerate(e)},e.prototype._setResultAt=function(t,e,r,n){if(n){var o=v(this._mapFn)(r,e);o===h?this._settledAt(l,e,o.error,!1):this._eachEntry(o,e,!1)}else this._remaining--,this._result[e]=r},e}(T);function $(t,e,r){return"function"!=typeof e?k.reject(new TypeError("map expects a function as a second argument"),r):k.resolve(t,r).then(function(t){if(!Array.isArray(t))throw new TypeError("map must be called with an array");return new Y(k,t,e,r).promise})}function z(t,e){return k.resolve(t,e)}function B(t,e){return k.reject(t,e)}var H={},J=function(t){function e(){return function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,t.apply(this,arguments))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(e,t),e.prototype._checkFullfillment=function(){if(0===this._remaining&&null!==this._result){var t=this._result.filter(function(t){return t!==H});b(this.promise,t),this._result=null}},e.prototype._setResultAt=function(t,e,r,n){if(n){this._result[e]=r;var o=v(this._mapFn)(r,e);o===h?this._settledAt(l,e,o.error,!1):this._eachEntry(o,e,!1)}else this._remaining--,r||(this._result[e]=H)},e}(Y);function Q(t,e,r){return"function"!=typeof e?k.reject(new TypeError("filter expects function as a second argument"),r):k.resolve(t,r).then(function(t){if(!Array.isArray(t))throw new TypeError("filter must be called with an array");return new J(k,t,e,r).promise})}var X=0,Z=void 0;function tt(t,e){ut[X]=t,ut[X+1]=e,2===(X+=2)&&_t()}var et="undefined"!=typeof window?window:void 0,rt=et||{},nt=rt.MutationObserver||rt.WebKitMutationObserver,ot="undefined"==typeof self&&"undefined"!=typeof process&&"[object process]"==={}.toString.call(process),it="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel;function st(){return function(){return setTimeout(ct,1)}}var ut=new Array(1e3);function ct(){for(var t=0;t<X;t+=2){(0,ut[t])(ut[t+1]),ut[t]=void 0,ut[t+1]=void 0}X=0}var at,ft,lt,ht,pt,yt,_t=void 0;ot?(pt=process.nextTick,yt=process.versions.node.match(/^(?:(\\d+)\\.)?(?:(\\d+)\\.)?(\\*|\\d+)$/),Array.isArray(yt)&&"0"===yt[1]&&"10"===yt[2]&&(pt=setImmediate),_t=function(){return pt(ct)}):nt?(ft=0,lt=new nt(ct),ht=document.createTextNode(""),lt.observe(ht,{characterData:!0}),_t=function(){return ht.data=ft=++ft%2}):it?((at=new MessageChannel).port1.onmessage=ct,_t=function(){return at.port2.postMessage(0)}):_t=void 0===et&&"function"==typeof require?function(){try{var t=Function("return this")().require("vertx");return void 0!==(Z=t.runOnLoop||t.runOnContext)?function(){Z(ct)}:st()}catch(t){return st()}}():st(),n.async=tt,n.after=function(t){return setTimeout(t,0)};var vt=z,dt=function(t,e){return n.async(t,e)};function mt(){n.on.apply(n,arguments)}function wt(){n.off.apply(n,arguments)}if("undefined"!=typeof window&&"object"==typeof window.__PROMISE_INSTRUMENTATION__){var bt=window.__PROMISE_INSTRUMENTATION__;for(var gt in o("instrument",!0),bt)bt.hasOwnProperty(gt)&&mt(gt,bt[gt])}var jt={asap:tt,cast:vt,Promise:k,EventTarget:r,all:I,allSettled:U,race:D,hash:q,hashSettled:L,rethrow:V,defer:W,denodeify:M,configure:o,on:mt,off:wt,resolve:z,reject:B,map:$,async:dt,filter:Q};t.default=jt,t.asap=tt,t.cast=vt,t.Promise=k,t.EventTarget=r,t.all=I,t.allSettled=U,t.race=D,t.hash=q,t.hashSettled=L,t.rethrow=V,t.defer=W,t.denodeify=M,t.configure=o,t.on=mt,t.off=wt,t.resolve=z,t.reject=B,t.map=$,t.async=dt,t.filter=Q,Object.defineProperty(t,"__esModule",{value:!0})});
window.Promise = RSVP.Promise;
}
"""
......@@ -293,6 +84,7 @@ let consoleLogJS = """
}
}
window.webkit.messageHandlers[oldLog].postMessage(message);
oldLogs[oldLog].apply(null, arguments);
}
})(k);
}
......@@ -873,7 +665,63 @@ let interceptFetchRequestsJS = """
})(window.fetch);
"""
public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler {
/**
https://developer.android.com/reference/android/webkit/WebView.HitTestResult
*/
let findElementsAtPointJS = """
window.\(JAVASCRIPT_BRIDGE_NAME)._findElementsAtPoint = function(x, y) {
var hitTestResultType = {
UNKNOWN_TYPE: 0,
PHONE_TYPE: 2,
GEO_TYPE: 3,
EMAIL_TYPE: 4,
IMAGE_TYPE: 5,
SRC_ANCHOR_TYPE: 7,
SRC_IMAGE_ANCHOR_TYPE: 8,
EDIT_TEXT_TYPE: 9
};
var element = document.elementFromPoint(x, y);
console.log(element);
var data = {
type: 0,
extra: null
};
while (element) {
if (element.tagName === 'IMG' && element.src) {
if (element.parentNode && element.parentNode.tagName === 'A' && element.parentNode.href) {
data.type = hitTestResultType.SRC_IMAGE_ANCHOR_TYPE;
} else {
data.type = hitTestResultType.IMAGE_TYPE;
}
data.extra = element.src;
break;
} else if (element.tagName === 'A' && element.href) {
if (element.href.indexOf('mailto:') === 0) {
data.type = hitTestResultType.EMAIL_TYPE;
data.extra = element.href.replace('mailto:', '');
} else if (element.href.indexOf('tel:') === 0) {
data.type = hitTestResultType.PHONE_TYPE;
data.extra = element.href.replace('tel:', '');
} else if (element.href.indexOf('geo:') === 0) {
data.type = hitTestResultType.GEO_TYPE;
data.extra = element.href.replace('geo:', '');
} else {
data.type = hitTestResultType.SRC_ANCHOR_TYPE;
data.extra = element.href;
}
break;
} else if (
(element.tagName === 'INPUT' && ['text', 'email', 'password', 'number', 'search', 'tel', 'url'].indexOf(element.type) >= 0) ||
element.tagName === 'TEXTAREA') {
data.type = hitTestResultType.EDIT_TEXT_TYPE
}
element = element.parentNode;
}
return data;
}
"""
public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler, UIGestureRecognizerDelegate {
var IABController: InAppBrowserWebViewController?
var channel: FlutterMethodChannel?
......@@ -889,6 +737,11 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
// in order to have the same behavior as Android
var activateShouldOverrideUrlLoading = false
// https://github.com/mozilla-mobile/firefox-ios/blob/50531a7e9e4d459fb11d4fcb7d4322e08103501f/Client/Frontend/Browser/ContextMenuHelper.swift
fileprivate var nativeHighlightLongPressRecognizer: UILongPressGestureRecognizer?
var longPressRecognizer: UILongPressGestureRecognizer?
init(frame: CGRect, configuration: WKWebViewConfiguration, IABController: InAppBrowserWebViewController?, channel: FlutterMethodChannel?) {
super.init(frame: frame, configuration: configuration)
self.channel = channel
......@@ -896,14 +749,102 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
uiDelegate = self
navigationDelegate = self
scrollView.delegate = self
self.longPressRecognizer = UILongPressGestureRecognizer()
self.longPressRecognizer!.delegate = self
self.longPressRecognizer!.addTarget(self, action: #selector(longPressGestureDetected))
}
required public init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
/*
public override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if let _ = sender as? UIMenuController {
print(action)
// disable/hide UIMenuController
return false
}
return super.canPerformAction(action, withSender: sender)
}*/
// @objc func uiMenuViewControllerDidShowMenu() {
// print("MENU\n\n")
// }
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
// BVC KVO events for all changes on the webview will call this.
// It is called frequently during a page load (particularly on progress changes and URL changes).
// As of iOS 12, WKContentView gesture setup is async, but it has been called by the time
// the webview is ready to load an URL. After this has happened, we can override the gesture.
func replaceGestureHandlerIfNeeded() {
DispatchQueue.main.async {
if self.gestureRecognizerWithDescriptionFragment("InAppWebView") == nil {
self.replaceWebViewLongPress()
}
}
}
private func replaceWebViewLongPress() {
// WebKit installs gesture handlers async. If `replaceWebViewLongPress` is called after a wkwebview in most cases a small delay is sufficient
// See also https://bugs.webkit.org/show_bug.cgi?id=193366
nativeHighlightLongPressRecognizer = gestureRecognizerWithDescriptionFragment("action=_highlightLongPressRecognized:")
if let nativeLongPressRecognizer = gestureRecognizerWithDescriptionFragment("action=_longPressRecognized:") {
nativeLongPressRecognizer.removeTarget(nil, action: nil)
nativeLongPressRecognizer.addTarget(self, action: #selector(self.longPressGestureDetected))
}
}
private func gestureRecognizerWithDescriptionFragment(_ descriptionFragment: String) -> UILongPressGestureRecognizer? {
let result = self.scrollView.subviews.compactMap({ $0.gestureRecognizers }).joined().first(where: {
(($0 as? UILongPressGestureRecognizer) != nil) && $0.description.contains(descriptionFragment)
})
return result as? UILongPressGestureRecognizer
}
@objc func longPressGestureDetected(_ sender: UIGestureRecognizer) {
if sender.state == .cancelled {
return
}
guard sender.state == .began else {
return
}
// To prevent the tapped link from proceeding with navigation, "cancel" the native WKWebView
// `_highlightLongPressRecognizer`. This preserves the original behavior as seen here:
// https://github.com/WebKit/webkit/blob/d591647baf54b4b300ca5501c21a68455429e182/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm#L1600-L1614
if let nativeHighlightLongPressRecognizer = self.nativeHighlightLongPressRecognizer,
nativeHighlightLongPressRecognizer.isEnabled {
nativeHighlightLongPressRecognizer.isEnabled = false
nativeHighlightLongPressRecognizer.isEnabled = true
}
//Finding actual touch location in webView
var touchLocation = sender.location(in: self)
touchLocation.x -= self.scrollView.contentInset.left
touchLocation.y -= self.scrollView.contentInset.top
touchLocation.x /= self.scrollView.zoomScale
touchLocation.y /= self.scrollView.zoomScale
self.evaluateJavaScript("window.\(JAVASCRIPT_BRIDGE_NAME)._findElementsAtPoint(\(touchLocation.x),\(touchLocation.y))", completionHandler: {(value, error) in
if error != nil {
print("Long press gesture recognizer error: \(error?.localizedDescription)")
} else {
self.onLongPressHitTestResult(hitTestResult: value as! [String: Any?])
}
})
}
public func prepare() {
self.scrollView.addGestureRecognizer(self.longPressRecognizer!)
addObserver(self,
forKeyPath: #keyPath(WKWebView.estimatedProgress),
options: .new,
......@@ -914,6 +855,12 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
options: [.new, .old],
context: nil)
// NotificationCenter.default.addObserver(
// self,
// selector: #selector(uiMenuViewControllerDidShowMenu),
// name: UIMenuController.didShowMenuNotification,
// object: nil)
configuration.userContentController = WKUserContentController()
configuration.preferences = WKPreferences()
......@@ -943,10 +890,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
configuration.userContentController.addUserScript(userScript)
}
// Prevents long press on links that cause WKWebView exit
let jscriptWebkitTouchCallout = WKUserScript(source: "document.body.style.webkitTouchCallout='none';", injectionTime: .atDocumentEnd, forMainFrameOnly: true)
configuration.userContentController.addUserScript(jscriptWebkitTouchCallout)
let promisePolyfillJSScript = WKUserScript(source: promisePolyfillJS, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(promisePolyfillJSScript)
......@@ -962,6 +905,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
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)
......@@ -1006,6 +952,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
}
accessibilityIgnoresInvertColors = (options?.accessibilityIgnoresInvertColors)!
}
configuration.suppressesIncrementalRendering = (options?.suppressesIncrementalRendering)!
......@@ -1045,10 +992,18 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
scrollView.automaticallyAdjustsScrollIndicatorInsets = (options?.automaticallyAdjustsScrollIndicatorInsets)!
}
scrollView.showsVerticalScrollIndicator = (options?.verticalScrollBarEnabled)!
scrollView.showsHorizontalScrollIndicator = (options?.horizontalScrollBarEnabled)!
scrollView.showsVerticalScrollIndicator = !(options?.disableVerticalScroll)!
scrollView.showsHorizontalScrollIndicator = !(options?.disableHorizontalScroll)!
scrollView.showsVerticalScrollIndicator = (options?.verticalScrollBarEnabled)!
scrollView.showsHorizontalScrollIndicator = (options?.horizontalScrollBarEnabled)!
scrollView.decelerationRate = 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.
......@@ -1085,6 +1040,17 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
}
}
public func getDecelerationRate(type: String) -> UIScrollView.DecelerationRate {
switch type {
case "NORMAL":
return .normal
case "FAST":
return .fast
default:
return .normal
}
}
public static func preWKWebViewConfiguration(options: InAppWebViewOptions?) -> WKWebViewConfiguration {
let configuration = WKWebViewConfiguration()
......@@ -1119,6 +1085,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
let newUrl = change?[NSKeyValueChangeKey.newKey] as? URL
onUpdateVisitedHistory(url: newUrl!.absoluteString)
}
replaceGestureHandlerIfNeeded()
}
public func goBackOrForward(steps: Int) {
......@@ -1252,6 +1219,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
}
if newOptionsMap["accessibilityIgnoresInvertColors"] != nil && options?.accessibilityIgnoresInvertColors != newOptions.accessibilityIgnoresInvertColors {
accessibilityIgnoresInvertColors = newOptions.accessibilityIgnoresInvertColors
}
}
if newOptionsMap["enableViewportScale"] != nil && options?.enableViewportScale != newOptions.enableViewportScale && newOptions.enableViewportScale {
......@@ -1342,6 +1312,13 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
}
}
if newOptionsMap["disableVerticalScroll"] != nil && options?.disableVerticalScroll != newOptions.disableVerticalScroll {
scrollView.showsVerticalScrollIndicator = !newOptions.disableVerticalScroll
}
if newOptionsMap["disableHorizontalScroll"] != nil && options?.disableHorizontalScroll != newOptions.disableHorizontalScroll {
scrollView.showsHorizontalScrollIndicator = !newOptions.disableHorizontalScroll
}
if newOptionsMap["verticalScrollBarEnabled"] != nil && options?.verticalScrollBarEnabled != newOptions.verticalScrollBarEnabled {
scrollView.showsVerticalScrollIndicator = newOptions.verticalScrollBarEnabled
}
......@@ -1349,11 +1326,26 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
scrollView.showsHorizontalScrollIndicator = newOptions.horizontalScrollBarEnabled
}
if newOptionsMap["disableVerticalScroll"] != nil && options?.disableVerticalScroll != newOptions.disableVerticalScroll {
scrollView.showsVerticalScrollIndicator = !newOptions.disableVerticalScroll
if newOptionsMap["decelerationRate"] != nil && options?.decelerationRate != newOptions.decelerationRate {
scrollView.decelerationRate = getDecelerationRate(type: newOptions.decelerationRate)
}
if newOptionsMap["disableHorizontalScroll"] != nil && options?.disableHorizontalScroll != newOptions.disableHorizontalScroll {
scrollView.showsHorizontalScrollIndicator = !newOptions.disableHorizontalScroll
if newOptionsMap["alwaysBounceVertical"] != nil && options?.alwaysBounceVertical != newOptions.alwaysBounceVertical {
scrollView.alwaysBounceVertical = newOptions.alwaysBounceVertical
}
if newOptionsMap["alwaysBounceHorizontal"] != nil && options?.alwaysBounceHorizontal != newOptions.alwaysBounceHorizontal {
scrollView.alwaysBounceHorizontal = newOptions.alwaysBounceHorizontal
}
if newOptionsMap["scrollsToTop"] != nil && options?.scrollsToTop != newOptions.scrollsToTop {
scrollView.scrollsToTop = newOptions.scrollsToTop
}
if newOptionsMap["isPagingEnabled"] != nil && options?.isPagingEnabled != newOptions.isPagingEnabled {
scrollView.scrollsToTop = newOptions.isPagingEnabled
}
if newOptionsMap["maximumZoomScale"] != nil && options?.maximumZoomScale != newOptions.maximumZoomScale {
scrollView.maximumZoomScale = CGFloat(newOptions.maximumZoomScale)
}
if newOptionsMap["minimumZoomScale"] != nil && options?.minimumZoomScale != newOptions.minimumZoomScale {
scrollView.minimumZoomScale = CGFloat(newOptions.minimumZoomScale)
}
if #available(iOS 9.0, *) {
......@@ -1512,10 +1504,13 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
shouldOverrideUrlLoading(url: url, method: navigationAction.request.httpMethod, headers: navigationAction.request.allHTTPHeaderFields, isForMainFrame: isForMainFrame, navigationType: navigationAction.navigationType, result: { (result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message ?? "")
decisionHandler(.allow)
return
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
self.updateUrlTextFieldForIABController(navigationAction: navigationAction)
decisionHandler(.allow)
return
}
else {
var response: [String: Any]
......@@ -2067,6 +2062,115 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
return nil
}
public func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
onWebContentProcessDidTerminate()
}
public func webView(_ webView: WKWebView,
didCommit navigation: WKNavigation!) {
onDidCommit()
}
public func webView(_ webView: WKWebView,
didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
onDidReceiveServerRedirectForProvisionalNavigation()
}
// @available(iOS 13.0, *)
// public func webView(_ webView: WKWebView,
// contextMenuConfigurationForElement elementInfo: WKContextMenuElementInfo,
// completionHandler: @escaping (UIContextMenuConfiguration?) -> Void) {
// let actionProvider: UIContextMenuActionProvider = { _ in
// let editMenu = UIMenu(title: "Edit...", children: [
// UIAction(title: "Copy") { action in
//
// },
// UIAction(title: "Duplicate") { action in
//
// }
// ])
// return UIMenu(title: "Title", children: [
// UIAction(title: "Share") { action in
//
// },
// editMenu
// ])
// }
// let contextMenuConfiguration = UIContextMenuConfiguration(identifier: nil, previewProvider: nil, actionProvider: actionProvider)
// //completionHandler(contextMenuConfiguration)
// completionHandler(nil)
// onContextMenuConfigurationForElement(linkURL: elementInfo.linkURL?.absoluteString, result: nil/*{(result) -> Void in
// if result is FlutterError {
// print((result as! FlutterError).message ?? "")
// }
// else if (result as? NSObject) == FlutterMethodNotImplemented {
// completionHandler(nil)
// }
// else {
// var response: [String: Any]
// if let r = result {
// response = r as! [String: Any]
// var action = response["action"] as? Int
// action = action != nil ? action : 0;
// switch action {
// case 0:
// break
// case 1:
// break
// default:
// completionHandler(nil)
// }
// return;
// }
// completionHandler(nil)
// }
// }*/)
// }
//
// @available(iOS 13.0, *)
// public func webView(_ webView: WKWebView,
// contextMenuDidEndForElement elementInfo: WKContextMenuElementInfo) {
// onContextMenuDidEndForElement(linkURL: elementInfo.linkURL?.absoluteString)
// }
//
// @available(iOS 13.0, *)
// public func webView(_ webView: WKWebView,
// contextMenuForElement elementInfo: WKContextMenuElementInfo,
// willCommitWithAnimator animator: UIContextMenuInteractionCommitAnimating) {
// onWillCommitWithAnimator(linkURL: elementInfo.linkURL?.absoluteString, result: nil/*{(result) -> Void in
// if result is FlutterError {
// print((result as! FlutterError).message ?? "")
// }
// else if (result as? NSObject) == FlutterMethodNotImplemented {
//
// }
// else {
// var response: [String: Any]
// if let r = result {
// response = r as! [String: Any]
// var action = response["action"] as? Int
// action = action != nil ? action : 0;
//// switch action {
//// case 0:
//// break
//// case 1:
//// break
//// default:
////
//// }
// return;
// }
//
// }
// }*/)
// }
//
// @available(iOS 13.0, *)
// public func webView(_ webView: WKWebView,
// contextMenuWillPresentForElement elementInfo: WKContextMenuElementInfo) {
// onContextMenuWillPresentForElement(linkURL: elementInfo.linkURL?.absoluteString)
// }
public func onLoadStart(url: String) {
let arguments: [String: Any] = ["url": url]
channel?.invokeMethod("onLoadStart", arguments: arguments)
......@@ -2211,6 +2315,13 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
channel?.invokeMethod("onUpdateVisitedHistory", arguments: arguments)
}
public func onLongPressHitTestResult(hitTestResult: [String: Any?]) {
let arguments: [String: Any?] = [
"hitTestResult": hitTestResult
]
channel?.invokeMethod("onLongPressHitTestResult", arguments: arguments)
}
public func onCallJsHandler(handlerName: String, _callHandlerID: Int64, args: String) {
let arguments: [String: Any] = ["handlerName": handlerName, "args": args]
channel?.invokeMethod("onCallJsHandler", arguments: arguments, result: {(result) -> Void in
......@@ -2228,6 +2339,38 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
})
}
public func onWebContentProcessDidTerminate() {
channel?.invokeMethod("onWebContentProcessDidTerminate", arguments: [])
}
public func onDidCommit() {
channel?.invokeMethod("onDidCommit", arguments: [])
}
public func onDidReceiveServerRedirectForProvisionalNavigation() {
channel?.invokeMethod("onDidReceiveServerRedirectForProvisionalNavigation", arguments: [])
}
// public func onContextMenuConfigurationForElement(linkURL: String?, result: FlutterResult?) {
// let arguments: [String: Any?] = ["linkURL": linkURL]
// channel?.invokeMethod("onContextMenuConfigurationForElement", arguments: arguments, result: result)
// }
//
// public func onContextMenuDidEndForElement(linkURL: String?) {
// let arguments: [String: Any?] = ["linkURL": linkURL]
// channel?.invokeMethod("onContextMenuDidEndForElement", arguments: arguments)
// }
//
// public func onWillCommitWithAnimator(linkURL: String?, result: FlutterResult?) {
// let arguments: [String: Any?] = ["linkURL": linkURL]
// channel?.invokeMethod("onWillCommitWithAnimator", arguments: arguments, result: result)
// }
//
// public func onContextMenuWillPresentForElement(linkURL: String?) {
// let arguments: [String: Any?] = ["linkURL": linkURL]
// channel?.invokeMethod("onContextMenuWillPresentForElement", arguments: arguments)
// }
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name.starts(with: "console") {
var messageLevel = 1
......@@ -2361,6 +2504,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
if #available(iOS 11.0, *) {
configuration.userContentController.removeAllContentRuleLists()
}
longPressRecognizer!.removeTarget(self, action: #selector(longPressGestureDetected))
longPressRecognizer!.delegate = nil
self.scrollView.removeGestureRecognizer(longPressRecognizer!)
uiDelegate = nil
navigationDelegate = nil
scrollView.delegate = nil
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -49,11 +49,17 @@ public class InAppWebViewOptions: Options {
var preferredContentMode = 0
var sharedCookiesEnabled = false
var automaticallyAdjustsScrollIndicatorInsets = false
var accessibilityIgnoresInvertColors = false
var decelerationRate = "NORMAL" // UIScrollView.DecelerationRate.normal
var alwaysBounceVertical = false
var alwaysBounceHorizontal = false
var scrollsToTop = true
var isPagingEnabled = false
var maximumZoomScale = 1.0
var minimumZoomScale = 1.0
override init(){
super.init()
}
}
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -90,7 +90,9 @@ class MyCookieManager: NSObject, FlutterPlugin {
if maxAge != nil {
properties[.maximumAge] = String(maxAge!)
}
properties[.secure] = (isSecure != nil && isSecure!) ? "TRUE" : "FALSE"
if isSecure != nil && isSecure! {
properties[.secure] = "TRUE"
}
let cookie = HTTPCookie(properties: properties)!
MyCookieManager.httpCookieStore!.setCookie(cookie, completionHandler: {() in
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -497,6 +497,11 @@ class InAppBrowser {
///**NOTE**: available on Android 21+.
void onPrint(String url) {}
///Event fired when an HTML element of the webview has been clicked and held.
///
///[hitTestResult] represents the hit result for hitting an HTML elements.
void onLongPressHitTestResult(LongPressHitTestResult hitTestResult) {}
///Event fired when the WebView notifies that a loading URL has been flagged by Safe Browsing.
///The default behavior is to show an interstitial to the user, with the reporting checkbox visible.
///
......@@ -537,6 +542,21 @@ class InAppBrowser {
///**NOTE**: available only on Android.
void androidOnGeolocationPermissionsHidePrompt() {}
///Invoked when the web view's web content process is terminated.
///
///**NOTE**: available only on iOS.
void iosOnWebContentProcessDidTerminate() {}
///Called when the web view begins to receive web content.
///
///**NOTE**: available only on iOS.
void iosOnDidCommit() {}
///Called when a web view receives a server redirect.
///
///**NOTE**: available only on iOS.
void iosOnDidReceiveServerRedirectForProvisionalNavigation() {}
void throwIsAlreadyOpened({String message = ''}) {
if (this.isOpened()) {
throw Exception([
......
File mode changed from 100644 to 100755
......@@ -253,6 +253,11 @@ class InAppWebView extends StatefulWidget {
///**NOTE**: available on Android 21+.
final void Function(InAppWebViewController controller, String url) onPrint;
///Event fired when an HTML element of the webview has been clicked and held.
///
///[hitTestResult] represents the hit result for hitting an HTML elements.
final void Function(InAppWebViewController controller, LongPressHitTestResult hitTestResult) onLongPressHitTestResult;
///Event fired when the webview notifies that a loading URL has been flagged by Safe Browsing.
///The default behavior is to show an interstitial to the user, with the reporting checkbox visible.
///
......@@ -293,6 +298,21 @@ class InAppWebView extends StatefulWidget {
///**NOTE**: available only on Android.
final Future<void> Function(InAppWebViewController controller) androidOnGeolocationPermissionsHidePrompt;
///Invoked when the web view's web content process is terminated.
///
///**NOTE**: available only on iOS.
final Future<void> Function(InAppWebViewController controller) iosOnWebContentProcessDidTerminate;
///Called when the web view begins to receive web content.
///
///**NOTE**: available only on iOS.
final Future<void> Function(InAppWebViewController controller) iosOnDidCommit;
///Called when a web view receives a server redirect.
///
///**NOTE**: available only on iOS.
final Future<void> Function(InAppWebViewController controller) iosOnDidReceiveServerRedirectForProvisionalNavigation;
///Initial url that will be loaded.
final String initialUrl;
......@@ -350,10 +370,14 @@ class InAppWebView extends StatefulWidget {
this.shouldInterceptFetchRequest,
this.onUpdateVisitedHistory,
this.onPrint,
this.onLongPressHitTestResult,
this.androidOnSafeBrowsingHit,
this.androidOnPermissionRequest,
this.androidOnGeolocationPermissionsShowPrompt,
this.androidOnGeolocationPermissionsHidePrompt,
this.iosOnWebContentProcessDidTerminate,
this.iosOnDidCommit,
this.iosOnDidReceiveServerRedirectForProvisionalNavigation,
this.gestureRecognizers,
}) : super(key: key);
......@@ -383,7 +407,7 @@ class _InAppWebViewState extends State<InAppWebView> {
gestureRecognizers: widget.gestureRecognizers,
layoutDirection: TextDirection.rtl,
creationParams: <String, dynamic>{
'initialUrl': widget.initialUrl,
'initialUrl': '${Uri.parse(widget.initialUrl)}',
'initialFile': widget.initialFile,
'initialData': widget.initialData?.toMap(),
'initialHeaders': widget.initialHeaders,
......@@ -401,7 +425,7 @@ class _InAppWebViewState extends State<InAppWebView> {
gestureRecognizers: widget.gestureRecognizers,
layoutDirection: TextDirection.rtl,
creationParams: <String, dynamic>{
'initialUrl': widget.initialUrl,
'initialUrl': '${Uri.parse(widget.initialUrl)}',
'initialFile': widget.initialFile,
'initialData': widget.initialData?.toMap(),
'initialHeaders': widget.initialHeaders,
......@@ -416,7 +440,7 @@ class _InAppWebViewState extends State<InAppWebView> {
onPlatformViewCreated: _onPlatformViewCreated,
gestureRecognizers: widget.gestureRecognizers,
creationParams: <String, dynamic>{
'initialUrl': widget.initialUrl,
'initialUrl': '${Uri.parse(widget.initialUrl)}',
'initialFile': widget.initialFile,
'initialData': widget.initialData?.toMap(),
'initialHeaders': widget.initialHeaders,
......@@ -744,6 +768,35 @@ class InAppWebViewController {
else if (_inAppBrowser != null)
_inAppBrowser.onUpdateVisitedHistory(url, androidIsReload);
return null;
case "onWebContentProcessDidTerminate":
if (_widget != null && _widget.iosOnWebContentProcessDidTerminate != null)
_widget.iosOnWebContentProcessDidTerminate(this);
else if (_inAppBrowser != null)
_inAppBrowser.iosOnWebContentProcessDidTerminate();
return null;
case "onDidCommit":
if (_widget != null && _widget.iosOnDidCommit != null)
_widget.iosOnDidCommit(this);
else if (_inAppBrowser != null)
_inAppBrowser.iosOnDidCommit();
return null;
case "onDidReceiveServerRedirectForProvisionalNavigation":
if (_widget != null && _widget.iosOnDidReceiveServerRedirectForProvisionalNavigation != null)
_widget.iosOnDidReceiveServerRedirectForProvisionalNavigation(this);
else if (_inAppBrowser != null)
_inAppBrowser.iosOnDidReceiveServerRedirectForProvisionalNavigation();
return null;
case "onLongPressHitTestResult":
Map<dynamic, dynamic> hitTestResultMap = call.arguments["hitTestResult"];
LongPressHitTestResultType type = LongPressHitTestResultType.fromValue(hitTestResultMap["type"].toInt());
String extra = hitTestResultMap["extra"];
LongPressHitTestResult hitTestResult = new LongPressHitTestResult(type: type, extra: extra);
if (_widget != null && _widget.onLongPressHitTestResult != null)
_widget.onLongPressHitTestResult(this, hitTestResult);
else if (_inAppBrowser != null)
_inAppBrowser.onLongPressHitTestResult(hitTestResult);
break;
case "onCallJsHandler":
String handlerName = call.arguments["handlerName"];
// decode args to json
......@@ -966,30 +1019,18 @@ class InAppWebViewController {
///This is not always the same as the URL passed to [InAppWebView.onLoadStarted] because although the load for that URL has begun, the current page may not have changed.
Future<String> getUrl() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
return await _channel.invokeMethod('getUrl', args);
}
///Gets the title for the current page.
Future<String> getTitle() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
return await _channel.invokeMethod('getTitle', args);
}
///Gets the progress for the current page. The progress value is between 0 and 100.
Future<int> getProgress() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
return await _channel.invokeMethod('getProgress', args);
}
......@@ -1160,10 +1201,6 @@ class InAppWebViewController {
{@required String url, Map<String, String> headers = const {}}) async {
assert(url != null && url.isNotEmpty);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened(message: 'Cannot laod $url!');
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headers);
await _channel.invokeMethod('loadUrl', args);
......@@ -1175,10 +1212,6 @@ class InAppWebViewController {
assert(url != null && url.isNotEmpty);
assert(postData != null);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened(message: 'Cannot laod $url!');
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('url', () => url);
args.putIfAbsent('postData', () => postData);
await _channel.invokeMethod('postUrl', args);
......@@ -1199,10 +1232,6 @@ class InAppWebViewController {
String androidHistoryUrl = "about:blank"}) async {
assert(data != null);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('data', () => data);
args.putIfAbsent('mimeType', () => mimeType);
args.putIfAbsent('encoding', () => encoding);
......@@ -1245,10 +1274,6 @@ class InAppWebViewController {
Map<String, String> headers = const {}}) async {
assert(assetFilePath != null && assetFilePath.isNotEmpty);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened(message: 'Cannot laod $assetFilePath!');
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('url', () => assetFilePath);
args.putIfAbsent('headers', () => headers);
await _channel.invokeMethod('loadFile', args);
......@@ -1257,50 +1282,30 @@ class InAppWebViewController {
///Reloads the WebView.
Future<void> reload() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('reload', args);
}
///Goes back in the history of the WebView.
Future<void> goBack() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('goBack', args);
}
///Returns a boolean value indicating whether the WebView can move backward.
Future<bool> canGoBack() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
return await _channel.invokeMethod('canGoBack', args);
}
///Goes forward in the history of the WebView.
Future<void> goForward() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('goForward', args);
}
///Returns a boolean value indicating whether the WebView can move forward.
Future<bool> canGoForward() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
return await _channel.invokeMethod('canGoForward', args);
}
......@@ -1309,10 +1314,6 @@ class InAppWebViewController {
assert(steps != null);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('steps', () => steps);
await _channel.invokeMethod('goBackOrForward', args);
}
......@@ -1322,10 +1323,6 @@ class InAppWebViewController {
assert(steps != null);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('steps', () => steps);
return await _channel.invokeMethod('canGoBackOrForward', args);
}
......@@ -1338,30 +1335,18 @@ class InAppWebViewController {
///Check if the WebView instance is in a loading state.
Future<bool> isLoading() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
return await _channel.invokeMethod('isLoading', args);
}
///Stops the WebView from loading.
Future<void> stopLoading() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('stopLoading', args);
}
///Evaluates JavaScript code into the WebView and returns the result of the evaluation.
Future<dynamic> evaluateJavascript({@required String source}) async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('source', () => source);
var data = await _channel.invokeMethod('evaluateJavascript', args);
if (data != null && Platform.isAndroid) data = json.decode(data);
......@@ -1371,10 +1356,6 @@ class InAppWebViewController {
///Injects an external JavaScript file into the WebView from a defined url.
Future<void> injectJavascriptFileFromUrl({@required String urlFile}) async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('urlFile', () => urlFile);
await _channel.invokeMethod('injectJavascriptFileFromUrl', args);
}
......@@ -1389,10 +1370,6 @@ class InAppWebViewController {
///Injects CSS into the WebView.
Future<void> injectCSSCode({@required String source}) async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('source', () => source);
await _channel.invokeMethod('injectCSSCode', args);
}
......@@ -1400,10 +1377,6 @@ class InAppWebViewController {
///Injects an external CSS file into the WebView from a defined url.
Future<void> injectCSSFileFromUrl({@required String urlFile}) async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('urlFile', () => urlFile);
await _channel.invokeMethod('injectStyleFile', args);
}
......@@ -1480,20 +1453,12 @@ class InAppWebViewController {
///**NOTE for iOS**: available from iOS 11.0+.
Future<Uint8List> takeScreenshot() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
return await _channel.invokeMethod('takeScreenshot', args);
}
///Sets the WebView options with the new [options] and evaluates them.
Future<void> setOptions({@required InAppWebViewWidgetOptions options}) async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
Map<String, dynamic> optionsMap = {};
optionsMap.addAll(options.crossPlatform?.toMap() ?? {});
......@@ -1509,10 +1474,6 @@ class InAppWebViewController {
///Gets the current WebView options. Returns the options with `null` value if they are not set yet.
Future<InAppWebViewWidgetOptions> getOptions() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
InAppWebViewWidgetOptions inAppWebViewWidgetOptions =
InAppWebViewWidgetOptions();
......@@ -1539,10 +1500,6 @@ class InAppWebViewController {
///The object returned from this method will not be updated to reflect any new state.
Future<WebHistory> getCopyBackForwardList() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
Map<dynamic, dynamic> result =
await _channel.invokeMethod('getCopyBackForwardList', args);
result = result.cast<String, dynamic>();
......@@ -1568,10 +1525,6 @@ class InAppWebViewController {
///Clears all the webview's cache.
Future<void> clearCache() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('clearCache', args);
}
......@@ -1585,10 +1538,6 @@ class InAppWebViewController {
Future<void> findAllAsync({@required String find}) async {
assert(find != null);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('find', () => find);
await _channel.invokeMethod('findAllAsync', args);
}
......@@ -1601,10 +1550,6 @@ class InAppWebViewController {
Future<void> findNext({@required bool forward}) async {
assert(forward != null);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('forward', () => forward);
await _channel.invokeMethod('findNext', args);
}
......@@ -1614,10 +1559,6 @@ class InAppWebViewController {
///**NOTE**: on iOS, this is implemented using CSS and Javascript.
Future<void> clearMatches() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('clearMatches', args);
}
......@@ -1641,10 +1582,6 @@ class InAppWebViewController {
Future<void> scrollTo({@required int x, @required int y}) async {
assert(x != null && y != null);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('x', () => x);
args.putIfAbsent('y', () => y);
await _channel.invokeMethod('scrollTo', args);
......@@ -1658,10 +1595,6 @@ class InAppWebViewController {
Future<void> scrollBy({@required int x, @required int y}) async {
assert(x != null && y != null);
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('x', () => x);
args.putIfAbsent('y', () => y);
await _channel.invokeMethod('scrollBy', args);
......@@ -1673,10 +1606,6 @@ class InAppWebViewController {
///On iOS, it is restricted to just this WebView.
Future<void> pauseTimers() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('pauseTimers', args);
}
......@@ -1685,10 +1614,6 @@ class InAppWebViewController {
///On iOS, it resumes all layout, parsing, and JavaScript timers to just this WebView.
Future<void> resumeTimers() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('resumeTimers', args);
}
......@@ -1697,20 +1622,12 @@ class InAppWebViewController {
///**NOTE**: available on Android 21+.
Future<void> printCurrentPage() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
await _channel.invokeMethod('printCurrentPage', args);
}
///Gets the height of the HTML content.
Future<int> getContentHeight() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
return await _channel.invokeMethod('getContentHeight', args);
}
......@@ -1721,10 +1638,6 @@ class InAppWebViewController {
///**NOTE**: available on Android 21+.
Future<void> zoomBy(double zoomFactor) async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
args.putIfAbsent('zoomFactor', () => zoomFactor);
return await _channel.invokeMethod('zoomBy', args);
}
......@@ -1732,10 +1645,6 @@ class InAppWebViewController {
///Gets the current scale of this WebView.
Future<double> getScale() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid);
}
return await _channel.invokeMethod('getScale', args);
}
......@@ -1766,10 +1675,6 @@ class AndroidInAppWebViewController {
///**NOTE**: available only on Android 27+.
Future<bool> startSafeBrowsing() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_controller._inAppBrowserUuid != null && _controller._inAppBrowser != null) {
_controller._inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _controller._inAppBrowserUuid);
}
return await _controller._channel.invokeMethod('startSafeBrowsing', args);
}
......@@ -1791,10 +1696,6 @@ class AndroidInAppWebViewController {
Future<bool> setSafeBrowsingWhitelist({@required List<String> hosts}) async {
assert(hosts != null);
Map<String, dynamic> args = <String, dynamic>{};
if (_controller._inAppBrowserUuid != null && _controller._inAppBrowser != null) {
_controller._inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _controller._inAppBrowserUuid);
}
args.putIfAbsent('hosts', () => hosts);
return await _controller._channel.invokeMethod('setSafeBrowsingWhitelist', args);
}
......@@ -1804,20 +1705,12 @@ class AndroidInAppWebViewController {
///**NOTE**: available only on Android 27+.
Future<String> getSafeBrowsingPrivacyPolicyUrl() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_controller._inAppBrowserUuid != null && _controller._inAppBrowser != null) {
_controller._inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _controller._inAppBrowserUuid);
}
return await _controller._channel.invokeMethod('getSafeBrowsingPrivacyPolicyUrl', args);
}
///Clears the SSL preferences table stored in response to proceeding with SSL certificate errors.
Future<void> clearSslPreferences() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_controller._inAppBrowserUuid != null && _controller._inAppBrowser != null) {
_controller._inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _controller._inAppBrowserUuid);
}
await _controller._channel.invokeMethod('clearSslPreferences', args);
}
......@@ -1830,10 +1723,6 @@ class AndroidInAppWebViewController {
///**NOTE**: available on Android 21+.
Future<void> clearClientCertPreferences() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_controller._inAppBrowserUuid != null && _controller._inAppBrowser != null) {
_controller._inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _controller._inAppBrowserUuid);
}
await _controller._channel.invokeMethod('clearClientCertPreferences', args);
}
......@@ -1841,20 +1730,12 @@ class AndroidInAppWebViewController {
///To pause JavaScript globally, use [pauseTimers()]. To resume WebView, call [resume()].
Future<void> pause() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_controller._inAppBrowserUuid != null && _controller._inAppBrowser != null) {
_controller._inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _controller._inAppBrowserUuid);
}
await _controller._channel.invokeMethod('pause', args);
}
///Resumes a WebView after a previous call to [pause()].
Future<void> resume() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_controller._inAppBrowserUuid != null && _controller._inAppBrowser != null) {
_controller._inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _controller._inAppBrowserUuid);
}
await _controller._channel.invokeMethod('resume', args);
}
......@@ -1863,10 +1744,6 @@ class AndroidInAppWebViewController {
///the current page may not have changed. Also, there may have been redirects resulting in a different URL to that originally requested.
Future<String> getOriginalUrl() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_controller._inAppBrowserUuid != null && _controller._inAppBrowser != null) {
_controller._inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _controller._inAppBrowserUuid);
}
return await _controller._channel.invokeMethod('getOriginalUrl', args);
}
......@@ -1883,10 +1760,12 @@ class IOSInAppWebViewController {
///Reloads the current page, performing end-to-end revalidation using cache-validating conditionals if possible.
Future<void> reloadFromOrigin() async {
Map<String, dynamic> args = <String, dynamic>{};
if (_controller._inAppBrowserUuid != null && _controller._inAppBrowser != null) {
_controller._inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _controller._inAppBrowserUuid);
}
await _controller._channel.invokeMethod('reloadFromOrigin', args);
}
///A Boolean value indicating whether all resources on the page have been loaded over securely encrypted connections.
Future<bool> hasOnlySecureContent() async {
Map<String, dynamic> args = <String, dynamic>{};
return await _controller._channel.invokeMethod('hasOnlySecureContent', args);
}
}
\ No newline at end of file
......@@ -1048,6 +1048,35 @@ class IOSWKDataDetectorTypes {
int get hashCode => _value.hashCode;
}
///IOSUIScrollViewDecelerationRate class represents a floating-point value that determines the rate of deceleration after the user lifts their finger.
class IOSUIScrollViewDecelerationRate {
final String _value;
const IOSUIScrollViewDecelerationRate._internal(this._value);
static IOSUIScrollViewDecelerationRate fromValue(String value) {
return ([
"NORMAL",
"FAST"
].contains(value))
? IOSUIScrollViewDecelerationRate._internal(value)
: null;
}
String toValue() => _value;
@override
String toString() => _value;
///The default deceleration rate for a scroll view: `0.998`.
static const NORMAL = const IOSUIScrollViewDecelerationRate._internal("NORMAL");
///A fast deceleration rate for a scroll view: `0.99`.
static const FAST = const IOSUIScrollViewDecelerationRate._internal("FAST");
bool operator ==(value) => value == _value;
@override
int get hashCode => _value.hashCode;
}
///UserPreferredContentMode class represents the content mode to prefer when loading and rendering a webpage.
class UserPreferredContentMode {
final int _value;
......@@ -2219,3 +2248,70 @@ class IOSWKWebsiteDataRecord {
return toMap().toString();
}
}
///Class representing the [LongPressHitTestResult] type.
class LongPressHitTestResultType {
final int _value;
const LongPressHitTestResultType._internal(this._value);
static LongPressHitTestResultType fromValue(int value) {
if (value != null && [0, 2, 3, 4, 5, 7, 8, 9].contains(value))
return LongPressHitTestResultType._internal(value);
return null;
}
int toValue() => _value;
@override
String toString() {
switch (_value) {
case 2:
return "PHONE_TYPE";
case 3:
return "GEO_TYPE";
case 4:
return "EMAIL_TYPE";
case 5:
return "IMAGE_TYPE";
case 7:
return "SRC_ANCHOR_TYPE";
case 8:
return "SRC_IMAGE_ANCHOR_TYPE";
case 9:
return "EDIT_TEXT_TYPE";
case 0:
default:
return "UNKNOWN_TYPE";
}
}
///Default [LongPressHitTestResult], where the target is unknown.
static const UNKNOWN_TYPE = const LongPressHitTestResultType._internal(0);
///[LongPressHitTestResult] for hitting a phone number.
static const PHONE_TYPE = const LongPressHitTestResultType._internal(2);
///[LongPressHitTestResult] for hitting a map address.
static const GEO_TYPE = const LongPressHitTestResultType._internal(3);
///[LongPressHitTestResult] for hitting an email address.
static const EMAIL_TYPE = const LongPressHitTestResultType._internal(4);
///[LongPressHitTestResult] for hitting an HTML::img tag.
static const IMAGE_TYPE = const LongPressHitTestResultType._internal(5);
///[LongPressHitTestResult] for hitting a HTML::a tag with src=http.
static const SRC_ANCHOR_TYPE = const LongPressHitTestResultType._internal(7);
///[LongPressHitTestResult] for hitting a HTML::a tag with src=http + HTML::img.
static const SRC_IMAGE_ANCHOR_TYPE = const LongPressHitTestResultType._internal(8);
///[LongPressHitTestResult] for hitting an edit text area.
static const EDIT_TEXT_TYPE = const LongPressHitTestResultType._internal(9);
bool operator ==(value) => value == _value;
@override
int get hashCode => _value.hashCode;
}
///LongPressHitTestResult class represents the hit result for hitting an HTML elements. Used by [onLongPressHitTestResult] event.
class LongPressHitTestResult {
///The type of the hit test result.
LongPressHitTestResultType type;
///Additional type-dependant information about the result.
String extra;
LongPressHitTestResult({this.type, this.extra});
}
File mode changed from 100644 to 100755
......@@ -621,6 +621,46 @@ 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.
///The default value is `false`.
///
///**NOTE**: available on iOS 11.0+.
bool accessibilityIgnoresInvertColors;
///A [IOSUIScrollViewDecelerationRate] value that determines the rate of deceleration after the user lifts their finger.
///The default value is [IOSUIScrollViewDecelerationRate.NORMAL].
IOSUIScrollViewDecelerationRate decelerationRate;
///A Boolean value that determines whether bouncing always occurs when vertical scrolling reaches the end of the content.
///The default value is `false`.
bool alwaysBounceVertical;
///A Boolean value that determines whether bouncing always occurs when horizontal scrolling reaches the end of the content view.
///The default value is `false`.
bool alwaysBounceHorizontal;
///A Boolean value that controls whether the scroll-to-top gesture is enabled.
///The scroll-to-top gesture is a tap on the status bar. When a user makes this gesture,
///the system asks the scroll view closest to the status bar to scroll to the top.
///The default value is `true`.
bool scrollsToTop;
///A Boolean value that determines whether paging is enabled for the scroll view.
///If the value of this property is true, the scroll view stops on multiples of the scroll view’s bounds when the user scrolls.
///The default value is `false`.
bool isPagingEnabled;
///A floating-point value that specifies the maximum scale factor that can be applied to the scroll view's content.
///This value determines how large the content can be scaled.
///It must be greater than the minimum zoom scale for zooming to be enabled.
///The default value is `1.0`.
double maximumZoomScale;
///A floating-point value that specifies the minimum scale factor that can be applied to the scroll view's content.
///This value determines how small the content can be scaled.
///The default value is `1.0`.
double minimumZoomScale;
IOSInAppWebViewOptions(
{this.disallowOverScroll = false,
this.enableViewportScale = false,
......@@ -635,7 +675,15 @@ class IOSInAppWebViewOptions
this.selectionGranularity = IOSWKSelectionGranularity.DYNAMIC,
this.dataDetectorTypes = const [IOSWKDataDetectorTypes.NONE],
this.sharedCookiesEnabled = false,
this.automaticallyAdjustsScrollIndicatorInsets = false});
this.automaticallyAdjustsScrollIndicatorInsets = false,
this.accessibilityIgnoresInvertColors = false,
this.decelerationRate = IOSUIScrollViewDecelerationRate.NORMAL,
this.alwaysBounceVertical = false,
this.alwaysBounceHorizontal = false,
this.scrollsToTop = true,
this.isPagingEnabled = false,
this.maximumZoomScale = 1.0,
this.minimumZoomScale = 1.0});
@override
Map<String, dynamic> toMap() {
......@@ -660,7 +708,15 @@ class IOSInAppWebViewOptions
"selectionGranularity": selectionGranularity.toValue(),
"dataDetectorTypes": dataDetectorTypesList,
"sharedCookiesEnabled": sharedCookiesEnabled,
"automaticallyAdjustsScrollIndicatorInsets": automaticallyAdjustsScrollIndicatorInsets
"automaticallyAdjustsScrollIndicatorInsets": automaticallyAdjustsScrollIndicatorInsets,
"accessibilityIgnoresInvertColors": accessibilityIgnoresInvertColors,
"decelerationRate": decelerationRate.toValue(),
"alwaysBounceVertical": alwaysBounceVertical,
"alwaysBounceHorizontal": alwaysBounceHorizontal,
"scrollsToTop": scrollsToTop,
"isPagingEnabled": isPagingEnabled,
"maximumZoomScale": maximumZoomScale,
"minimumZoomScale": minimumZoomScale
};
}
......@@ -695,6 +751,14 @@ class IOSInAppWebViewOptions
options.dataDetectorTypes = dataDetectorTypes;
options.sharedCookiesEnabled = map["sharedCookiesEnabled"];
options.automaticallyAdjustsScrollIndicatorInsets = map["automaticallyAdjustsScrollIndicatorInsets"];
options.accessibilityIgnoresInvertColors = map["accessibilityIgnoresInvertColors"];
options.decelerationRate = IOSUIScrollViewDecelerationRate.fromValue(map["decelerationRate"]);
options.alwaysBounceVertical = map["alwaysBounceVertical"];
options.alwaysBounceHorizontal = map["alwaysBounceHorizontal"];
options.scrollsToTop = map["scrollsToTop"];
options.isPagingEnabled = map["isPagingEnabled"];
options.maximumZoomScale = map["maximumZoomScale"];
options.minimumZoomScale = map["minimumZoomScale"];
return options;
}
}
......@@ -752,7 +816,7 @@ class AndroidInAppBrowserOptions implements BrowserOptions, AndroidOptions {
///Set to `false` to not close the InAppBrowser when the user click on the back button and the WebView cannot go back to the history. The default value is `true`.
bool closeOnCannotGoBack;
///Set to `false` to hide the progress bar at the bottom of the toolbar at the top. The default value is `true`.
///Set to `false` to hide the progressz bar at the bottom of the toolbar at the top. The default value is `true`.
bool progressBar;
AndroidInAppBrowserOptions(
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -5,8 +5,8 @@ author: Lorenzo Pichilli <pichillilorenzo@gmail.com>
homepage: https://github.com/pichillilorenzo/flutter_inappwebview
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
flutter: ">=1.10.0 <2.0.0"
sdk: ">=2.7.0 <3.0.0"
flutter: ">=1.12.13+hotfix.5"
dependencies:
flutter:
......
......@@ -5,5 +5,6 @@ dart tool/env.dart
cd nodejs_server_test_auth_basic_and_ssl
node index.js &
cd ../example
flutter clean
flutter driver -t test_driver/app.dart
kill $(jobs -p)
\ No newline at end of file
File mode changed from 100644 to 100755
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