Commit 5943059b authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

v3.2.0, added context menu classes, updated docs, fix #235, fix #337, fix #341

parent ecf8d45d
## 3.1.1
## 3.2.0
- Added `ContextMenu` and `ContextMenuItem` classes [#235](https://github.com/pichillilorenzo/flutter_inappwebview/issues/235)
- Added `onCreateContextMenu`, `onHideContextMenu`, `onContextMenuActionItemClicked` context menu events
- Added `contextMenu` to WebView
- Added `disableContextMenu` WebView option
- Added `getSelectedText`, `getHitTestResult` methods to WebView Controller
- Fixed `Confirmation dialog (onbeforeunload) displayed after popped from webview page` [#337](https://github.com/pichillilorenzo/flutter_inappwebview/issues/337)
- Fixed `CookieManager.setCookie` `expiresDate` option
- Fixed `Scrolling not smooth on iOS` [#341](https://github.com/pichillilorenzo/flutter_inappwebview/issues/341)
### BREAKING CHANGES
- Renamed `LongPressHitTestResult` to `InAppWebViewHitTestResult`.
- Renamed `LongPressHitTestResultType` to `InAppWebViewHitTestResultType`.
## 3.1.0
......
This diff is collapsed.
......@@ -136,6 +136,7 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
Shared.activity.startActivity(myIntent);
result.success(true);
break;
default:
result.notImplemented();
......
......@@ -40,11 +40,12 @@ public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandl
{
String url = (String) call.argument("url");
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
List<HashMap<String, Object>> menuItemList = (List<HashMap<String, Object>>) call.argument("menuItemList");
String uuidFallback = (String) call.argument("uuidFallback");
Map<String, String> headersFallback = (Map<String, String>) call.argument("headersFallback");
HashMap<String, Object> optionsFallback = (HashMap<String, Object>) call.argument("optionsFallback");
List<HashMap<String, Object>> menuItemList = (List<HashMap<String, Object>>) call.argument("menuItemList");
open(activity, uuid, url, options, uuidFallback, headersFallback, optionsFallback, menuItemList, result);
HashMap<String, Object> contextMenuFallback = (HashMap<String, Object>) call.argument("contextMenuFallback");
open(activity, uuid, url, options, menuItemList, uuidFallback, headersFallback, optionsFallback, contextMenuFallback, result);
}
break;
default:
......@@ -52,8 +53,8 @@ public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandl
}
}
public void open(Activity activity, String uuid, String url, HashMap<String, Object> options, String uuidFallback,
Map<String, String> headersFallback, HashMap<String, Object> optionsFallback, List<HashMap<String, Object>> menuItemList, MethodChannel.Result result) {
public void open(Activity activity, String uuid, String url, HashMap<String, Object> options, List<HashMap<String, Object>> menuItemList, String uuidFallback,
Map<String, String> headersFallback, HashMap<String, Object> optionsFallback, HashMap<String, Object> contextMenuFallback, MethodChannel.Result result) {
Intent intent = null;
Bundle extras = new Bundle();
......@@ -62,9 +63,11 @@ public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandl
extras.putBoolean("isData", false);
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putSerializable("headers", (Serializable) headersFallback);
extras.putSerializable("menuItemList", (Serializable) menuItemList);
extras.putSerializable("headers", (Serializable) headersFallback);
extras.putSerializable("contextMenu", (Serializable) contextMenuFallback);
if (CustomTabActivityHelper.isAvailable(activity)) {
intent = new Intent(activity, ChromeCustomTabsActivity.class);
}
......
......@@ -72,6 +72,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha
fromActivity = b.getString("fromActivity");
HashMap<String, Object> optionsMap = (HashMap<String, Object>) b.getSerializable("options");
HashMap<String, Object> contextMenu = (HashMap<String, Object>) b.getSerializable("contextMenu");
options = new InAppBrowserOptions();
options.parse(optionsMap);
......@@ -79,6 +80,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha
InAppWebViewOptions webViewOptions = new InAppWebViewOptions();
webViewOptions.parse(optionsMap);
webView.options = webViewOptions;
webView.contextMenu = contextMenu;
actionBar = getSupportActionBar();
......@@ -223,7 +225,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha
result.success(isHidden);
break;
case "takeScreenshot":
result.success(takeScreenshot());
takeScreenshot(result);
break;
case "setOptions":
{
......@@ -330,6 +332,16 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha
case "getScale":
result.success(getScale());
break;
case "getSelectedText":
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getSelectedText(result);
} else {
result.success(null);
}
break;
case "getHitTestResult":
result.success(getHitTestResult());
break;
default:
result.notImplemented();
}
......@@ -619,24 +631,11 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha
close(null);
}
public byte[] takeScreenshot() {
if (webView != null) {
Picture picture = webView.capturePicture();
Bitmap b = Bitmap.createBitmap( webView.getWidth(),
webView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
picture.draw(c);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
try {
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return byteArrayOutputStream.toByteArray();
}
return null;
public void takeScreenshot(MethodChannel.Result result) {
if (webView != null)
webView.takeScreenshot(result);
else
result.success(null);
}
public void setOptions(InAppBrowserOptions newOptions, HashMap<String, Object> newOptionsMap) {
......@@ -843,6 +842,25 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha
return null;
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void getSelectedText(MethodChannel.Result result) {
if (webView != null)
webView.getSelectedText(result);
else
result.success(null);
}
public Map<String, Object> getHitTestResult() {
if (webView != null) {
WebView.HitTestResult hitTestResult = webView.getHitTestResult();
Map<String, Object> obj = new HashMap<>();
obj.put("type", hitTestResult.getType());
obj.put("extra", hitTestResult.getExtra());
return obj;
}
return null;
}
public void dispose() {
channel.setMethodCallHandler(null);
if (webView != null) {
......
......@@ -70,7 +70,8 @@ public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
String url = (String) call.argument("url");
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
Map<String, String> headers = (Map<String, String>) call.argument("headers");
openUrl(activity, uuid, url, options, headers);
HashMap<String, Object> contextMenu = (HashMap<String, Object>) call.argument("contextMenu");
openUrl(activity, uuid, url, options, headers, contextMenu);
}
result.success(true);
break;
......@@ -86,7 +87,8 @@ public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
}
HashMap<String, Object> options = (HashMap<String, Object>) call.argument("options");
Map<String, String> headers = (Map<String, String>) call.argument("headers");
openUrl(activity, uuid, url, options, headers);
HashMap<String, Object> contextMenu = (HashMap<String, Object>) call.argument("contextMenu");
openUrl(activity, uuid, url, options, headers, contextMenu);
}
result.success(true);
break;
......@@ -98,7 +100,8 @@ public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
String encoding = (String) call.argument("encoding");
String baseUrl = (String) call.argument("baseUrl");
String historyUrl = (String) call.argument("historyUrl");
openData(activity, uuid, options, data, mimeType, encoding, baseUrl, historyUrl);
HashMap<String, Object> contextMenu = (HashMap<String, Object>) call.argument("contextMenu");
openData(activity, uuid, options, data, mimeType, encoding, baseUrl, historyUrl, contextMenu);
}
result.success(true);
break;
......@@ -189,7 +192,7 @@ public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
}
}
public void openUrl(Activity activity, String uuid, String url, HashMap<String, Object> options, Map<String, String> headers) {
public void openUrl(Activity activity, String uuid, String url, HashMap<String, Object> options, Map<String, String> headers, HashMap<String, Object> contextMenu) {
Bundle extras = new Bundle();
extras.putString("fromActivity", activity.getClass().getName());
extras.putString("url", url);
......@@ -197,10 +200,11 @@ public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
extras.putString("uuid", uuid);
extras.putSerializable("options", options);
extras.putSerializable("headers", (Serializable) headers);
extras.putSerializable("contextMenu", (Serializable) contextMenu);
startInAppBrowserActivity(activity, extras);
}
public void openData(Activity activity, String uuid, HashMap<String, Object> options, String data, String mimeType, String encoding, String baseUrl, String historyUrl) {
public void openData(Activity activity, String uuid, HashMap<String, Object> options, String data, String mimeType, String encoding, String baseUrl, String historyUrl, HashMap<String, Object> contextMenu) {
Bundle extras = new Bundle();
extras.putBoolean("isData", true);
extras.putString("uuid", uuid);
......@@ -210,6 +214,7 @@ public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
extras.putString("encoding", encoding);
extras.putString("baseUrl", baseUrl);
extras.putString("historyUrl", historyUrl);
extras.putSerializable("contextMenu", (Serializable) contextMenu);
startInAppBrowserActivity(activity, extras);
}
......
......@@ -4,6 +4,8 @@ import android.app.Activity;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.View;
......@@ -49,15 +51,16 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
displayListenerProxy.onPreWebViewInitialization(displayManager);
String initialUrl = (String) params.get("initialUrl");
String initialFile = (String) params.get("initialFile");
Map<String, String> initialData = (Map<String, String>) params.get("initialData");
Map<String, String> initialHeaders = (Map<String, String>) params.get("initialHeaders");
final String initialFile = (String) params.get("initialFile");
final Map<String, String> initialData = (Map<String, String>) params.get("initialData");
final Map<String, String> initialHeaders = (Map<String, String>) params.get("initialHeaders");
HashMap<String, Object> initialOptions = (HashMap<String, Object>) params.get("initialOptions");
HashMap<String, Object> contextMenu = (HashMap<String, Object>) params.get("contextMenu");
InAppWebViewOptions options = new InAppWebViewOptions();
options.parse(initialOptions);
webView = new InAppWebView(Shared.activity, this, id, options, containerView);
webView = new InAppWebView(Shared.activity, this, id, options, contextMenu, containerView);
displayListenerProxy.onPostWebViewInitialization(displayManager);
// fix https://github.com/pichillilorenzo/flutter_inappwebview/issues/182
......@@ -86,16 +89,23 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
}
}
if (initialData != null) {
String data = initialData.get("data");
String mimeType = initialData.get("mimeType");
String encoding = initialData.get("encoding");
String baseUrl = initialData.get("baseUrl");
String historyUrl = initialData.get("historyUrl");
webView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
}
else
webView.loadUrl(initialUrl, initialHeaders);
final String finalInitialUrl = initialUrl;
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
if (initialData != null) {
String data = initialData.get("data");
String mimeType = initialData.get("mimeType");
String encoding = initialData.get("encoding");
String baseUrl = initialData.get("baseUrl");
String historyUrl = initialData.get("historyUrl");
webView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
}
else
webView.loadUrl(finalInitialUrl, initialHeaders);
}
});
if (containerView == null && id instanceof String) {
Map<String, Object> obj = new HashMap<>();
......@@ -381,6 +391,24 @@ public class FlutterWebView implements PlatformView, MethodCallHandler {
case "getScale":
result.success((webView != null) ? webView.getUpdatedScale() : null);
break;
case "getSelectedText":
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.getSelectedText(result);
} else {
result.success(null);
}
break;
case "getHitTestResult":
if (webView != null) {
WebView.HitTestResult hitTestResult = webView.getHitTestResult();
Map<String, Object> obj = new HashMap<>();
obj.put("type", hitTestResult.getType());
obj.put("extra", hitTestResult.getExtra());
result.success(obj);
} else {
result.success(null);
}
break;
default:
result.notImplemented();
}
......
......@@ -42,6 +42,7 @@ public class InAppWebViewOptions implements Options {
public Boolean transparentBackground = false;
public Boolean disableVerticalScroll = false;
public Boolean disableHorizontalScroll = false;
public Boolean disableContextMenu = false;
public Integer textZoom = 100;
public Boolean clearSessionCache = false;
......@@ -165,6 +166,9 @@ public class InAppWebViewOptions implements Options {
case "disableHorizontalScroll":
disableHorizontalScroll = (Boolean) value;
break;
case "disableContextMenu":
disableContextMenu = (Boolean) value;
break;
case "textZoom":
textZoom = (Integer) value;
break;
......@@ -323,6 +327,7 @@ public class InAppWebViewOptions implements Options {
options.put("transparentBackground", transparentBackground);
options.put("disableVerticalScroll", disableVerticalScroll);
options.put("disableHorizontalScroll", disableHorizontalScroll);
options.put("disableContextMenu", disableContextMenu);
options.put("textZoom", textZoom);
options.put("clearSessionCache", clearSessionCache);
options.put("builtInZoomControls", builtInZoomControls);
......
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="8dip"/>
<solid android:color="#FFF"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0"
android:background="@drawable/floating_action_mode_shape"
android:elevation="4dp">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"></LinearLayout>
</HorizontalScrollView>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:background="?android:attr/selectableItemBackground"
android:textColor="#000"
tools:text="Copy" />
\ 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-11 15:01:02.801973","version":"1.17.0"}
\ 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-21 03:31:36.578209","version":"1.17.0"}
\ No newline at end of file
......@@ -2,10 +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/test_driver/app.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"
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
......@@ -11,12 +13,33 @@ class InAppWebViewExampleScreen extends StatefulWidget {
class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
InAppWebViewController webView;
ContextMenu contextMenu;
String url = "";
double progress = 0;
@override
void initState() {
super.initState();
contextMenu = ContextMenu(
onCreateContextMenu: (hitTestResult) async {
print("onCreateContextMenu");
print(hitTestResult.extra);
print(await webView.getSelectedText());
},
onHideContextMenu: () {
print("onHideContextMenu");
},
onContextMenuActionItemClicked: (contextMenuItemClicked) {
var id = (Platform.isAndroid) ? contextMenuItemClicked.androidId : contextMenuItemClicked.iosId;
print("onContextMenuActionItemClicked: " + id.toString() + " " + contextMenuItemClicked.title);
}
);
contextMenu.menuItems = [
ContextMenuItem(androidId: 1, iosId: "1", title: "Special", action: () async {
print("Menu item Special clicked!");
})
];
}
@override
......@@ -49,12 +72,13 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
decoration:
BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: InAppWebView(
initialUrl: "s",
contextMenu: contextMenu,
initialUrl: "https://github.com/flutter",
// initialFile: "assets/index.html",
initialHeaders: {},
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
debuggingEnabled: true
),
),
onWebViewCreated: (InAppWebViewController controller) {
......@@ -106,7 +130,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
setState(() {
this.url = url;
});
},
}
),
),
),
......
final environment = {"NODE_SERVER_IP":"192.168.1.20"};
\ No newline at end of file
final environment = {"NODE_SERVER_IP":"192.168.1.21"};
\ No newline at end of file
......@@ -38,11 +38,12 @@ public class ChromeSafariBrowserManager: NSObject, FlutterPlugin {
case "open":
let url = arguments!["url"] as! String
let options = arguments!["options"] as! [String: Any?]
let menuItemList = arguments!["menuItemList"] as! [[String: Any]]
let uuidFallback: String = arguments!["uuidFallback"] as! String
let headersFallback = arguments!["headersFallback"] as! [String: String]
let optionsFallback = arguments!["optionsFallback"] as! [String: Any?]
let menuItemList = arguments!["menuItemList"] as! [[String: Any]]
open(uuid: uuid, url: url, options: options, uuidFallback: uuidFallback, headersFallback: headersFallback, optionsFallback: optionsFallback, menuItemList: menuItemList, result: result)
let contextMenuFallback = arguments!["contextMenuFallback"] as! [String: Any]
open(uuid: uuid, url: url, options: options, menuItemList: menuItemList, uuidFallback: uuidFallback, headersFallback: headersFallback, optionsFallback: optionsFallback, contextMenuFallback: contextMenuFallback, result: result)
break
default:
result(FlutterMethodNotImplemented)
......@@ -50,7 +51,7 @@ public class ChromeSafariBrowserManager: NSObject, FlutterPlugin {
}
}
public func open(uuid: String, url: String, options: [String: Any?], uuidFallback: String?, headersFallback: [String: String], optionsFallback: [String: Any?], menuItemList: [[String: Any]], result: @escaping FlutterResult) {
public func open(uuid: String, url: String, options: [String: Any?], menuItemList: [[String: Any]], uuidFallback: String, headersFallback: [String: String], optionsFallback: [String: Any?], contextMenuFallback: [String: Any], result: @escaping FlutterResult) {
let absoluteUrl = URL(string: url)!.absoluteURL
if self.previousStatusBarStyle == -1 {
......@@ -105,7 +106,7 @@ public class ChromeSafariBrowserManager: NSObject, FlutterPlugin {
return
}
SwiftFlutterPlugin.instance!.inAppBrowserManager!.openUrl(uuid: uuidFallback!, url: url, options: optionsFallback, headers: headersFallback)
SwiftFlutterPlugin.instance!.inAppBrowserManager!.openUrl(uuid: uuidFallback, url: url, options: optionsFallback, headers: headersFallback, contextMenu: contextMenuFallback)
}
}
}
......@@ -38,12 +38,13 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
let initialData = args["initialData"] as? [String: String]
let initialHeaders = args["initialHeaders"] as? [String: String]
let initialOptions = args["initialOptions"] as! [String: Any?]
let contextMenu = args["contextMenu"] as? [String: Any]
let options = InAppWebViewOptions()
let _ = options.parse(options: initialOptions)
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(options: options)
webView = InAppWebView(frame: myView!.bounds, configuration: preWebviewConfiguration, IABController: nil, channel: channel!)
webView = InAppWebView(frame: myView!.bounds, configuration: preWebviewConfiguration, IABController: nil, contextMenu: contextMenu, channel: channel!)
webView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
myView!.autoresizesSubviews = true
myView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
......@@ -98,7 +99,7 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
deinit {
print("FlutterWebViewController - dealloc")
channel?.setMethodCallHandler(nil)
webView!.dispose()
webView?.dispose()
webView = nil
myView = nil
}
......@@ -373,7 +374,8 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
case "printCurrentPage":
if webView != nil {
webView!.printCurrentPage(printCompletionHandler: {(completed, error) in
if !completed, let _ = error {
if !completed, let err = error {
print(err.localizedDescription)
result(false)
return
}
......@@ -398,6 +400,32 @@ public class FlutterWebViewController: FlutterMethodCallDelegate, FlutterPlatfor
case "hasOnlySecureContent":
result( (webView != nil) ? webView!.hasOnlySecureContent : nil )
break
case "getSelectedText":
if webView != nil {
webView!.getSelectedText { (value, error) in
if let err = error {
print(err.localizedDescription)
}
result(value)
}
}
else {
result(nil)
}
break
case "getHitTestResult":
if webView != nil {
webView!.getHitTestResult { (value, error) in
if let err = error {
print(err.localizedDescription)
}
result(value)
}
}
else {
result(nil)
}
break
default:
result(FlutterMethodNotImplemented)
break
......
......@@ -41,7 +41,8 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
let url = arguments!["url"] as! String
let options = arguments!["options"] as! [String: Any?]
let headers = arguments!["headers"] as! [String: String]
openUrl(uuid: uuid, url: url, options: options, headers: headers)
let contextMenu = arguments!["contextMenu"] as! [String: Any]
openUrl(uuid: uuid, url: url, options: options, headers: headers, contextMenu: contextMenu)
result(true)
break
case "openFile":
......@@ -56,7 +57,8 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
}
let options = arguments!["options"] as! [String: Any?]
let headers = arguments!["headers"] as! [String: String]
openUrl(uuid: uuid, url: url, options: options, headers: headers)
let contextMenu = arguments!["contextMenu"] as! [String: Any]
openUrl(uuid: uuid, url: url, options: options, headers: headers, contextMenu: contextMenu)
result(true)
break
case "openData":
......@@ -65,7 +67,8 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
let mimeType = arguments!["mimeType"] as! String
let encoding = arguments!["encoding"] as! String
let baseUrl = arguments!["baseUrl"] as! String
openData(uuid: uuid, options: options, data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
let contextMenu = arguments!["contextMenu"] as! [String: Any]
openData(uuid: uuid, options: options, data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl, contextMenu: contextMenu)
result(true)
break
case "openWithSystemBrowser":
......@@ -110,7 +113,7 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
return webViewController
}
public func openUrl(uuid: String, url: String, options: [String: Any?], headers: [String: String]) {
public func openUrl(uuid: String, url: String, options: [String: Any?], headers: [String: String], contextMenu: [String: Any]) {
let absoluteUrl = URL(string: url)!.absoluteURL
let webViewController = prepareInAppBrowserWebViewController(options: options)
......@@ -119,6 +122,7 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
webViewController.tmpWindow = tmpWindow
webViewController.initURL = absoluteUrl
webViewController.initHeaders = headers
webViewController.contextMenu = contextMenu
if webViewController.isHidden {
webViewController.view.isHidden = true
......@@ -137,7 +141,7 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
}
}
public func openData(uuid: String, options: [String: Any?], data: String, mimeType: String, encoding: String, baseUrl: String) {
public func openData(uuid: String, options: [String: Any?], data: String, mimeType: String, encoding: String, baseUrl: String, contextMenu: [String: Any]) {
let webViewController = prepareInAppBrowserWebViewController(options: options)
webViewController.uuid = uuid
......@@ -146,6 +150,7 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
webViewController.initMimeType = mimeType
webViewController.initEncoding = encoding
webViewController.initBaseUrl = baseUrl
webViewController.contextMenu = contextMenu
if webViewController.isHidden {
webViewController.view.isHidden = true
......
......@@ -17,7 +17,7 @@ typealias NewerClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, B
public class InAppWebView_IBWrapper: InAppWebView {
required init(coder: NSCoder) {
let config = WKWebViewConfiguration()
super.init(frame: .zero, configuration: config, IABController: nil, channel: nil)
super.init(frame: .zero, configuration: config, IABController: nil, contextMenu: nil, channel: nil)
self.translatesAutoresizingMaskIntoConstraints = false
}
}
......@@ -46,6 +46,7 @@ public class InAppBrowserWebViewController: UIViewController, FlutterPlugin, UIS
var webView: InAppWebView!
var channel: FlutterMethodChannel?
var initURL: URL?
var contextMenu: [String: Any]?
var tmpWindow: UIWindow?
var browserOptions: InAppBrowserOptions?
var webViewOptions: InAppWebViewOptions?
......@@ -281,6 +282,32 @@ public class InAppBrowserWebViewController: UIViewController, FlutterPlugin, UIS
case "hasOnlySecureContent":
result(webView.hasOnlySecureContent)
break
case "getSelectedText":
if webView != nil {
webView!.getSelectedText { (value, error) in
if let err = error {
print(err.localizedDescription)
}
result(value)
}
}
else {
result(nil)
}
break
case "getHitTestResult":
if webView != nil {
webView!.getHitTestResult { (value, error) in
if let err = error {
print(err.localizedDescription)
}
result(value)
}
}
else {
result(nil)
}
break
default:
result(FlutterMethodNotImplemented)
break
......@@ -290,7 +317,7 @@ public class InAppBrowserWebViewController: UIViewController, FlutterPlugin, UIS
public override func viewWillAppear(_ animated: Bool) {
if !viewPrepared {
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(options: webViewOptions)
self.webView = InAppWebView(frame: .zero, configuration: preWebviewConfiguration, IABController: self, channel: channel!)
self.webView = InAppWebView(frame: .zero, configuration: preWebviewConfiguration, IABController: self, contextMenu: contextMenu, channel: channel!)
self.containerWebView.addSubview(self.webView)
prepareConstraints()
prepareWebView()
......@@ -685,7 +712,8 @@ public class InAppBrowserWebViewController: UIViewController, FlutterPlugin, UIS
tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
onExit()
channel!.setMethodCallHandler(nil)
channel?.setMethodCallHandler(nil)
channel = nil
}
public func onBrowserCreated() {
......
This diff is collapsed.
......@@ -33,6 +33,7 @@ public class InAppWebViewOptions: Options {
var transparentBackground = false
var disableVerticalScroll = false
var disableHorizontalScroll = false
var disableContextMenu = false
var disallowOverScroll = false
var enableViewportScale = false
......
......@@ -31,11 +31,10 @@ public class SafariViewController: SFSafariViewController, FlutterPlugin, SFSafa
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
// let arguments = call.arguments as? NSDictionary
switch call.method {
case "close":
close()
close(result: result)
break
default:
result(FlutterMethodNotImplemented)
......@@ -67,7 +66,7 @@ public class SafariViewController: SFSafariViewController, FlutterPlugin, SFSafa
self.modalTransitionStyle = UIModalTransitionStyle(rawValue: (safariOptions?.transitionStyle)!)!
}
func close() {
func close(result: FlutterResult?) {
dismiss(animated: true)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(400), execute: {() -> Void in
......@@ -75,11 +74,14 @@ public class SafariViewController: SFSafariViewController, FlutterPlugin, SFSafa
UIApplication.shared.delegate?.window??.makeKeyAndVisible()
self.onChromeSafariBrowserClosed()
self.dispose()
if result != nil {
result!(true)
}
})
}
public func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
close()
close(result: nil)
}
public func safariViewController(_ controller: SFSafariViewController,
......
......@@ -35,3 +35,4 @@ export 'src/webview_options.dart';
export 'src/content_blocker.dart';
export 'src/http_auth_credentials_database.dart';
export 'src/web_storage_manager.dart';
export 'src/context_menu.dart';
......@@ -61,6 +61,8 @@ class ChromeSafariBrowser {
///[headersFallback]: The additional header of the [InAppBrowser] instance fallback to be used in the HTTP request for this URL, specified as a map from name to value.
///
///[optionsFallback]: Options used by the [InAppBrowser] instance fallback.
///
///[contextMenuFallback]: Context Menu used by the [InAppBrowser] instance fallback.
Future<void> open(
{@required String url,
ChromeSafariBrowserClassOptions options,
......@@ -81,11 +83,12 @@ class ChromeSafariBrowser {
args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('url', () => url);
args.putIfAbsent('options', () => options?.toMap() ?? {});
args.putIfAbsent('menuItemList', () => menuItemList);
args.putIfAbsent('uuidFallback',
() => (browserFallback != null) ? browserFallback.uuid : '');
args.putIfAbsent('headersFallback', () => headersFallback);
args.putIfAbsent('optionsFallback', () => optionsFallback?.toMap() ?? {});
args.putIfAbsent('menuItemList', () => menuItemList);
args.putIfAbsent('contextMenuFallback', () => browserFallback?.contextMenu?.toMap() ?? {});
await _sharedChannel.invokeMethod('open', args);
this._isOpened = true;
}
......
import 'package:flutter/foundation.dart';
import 'package:flutter_inappwebview/src/webview.dart';
import 'types.dart';
///Class that represents the WebView context menu. It used by [WebView.contextMenu].
///
///**NOTE**: To make it work properly on Android, JavaScript should be enabled!
class ContextMenu {
///Event fired when the context menu for this WebView is being built.
///
///[hitTestResult] represents the hit result for hitting an HTML elements.
final void Function(InAppWebViewHitTestResult hitTestResult) onCreateContextMenu;
///Event fired when the context menu for this WebView is being hidden.
final void Function() onHideContextMenu;
///Event fired when a context menu item has been clicked.
///
///[contextMenuItemClicked] represents the [ContextMenuItem] clicked.
final void Function(ContextMenuItem contextMenuItemClicked) onContextMenuActionItemClicked;
///List of the custom [ContextMenuItem].
List<ContextMenuItem> menuItems = List();
ContextMenu({
this.menuItems,
this.onCreateContextMenu,
this.onHideContextMenu,
this.onContextMenuActionItemClicked
});
Map<String, dynamic> toMap() {
return {
"menuItems": menuItems.map((menuItem) => menuItem?.toMap()).toList()
};
}
Map<String, dynamic> toJson() {
return this.toMap();
}
}
///Class that represent an item of the [ContextMenu].
class ContextMenuItem {
///Android menu item ID.
int androidId;
///iOS menu item ID.
String iosId;
///Menu item title.
String title;
///Menu item action that will be called when an user clicks on it.
Function() action;
ContextMenuItem({@required this.androidId, @required this.iosId, @required this.title, this.action});
Map<String, dynamic> toMap() {
return {
"androidId": androidId,
"iosId": iosId,
"title": title
};
}
Map<String, dynamic> toJson() {
return this.toMap();
}
}
import 'package:flutter/services.dart';
import 'context_menu.dart';
import 'types.dart';
import 'webview.dart';
import 'in_app_webview_controller.dart';
......@@ -16,46 +17,48 @@ class HeadlessInAppWebView implements WebView {
///WebView Controller that can be used to access the [InAppWebViewController] API.
InAppWebViewController webViewController;
HeadlessInAppWebView(
{this.onWebViewCreated,
this.onLoadStart,
this.onLoadStop,
this.onLoadError,
this.onLoadHttpError,
this.onProgressChanged,
this.onConsoleMessage,
this.shouldOverrideUrlLoading,
this.onLoadResource,
this.onScrollChanged,
this.onDownloadStart,
this.onLoadResourceCustomScheme,
this.onCreateWindow,
this.onJsAlert,
this.onJsConfirm,
this.onJsPrompt,
this.onReceivedHttpAuthRequest,
this.onReceivedServerTrustAuthRequest,
this.onReceivedClientCertRequest,
this.onFindResultReceived,
this.shouldInterceptAjaxRequest,
this.onAjaxReadyStateChange,
this.onAjaxProgress,
this.shouldInterceptFetchRequest,
this.onUpdateVisitedHistory,
this.onPrint,
this.onLongPressHitTestResult,
this.androidOnSafeBrowsingHit,
this.androidOnPermissionRequest,
this.androidOnGeolocationPermissionsShowPrompt,
this.androidOnGeolocationPermissionsHidePrompt,
this.iosOnWebContentProcessDidTerminate,
this.iosOnDidCommit,
this.iosOnDidReceiveServerRedirectForProvisionalNavigation,
this.initialUrl,
this.initialFile,
this.initialData,
this.initialHeaders,
this.initialOptions}) {
HeadlessInAppWebView({
this.onWebViewCreated,
this.onLoadStart,
this.onLoadStop,
this.onLoadError,
this.onLoadHttpError,
this.onProgressChanged,
this.onConsoleMessage,
this.shouldOverrideUrlLoading,
this.onLoadResource,
this.onScrollChanged,
this.onDownloadStart,
this.onLoadResourceCustomScheme,
this.onCreateWindow,
this.onJsAlert,
this.onJsConfirm,
this.onJsPrompt,
this.onReceivedHttpAuthRequest,
this.onReceivedServerTrustAuthRequest,
this.onReceivedClientCertRequest,
this.onFindResultReceived,
this.shouldInterceptAjaxRequest,
this.onAjaxReadyStateChange,
this.onAjaxProgress,
this.shouldInterceptFetchRequest,
this.onUpdateVisitedHistory,
this.onPrint,
this.onLongPressHitTestResult,
this.androidOnSafeBrowsingHit,
this.androidOnPermissionRequest,
this.androidOnGeolocationPermissionsShowPrompt,
this.androidOnGeolocationPermissionsHidePrompt,
this.iosOnWebContentProcessDidTerminate,
this.iosOnDidCommit,
this.iosOnDidReceiveServerRedirectForProvisionalNavigation,
this.initialUrl,
this.initialFile,
this.initialData,
this.initialHeaders,
this.initialOptions,
this.contextMenu
}) {
uuid = uuidGenerator.v4();
webViewController = new InAppWebViewController(uuid, this);
}
......@@ -83,7 +86,8 @@ class HeadlessInAppWebView implements WebView {
'initialFile': this.initialFile,
'initialData': this.initialData?.toMap(),
'initialHeaders': this.initialHeaders,
'initialOptions': this.initialOptions?.toMap()
'initialOptions': this.initialOptions?.toMap(),
'contextMenu': this.contextMenu?.toMap() ?? {}
});
await _sharedChannel.invokeMethod('createHeadlessWebView', args);
}
......@@ -130,6 +134,9 @@ class HeadlessInAppWebView implements WebView {
@override
final InAppWebViewGroupOptions initialOptions;
@override
final ContextMenu contextMenu;
@override
final String initialUrl;
......@@ -210,7 +217,7 @@ class HeadlessInAppWebView implements WebView {
@override
final void Function(InAppWebViewController controller,
LongPressHitTestResult hitTestResult) onLongPressHitTestResult;
InAppWebViewHitTestResult hitTestResult) onLongPressHitTestResult;
@override
final void Function(InAppWebViewController controller, String url) onPrint;
......
......@@ -4,6 +4,7 @@ import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'context_menu.dart';
import 'in_app_webview_controller.dart';
import 'webview_options.dart';
......@@ -12,7 +13,12 @@ import 'types.dart';
///This class uses the native WebView of the platform.
///The [webViewController] field can be used to access the [InAppWebViewController] API.
class InAppBrowser {
///Browser's UUID
String uuid;
///Context menu used by the browser
ContextMenu contextMenu;
Map<String, JavaScriptHandlerCallback> javaScriptHandlersMap =
HashMap<String, JavaScriptHandlerCallback>();
bool _isOpened = false;
......@@ -67,6 +73,7 @@ class InAppBrowser {
args.putIfAbsent('url', () => url);
args.putIfAbsent('headers', () => headers);
args.putIfAbsent('options', () => options?.toMap() ?? {});
args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {});
await _sharedChannel.invokeMethod('openUrl', args);
}
......@@ -117,6 +124,7 @@ class InAppBrowser {
args.putIfAbsent('url', () => assetFilePath);
args.putIfAbsent('headers', () => headers);
args.putIfAbsent('options', () => options?.toMap() ?? {});
args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {});
await _sharedChannel.invokeMethod('openFile', args);
}
......@@ -146,6 +154,7 @@ class InAppBrowser {
args.putIfAbsent('encoding', () => encoding);
args.putIfAbsent('baseUrl', () => baseUrl);
args.putIfAbsent('historyUrl', () => androidHistoryUrl);
args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {});
await _sharedChannel.invokeMethod('openData', args);
}
......@@ -429,7 +438,7 @@ class InAppBrowser {
///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) {}
void onLongPressHitTestResult(InAppWebViewHitTestResult 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.
......
......@@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart';
import 'context_menu.dart';
import 'webview.dart';
import 'types.dart';
import 'in_app_webview_controller.dart';
......@@ -38,6 +39,7 @@ class InAppWebView extends StatefulWidget implements WebView {
this.initialData,
this.initialHeaders = const {},
@required this.initialOptions,
this.contextMenu,
this.onWebViewCreated,
this.onLoadStart,
this.onLoadStop,
......@@ -112,6 +114,9 @@ class InAppWebView extends StatefulWidget implements WebView {
@override
final String initialUrl;
@override
final ContextMenu contextMenu;
@override
final Future<void> Function(InAppWebViewController controller) iosOnDidCommit;
......@@ -189,7 +194,7 @@ class InAppWebView extends StatefulWidget implements WebView {
@override
final void Function(InAppWebViewController controller,
LongPressHitTestResult hitTestResult) onLongPressHitTestResult;
InAppWebViewHitTestResult hitTestResult) onLongPressHitTestResult;
@override
final void Function(InAppWebViewController controller, String url) onPrint;
......@@ -258,7 +263,8 @@ class _InAppWebViewState extends State<InAppWebView> {
'initialFile': widget.initialFile,
'initialData': widget.initialData?.toMap(),
'initialHeaders': widget.initialHeaders,
'initialOptions': widget.initialOptions?.toMap() ?? {}
'initialOptions': widget.initialOptions?.toMap() ?? {},
'contextMenu': widget.contextMenu?.toMap() ?? {}
},
creationParamsCodec: const StandardMessageCodec(),
);
......@@ -291,7 +297,8 @@ class _InAppWebViewState extends State<InAppWebView> {
'initialFile': widget.initialFile,
'initialData': widget.initialData?.toMap(),
'initialHeaders': widget.initialHeaders,
'initialOptions': widget.initialOptions?.toMap() ?? {}
'initialOptions': widget.initialOptions?.toMap() ?? {},
'contextMenu': widget.contextMenu?.toMap() ?? {}
},
creationParamsCodec: const StandardMessageCodec(),
);
......
......@@ -346,12 +346,12 @@ class InAppWebViewController {
_webview.iosOnWebContentProcessDidTerminate(this);
else if (_inAppBrowser != null)
_inAppBrowser.iosOnWebContentProcessDidTerminate();
return null;
break;
case "onDidCommit":
if (_webview != null && _webview.iosOnDidCommit != null)
_webview.iosOnDidCommit(this);
else if (_inAppBrowser != null) _inAppBrowser.iosOnDidCommit();
return null;
break;
case "onDidReceiveServerRedirectForProvisionalNavigation":
if (_webview != null &&
_webview.iosOnDidReceiveServerRedirectForProvisionalNavigation !=
......@@ -359,21 +359,80 @@ class InAppWebViewController {
_webview.iosOnDidReceiveServerRedirectForProvisionalNavigation(this);
else if (_inAppBrowser != null)
_inAppBrowser.iosOnDidReceiveServerRedirectForProvisionalNavigation();
return null;
break;
case "onLongPressHitTestResult":
Map<dynamic, dynamic> hitTestResultMap =
call.arguments["hitTestResult"];
LongPressHitTestResultType type = LongPressHitTestResultType.fromValue(
InAppWebViewHitTestResultType type = InAppWebViewHitTestResultType.fromValue(
hitTestResultMap["type"].toInt());
String extra = hitTestResultMap["extra"];
LongPressHitTestResult hitTestResult =
new LongPressHitTestResult(type: type, extra: extra);
InAppWebViewHitTestResult hitTestResult = InAppWebViewHitTestResult(type: type, extra: extra);
if (_webview != null && _webview.onLongPressHitTestResult != null)
_webview.onLongPressHitTestResult(this, hitTestResult);
else if (_inAppBrowser != null)
_inAppBrowser.onLongPressHitTestResult(hitTestResult);
break;
case "onCreateContextMenu":
ContextMenu contextMenu;
if (_webview != null && _webview.contextMenu != null) {
contextMenu = _webview.contextMenu;
} else if (_inAppBrowser != null && _inAppBrowser.contextMenu != null) {
contextMenu = _inAppBrowser.contextMenu;
}
if (contextMenu != null && contextMenu.onCreateContextMenu != null) {
Map<dynamic, dynamic> hitTestResultMap =
call.arguments["hitTestResult"];
InAppWebViewHitTestResultType type = InAppWebViewHitTestResultType.fromValue(
hitTestResultMap["type"].toInt());
String extra = hitTestResultMap["extra"];
InAppWebViewHitTestResult hitTestResult = InAppWebViewHitTestResult(type: type, extra: extra);
contextMenu.onCreateContextMenu(hitTestResult);
}
break;
case "onHideContextMenu":
ContextMenu contextMenu;
if (_webview != null && _webview.contextMenu != null) {
contextMenu = _webview.contextMenu;
} else if (_inAppBrowser != null && _inAppBrowser.contextMenu != null) {
contextMenu = _inAppBrowser.contextMenu;
}
if (contextMenu != null && contextMenu.onHideContextMenu != null) {
contextMenu.onHideContextMenu();
}
break;
case "onContextMenuActionItemClicked":
ContextMenu contextMenu;
if (_webview != null && _webview.contextMenu != null) {
contextMenu = _webview.contextMenu;
} else if (_inAppBrowser != null && _inAppBrowser.contextMenu != null) {
contextMenu = _inAppBrowser.contextMenu;
}
if (contextMenu != null) {
int androidId = call.arguments["androidId"];
String iosId = call.arguments["iosId"];
String title = call.arguments["title"];
ContextMenuItem menuItemClicked = ContextMenuItem(androidId: androidId, iosId: iosId, title: title, action: null);
for (var menuItem in contextMenu.menuItems) {
if ((Platform.isAndroid && menuItem.androidId == androidId) ||
(Platform.isIOS && menuItem.iosId == iosId)) {
menuItemClicked = menuItem;
menuItem?.action();
break;
}
}
if (contextMenu.onContextMenuActionItemClicked != null) {
contextMenu.onContextMenuActionItemClicked(menuItemClicked);
}
}
break;
case "onCallJsHandler":
String handlerName = call.arguments["handlerName"];
// decode args to json
......@@ -1198,7 +1257,7 @@ class InAppWebViewController {
return await _channel.invokeMethod('getContentHeight', args);
}
///Gets the height of the HTML content.
///Performs a zoom operation in this WebView.
///
///[zoomFactor] represents the zoom factor to apply. On Android, the zoom factor will be clamped to the Webview's zoom limits and, also, this value must be in the range 0.01 to 100.0 inclusive.
///
......@@ -1215,6 +1274,27 @@ class InAppWebViewController {
return await _channel.invokeMethod('getScale', args);
}
///Gets the selected text.
///
///**NOTE**: This method is implemented with using JavaScript.
///Available only on Android 19+.
Future<String> getSelectedText() async {
Map<String, dynamic> args = <String, dynamic>{};
return await _channel.invokeMethod('getSelectedText', args);
}
///Gets the hit result for hitting an HTML elements.
///
///**NOTE**: On iOS it is implemented using JavaScript.
Future<InAppWebViewHitTestResult> getHitTestResult() async {
Map<String, dynamic> args = <String, dynamic>{};
var hitTestResultMap = await _channel.invokeMethod('getHitTestResult', args);
InAppWebViewHitTestResultType type = InAppWebViewHitTestResultType.fromValue(
hitTestResultMap["type"].toInt());
String extra = hitTestResultMap["extra"];
return InAppWebViewHitTestResult(type: type, extra: extra);
}
///Gets the default user agent.
static Future<String> getDefaultUserAgent() async {
Map<String, dynamic> args = <String, dynamic>{};
......
......@@ -2297,13 +2297,13 @@ class IOSWKWebsiteDataRecord {
}
}
///Class representing the [LongPressHitTestResult] type.
class LongPressHitTestResultType {
///Class representing the [InAppWebViewHitTestResult] type.
class InAppWebViewHitTestResultType {
final int _value;
const LongPressHitTestResultType._internal(this._value);
static LongPressHitTestResultType fromValue(int value) {
const InAppWebViewHitTestResultType._internal(this._value);
static InAppWebViewHitTestResultType fromValue(int value) {
if (value != null && [0, 2, 3, 4, 5, 7, 8, 9].contains(value))
return LongPressHitTestResultType._internal(value);
return InAppWebViewHitTestResultType._internal(value);
return null;
}
......@@ -2331,22 +2331,22 @@ class LongPressHitTestResultType {
}
}
///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);
///Default [InAppWebViewHitTestResult], where the target is unknown.
static const UNKNOWN_TYPE = const InAppWebViewHitTestResultType._internal(0);
///[InAppWebViewHitTestResult] for hitting a phone number.
static const PHONE_TYPE = const InAppWebViewHitTestResultType._internal(2);
///[InAppWebViewHitTestResult] for hitting a map address.
static const GEO_TYPE = const InAppWebViewHitTestResultType._internal(3);
///[InAppWebViewHitTestResult] for hitting an email address.
static const EMAIL_TYPE = const InAppWebViewHitTestResultType._internal(4);
///[InAppWebViewHitTestResult] for hitting an HTML::img tag.
static const IMAGE_TYPE = const InAppWebViewHitTestResultType._internal(5);
///[InAppWebViewHitTestResult] for hitting a HTML::a tag with src=http.
static const SRC_ANCHOR_TYPE = const InAppWebViewHitTestResultType._internal(7);
///[InAppWebViewHitTestResult] for hitting a HTML::a tag with src=http + HTML::img.
static const SRC_IMAGE_ANCHOR_TYPE = const InAppWebViewHitTestResultType._internal(8);
///[InAppWebViewHitTestResult] for hitting an edit text area.
static const EDIT_TEXT_TYPE = const InAppWebViewHitTestResultType._internal(9);
bool operator ==(value) => value == _value;
......@@ -2354,12 +2354,12 @@ class LongPressHitTestResultType {
int get hashCode => _value.hashCode;
}
///Class that represents the hit result for hitting an HTML elements. Used by [onLongPressHitTestResult] event.
class LongPressHitTestResult {
///Class that represents the hit result for hitting an HTML elements.
class InAppWebViewHitTestResult {
///The type of the hit test result.
LongPressHitTestResultType type;
InAppWebViewHitTestResultType type;
///Additional type-dependant information about the result.
String extra;
LongPressHitTestResult({this.type, this.extra});
InAppWebViewHitTestResult({this.type, this.extra});
}
import 'package:flutter_inappwebview/src/context_menu.dart';
import 'types.dart';
import 'in_app_webview_controller.dart';
......@@ -233,7 +235,7 @@ abstract class WebView {
///
///[hitTestResult] represents the hit result for hitting an HTML elements.
final void Function(InAppWebViewController controller,
LongPressHitTestResult hitTestResult) onLongPressHitTestResult;
InAppWebViewHitTestResult 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.
......@@ -308,44 +310,49 @@ abstract class WebView {
///Initial options that will be used.
final InAppWebViewGroupOptions initialOptions;
WebView(
{this.onWebViewCreated,
this.onLoadStart,
this.onLoadStop,
this.onLoadError,
this.onLoadHttpError,
this.onProgressChanged,
this.onConsoleMessage,
this.shouldOverrideUrlLoading,
this.onLoadResource,
this.onScrollChanged,
this.onDownloadStart,
this.onLoadResourceCustomScheme,
this.onCreateWindow,
this.onJsAlert,
this.onJsConfirm,
this.onJsPrompt,
this.onReceivedHttpAuthRequest,
this.onReceivedServerTrustAuthRequest,
this.onReceivedClientCertRequest,
this.onFindResultReceived,
this.shouldInterceptAjaxRequest,
this.onAjaxReadyStateChange,
this.onAjaxProgress,
this.shouldInterceptFetchRequest,
this.onUpdateVisitedHistory,
this.onPrint,
this.onLongPressHitTestResult,
this.androidOnSafeBrowsingHit,
this.androidOnPermissionRequest,
this.androidOnGeolocationPermissionsShowPrompt,
this.androidOnGeolocationPermissionsHidePrompt,
this.iosOnWebContentProcessDidTerminate,
this.iosOnDidCommit,
this.iosOnDidReceiveServerRedirectForProvisionalNavigation,
this.initialUrl,
this.initialFile,
this.initialData,
this.initialHeaders,
this.initialOptions});
///Context menu which contains custom menu items to be shown when [ContextMenu] is presented.
final ContextMenu contextMenu;
WebView({
this.onWebViewCreated,
this.onLoadStart,
this.onLoadStop,
this.onLoadError,
this.onLoadHttpError,
this.onProgressChanged,
this.onConsoleMessage,
this.shouldOverrideUrlLoading,
this.onLoadResource,
this.onScrollChanged,
this.onDownloadStart,
this.onLoadResourceCustomScheme,
this.onCreateWindow,
this.onJsAlert,
this.onJsConfirm,
this.onJsPrompt,
this.onReceivedHttpAuthRequest,
this.onReceivedServerTrustAuthRequest,
this.onReceivedClientCertRequest,
this.onFindResultReceived,
this.shouldInterceptAjaxRequest,
this.onAjaxReadyStateChange,
this.onAjaxProgress,
this.shouldInterceptFetchRequest,
this.onUpdateVisitedHistory,
this.onPrint,
this.onLongPressHitTestResult,
this.androidOnSafeBrowsingHit,
this.androidOnPermissionRequest,
this.androidOnGeolocationPermissionsShowPrompt,
this.androidOnGeolocationPermissionsHidePrompt,
this.iosOnWebContentProcessDidTerminate,
this.iosOnDidCommit,
this.iosOnDidReceiveServerRedirectForProvisionalNavigation,
this.initialUrl,
this.initialFile,
this.initialData,
this.initialHeaders,
this.initialOptions,
this.contextMenu
});
}
\ No newline at end of file
......@@ -128,6 +128,9 @@ class InAppWebViewOptions
///Set to `true` to disable horizontal scroll. The default value is `false`.
bool disableHorizontalScroll;
///Set to `true` to disable context menu. The default value is `false`.
bool disableContextMenu;
InAppWebViewOptions(
{this.useShouldOverrideUrlLoading = false,
this.useOnLoadResource = false,
......@@ -152,7 +155,8 @@ class InAppWebViewOptions
this.cacheEnabled = true,
this.transparentBackground = false,
this.disableVerticalScroll = false,
this.disableHorizontalScroll = false}) {
this.disableHorizontalScroll = false,
this.disableContextMenu = false}) {
if (this.minimumFontSize == null)
this.minimumFontSize = Platform.isAndroid ? 8 : 0;
assert(!this.resourceCustomSchemes.contains("http") &&
......@@ -189,7 +193,8 @@ class InAppWebViewOptions
"cacheEnabled": cacheEnabled,
"transparentBackground": transparentBackground,
"disableVerticalScroll": disableVerticalScroll,
"disableHorizontalScroll": disableHorizontalScroll
"disableHorizontalScroll": disableHorizontalScroll,
"disableContextMenu": disableContextMenu
};
}
......@@ -234,6 +239,7 @@ class InAppWebViewOptions
options.transparentBackground = map["transparentBackground"];
options.disableVerticalScroll = map["disableVerticalScroll"];
options.disableHorizontalScroll = map["disableHorizontalScroll"];
options.disableContextMenu = map["disableContextMenu"];
return options;
}
}
......
name: flutter_inappwebview
description: A Flutter plugin that allows you to add an inline webview or open an in-app browser window.
version: 3.1.0
version: 3.2.0
homepage: https://github.com/pichillilorenzo/flutter_inappwebview
environment:
......
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