added clearHistory webview methods on Android, setContextMenu and clearFocus webview methods, added ContextMenuOptions class

This commit is contained in:
Lorenzo Pichilli 2020-05-30 20:23:33 +02:00
parent ad56ca6621
commit 9f9232e1f3
17 changed files with 305 additions and 78 deletions

View File

@ -3,12 +3,14 @@
- Updated API docs - Updated API docs
- Updated Android context menu workaround - Updated Android context menu workaround
- Calling `onCreateContextMenu` event on iOS also when the context menu is disabled in order to have the same effect as Android - Calling `onCreateContextMenu` event on iOS also when the context menu is disabled in order to have the same effect as Android
- Added `options` attribute to `ContextMenu` class and created `ContextMenuOptions` class
- Added Android keyboard workaround to hide the keyboard when clicking other HTML elements, losing the focus on the previous input - Added Android keyboard workaround to hide the keyboard when clicking other HTML elements, losing the focus on the previous input
- Added `onEnterFullscreen`, `onExitFullscreen` webview events [#275](https://github.com/pichillilorenzo/flutter_inappwebview/issues/275) - Added `onEnterFullscreen`, `onExitFullscreen` webview events [#275](https://github.com/pichillilorenzo/flutter_inappwebview/issues/275)
- Added Android support to use camera on HTML inputs that requires it, such as `<input type="file" accept="image/*" capture>` [#353](https://github.com/pichillilorenzo/flutter_inappwebview/issues/353) - Added Android support to use camera on HTML inputs that requires it, such as `<input type="file" accept="image/*" capture>` [#353](https://github.com/pichillilorenzo/flutter_inappwebview/issues/353)
- Added `overScrollMode`, `networkAvailable`, `scrollBarStyle`, `verticalScrollbarPosition`, `scrollBarDefaultDelayBeforeFade`, `scrollbarFadingEnabled`, `scrollBarFadeDuration`, `rendererPriorityPolicy`, `useShouldInterceptRequest`, `useOnRenderProcessGone` webview options on Android - Added `overScrollMode`, `networkAvailable`, `scrollBarStyle`, `verticalScrollbarPosition`, `scrollBarDefaultDelayBeforeFade`, `scrollbarFadingEnabled`, `scrollBarFadeDuration`, `rendererPriorityPolicy`, `useShouldInterceptRequest`, `useOnRenderProcessGone` webview options on Android
- Added `pageDown`, `pageUp`, `saveWebArchive`, `zoomIn`, `zoomOut` webview methods on Android - Added `pageDown`, `pageUp`, `saveWebArchive`, `zoomIn`, `zoomOut`, `clearHistory` webview methods on Android
- Added `getCurrentWebViewPackage` static webview method on Android - Added `getCurrentWebViewPackage` static webview method on Android
- Added `setContextMenu`, `clearFocus` methods to webview controller
- Added `onPageCommitVisible` webview event - Added `onPageCommitVisible` webview event
- Added `androidShouldInterceptRequest`, `androidOnRenderProcessUnresponsive`, `androidOnRenderProcessResponsive`, `androidOnRenderProcessGone`, `androidOnFormResubmission`, `androidOnScaleChanged` Android events - Added `androidShouldInterceptRequest`, `androidOnRenderProcessUnresponsive`, `androidOnRenderProcessResponsive`, `androidOnRenderProcessGone`, `androidOnFormResubmission`, `androidOnScaleChanged` Android events
- Added `toString()` method to various classes in order to have a better output instead of simply `Instance of ...` - Added `toString()` method to various classes in order to have a better output instead of simply `Instance of ...`
@ -23,6 +25,7 @@
- Android `clearClientCertPreferences`, `getSafeBrowsingPrivacyPolicyUrl`, `setSafeBrowsingWhitelist` webview methods are static now - Android `clearClientCertPreferences`, `getSafeBrowsingPrivacyPolicyUrl`, `setSafeBrowsingWhitelist` webview methods are static now
- Removed iOS event `onDidCommit`; it has been renamed to `onPageCommitVisible` and made cross-platform - Removed iOS event `onDidCommit`; it has been renamed to `onPageCommitVisible` and made cross-platform
- `contextMenu` is `final` now
## 3.2.0 ## 3.2.0

View File

@ -400,6 +400,8 @@ Screenshots:
* `getScale`: Gets the current scale of this WebView. * `getScale`: Gets the current scale of this WebView.
* `getSelectedText`: Gets the selected text. * `getSelectedText`: Gets the selected text.
* `getHitTestResult`: Gets the hit result for hitting an HTML elements. * `getHitTestResult`: Gets the hit result for hitting an HTML elements.
* `clearFocus`: Clears the current focus. It will clear also, for example, the current text selection.
* `setContextMenu(ContextMenu contextMenu)`: Sets or updates the WebView context menu to be used next time it will appear.
* `static getDefaultUserAgent`: Gets the default user agent. * `static getDefaultUserAgent`: Gets the default user agent.
##### `InAppWebViewController` Android-specific methods ##### `InAppWebViewController` Android-specific methods
@ -416,6 +418,7 @@ Android-specific methods can be called using the `InAppWebViewController.android
* `saveWebArchive({@required String basename, @required bool autoname})`: Saves the current view as a web archive. * `saveWebArchive({@required String basename, @required bool autoname})`: Saves the current view as a web archive.
* `zoomIn`: Performs zoom in in this WebView. * `zoomIn`: Performs zoom in in this WebView.
* `zoomOut`: Performs zoom out in this WebView. * `zoomOut`: Performs zoom out in this WebView.
* `clearHistory`: Clears the internal back/forward list.
* `static clearClientCertPreferences`: Clears the client certificate preferences stored in response to proceeding/cancelling client cert requests. * `static clearClientCertPreferences`: Clears the client certificate preferences stored in response to proceeding/cancelling client cert requests.
* `static getSafeBrowsingPrivacyPolicyUrl`: Returns a URL pointing to the privacy policy for Safe Browsing reporting. This value will never be `null`. * `static getSafeBrowsingPrivacyPolicyUrl`: Returns a URL pointing to the privacy policy for Safe Browsing reporting. This value will never be `null`.
* `static setSafeBrowsingWhitelist({@required List<String> hosts})`: Sets the list of hosts (domain names/IP addresses) that are exempt from SafeBrowsing checks. The list is global for all the WebViews. * `static setSafeBrowsingWhitelist({@required List<String> hosts})`: Sets the list of hosts (domain names/IP addresses) that are exempt from SafeBrowsing checks. The list is global for all the WebViews.
@ -665,6 +668,11 @@ class _MyAppState extends State<MyApp> {
super.initState(); super.initState();
contextMenu = ContextMenu( contextMenu = ContextMenu(
menuItems: [
ContextMenuItem(androidId: 1, iosId: "1", title: "Special", action: () async {
print("Menu item Special clicked!");
})
],
onCreateContextMenu: (hitTestResult) async { onCreateContextMenu: (hitTestResult) async {
print("onCreateContextMenu"); print("onCreateContextMenu");
print(hitTestResult.extra); print(hitTestResult.extra);
@ -679,12 +687,6 @@ class _MyAppState extends State<MyApp> {
} }
); );
contextMenu.menuItems = [
ContextMenuItem(androidId: 1, iosId: "1", title: "Special", action: () async {
print("Menu item Special clicked!");
})
];
} }
@override @override
@ -782,6 +784,10 @@ class _MyAppState extends State<MyApp> {
} }
``` ```
### `ContextMenu` options
* `hideDefaultSystemContextMenuItems`: Whether all the default system context menu items should be hidden or not. The default value is `false`.
### `ContextMenu` Events ### `ContextMenu` Events
* `onCreateContextMenu`: Event fired when the context menu for this WebView is being built. * `onCreateContextMenu`: Event fired when the context menu for this WebView is being built.
@ -1182,7 +1188,7 @@ class _MyAppState extends State<MyApp> {
url: "https://flutter.dev/", url: "https://flutter.dev/",
options: ChromeSafariBrowserClassOptions( options: ChromeSafariBrowserClassOptions(
android: AndroidChromeCustomTabsOptions(addDefaultShareMenuItem: false), android: AndroidChromeCustomTabsOptions(addDefaultShareMenuItem: false),
ios: IosSafariOptions(barCollapsingEnabled: true))); ios: IOSSafariOptions(barCollapsingEnabled: true)));
}, },
child: Text("Open Chrome Safari Browser")), child: Text("Open Chrome Safari Browser")),
), ),
@ -1190,7 +1196,6 @@ class _MyAppState extends State<MyApp> {
); );
} }
} }
``` ```
Screenshots: Screenshots:

View File

@ -365,6 +365,17 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha
case "zoomOut": case "zoomOut":
result.success(zoomOut()); result.success(zoomOut());
break; break;
case "clearFocus":
clearFocus();
result.success(true);
break;
case "setContextMenu":
{
Map<String, Object> contextMenu = (Map<String, Object>) call.argument("contextMenu");
setContextMenu(contextMenu);
}
result.success(true);
break;
default: default:
result.notImplemented(); result.notImplemented();
} }
@ -909,6 +920,16 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha
return false; return false;
} }
public void clearFocus() {
if (webView != null)
webView.clearFocus();
}
public void setContextMenu(Map<String, Object> contextMenu) {
if (webView != null)
webView.contextMenu = contextMenu;
}
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); channel.setMethodCallHandler(null);
activityResultListeners.clear(); activityResultListeners.clear();

View File

@ -30,10 +30,10 @@ public class InAppBrowserOptions implements Options<InAppBrowserActivity> {
switch (key) { switch (key) {
case "hidden": case "hidden":
hidden = (boolean) value; hidden = (Boolean) value;
break; break;
case "toolbarTop": case "toolbarTop":
toolbarTop = (boolean) value; toolbarTop = (Boolean) value;
break; break;
case "toolbarTopBackgroundColor": case "toolbarTopBackgroundColor":
toolbarTopBackgroundColor = (String) value; toolbarTopBackgroundColor = (String) value;
@ -42,16 +42,16 @@ public class InAppBrowserOptions implements Options<InAppBrowserActivity> {
toolbarTopFixedTitle = (String) value; toolbarTopFixedTitle = (String) value;
break; break;
case "hideUrlBar": case "hideUrlBar":
hideUrlBar = (boolean) value; hideUrlBar = (Boolean) value;
break; break;
case "hideTitleBar": case "hideTitleBar":
hideTitleBar = (boolean) value; hideTitleBar = (Boolean) value;
break; break;
case "closeOnCannotGoBack": case "closeOnCannotGoBack":
closeOnCannotGoBack = (boolean) value; closeOnCannotGoBack = (Boolean) value;
break; break;
case "progressBar": case "progressBar":
progressBar = (boolean) value; progressBar = (Boolean) value;
break; break;
} }
} }

View File

@ -0,0 +1,43 @@
package com.pichillilorenzo.flutter_inappwebview.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.Options;
import java.util.HashMap;
import java.util.Map;
public class ContextMenuOptions implements Options<Object> {
public static final String LOG_TAG = "ContextMenuOptions";
public Boolean hideDefaultSystemContextMenuItems = false;
public ContextMenuOptions parse(Map<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 "hideDefaultSystemContextMenuItems":
hideDefaultSystemContextMenuItems = (Boolean) value;
break;
}
}
return this;
}
public Map<String, Object> toMap() {
Map<String, Object> options = new HashMap<>();
options.put("hideDefaultSystemContextMenuItems", hideDefaultSystemContextMenuItems);
return options;
}
@Override
public Map<String, Object> getRealOptions(Object webView) {
Map<String, Object> realOptions = toMap();
return realOptions;
}
}

View File

@ -52,8 +52,8 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
final String initialFile = (String) params.get("initialFile"); final String initialFile = (String) params.get("initialFile");
final Map<String, String> initialData = (Map<String, String>) params.get("initialData"); final Map<String, String> initialData = (Map<String, String>) params.get("initialData");
final Map<String, String> initialHeaders = (Map<String, String>) params.get("initialHeaders"); final Map<String, String> initialHeaders = (Map<String, String>) params.get("initialHeaders");
HashMap<String, Object> initialOptions = (HashMap<String, Object>) params.get("initialOptions"); Map<String, Object> initialOptions = (Map<String, Object>) params.get("initialOptions");
HashMap<String, Object> contextMenu = (HashMap<String, Object>) params.get("contextMenu"); Map<String, Object> contextMenu = (Map<String, Object>) params.get("contextMenu");
InAppWebViewOptions options = new InAppWebViewOptions(); InAppWebViewOptions options = new InAppWebViewOptions();
options.parse(initialOptions); options.parse(initialOptions);
@ -440,6 +440,23 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
result.success(false); result.success(false);
} }
break; break;
case "clearFocus":
if (webView != null) {
webView.clearFocus();
result.success(true);
} else {
result.success(false);
}
break;
case "setContextMenu":
if (webView != null) {
Map<String, Object> contextMenu = (Map<String, Object>) call.argument("contextMenu");
webView.contextMenu = contextMenu;
result.success(true);
} else {
result.success(false);
}
break;
default: default:
result.notImplemented(); result.notImplemented();
} }

View File

@ -82,7 +82,7 @@ final public class InAppWebView extends InputAwareWebView {
public Pattern regexToCancelSubFramesLoadingCompiled; public Pattern regexToCancelSubFramesLoadingCompiled;
public GestureDetector gestureDetector = null; public GestureDetector gestureDetector = null;
public LinearLayout floatingContextMenu = null; public LinearLayout floatingContextMenu = null;
public HashMap<String, Object> contextMenu = null; public Map<String, Object> contextMenu = null;
public Handler headlessHandler = new Handler(Looper.getMainLooper()); public Handler headlessHandler = new Handler(Looper.getMainLooper());
public Runnable checkScrollStoppedTask; public Runnable checkScrollStoppedTask;
@ -608,7 +608,7 @@ final public class InAppWebView extends InputAwareWebView {
super(context, attrs, defaultStyle); super(context, attrs, defaultStyle);
} }
public InAppWebView(Context context, Object obj, Object id, InAppWebViewOptions options, HashMap<String, Object> contextMenu, View containerView) { public InAppWebView(Context context, Object obj, Object id, InAppWebViewOptions options, Map<String, Object> contextMenu, View containerView) {
super(context, containerView); super(context, containerView);
if (obj instanceof InAppBrowserActivity) if (obj instanceof InAppBrowserActivity)
this.inAppBrowserActivity = (InAppBrowserActivity) obj; this.inAppBrowserActivity = (InAppBrowserActivity) obj;
@ -1597,6 +1597,18 @@ final public class InAppWebView extends InputAwareWebView {
HorizontalScrollView horizontalScrollView = (HorizontalScrollView) floatingContextMenu.getChildAt(0); HorizontalScrollView horizontalScrollView = (HorizontalScrollView) floatingContextMenu.getChildAt(0);
LinearLayout menuItemListLayout = (LinearLayout) horizontalScrollView.getChildAt(0); LinearLayout menuItemListLayout = (LinearLayout) horizontalScrollView.getChildAt(0);
List<Map<String, Object>> customMenuItems = new ArrayList<>();
ContextMenuOptions contextMenuOptions = new ContextMenuOptions();
if (contextMenu != null) {
customMenuItems = (List<Map<String, Object>>) contextMenu.get("menuItems");
Map<String, Object> contextMenuOptionsMap = (Map<String, Object>) contextMenu.get("options");
if (contextMenuOptionsMap != null) {
contextMenuOptions.parse(contextMenuOptionsMap);
}
}
customMenuItems = customMenuItems == null ? new ArrayList<Map<String, Object>>() : customMenuItems;
if (contextMenuOptions.hideDefaultSystemContextMenuItems == null || !contextMenuOptions.hideDefaultSystemContextMenuItems) {
for (int i = 0; i < actionMenu.size(); i++) { for (int i = 0; i < actionMenu.size(); i++) {
final MenuItem menuItem = actionMenu.getItem(i); final MenuItem menuItem = actionMenu.getItem(i);
final int itemId = menuItem.getItemId(); final int itemId = menuItem.getItemId();
@ -1623,11 +1635,9 @@ final public class InAppWebView extends InputAwareWebView {
menuItemListLayout.addView(text); menuItemListLayout.addView(text);
} }
} }
}
if (contextMenu != null) { for (final Map<String, Object> menuItem : customMenuItems) {
List<HashMap<String, Object>> customMenuItems = (List<HashMap<String, Object>>) contextMenu.get("menuItems");
if (customMenuItems != null) {
for (final HashMap<String, Object> menuItem : customMenuItems) {
final int itemId = (int) menuItem.get("androidId"); final int itemId = (int) menuItem.get("androidId");
final String itemTitle = (String) menuItem.get("title"); final String itemTitle = (String) menuItem.get("title");
TextView text = (TextView) LayoutInflater.from(this.getContext()) TextView text = (TextView) LayoutInflater.from(this.getContext())
@ -1636,7 +1646,6 @@ final public class InAppWebView extends InputAwareWebView {
text.setOnClickListener(new OnClickListener() { text.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
// clearFocus();
hideContextMenu(); hideContextMenu();
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
@ -1653,8 +1662,6 @@ final public class InAppWebView extends InputAwareWebView {
} }
} }
}
}
final int x = (lastTouch != null) ? lastTouch.x : 0; final int x = (lastTouch != null) ? lastTouch.x : 0;
final int y = (lastTouch != null) ? lastTouch.y : 0; final int y = (lastTouch != null) ? lastTouch.y : 0;

View File

@ -3,8 +3,7 @@ package com.pichillilorenzo.flutter_inappwebview;
import java.util.Map; import java.util.Map;
public interface Options<T> { public interface Options<T> {
static String LOG_TAG = "Options";
public Options parse(Map<String, Object> options); public Options parse(Map<String, Object> options);
public Map<String, Object> toMap(); public Map<String, Object> toMap();
public Map<String, Object> getRealOptions(T webView); public Map<String, Object> getRealOptions(T obj);
} }

View File

@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.0+hotfix.6/","dependencies":[]}],"android":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.0+hotfix.6/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"e2e","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"permission_handler","dependencies":[]}],"date_created":"2020-05-29 19:53:44.213613","version":"1.17.1"} {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.0+hotfix.6/","dependencies":[]}],"android":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.0+hotfix.6/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"e2e","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"permission_handler","dependencies":[]}],"date_created":"2020-05-30 19:55:39.840707","version":"1.17.1"}

View File

@ -23,6 +23,16 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
super.initState(); super.initState();
contextMenu = ContextMenu( contextMenu = ContextMenu(
menuItems: [
ContextMenuItem(androidId: 1, iosId: "1", title: "Special", action: () async {
print("Menu item Special clicked!");
print(await webView.getSelectedText());
await webView.clearFocus();
})
],
options: ContextMenuOptions(
hideDefaultSystemContextMenuItems: true
),
onCreateContextMenu: (hitTestResult) async { onCreateContextMenu: (hitTestResult) async {
print("onCreateContextMenu"); print("onCreateContextMenu");
print(hitTestResult.extra); print(hitTestResult.extra);
@ -31,16 +41,11 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
onHideContextMenu: () { onHideContextMenu: () {
print("onHideContextMenu"); print("onHideContextMenu");
}, },
onContextMenuActionItemClicked: (contextMenuItemClicked) { onContextMenuActionItemClicked: (contextMenuItemClicked) async {
var id = (Platform.isAndroid) ? contextMenuItemClicked.androidId : contextMenuItemClicked.iosId; var id = (Platform.isAndroid) ? contextMenuItemClicked.androidId : contextMenuItemClicked.iosId;
print("onContextMenuActionItemClicked: " + id.toString() + " " + contextMenuItemClicked.title); print("onContextMenuActionItemClicked: " + id.toString() + " " + contextMenuItemClicked.title);
} }
); );
contextMenu.menuItems = [
ContextMenuItem(androidId: 1, iosId: "1", title: "Special", action: () async {
print("Menu item Special clicked!");
})
];
} }
@override @override
@ -74,17 +79,14 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
BoxDecoration(border: Border.all(color: Colors.blueAccent)), BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: InAppWebView( child: InAppWebView(
contextMenu: contextMenu, contextMenu: contextMenu,
// initialUrl: "https://github.com/flutter", initialUrl: "https://github.com/flutter",
initialFile: "assets/index.html", // initialFile: "assets/index.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: InAppWebViewGroupOptions( initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions( crossPlatform: InAppWebViewOptions(
debuggingEnabled: true, debuggingEnabled: true,
useShouldOverrideUrlLoading: true useShouldOverrideUrlLoading: true
), ),
android: AndroidInAppWebViewOptions(
supportMultipleWindows: true
)
), ),
onWebViewCreated: (InAppWebViewController controller) { onWebViewCreated: (InAppWebViewController controller) {
webView = controller; webView = controller;

View File

@ -0,0 +1,17 @@
//
// ContextMenuOptions.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 30/05/2020.
//
import Foundation
class ContextMenuOptions: Options<NSObject> {
var hideDefaultSystemContextMenuItems = false;
override init(){
super.init()
}
}

View File

@ -426,6 +426,23 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
result(nil) result(nil)
} }
break break
case "clearFocus":
if webView != nil {
webView!.clearFocus()
result(true)
} else {
result(false)
}
break
case "setContextMenu":
if webView != nil {
let contextMenu = arguments!["contextMenu"] as? [String: Any]
webView!.contextMenu = contextMenu
result(true)
} else {
result(false)
}
break
default: default:
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)
break break

View File

@ -308,6 +308,24 @@ public class InAppBrowserWebViewController: UIViewController, FlutterPlugin, UIS
result(nil) result(nil)
} }
break break
case "clearFocus":
if webView != nil {
webView!.clearFocus()
result(true)
} else {
result(false)
}
break
case "setContextMenu":
if webView != nil {
let contextMenu = arguments!["contextMenu"] as? [String: Any]
webView!.contextMenu = contextMenu
result(true)
} else {
result(false)
}
break
default: default:
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)
break break

View File

@ -905,6 +905,16 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
return false return false
} }
if let menu = contextMenu {
let contextMenuOptions = ContextMenuOptions()
if let contextMenuOptionsMap = menu["options"] as? [String: Any?] {
let _ = contextMenuOptions.parse(options: contextMenuOptionsMap)
if !action.description.starts(with: "onContextMenuActionItemClicked-") && contextMenuOptions.hideDefaultSystemContextMenuItems {
return false
}
}
}
if contextMenuIsShowing, !action.description.starts(with: "onContextMenuActionItemClicked-") { if contextMenuIsShowing, !action.description.starts(with: "onContextMenuActionItemClicked-") {
let id = action.description.compactMap({ $0.asciiValue?.description }).joined() let id = action.description.compactMap({ $0.asciiValue?.description }).joined()
let arguments: [String: Any?] = [ let arguments: [String: Any?] = [
@ -2729,6 +2739,10 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
} }
} }
public func clearFocus() {
self.scrollView.subviews.first?.resignFirstResponder()
}
public func dispose() { public func dispose() {
stopLoading() stopLoading()
configuration.userContentController.removeScriptMessageHandler(forName: "consoleLog") configuration.userContentController.removeScriptMessageHandler(forName: "consoleLog")

View File

@ -1,6 +1,6 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_inappwebview/src/webview.dart';
import 'webview.dart';
import 'types.dart'; import 'types.dart';
///Class that represents the WebView context menu. It used by [WebView.contextMenu]. ///Class that represents the WebView context menu. It used by [WebView.contextMenu].
@ -22,24 +22,35 @@ class ContextMenu {
final void Function(ContextMenuItem contextMenuItemClicked) final void Function(ContextMenuItem contextMenuItemClicked)
onContextMenuActionItemClicked; onContextMenuActionItemClicked;
///Context menu options.
final ContextMenuOptions options;
///List of the custom [ContextMenuItem]. ///List of the custom [ContextMenuItem].
List<ContextMenuItem> menuItems = List(); final List<ContextMenuItem> menuItems;
ContextMenu( ContextMenu(
{this.menuItems, {this.menuItems = const [],
this.onCreateContextMenu, this.onCreateContextMenu,
this.onHideContextMenu, this.onHideContextMenu,
this.onContextMenuActionItemClicked}); this.options,
this.onContextMenuActionItemClicked})
: assert(menuItems != null);
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return { return {
"menuItems": menuItems.map((menuItem) => menuItem?.toMap()).toList() "menuItems": menuItems.map((menuItem) => menuItem?.toMap()).toList(),
"options": options?.toMap()
}; };
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return this.toMap(); return this.toMap();
} }
@override
String toString() {
return toMap().toString();
}
} }
///Class that represent an item of the [ContextMenu]. ///Class that represent an item of the [ContextMenu].
@ -69,4 +80,32 @@ class ContextMenuItem {
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return this.toMap(); return this.toMap();
} }
@override
String toString() {
return toMap().toString();
}
}
///Class that represents available options used by [ContextMenu].
class ContextMenuOptions {
///Whether all the default system context menu items should be hidden or not. The default value is `false`.
bool hideDefaultSystemContextMenuItems;
ContextMenuOptions({this.hideDefaultSystemContextMenuItems = false});
Map<String, dynamic> toMap() {
return {
"hideDefaultSystemContextMenuItems": hideDefaultSystemContextMenuItems
};
}
Map<String, dynamic> toJson() {
return this.toMap();
}
@override
String toString() {
return toMap().toString();
}
} }

View File

@ -13,10 +13,10 @@ import 'types.dart';
///This class uses the native WebView of the platform. ///This class uses the native WebView of the platform.
///The [webViewController] field can be used to access the [InAppWebViewController] API. ///The [webViewController] field can be used to access the [InAppWebViewController] API.
class InAppBrowser { class InAppBrowser {
///Browser's UUID ///Browser's UUID.
String uuid; String uuid;
///Context menu used by the browser ///Context menu used by the browser. It should be set before opening the browser.
ContextMenu contextMenu; ContextMenu contextMenu;
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap = Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap =

View File

@ -1487,6 +1487,23 @@ class InAppWebViewController {
return InAppWebViewHitTestResult(type: type, extra: extra); return InAppWebViewHitTestResult(type: type, extra: extra);
} }
///Clears the current focus. It will clear also, for example, the current text selection.
///
///**Official Android API**: https://developer.android.com/reference/android/view/ViewGroup#clearFocus()
///**Official iOS API**: https://developer.apple.com/documentation/uikit/uiresponder/1621097-resignfirstresponder
Future<void> clearFocus() async {
Map<String, dynamic> args = <String, dynamic>{};
return await _channel.invokeMethod('clearFocus', args);
}
///Sets or updates the WebView context menu to be used next time it will appear.
Future<void> setContextMenu(ContextMenu contextMenu) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("contextMenu", () => contextMenu?.toMap());
await _channel.invokeMethod('setContextMenu', args);
_inAppBrowser?.contextMenu = contextMenu;
}
///Gets the default user agent. ///Gets the default user agent.
/// ///
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebSettings#getDefaultUserAgent(android.content.Context) ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebSettings#getDefaultUserAgent(android.content.Context)
@ -1617,6 +1634,14 @@ class AndroidInAppWebViewController {
return await _controller._channel.invokeMethod('zoomOut', args); return await _controller._channel.invokeMethod('zoomOut', args);
} }
///Clears the internal back/forward list.
///
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#clearHistory()
Future<void> clearHistory() async {
Map<String, dynamic> args = <String, dynamic>{};
return await _controller._channel.invokeMethod('clearHistory', args);
}
///Clears the client certificate preferences stored in response to proceeding/cancelling client cert requests. ///Clears the client certificate preferences stored in response to proceeding/cancelling client cert requests.
///Note that WebView automatically clears these preferences when the system keychain is updated. ///Note that WebView automatically clears these preferences when the system keychain is updated.
///The preferences are shared by all the WebViews that are created by the embedder application. ///The preferences are shared by all the WebViews that are created by the embedder application.