added Find Interaction Controller
This commit is contained in:
parent
06ef336c28
commit
f5a048cb69
|
@ -5,8 +5,9 @@
|
||||||
- Added `ProxyController` for Android
|
- Added `ProxyController` for Android
|
||||||
- Added `PrintJobController` to manage print jobs
|
- Added `PrintJobController` to manage print jobs
|
||||||
- Added `WebAuthenticationSession` for iOS
|
- Added `WebAuthenticationSession` for iOS
|
||||||
|
- Added `FindInteractionController` for Android and iOS
|
||||||
- Added `pauseAllMediaPlayback`, `setAllMediaPlaybackSuspended`, `closeAllMediaPresentations`, `requestMediaPlaybackState`, `isInFullscreen`, `getCameraCaptureState`, `setCameraCaptureState`, `getMicrophoneCaptureState`, `setMicrophoneCaptureState` WebView controller methods
|
- Added `pauseAllMediaPlayback`, `setAllMediaPlaybackSuspended`, `closeAllMediaPresentations`, `requestMediaPlaybackState`, `isInFullscreen`, `getCameraCaptureState`, `setCameraCaptureState`, `getMicrophoneCaptureState`, `setMicrophoneCaptureState` WebView controller methods
|
||||||
- Added `underPageBackgroundColor`, `isTextInteractionEnabled`, `isSiteSpecificQuirksModeEnabled`, `upgradeKnownHostsToHTTPS`, `forceDarkStrategy`, `willSuppressErrorPage`, `algorithmicDarkeningAllowed`, `requestedWithHeaderMode`, `enterpriseAuthenticationAppLinkPolicyEnabled` WebView settings
|
- Added `underPageBackgroundColor`, `isTextInteractionEnabled`, `isSiteSpecificQuirksModeEnabled`, `upgradeKnownHostsToHTTPS`, `forceDarkStrategy`, `willSuppressErrorPage`, `algorithmicDarkeningAllowed`, `requestedWithHeaderMode`, `enterpriseAuthenticationAppLinkPolicyEnabled`, `isElementFullscreenEnabled`, `isFindInteractionEnabled` WebView settings
|
||||||
- Added `onCameraCaptureStateChanged`, `onMicrophoneCaptureStateChanged` WebView events
|
- Added `onCameraCaptureStateChanged`, `onMicrophoneCaptureStateChanged` WebView events
|
||||||
- Added support for `onPermissionRequest` event on iOS 15.0+
|
- Added support for `onPermissionRequest` event on iOS 15.0+
|
||||||
- Added `debugLoggingSettings` static property for WebView and ChromeSafariBrowser
|
- Added `debugLoggingSettings` static property for WebView and ChromeSafariBrowser
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package com.pichillilorenzo.flutter_inappwebview.find_interaction;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.flutter.plugin.common.MethodCall;
|
||||||
|
import io.flutter.plugin.common.MethodChannel;
|
||||||
|
|
||||||
|
public class FindInteractionChannelDelegate extends ChannelDelegateImpl {
|
||||||
|
@Nullable
|
||||||
|
private FindInteractionController findInteractionController;
|
||||||
|
|
||||||
|
public FindInteractionChannelDelegate(@NonNull FindInteractionController findInteractionController, @NonNull MethodChannel channel) {
|
||||||
|
super(channel);
|
||||||
|
this.findInteractionController = findInteractionController;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) {
|
||||||
|
switch (call.method) {
|
||||||
|
case "findAllAsync":
|
||||||
|
if (findInteractionController != null && findInteractionController.webView != null) {
|
||||||
|
String find = (String) call.argument("find");
|
||||||
|
findInteractionController.webView.findAllAsync(find);
|
||||||
|
}
|
||||||
|
result.success(true);
|
||||||
|
break;
|
||||||
|
case "findNext":
|
||||||
|
if (findInteractionController != null && findInteractionController.webView != null) {
|
||||||
|
Boolean forward = (Boolean) call.argument("forward");
|
||||||
|
findInteractionController.webView.findNext(forward);
|
||||||
|
}
|
||||||
|
result.success(true);
|
||||||
|
break;
|
||||||
|
case "clearMatches":
|
||||||
|
if (findInteractionController != null && findInteractionController.webView != null) {
|
||||||
|
findInteractionController.webView.clearMatches();
|
||||||
|
}
|
||||||
|
result.success(true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result.notImplemented();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) {
|
||||||
|
MethodChannel channel = getChannel();
|
||||||
|
if (channel == null) return;
|
||||||
|
Map<String, Object> obj = new HashMap<>();
|
||||||
|
obj.put("activeMatchOrdinal", activeMatchOrdinal);
|
||||||
|
obj.put("numberOfMatches", numberOfMatches);
|
||||||
|
obj.put("isDoneCounting", isDoneCounting);
|
||||||
|
channel.invokeMethod("onFindResultReceived", obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
findInteractionController = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.pichillilorenzo.flutter_inappwebview.find_interaction;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
|
||||||
|
|
||||||
|
import io.flutter.plugin.common.MethodChannel;
|
||||||
|
|
||||||
|
public class FindInteractionController implements Disposable {
|
||||||
|
static final String LOG_TAG = "FindInteractionController";
|
||||||
|
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_find_interaction_";
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public InAppWebViewInterface webView;
|
||||||
|
@Nullable
|
||||||
|
public FindInteractionChannelDelegate channelDelegate;
|
||||||
|
@Nullable
|
||||||
|
public FindInteractionSettings settings;
|
||||||
|
|
||||||
|
public FindInteractionController(@NonNull InAppWebViewInterface webView, @NonNull InAppWebViewFlutterPlugin plugin,
|
||||||
|
@NonNull Object id, @Nullable FindInteractionSettings settings) {
|
||||||
|
this.webView = webView;
|
||||||
|
this.settings = settings;
|
||||||
|
final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
|
||||||
|
this.channelDelegate = new FindInteractionChannelDelegate(this, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prepare() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
if (channelDelegate != null) {
|
||||||
|
channelDelegate.dispose();
|
||||||
|
channelDelegate = null;
|
||||||
|
}
|
||||||
|
webView = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.pichillilorenzo.flutter_inappwebview.find_interaction;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.ISettings;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class FindInteractionSettings implements ISettings<FindInteractionController> {
|
||||||
|
public static final String LOG_TAG = "FindInteractionSettings";
|
||||||
|
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public FindInteractionSettings parse(@NonNull Map<String, Object> settings) {
|
||||||
|
// for (Map.Entry<String, Object> pair : settings.entrySet()) {
|
||||||
|
// String key = pair.getKey();
|
||||||
|
// Object value = pair.getValue();
|
||||||
|
// if (value == null) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// switch (key) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Map<String, Object> toMap() {
|
||||||
|
Map<String, Object> settings = new HashMap<>();
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getRealSettings(@NonNull FindInteractionController findInteractionController) {
|
||||||
|
Map<String, Object> realSettings = toMap();
|
||||||
|
return realSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.find_interaction.FindInteractionController;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.R;
|
import com.pichillilorenzo.flutter_inappwebview.R;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||||
|
@ -109,6 +110,10 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
|
||||||
webView.inAppBrowserDelegate = this;
|
webView.inAppBrowserDelegate = this;
|
||||||
webView.plugin = manager.plugin;
|
webView.plugin = manager.plugin;
|
||||||
|
|
||||||
|
FindInteractionController findInteractionController = new FindInteractionController(webView, manager.plugin, id, null);
|
||||||
|
webView.findInteractionController = findInteractionController;
|
||||||
|
findInteractionController.prepare();
|
||||||
|
|
||||||
final MethodChannel channel = new MethodChannel(manager.plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
|
final MethodChannel channel = new MethodChannel(manager.plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
|
||||||
channelDelegate = new InAppBrowserChannelDelegate(channel);
|
channelDelegate = new InAppBrowserChannelDelegate(channel);
|
||||||
webView.channelDelegate = new WebViewChannelDelegate(webView, channel);
|
webView.channelDelegate = new WebViewChannelDelegate(webView, channel);
|
||||||
|
|
|
@ -13,6 +13,7 @@ import androidx.webkit.WebViewCompat;
|
||||||
import androidx.webkit.WebViewFeature;
|
import androidx.webkit.WebViewFeature;
|
||||||
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.Util;
|
import com.pichillilorenzo.flutter_inappwebview.Util;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.find_interaction.FindInteractionChannelDelegate;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserActivity;
|
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserActivity;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserSettings;
|
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserSettings;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobSettings;
|
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobSettings;
|
||||||
|
@ -73,24 +74,31 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) {
|
public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) {
|
||||||
switch (call.method) {
|
WebViewChannelDelegateMethods method = null;
|
||||||
case "getUrl":
|
try {
|
||||||
|
method = WebViewChannelDelegateMethods.valueOf(call.method);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
result.notImplemented();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (method) {
|
||||||
|
case getUrl:
|
||||||
result.success((webView != null) ? webView.getUrl() : null);
|
result.success((webView != null) ? webView.getUrl() : null);
|
||||||
break;
|
break;
|
||||||
case "getTitle":
|
case getTitle:
|
||||||
result.success((webView != null) ? webView.getTitle() : null);
|
result.success((webView != null) ? webView.getTitle() : null);
|
||||||
break;
|
break;
|
||||||
case "getProgress":
|
case getProgress:
|
||||||
result.success((webView != null) ? webView.getProgress() : null);
|
result.success((webView != null) ? webView.getProgress() : null);
|
||||||
break;
|
break;
|
||||||
case "loadUrl":
|
case loadUrl:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
Map<String, Object> urlRequest = (Map<String, Object>) call.argument("urlRequest");
|
Map<String, Object> urlRequest = (Map<String, Object>) call.argument("urlRequest");
|
||||||
webView.loadUrl(URLRequest.fromMap(urlRequest));
|
webView.loadUrl(URLRequest.fromMap(urlRequest));
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "postUrl":
|
case postUrl:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
String url = (String) call.argument("url");
|
String url = (String) call.argument("url");
|
||||||
byte[] postData = (byte[]) call.argument("postData");
|
byte[] postData = (byte[]) call.argument("postData");
|
||||||
|
@ -98,7 +106,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "loadData":
|
case loadData:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
String data = (String) call.argument("data");
|
String data = (String) call.argument("data");
|
||||||
String mimeType = (String) call.argument("mimeType");
|
String mimeType = (String) call.argument("mimeType");
|
||||||
|
@ -109,7 +117,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "loadFile":
|
case loadFile:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
String assetFilePath = (String) call.argument("assetFilePath");
|
String assetFilePath = (String) call.argument("assetFilePath");
|
||||||
try {
|
try {
|
||||||
|
@ -122,7 +130,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "evaluateJavascript":
|
case evaluateJavascript:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
String source = (String) call.argument("source");
|
String source = (String) call.argument("source");
|
||||||
Map<String, Object> contentWorldMap = (Map<String, Object>) call.argument("contentWorld");
|
Map<String, Object> contentWorldMap = (Map<String, Object>) call.argument("contentWorld");
|
||||||
|
@ -138,7 +146,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "injectJavascriptFileFromUrl":
|
case injectJavascriptFileFromUrl:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
String urlFile = (String) call.argument("urlFile");
|
String urlFile = (String) call.argument("urlFile");
|
||||||
Map<String, Object> scriptHtmlTagAttributes = (Map<String, Object>) call.argument("scriptHtmlTagAttributes");
|
Map<String, Object> scriptHtmlTagAttributes = (Map<String, Object>) call.argument("scriptHtmlTagAttributes");
|
||||||
|
@ -146,14 +154,14 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "injectCSSCode":
|
case injectCSSCode:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
String source = (String) call.argument("source");
|
String source = (String) call.argument("source");
|
||||||
webView.injectCSSCode(source);
|
webView.injectCSSCode(source);
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "injectCSSFileFromUrl":
|
case injectCSSFileFromUrl:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
String urlFile = (String) call.argument("urlFile");
|
String urlFile = (String) call.argument("urlFile");
|
||||||
Map<String, Object> cssLinkHtmlTagAttributes = (Map<String, Object>) call.argument("cssLinkHtmlTagAttributes");
|
Map<String, Object> cssLinkHtmlTagAttributes = (Map<String, Object>) call.argument("cssLinkHtmlTagAttributes");
|
||||||
|
@ -161,44 +169,44 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "reload":
|
case reload:
|
||||||
if (webView != null)
|
if (webView != null)
|
||||||
webView.reload();
|
webView.reload();
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "goBack":
|
case goBack:
|
||||||
if (webView != null)
|
if (webView != null)
|
||||||
webView.goBack();
|
webView.goBack();
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "canGoBack":
|
case canGoBack:
|
||||||
result.success((webView != null) && webView.canGoBack());
|
result.success((webView != null) && webView.canGoBack());
|
||||||
break;
|
break;
|
||||||
case "goForward":
|
case goForward:
|
||||||
if (webView != null)
|
if (webView != null)
|
||||||
webView.goForward();
|
webView.goForward();
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "canGoForward":
|
case canGoForward:
|
||||||
result.success((webView != null) && webView.canGoForward());
|
result.success((webView != null) && webView.canGoForward());
|
||||||
break;
|
break;
|
||||||
case "goBackOrForward":
|
case goBackOrForward:
|
||||||
if (webView != null)
|
if (webView != null)
|
||||||
webView.goBackOrForward((Integer) call.argument("steps"));
|
webView.goBackOrForward((Integer) call.argument("steps"));
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "canGoBackOrForward":
|
case canGoBackOrForward:
|
||||||
result.success((webView != null) && webView.canGoBackOrForward((Integer) call.argument("steps")));
|
result.success((webView != null) && webView.canGoBackOrForward((Integer) call.argument("steps")));
|
||||||
break;
|
break;
|
||||||
case "stopLoading":
|
case stopLoading:
|
||||||
if (webView != null)
|
if (webView != null)
|
||||||
webView.stopLoading();
|
webView.stopLoading();
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "isLoading":
|
case isLoading:
|
||||||
result.success((webView != null) && webView.isLoading());
|
result.success((webView != null) && webView.isLoading());
|
||||||
break;
|
break;
|
||||||
case "takeScreenshot":
|
case takeScreenshot:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
Map<String, Object> screenshotConfiguration = (Map<String, Object>) call.argument("screenshotConfiguration");
|
Map<String, Object> screenshotConfiguration = (Map<String, Object>) call.argument("screenshotConfiguration");
|
||||||
webView.takeScreenshot(screenshotConfiguration, result);
|
webView.takeScreenshot(screenshotConfiguration, result);
|
||||||
|
@ -206,7 +214,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
else
|
else
|
||||||
result.success(null);
|
result.success(null);
|
||||||
break;
|
break;
|
||||||
case "setSettings":
|
case setSettings:
|
||||||
if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
|
if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
|
||||||
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
|
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
|
||||||
InAppBrowserSettings inAppBrowserSettings = new InAppBrowserSettings();
|
InAppBrowserSettings inAppBrowserSettings = new InAppBrowserSettings();
|
||||||
|
@ -221,7 +229,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "getSettings":
|
case getSettings:
|
||||||
if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
|
if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
|
||||||
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
|
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
|
||||||
result.success(inAppBrowserActivity.getCustomSettings());
|
result.success(inAppBrowserActivity.getCustomSettings());
|
||||||
|
@ -229,7 +237,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success((webView != null) ? webView.getCustomSettings() : null);
|
result.success((webView != null) ? webView.getCustomSettings() : null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "close":
|
case close:
|
||||||
if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
|
if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
|
||||||
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
|
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
|
||||||
inAppBrowserActivity.close(result);
|
inAppBrowserActivity.close(result);
|
||||||
|
@ -237,7 +245,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.notImplemented();
|
result.notImplemented();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "show":
|
case show:
|
||||||
if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
|
if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
|
||||||
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
|
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
|
||||||
inAppBrowserActivity.show();
|
inAppBrowserActivity.show();
|
||||||
|
@ -246,7 +254,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.notImplemented();
|
result.notImplemented();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "hide":
|
case hide:
|
||||||
if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
|
if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
|
||||||
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
|
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
|
||||||
inAppBrowserActivity.hide();
|
inAppBrowserActivity.hide();
|
||||||
|
@ -255,10 +263,10 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.notImplemented();
|
result.notImplemented();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "getCopyBackForwardList":
|
case getCopyBackForwardList:
|
||||||
result.success((webView != null) ? webView.getCopyBackForwardList() : null);
|
result.success((webView != null) ? webView.getCopyBackForwardList() : null);
|
||||||
break;
|
break;
|
||||||
case "startSafeBrowsing":
|
case startSafeBrowsing:
|
||||||
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) {
|
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) {
|
||||||
WebViewCompat.startSafeBrowsing(webView.getContext(), new ValueCallback<Boolean>() {
|
WebViewCompat.startSafeBrowsing(webView.getContext(), new ValueCallback<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -271,37 +279,37 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "clearCache":
|
case clearCache:
|
||||||
if (webView != null)
|
if (webView != null)
|
||||||
webView.clearAllCache();
|
webView.clearAllCache();
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "clearSslPreferences":
|
case clearSslPreferences:
|
||||||
if (webView != null)
|
if (webView != null)
|
||||||
webView.clearSslPreferences();
|
webView.clearSslPreferences();
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "findAllAsync":
|
case findAllAsync:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
String find = (String) call.argument("find");
|
String find = (String) call.argument("find");
|
||||||
webView.findAllAsync(find);
|
webView.findAllAsync(find);
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "findNext":
|
case findNext:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
Boolean forward = (Boolean) call.argument("forward");
|
Boolean forward = (Boolean) call.argument("forward");
|
||||||
webView.findNext(forward);
|
webView.findNext(forward);
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "clearMatches":
|
case clearMatches:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
webView.clearMatches();
|
webView.clearMatches();
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "scrollTo":
|
case scrollTo:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
Integer x = (Integer) call.argument("x");
|
Integer x = (Integer) call.argument("x");
|
||||||
Integer y = (Integer) call.argument("y");
|
Integer y = (Integer) call.argument("y");
|
||||||
|
@ -310,7 +318,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "scrollBy":
|
case scrollBy:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
Integer x = (Integer) call.argument("x");
|
Integer x = (Integer) call.argument("x");
|
||||||
Integer y = (Integer) call.argument("y");
|
Integer y = (Integer) call.argument("y");
|
||||||
|
@ -319,31 +327,31 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "pause":
|
case pause:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
webView.onPause();
|
webView.onPause();
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "resume":
|
case resume:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
webView.onResume();
|
webView.onResume();
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "pauseTimers":
|
case pauseTimers:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
webView.pauseTimers();
|
webView.pauseTimers();
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "resumeTimers":
|
case resumeTimers:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
webView.resumeTimers();
|
webView.resumeTimers();
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "printCurrentPage":
|
case printCurrentPage:
|
||||||
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
PrintJobSettings settings = new PrintJobSettings();
|
PrintJobSettings settings = new PrintJobSettings();
|
||||||
Map<String, Object> settingsMap = (Map<String, Object>) call.argument("settings");
|
Map<String, Object> settingsMap = (Map<String, Object>) call.argument("settings");
|
||||||
|
@ -355,31 +363,31 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "getContentHeight":
|
case getContentHeight:
|
||||||
if (webView instanceof InAppWebView) {
|
if (webView instanceof InAppWebView) {
|
||||||
result.success(webView.getContentHeight());
|
result.success(webView.getContentHeight());
|
||||||
} else {
|
} else {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "zoomBy":
|
case zoomBy:
|
||||||
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
double zoomFactor = (double) call.argument("zoomFactor");
|
double zoomFactor = (double) call.argument("zoomFactor");
|
||||||
webView.zoomBy((float) zoomFactor);
|
webView.zoomBy((float) zoomFactor);
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "getOriginalUrl":
|
case getOriginalUrl:
|
||||||
result.success((webView != null) ? webView.getOriginalUrl() : null);
|
result.success((webView != null) ? webView.getOriginalUrl() : null);
|
||||||
break;
|
break;
|
||||||
case "getZoomScale":
|
case getZoomScale:
|
||||||
if (webView instanceof InAppWebView) {
|
if (webView instanceof InAppWebView) {
|
||||||
result.success(webView.getZoomScale());
|
result.success(webView.getZoomScale());
|
||||||
} else {
|
} else {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "getSelectedText":
|
case getSelectedText:
|
||||||
if ((webView instanceof InAppWebView && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)) {
|
if ((webView instanceof InAppWebView && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)) {
|
||||||
webView.getSelectedText(new ValueCallback<String>() {
|
webView.getSelectedText(new ValueCallback<String>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -391,14 +399,14 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "getHitTestResult":
|
case getHitTestResult:
|
||||||
if (webView instanceof InAppWebView) {
|
if (webView instanceof InAppWebView) {
|
||||||
result.success(HitTestResult.fromWebViewHitTestResult(webView.getHitTestResult()).toMap());
|
result.success(HitTestResult.fromWebViewHitTestResult(webView.getHitTestResult()).toMap());
|
||||||
} else {
|
} else {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "pageDown":
|
case pageDown:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
boolean bottom = (boolean) call.argument("bottom");
|
boolean bottom = (boolean) call.argument("bottom");
|
||||||
result.success(webView.pageDown(bottom));
|
result.success(webView.pageDown(bottom));
|
||||||
|
@ -406,7 +414,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "pageUp":
|
case pageUp:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
boolean top = (boolean) call.argument("top");
|
boolean top = (boolean) call.argument("top");
|
||||||
result.success(webView.pageUp(top));
|
result.success(webView.pageUp(top));
|
||||||
|
@ -414,7 +422,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "saveWebArchive":
|
case saveWebArchive:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
String filePath = (String) call.argument("filePath");
|
String filePath = (String) call.argument("filePath");
|
||||||
boolean autoname = (boolean) call.argument("autoname");
|
boolean autoname = (boolean) call.argument("autoname");
|
||||||
|
@ -428,75 +436,75 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "zoomIn":
|
case zoomIn:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
result.success(webView.zoomIn());
|
result.success(webView.zoomIn());
|
||||||
} else {
|
} else {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "zoomOut":
|
case zoomOut:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
result.success(webView.zoomOut());
|
result.success(webView.zoomOut());
|
||||||
} else {
|
} else {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "clearFocus":
|
case clearFocus:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
webView.clearFocus();
|
webView.clearFocus();
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "setContextMenu":
|
case setContextMenu:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
Map<String, Object> contextMenu = (Map<String, Object>) call.argument("contextMenu");
|
Map<String, Object> contextMenu = (Map<String, Object>) call.argument("contextMenu");
|
||||||
webView.setContextMenu(contextMenu);
|
webView.setContextMenu(contextMenu);
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "requestFocusNodeHref":
|
case requestFocusNodeHref:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
result.success(webView.requestFocusNodeHref());
|
result.success(webView.requestFocusNodeHref());
|
||||||
} else {
|
} else {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "requestImageRef":
|
case requestImageRef:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
result.success(webView.requestImageRef());
|
result.success(webView.requestImageRef());
|
||||||
} else {
|
} else {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "getScrollX":
|
case getScrollX:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
result.success(webView.getScrollX());
|
result.success(webView.getScrollX());
|
||||||
} else {
|
} else {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "getScrollY":
|
case getScrollY:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
result.success(webView.getScrollY());
|
result.success(webView.getScrollY());
|
||||||
} else {
|
} else {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "getCertificate":
|
case getCertificate:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
result.success(SslCertificateExt.toMap(webView.getCertificate()));
|
result.success(SslCertificateExt.toMap(webView.getCertificate()));
|
||||||
} else {
|
} else {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "clearHistory":
|
case clearHistory:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
webView.clearHistory();
|
webView.clearHistory();
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "addUserScript":
|
case addUserScript:
|
||||||
if (webView != null && webView.getUserContentController() != null) {
|
if (webView != null && webView.getUserContentController() != null) {
|
||||||
Map<String, Object> userScriptMap = (Map<String, Object>) call.argument("userScript");
|
Map<String, Object> userScriptMap = (Map<String, Object>) call.argument("userScript");
|
||||||
UserScript userScript = UserScript.fromMap(userScriptMap);
|
UserScript userScript = UserScript.fromMap(userScriptMap);
|
||||||
|
@ -505,7 +513,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "removeUserScript":
|
case removeUserScript:
|
||||||
if (webView != null && webView.getUserContentController() != null) {
|
if (webView != null && webView.getUserContentController() != null) {
|
||||||
Integer index = (Integer) call.argument("index");
|
Integer index = (Integer) call.argument("index");
|
||||||
Map<String, Object> userScriptMap = (Map<String, Object>) call.argument("userScript");
|
Map<String, Object> userScriptMap = (Map<String, Object>) call.argument("userScript");
|
||||||
|
@ -515,20 +523,20 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "removeUserScriptsByGroupName":
|
case removeUserScriptsByGroupName:
|
||||||
if (webView != null && webView.getUserContentController() != null) {
|
if (webView != null && webView.getUserContentController() != null) {
|
||||||
String groupName = (String) call.argument("groupName");
|
String groupName = (String) call.argument("groupName");
|
||||||
webView.getUserContentController().removeUserOnlyScriptsByGroupName(groupName);
|
webView.getUserContentController().removeUserOnlyScriptsByGroupName(groupName);
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "removeAllUserScripts":
|
case removeAllUserScripts:
|
||||||
if (webView != null && webView.getUserContentController() != null) {
|
if (webView != null && webView.getUserContentController() != null) {
|
||||||
webView.getUserContentController().removeAllUserOnlyScripts();
|
webView.getUserContentController().removeAllUserOnlyScripts();
|
||||||
}
|
}
|
||||||
result.success(true);
|
result.success(true);
|
||||||
break;
|
break;
|
||||||
case "callAsyncJavaScript":
|
case callAsyncJavaScript:
|
||||||
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
String functionBody = (String) call.argument("functionBody");
|
String functionBody = (String) call.argument("functionBody");
|
||||||
Map<String, Object> functionArguments = (Map<String, Object>) call.argument("arguments");
|
Map<String, Object> functionArguments = (Map<String, Object>) call.argument("arguments");
|
||||||
|
@ -545,7 +553,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "isSecureContext":
|
case isSecureContext:
|
||||||
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
webView.isSecureContext(new ValueCallback<Boolean>() {
|
webView.isSecureContext(new ValueCallback<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -557,7 +565,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "createWebMessageChannel":
|
case createWebMessageChannel:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
if (webView instanceof InAppWebView && WebViewFeature.isFeatureSupported(WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL)) {
|
if (webView instanceof InAppWebView && WebViewFeature.isFeatureSupported(WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL)) {
|
||||||
result.success(webView.createCompatWebMessageChannel().toMap());
|
result.success(webView.createCompatWebMessageChannel().toMap());
|
||||||
|
@ -568,7 +576,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(null);
|
result.success(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "postWebMessage":
|
case postWebMessage:
|
||||||
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.POST_WEB_MESSAGE)) {
|
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.POST_WEB_MESSAGE)) {
|
||||||
Map<String, Object> message = (Map<String, Object>) call.argument("message");
|
Map<String, Object> message = (Map<String, Object>) call.argument("message");
|
||||||
String targetOrigin = (String) call.argument("targetOrigin");
|
String targetOrigin = (String) call.argument("targetOrigin");
|
||||||
|
@ -600,7 +608,7 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(true);
|
result.success(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "addWebMessageListener":
|
case addWebMessageListener:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
Map<String, Object> webMessageListenerMap = (Map<String, Object>) call.argument("webMessageListener");
|
Map<String, Object> webMessageListenerMap = (Map<String, Object>) call.argument("webMessageListener");
|
||||||
WebMessageListener webMessageListener = WebMessageListener.fromMap(webView, webView.getPlugin().messenger, webMessageListenerMap);
|
WebMessageListener webMessageListener = WebMessageListener.fromMap(webView, webView.getPlugin().messenger, webMessageListenerMap);
|
||||||
|
@ -618,32 +626,35 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
||||||
result.success(true);
|
result.success(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "canScrollVertically":
|
case canScrollVertically:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
result.success(webView.canScrollVertically());
|
result.success(webView.canScrollVertically());
|
||||||
} else {
|
} else {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "canScrollHorizontally":
|
case canScrollHorizontally:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
result.success(webView.canScrollHorizontally());
|
result.success(webView.canScrollHorizontally());
|
||||||
} else {
|
} else {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "isInFullscreen":
|
case isInFullscreen:
|
||||||
if (webView != null) {
|
if (webView != null) {
|
||||||
result.success(webView.isInFullscreen());
|
result.success(webView.isInFullscreen());
|
||||||
} else {
|
} else {
|
||||||
result.success(false);
|
result.success(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
result.notImplemented();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* Use {@link FindInteractionChannelDelegate#onFindResultReceived} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) {
|
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) {
|
||||||
MethodChannel channel = getChannel();
|
MethodChannel channel = getChannel();
|
||||||
if (channel == null) return;
|
if (channel == null) return;
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
package com.pichillilorenzo.flutter_inappwebview.webview;
|
||||||
|
|
||||||
|
public enum WebViewChannelDelegateMethods {
|
||||||
|
getUrl,
|
||||||
|
getTitle,
|
||||||
|
getProgress,
|
||||||
|
loadUrl,
|
||||||
|
postUrl,
|
||||||
|
loadData,
|
||||||
|
loadFile,
|
||||||
|
evaluateJavascript,
|
||||||
|
injectJavascriptFileFromUrl,
|
||||||
|
injectCSSCode,
|
||||||
|
injectCSSFileFromUrl,
|
||||||
|
reload,
|
||||||
|
goBack,
|
||||||
|
canGoBack,
|
||||||
|
goForward,
|
||||||
|
canGoForward,
|
||||||
|
goBackOrForward,
|
||||||
|
canGoBackOrForward,
|
||||||
|
stopLoading,
|
||||||
|
isLoading,
|
||||||
|
takeScreenshot,
|
||||||
|
setSettings,
|
||||||
|
getSettings,
|
||||||
|
close,
|
||||||
|
show,
|
||||||
|
hide,
|
||||||
|
getCopyBackForwardList,
|
||||||
|
startSafeBrowsing,
|
||||||
|
clearCache,
|
||||||
|
clearSslPreferences,
|
||||||
|
findAllAsync,
|
||||||
|
findNext,
|
||||||
|
clearMatches,
|
||||||
|
scrollTo,
|
||||||
|
scrollBy,
|
||||||
|
pause,
|
||||||
|
resume,
|
||||||
|
pauseTimers,
|
||||||
|
resumeTimers,
|
||||||
|
printCurrentPage,
|
||||||
|
getContentHeight,
|
||||||
|
zoomBy,
|
||||||
|
getOriginalUrl,
|
||||||
|
getZoomScale,
|
||||||
|
getSelectedText,
|
||||||
|
getHitTestResult,
|
||||||
|
pageDown,
|
||||||
|
pageUp,
|
||||||
|
saveWebArchive,
|
||||||
|
zoomIn,
|
||||||
|
zoomOut,
|
||||||
|
clearFocus,
|
||||||
|
setContextMenu,
|
||||||
|
requestFocusNodeHref,
|
||||||
|
requestImageRef,
|
||||||
|
getScrollX,
|
||||||
|
getScrollY,
|
||||||
|
getCertificate,
|
||||||
|
clearHistory,
|
||||||
|
addUserScript,
|
||||||
|
removeUserScript,
|
||||||
|
removeUserScriptsByGroupName,
|
||||||
|
removeAllUserScripts,
|
||||||
|
callAsyncJavaScript,
|
||||||
|
isSecureContext,
|
||||||
|
createWebMessageChannel,
|
||||||
|
postWebMessage,
|
||||||
|
addWebMessageListener,
|
||||||
|
canScrollVertically,
|
||||||
|
canScrollHorizontally,
|
||||||
|
isInFullscreen
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ import androidx.webkit.WebViewCompat;
|
||||||
import androidx.webkit.WebViewFeature;
|
import androidx.webkit.WebViewFeature;
|
||||||
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
|
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.find_interaction.FindInteractionController;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
|
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshLayout;
|
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshLayout;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshSettings;
|
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshSettings;
|
||||||
|
@ -84,6 +85,10 @@ public class FlutterWebView implements PlatformWebView {
|
||||||
pullToRefreshLayout.prepare();
|
pullToRefreshLayout.prepare();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FindInteractionController findInteractionController = new FindInteractionController(webView, plugin, id, null);
|
||||||
|
webView.findInteractionController = findInteractionController;
|
||||||
|
findInteractionController.prepare();
|
||||||
|
|
||||||
webView.prepare();
|
webView.prepare();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ import androidx.webkit.WebViewCompat;
|
||||||
import androidx.webkit.WebViewFeature;
|
import androidx.webkit.WebViewFeature;
|
||||||
|
|
||||||
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
|
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
|
||||||
|
import com.pichillilorenzo.flutter_inappwebview.find_interaction.FindInteractionController;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobController;
|
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobController;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobManager;
|
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobManager;
|
||||||
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobSettings;
|
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobSettings;
|
||||||
|
@ -167,6 +168,9 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
|
||||||
|
|
||||||
private List<UserScript> initialUserOnlyScript = new ArrayList<>();
|
private List<UserScript> initialUserOnlyScript = new ArrayList<>();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public FindInteractionController findInteractionController;
|
||||||
|
|
||||||
public InAppWebView(Context context) {
|
public InAppWebView(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
@ -406,7 +410,10 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
|
||||||
setFindListener(new FindListener() {
|
setFindListener(new FindListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) {
|
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) {
|
||||||
if (channelDelegate != null) channelDelegate.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting);
|
if (findInteractionController != null && findInteractionController.channelDelegate != null)
|
||||||
|
findInteractionController.channelDelegate.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting);
|
||||||
|
if (channelDelegate != null)
|
||||||
|
channelDelegate.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1929,6 +1936,10 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
userContentController.dispose();
|
userContentController.dispose();
|
||||||
|
if (findInteractionController != null) {
|
||||||
|
findInteractionController.dispose();
|
||||||
|
findInteractionController = null;
|
||||||
|
}
|
||||||
if (windowId != null) {
|
if (windowId != null) {
|
||||||
InAppWebViewChromeClient.windowWebViewMessages.remove(windowId);
|
InAppWebViewChromeClient.windowWebViewMessages.remove(windowId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void findInteractions() {
|
||||||
|
final shouldSkip = kIsWeb
|
||||||
|
? true
|
||||||
|
: ![
|
||||||
|
TargetPlatform.android,
|
||||||
|
TargetPlatform.iOS,
|
||||||
|
TargetPlatform.macOS,
|
||||||
|
].contains(defaultTargetPlatform);
|
||||||
|
|
||||||
|
testWidgets('find interactions', (WidgetTester tester) async {
|
||||||
|
final Completer controllerCompleter = Completer<InAppWebViewController>();
|
||||||
|
final Completer<void> pageLoaded = Completer<void>();
|
||||||
|
final findInteractionController = FindInteractionController();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: InAppWebView(
|
||||||
|
key: GlobalKey(),
|
||||||
|
initialFile: "test_assets/in_app_webview_initial_file_test.html",
|
||||||
|
findInteractionController: findInteractionController,
|
||||||
|
initialSettings: InAppWebViewSettings(
|
||||||
|
clearCache: true,
|
||||||
|
isFindInteractionEnabled: true
|
||||||
|
),
|
||||||
|
onWebViewCreated: (controller) {
|
||||||
|
controllerCompleter.complete(controller);
|
||||||
|
},
|
||||||
|
onLoadStop: (controller, url) {
|
||||||
|
pageLoaded.complete();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await pageLoaded.future;
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
await Future.delayed(Duration(seconds: 1));
|
||||||
|
|
||||||
|
const firstSearchText = "InAppWebViewInitialFileTest";
|
||||||
|
await expectLater(findInteractionController.findAllAsync(find: firstSearchText), completes);
|
||||||
|
if ([TargetPlatform.iOS, TargetPlatform.macOS].contains(defaultTargetPlatform)) {
|
||||||
|
expect(await findInteractionController.getSearchText(), firstSearchText);
|
||||||
|
final session = await findInteractionController.getActiveFindSession();
|
||||||
|
expect(session!.resultCount, 2);
|
||||||
|
}
|
||||||
|
await expectLater(findInteractionController.findNext(forward: true), completes);
|
||||||
|
await expectLater(findInteractionController.findNext(forward: false), completes);
|
||||||
|
await expectLater(findInteractionController.clearMatches(), completes);
|
||||||
|
|
||||||
|
if ([TargetPlatform.iOS, TargetPlatform.macOS].contains(defaultTargetPlatform)) {
|
||||||
|
const secondSearchText = "text";
|
||||||
|
await expectLater(
|
||||||
|
findInteractionController.setSearchText(secondSearchText), completes);
|
||||||
|
await expectLater(
|
||||||
|
findInteractionController.presentFindNavigator(), completes);
|
||||||
|
expect(await findInteractionController.getSearchText(), secondSearchText);
|
||||||
|
expect(await findInteractionController.isFindNavigatorVisible(), true);
|
||||||
|
await expectLater(findInteractionController.updateResultCount(), completes);
|
||||||
|
await expectLater(
|
||||||
|
findInteractionController.dismissFindNavigator(), completes);
|
||||||
|
expect(await findInteractionController.isFindNavigatorVisible(), false);
|
||||||
|
}
|
||||||
|
}, skip: shouldSkip);
|
||||||
|
|
||||||
|
testWidgets('onFindResultReceived', (WidgetTester tester) async {
|
||||||
|
final Completer controllerCompleter = Completer<InAppWebViewController>();
|
||||||
|
final Completer<void> pageLoaded = Completer<void>();
|
||||||
|
final Completer<int> numberOfMatchesCompleter = Completer<int>();
|
||||||
|
final findInteractionController = FindInteractionController(
|
||||||
|
onFindResultReceived: (controller, int activeMatchOrdinal,
|
||||||
|
int numberOfMatches, bool isDoneCounting) async {
|
||||||
|
if (isDoneCounting && !numberOfMatchesCompleter.isCompleted) {
|
||||||
|
numberOfMatchesCompleter.complete(numberOfMatches);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: InAppWebView(
|
||||||
|
key: GlobalKey(),
|
||||||
|
initialFile: "test_assets/in_app_webview_initial_file_test.html",
|
||||||
|
initialSettings: InAppWebViewSettings(
|
||||||
|
clearCache: true,
|
||||||
|
isFindInteractionEnabled: false
|
||||||
|
),
|
||||||
|
findInteractionController: findInteractionController,
|
||||||
|
onWebViewCreated: (controller) {
|
||||||
|
controllerCompleter.complete(controller);
|
||||||
|
},
|
||||||
|
onLoadStop: (controller, url) {
|
||||||
|
pageLoaded.complete();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
var controller = await controllerCompleter.future;
|
||||||
|
await pageLoaded.future;
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
await Future.delayed(Duration(seconds: 1));
|
||||||
|
|
||||||
|
await controller.findAllAsync(find: "InAppWebViewInitialFileTest");
|
||||||
|
final int numberOfMatches = await numberOfMatchesCompleter.future;
|
||||||
|
expect(numberOfMatches, 2);
|
||||||
|
}, skip: shouldSkip);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'find_interactions.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
final shouldSkip = kIsWeb;
|
||||||
|
|
||||||
|
group('FindInteractionController', () {
|
||||||
|
findInteractions();
|
||||||
|
}, skip: shouldSkip);
|
||||||
|
}
|
|
@ -37,7 +37,6 @@ import 'load_file_url.dart';
|
||||||
import 'load_url.dart';
|
import 'load_url.dart';
|
||||||
import 'on_console_message.dart';
|
import 'on_console_message.dart';
|
||||||
import 'on_download_start_request.dart';
|
import 'on_download_start_request.dart';
|
||||||
import 'on_find_result_received.dart';
|
|
||||||
import 'on_js_before_unload.dart';
|
import 'on_js_before_unload.dart';
|
||||||
import 'on_received_error.dart';
|
import 'on_received_error.dart';
|
||||||
import 'on_received_http_error.dart';
|
import 'on_received_http_error.dart';
|
||||||
|
@ -106,7 +105,6 @@ void main() {
|
||||||
contentBlocker();
|
contentBlocker();
|
||||||
httpAuthCredentialDatabase();
|
httpAuthCredentialDatabase();
|
||||||
onConsoleMessage();
|
onConsoleMessage();
|
||||||
onFindResultReceived();
|
|
||||||
onDownloadStartRequest();
|
onDownloadStartRequest();
|
||||||
javascriptDialogs();
|
javascriptDialogs();
|
||||||
onReceivedHttpError();
|
onReceivedHttpError();
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
|
|
||||||
void onFindResultReceived() {
|
|
||||||
final shouldSkip = kIsWeb
|
|
||||||
? true
|
|
||||||
: ![
|
|
||||||
TargetPlatform.android,
|
|
||||||
TargetPlatform.iOS,
|
|
||||||
TargetPlatform.macOS,
|
|
||||||
].contains(defaultTargetPlatform);
|
|
||||||
|
|
||||||
testWidgets('onFindResultReceived', (WidgetTester tester) async {
|
|
||||||
final Completer controllerCompleter = Completer<InAppWebViewController>();
|
|
||||||
final Completer<void> pageLoaded = Completer<void>();
|
|
||||||
final Completer<int> numberOfMatchesCompleter = Completer<int>();
|
|
||||||
await tester.pumpWidget(
|
|
||||||
Directionality(
|
|
||||||
textDirection: TextDirection.ltr,
|
|
||||||
child: InAppWebView(
|
|
||||||
key: GlobalKey(),
|
|
||||||
initialFile: "test_assets/in_app_webview_initial_file_test.html",
|
|
||||||
initialSettings: InAppWebViewSettings(
|
|
||||||
clearCache: true,
|
|
||||||
),
|
|
||||||
onWebViewCreated: (controller) {
|
|
||||||
controllerCompleter.complete(controller);
|
|
||||||
},
|
|
||||||
onLoadStop: (controller, url) {
|
|
||||||
pageLoaded.complete();
|
|
||||||
},
|
|
||||||
onFindResultReceived: (controller, int activeMatchOrdinal,
|
|
||||||
int numberOfMatches, bool isDoneCounting) async {
|
|
||||||
if (isDoneCounting && !numberOfMatchesCompleter.isCompleted) {
|
|
||||||
numberOfMatchesCompleter.complete(numberOfMatches);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
var controller = await controllerCompleter.future;
|
|
||||||
await pageLoaded.future;
|
|
||||||
|
|
||||||
await tester.pump();
|
|
||||||
await Future.delayed(Duration(seconds: 1));
|
|
||||||
|
|
||||||
await controller.findAllAsync(find: "InAppWebViewInitialFileTest");
|
|
||||||
final int numberOfMatches = await numberOfMatchesCompleter.future;
|
|
||||||
expect(numberOfMatches, 2);
|
|
||||||
}, skip: shouldSkip);
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'in_app_webview/main.dart' as in_app_webview_tests;
|
import 'in_app_webview/main.dart' as in_app_webview_tests;
|
||||||
|
import 'find_interaction_controller/main.dart' as find_interaction_controller_tests;
|
||||||
import 'service_worker_controller/main.dart' as service_worker_controller_tests;
|
import 'service_worker_controller/main.dart' as service_worker_controller_tests;
|
||||||
import 'proxy_controller/main.dart' as proxy_controller_tests;
|
import 'proxy_controller/main.dart' as proxy_controller_tests;
|
||||||
import 'headless_in_app_webview/main.dart' as headless_in_app_webview_tests;
|
import 'headless_in_app_webview/main.dart' as headless_in_app_webview_tests;
|
||||||
|
@ -26,8 +27,13 @@ void main() {
|
||||||
ChromeSafariBrowser.debugLoggingSettings.maxLogMessageLength = 7000;
|
ChromeSafariBrowser.debugLoggingSettings.maxLogMessageLength = 7000;
|
||||||
WebAuthenticationSession.debugLoggingSettings.usePrint = true;
|
WebAuthenticationSession.debugLoggingSettings.usePrint = true;
|
||||||
WebAuthenticationSession.debugLoggingSettings.maxLogMessageLength = 7000;
|
WebAuthenticationSession.debugLoggingSettings.maxLogMessageLength = 7000;
|
||||||
|
PullToRefreshController.debugLoggingSettings.usePrint = true;
|
||||||
|
PullToRefreshController.debugLoggingSettings.maxLogMessageLength = 7000;
|
||||||
|
FindInteractionController.debugLoggingSettings.usePrint = true;
|
||||||
|
FindInteractionController.debugLoggingSettings.maxLogMessageLength = 7000;
|
||||||
|
|
||||||
in_app_webview_tests.main();
|
in_app_webview_tests.main();
|
||||||
|
find_interaction_controller_tests.main();
|
||||||
service_worker_controller_tests.main();
|
service_worker_controller_tests.main();
|
||||||
proxy_controller_tests.main();
|
proxy_controller_tests.main();
|
||||||
headless_in_app_webview_tests.main();
|
headless_in_app_webview_tests.main();
|
||||||
|
|
|
@ -19,12 +19,15 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||||
InAppWebViewSettings settings = InAppWebViewSettings(
|
InAppWebViewSettings settings = InAppWebViewSettings(
|
||||||
useShouldOverrideUrlLoading: true,
|
useShouldOverrideUrlLoading: true,
|
||||||
mediaPlaybackRequiresUserGesture: false,
|
mediaPlaybackRequiresUserGesture: false,
|
||||||
|
isFindInteractionEnabled: false,
|
||||||
allowsInlineMediaPlayback: true,
|
allowsInlineMediaPlayback: true,
|
||||||
iframeAllow: "camera; microphone",
|
iframeAllow: "camera; microphone",
|
||||||
iframeAllowFullscreen: true
|
iframeAllowFullscreen: true
|
||||||
);
|
);
|
||||||
|
|
||||||
PullToRefreshController? pullToRefreshController;
|
PullToRefreshController? pullToRefreshController;
|
||||||
|
FindInteractionController? findInteractionController;
|
||||||
|
|
||||||
late ContextMenu contextMenu;
|
late ContextMenu contextMenu;
|
||||||
String url = "";
|
String url = "";
|
||||||
double progress = 0;
|
double progress = 0;
|
||||||
|
@ -79,6 +82,14 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
findInteractionController = kIsWeb
|
||||||
|
? null
|
||||||
|
: FindInteractionController(
|
||||||
|
onFindResultReceived: (controller, activeMatchOrdinal, numberOfMatches, isDoneCounting) => {
|
||||||
|
print("$activeMatchOrdinal $numberOfMatches $isDoneCounting")
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -114,7 +125,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||||
InAppWebView(
|
InAppWebView(
|
||||||
key: webViewKey,
|
key: webViewKey,
|
||||||
initialUrlRequest:
|
initialUrlRequest:
|
||||||
URLRequest(url: Uri.parse('https://github.com/flutter/')),
|
URLRequest(url: Uri.parse('https://developer.apple.com/videos/play/wwdc2022/10049/?time=264')),
|
||||||
// initialUrlRequest:
|
// initialUrlRequest:
|
||||||
// URLRequest(url: Uri.parse(Uri.base.toString().replaceFirst("/#/", "/") + 'page.html')),
|
// URLRequest(url: Uri.parse(Uri.base.toString().replaceFirst("/#/", "/") + 'page.html')),
|
||||||
// initialFile: "assets/index.html",
|
// initialFile: "assets/index.html",
|
||||||
|
@ -122,6 +133,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||||
initialSettings: settings,
|
initialSettings: settings,
|
||||||
// contextMenu: contextMenu,
|
// contextMenu: contextMenu,
|
||||||
pullToRefreshController: pullToRefreshController,
|
pullToRefreshController: pullToRefreshController,
|
||||||
|
findInteractionController: findInteractionController,
|
||||||
onWebViewCreated: (controller) async {
|
onWebViewCreated: (controller) async {
|
||||||
webViewController = controller;
|
webViewController = controller;
|
||||||
},
|
},
|
||||||
|
@ -167,6 +179,32 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
||||||
this.url = url.toString();
|
this.url = url.toString();
|
||||||
urlController.text = this.url;
|
urlController.text = this.url;
|
||||||
});
|
});
|
||||||
|
await findInteractionController?.findAllAsync(find: "video");
|
||||||
|
// print(await findInteractionController?.getActiveFindSession());
|
||||||
|
await Future.delayed(Duration(seconds: 1));
|
||||||
|
findInteractionController?.findNext(forward: true);
|
||||||
|
findInteractionController?.findNext(forward: true);
|
||||||
|
findInteractionController?.findNext(forward: true);
|
||||||
|
await Future.delayed(Duration(seconds: 1));
|
||||||
|
// findInteractionController?.clearMatches();
|
||||||
|
findInteractionController?.findNext(forward: true);
|
||||||
|
findInteractionController?.findNext(forward: true);
|
||||||
|
findInteractionController?.findNext(forward: true);
|
||||||
|
findInteractionController?.findNext(forward: true);
|
||||||
|
await Future.delayed(Duration(seconds: 1));
|
||||||
|
findInteractionController?.clearMatches();
|
||||||
|
// print(await findInteractionController?.getSearchText());
|
||||||
|
// findInteractionController?.findNext(forward: true);
|
||||||
|
// findInteractionController?.findNext(forward: false);
|
||||||
|
// findInteractionController?.setSearchText("text");
|
||||||
|
// print(await findInteractionController?.getSearchText());
|
||||||
|
// print(await findInteractionController?.isFindNavigatorVisible());
|
||||||
|
// findInteractionController?.updateResultCount();
|
||||||
|
// findInteractionController?.clearMatches();
|
||||||
|
// findInteractionController?.presentFindNavigator();
|
||||||
|
// await Future.delayed(Duration(milliseconds: 500));
|
||||||
|
// findInteractionController?.dismissFindNavigator();
|
||||||
|
// print(await findInteractionController?.isFindNavigatorVisible());
|
||||||
},
|
},
|
||||||
onReceivedError: (controller, request, error) {
|
onReceivedError: (controller, request, error) {
|
||||||
pullToRefreshController?.endRefreshing();
|
pullToRefreshController?.endRefreshing();
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
//
|
||||||
|
// FindInteractionChannelDelegate.swift
|
||||||
|
// flutter_inappwebview
|
||||||
|
//
|
||||||
|
// Created by Lorenzo Pichilli on 07/10/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public class FindInteractionChannelDelegate : ChannelDelegate {
|
||||||
|
private weak var findInteractionController: FindInteractionController?
|
||||||
|
|
||||||
|
public init(findInteractionController: FindInteractionController, channel: FlutterMethodChannel) {
|
||||||
|
super.init(channel: channel)
|
||||||
|
self.findInteractionController = findInteractionController
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||||
|
let arguments = call.arguments as? NSDictionary
|
||||||
|
|
||||||
|
switch call.method {
|
||||||
|
case "findAllAsync":
|
||||||
|
if let findInteractionController = findInteractionController {
|
||||||
|
let find = arguments!["find"] as! String
|
||||||
|
findInteractionController.findAllAsync(find: find, completionHandler: {(value, error) in
|
||||||
|
if error != nil {
|
||||||
|
result(FlutterError(code: "FindInteractionChannelDelegate", message: error?.localizedDescription, details: nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result(true)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "findNext":
|
||||||
|
if let findInteractionController = findInteractionController {
|
||||||
|
let forward = arguments!["forward"] as! Bool
|
||||||
|
findInteractionController.findNext(forward: forward, completionHandler: {(value, error) in
|
||||||
|
if error != nil {
|
||||||
|
result(FlutterError(code: "FindInteractionChannelDelegate", message: error?.localizedDescription, details: nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result(true)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "clearMatches":
|
||||||
|
if let findInteractionController = findInteractionController {
|
||||||
|
findInteractionController.clearMatches(completionHandler: {(value, error) in
|
||||||
|
if error != nil {
|
||||||
|
result(FlutterError(code: "FindInteractionChannelDelegate", message: error?.localizedDescription, details: nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result(true)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "setSearchText":
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
if let interaction = findInteractionController?.webView?.findInteraction {
|
||||||
|
let searchText = arguments!["searchText"] as? String
|
||||||
|
interaction.searchText = searchText
|
||||||
|
result(true)
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "getSearchText":
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
if let interaction = findInteractionController?.webView?.findInteraction {
|
||||||
|
result(interaction.searchText)
|
||||||
|
} else {
|
||||||
|
result(nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result(nil)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "isFindNavigatorVisible":
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
if let interaction = findInteractionController?.webView?.findInteraction {
|
||||||
|
result(interaction.isFindNavigatorVisible)
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "updateResultCount":
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
if let interaction = findInteractionController?.webView?.findInteraction {
|
||||||
|
interaction.updateResultCount()
|
||||||
|
result(true)
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "presentFindNavigator":
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
if let interaction = findInteractionController?.webView?.findInteraction {
|
||||||
|
interaction.presentFindNavigator(showingReplace: false)
|
||||||
|
result(true)
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "dismissFindNavigator":
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
if let interaction = findInteractionController?.webView?.findInteraction {
|
||||||
|
interaction.dismissFindNavigator()
|
||||||
|
result(true)
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result(false)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "getActiveFindSession":
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
if let interaction = findInteractionController?.webView?.findInteraction {
|
||||||
|
result(interaction.activeFindSession?.toMap())
|
||||||
|
} else {
|
||||||
|
result(nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result(nil)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
result(FlutterMethodNotImplemented)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func onFindResultReceived(activeMatchOrdinal: Int, numberOfMatches: Int, isDoneCounting: Bool) {
|
||||||
|
let arguments: [String : Any?] = [
|
||||||
|
"activeMatchOrdinal": activeMatchOrdinal,
|
||||||
|
"numberOfMatches": numberOfMatches,
|
||||||
|
"isDoneCounting": isDoneCounting
|
||||||
|
]
|
||||||
|
channel?.invokeMethod("onFindResultReceived", arguments: arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func dispose() {
|
||||||
|
super.dispose()
|
||||||
|
findInteractionController = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
dispose()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
//
|
||||||
|
// FindInteractionController.swift
|
||||||
|
// flutter_inappwebview
|
||||||
|
//
|
||||||
|
// Created by Lorenzo Pichilli on 07/10/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Flutter
|
||||||
|
|
||||||
|
public class FindInteractionController : NSObject, Disposable {
|
||||||
|
|
||||||
|
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_find_interaction_";
|
||||||
|
var webView: InAppWebView?
|
||||||
|
var channelDelegate: FindInteractionChannelDelegate?
|
||||||
|
var settings: FindInteractionSettings?
|
||||||
|
var shouldCallOnRefresh = false
|
||||||
|
|
||||||
|
public init(registrar: FlutterPluginRegistrar, id: Any, webView: InAppWebView, settings: FindInteractionSettings?) {
|
||||||
|
super.init()
|
||||||
|
self.webView = webView
|
||||||
|
self.settings = settings
|
||||||
|
let channel = FlutterMethodChannel(name: FindInteractionController.METHOD_CHANNEL_NAME_PREFIX + String(describing: id),
|
||||||
|
binaryMessenger: registrar.messenger())
|
||||||
|
self.channelDelegate = FindInteractionChannelDelegate(findInteractionController: self, channel: channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func prepare() {
|
||||||
|
// if let settings = settings {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public func findAllAsync(find: String?, completionHandler: ((Any?, Error?) -> Void)?) {
|
||||||
|
guard let webView else {
|
||||||
|
if let completionHandler = completionHandler {
|
||||||
|
completionHandler(nil, nil)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if #available(iOS 16.0, *), webView.isFindInteractionEnabled {
|
||||||
|
if let interaction = webView.findInteraction {
|
||||||
|
interaction.searchText = find
|
||||||
|
interaction.presentFindNavigator(showingReplace: false)
|
||||||
|
}
|
||||||
|
if let completionHandler = completionHandler {
|
||||||
|
completionHandler(nil, nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let startSearch = "window.\(JAVASCRIPT_BRIDGE_NAME)._findAllAsync('\(find ?? "")');"
|
||||||
|
webView.evaluateJavaScript(startSearch, completionHandler: completionHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func findNext(forward: Bool, completionHandler: ((Any?, Error?) -> Void)?) {
|
||||||
|
guard let webView else {
|
||||||
|
if let completionHandler = completionHandler {
|
||||||
|
completionHandler(nil, nil)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if #available(iOS 16.0, *), webView.isFindInteractionEnabled {
|
||||||
|
if let interaction = webView.findInteraction {
|
||||||
|
if forward {
|
||||||
|
interaction.findNext()
|
||||||
|
} else {
|
||||||
|
interaction.findPrevious()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let completionHandler = completionHandler {
|
||||||
|
completionHandler(nil, nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
webView.evaluateJavaScript("window.\(JAVASCRIPT_BRIDGE_NAME)._findNext(\(forward ? "true" : "false"));", completionHandler: completionHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func clearMatches(completionHandler: ((Any?, Error?) -> Void)?) {
|
||||||
|
guard let webView else {
|
||||||
|
if let completionHandler = completionHandler {
|
||||||
|
completionHandler(nil, nil)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if #available(iOS 16.0, *), webView.isFindInteractionEnabled {
|
||||||
|
if let interaction = webView.findInteraction {
|
||||||
|
interaction.searchText = nil
|
||||||
|
interaction.dismissFindNavigator()
|
||||||
|
}
|
||||||
|
if let completionHandler = completionHandler {
|
||||||
|
completionHandler(nil, nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
webView.evaluateJavaScript("window.\(JAVASCRIPT_BRIDGE_NAME)._clearMatches();", completionHandler: completionHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func dispose() {
|
||||||
|
channelDelegate?.dispose()
|
||||||
|
channelDelegate = nil
|
||||||
|
webView = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
debugPrint("FindInteractionControl - dealloc")
|
||||||
|
dispose()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
//
|
||||||
|
// FindInteractionSettings.swift
|
||||||
|
// flutter_inappwebview
|
||||||
|
//
|
||||||
|
// Created by Lorenzo Pichilli on 07/10/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public class FindInteractionSettings : ISettings<FindInteractionController> {
|
||||||
|
|
||||||
|
override init(){
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func parse(settings: [String: Any?]) -> FindInteractionSettings {
|
||||||
|
let _ = super.parse(settings: settings)
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
override func getRealSettings(obj: FindInteractionController?) -> [String: Any?] {
|
||||||
|
let realSettings: [String: Any?] = toMap()
|
||||||
|
return realSettings
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,6 +77,12 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
||||||
pullToRefreshControl.delegate = webView
|
pullToRefreshControl.delegate = webView
|
||||||
pullToRefreshControl.prepare()
|
pullToRefreshControl.prepare()
|
||||||
|
|
||||||
|
let findInteractionController = FindInteractionController(
|
||||||
|
registrar: SwiftFlutterPlugin.instance!.registrar!,
|
||||||
|
id: id, webView: webView, settings: nil)
|
||||||
|
webView.findInteractionController = findInteractionController
|
||||||
|
findInteractionController.prepare()
|
||||||
|
|
||||||
prepareWebView()
|
prepareWebView()
|
||||||
webView.windowCreated = true
|
webView.windowCreated = true
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,12 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView, Disposable
|
||||||
webView!.pullToRefreshControl = pullToRefreshControl
|
webView!.pullToRefreshControl = pullToRefreshControl
|
||||||
pullToRefreshControl.delegate = webView!
|
pullToRefreshControl.delegate = webView!
|
||||||
pullToRefreshControl.prepare()
|
pullToRefreshControl.prepare()
|
||||||
|
|
||||||
|
let findInteractionController = FindInteractionController(
|
||||||
|
registrar: SwiftFlutterPlugin.instance!.registrar!,
|
||||||
|
id: viewId, webView: webView!, settings: nil)
|
||||||
|
webView!.findInteractionController = findInteractionController
|
||||||
|
findInteractionController.prepare()
|
||||||
|
|
||||||
webView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
webView!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||||
myView!.autoresizesSubviews = true
|
myView!.autoresizesSubviews = true
|
||||||
|
|
|
@ -12,7 +12,8 @@ import WebKit
|
||||||
public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
||||||
WKNavigationDelegate, WKScriptMessageHandler, UIGestureRecognizerDelegate,
|
WKNavigationDelegate, WKScriptMessageHandler, UIGestureRecognizerDelegate,
|
||||||
WKDownloadDelegate,
|
WKDownloadDelegate,
|
||||||
PullToRefreshDelegate, Disposable {
|
PullToRefreshDelegate,
|
||||||
|
Disposable {
|
||||||
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_"
|
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_"
|
||||||
|
|
||||||
var id: Any? // viewId
|
var id: Any? // viewId
|
||||||
|
@ -22,6 +23,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
||||||
var channelDelegate: WebViewChannelDelegate?
|
var channelDelegate: WebViewChannelDelegate?
|
||||||
var settings: InAppWebViewSettings?
|
var settings: InAppWebViewSettings?
|
||||||
var pullToRefreshControl: PullToRefreshControl?
|
var pullToRefreshControl: PullToRefreshControl?
|
||||||
|
var findInteractionController: FindInteractionController?
|
||||||
var webMessageChannels: [String:WebMessageChannel] = [:]
|
var webMessageChannels: [String:WebMessageChannel] = [:]
|
||||||
var webMessageListeners: [WebMessageListener] = []
|
var webMessageListeners: [WebMessageListener] = []
|
||||||
var currentOriginalUrl: URL?
|
var currentOriginalUrl: URL?
|
||||||
|
@ -329,7 +331,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
||||||
name: UIMenuController.didHideMenuNotification,
|
name: UIMenuController.didHideMenuNotification,
|
||||||
object: nil)
|
object: nil)
|
||||||
|
|
||||||
// if #available(iOS 15.0, *) {
|
// TODO: Still not working on iOS 16.0!
|
||||||
|
// if #available(iOS 16.0, *) {
|
||||||
// addObserver(self,
|
// addObserver(self,
|
||||||
// forKeyPath: #keyPath(WKWebView.fullscreenState),
|
// forKeyPath: #keyPath(WKWebView.fullscreenState),
|
||||||
// options: .new,
|
// options: .new,
|
||||||
|
@ -413,6 +416,10 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
isFindInteractionEnabled = settings.isFindInteractionEnabled
|
||||||
|
}
|
||||||
|
|
||||||
// debugging is always enabled for iOS,
|
// debugging is always enabled for iOS,
|
||||||
// there isn't any option to set about it such as on Android.
|
// there isn't any option to set about it such as on Android.
|
||||||
|
|
||||||
|
@ -456,6 +463,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
||||||
|
|
||||||
if #available(iOS 15.4, *) {
|
if #available(iOS 15.4, *) {
|
||||||
configuration.preferences.isSiteSpecificQuirksModeEnabled = settings.isSiteSpecificQuirksModeEnabled
|
configuration.preferences.isSiteSpecificQuirksModeEnabled = settings.isSiteSpecificQuirksModeEnabled
|
||||||
|
configuration.preferences.isElementFullscreenEnabled = settings.isElementFullscreenEnabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -669,7 +677,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// else if keyPath == #keyPath(WKWebView.fullscreenState) {
|
} else if #available(iOS 16.0, *) {
|
||||||
|
// TODO: Still not working on iOS 16.0!
|
||||||
|
// if keyPath == #keyPath(WKWebView.fullscreenState) {
|
||||||
// if fullscreenState == .enteringFullscreen {
|
// if fullscreenState == .enteringFullscreen {
|
||||||
// channelDelegate?.onEnterFullscreen()
|
// channelDelegate?.onEnterFullscreen()
|
||||||
// } else if fullscreenState == .exitingFullscreen {
|
// } else if fullscreenState == .exitingFullscreen {
|
||||||
|
@ -2513,6 +2523,12 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func onEnterFullscreen(_ notification: Notification) {
|
@objc func onEnterFullscreen(_ notification: Notification) {
|
||||||
|
// TODO: Still not working on iOS 16.0!
|
||||||
|
// if #available(iOS 16.0, *) {
|
||||||
|
// channelDelegate?.onEnterFullscreen()
|
||||||
|
// inFullscreen = true
|
||||||
|
// }
|
||||||
|
// else
|
||||||
if (isVideoPlayerWindow(notification.object as AnyObject?)) {
|
if (isVideoPlayerWindow(notification.object as AnyObject?)) {
|
||||||
channelDelegate?.onEnterFullscreen()
|
channelDelegate?.onEnterFullscreen()
|
||||||
inFullscreen = true
|
inFullscreen = true
|
||||||
|
@ -2520,6 +2536,12 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func onExitFullscreen(_ notification: Notification) {
|
@objc func onExitFullscreen(_ notification: Notification) {
|
||||||
|
// TODO: Still not working on iOS 16.0!
|
||||||
|
// if #available(iOS 16.0, *) {
|
||||||
|
// channelDelegate?.onExitFullscreen()
|
||||||
|
// inFullscreen = false
|
||||||
|
// }
|
||||||
|
// else
|
||||||
if (isVideoPlayerWindow(notification.object as AnyObject?)) {
|
if (isVideoPlayerWindow(notification.object as AnyObject?)) {
|
||||||
channelDelegate?.onExitFullscreen()
|
channelDelegate?.onExitFullscreen()
|
||||||
inFullscreen = false
|
inFullscreen = false
|
||||||
|
@ -2648,6 +2670,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
||||||
if let wId = _windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
if let wId = _windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||||
webView = webViewTransport.webView
|
webView = webViewTransport.webView
|
||||||
}
|
}
|
||||||
|
webView.findInteractionController?.channelDelegate?.onFindResultReceived(activeMatchOrdinal: activeMatchOrdinal, numberOfMatches: numberOfMatches, isDoneCounting: isDoneCounting)
|
||||||
webView.channelDelegate?.onFindResultReceived(activeMatchOrdinal: activeMatchOrdinal, numberOfMatches: numberOfMatches, isDoneCounting: isDoneCounting)
|
webView.channelDelegate?.onFindResultReceived(activeMatchOrdinal: activeMatchOrdinal, numberOfMatches: numberOfMatches, isDoneCounting: isDoneCounting)
|
||||||
} else if message.name == "onCallAsyncJavaScriptResultBelowIOS14Received" {
|
} else if message.name == "onCallAsyncJavaScriptResultBelowIOS14Received" {
|
||||||
let body = message.body as! [String: Any?]
|
let body = message.body as! [String: Any?]
|
||||||
|
@ -2701,19 +2724,6 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func findAllAsync(find: String?, completionHandler: ((Any?, Error?) -> Void)?) {
|
|
||||||
let startSearch = "window.\(JAVASCRIPT_BRIDGE_NAME)._findAllAsync('\(find ?? "")');"
|
|
||||||
evaluateJavaScript(startSearch, completionHandler: completionHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func findNext(forward: Bool, completionHandler: ((Any?, Error?) -> Void)?) {
|
|
||||||
evaluateJavaScript("window.\(JAVASCRIPT_BRIDGE_NAME)._findNext(\(forward ? "true" : "false"));", completionHandler: completionHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func clearMatches(completionHandler: ((Any?, Error?) -> Void)?) {
|
|
||||||
evaluateJavaScript("window.\(JAVASCRIPT_BRIDGE_NAME)._clearMatches();", completionHandler: completionHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func scrollTo(x: Int, y: Int, animated: Bool) {
|
public func scrollTo(x: Int, y: Int, animated: Bool) {
|
||||||
scrollView.setContentOffset(CGPoint(x: x, y: y), animated: animated)
|
scrollView.setContentOffset(CGPoint(x: x, y: y), animated: animated)
|
||||||
}
|
}
|
||||||
|
@ -3004,8 +3014,11 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
||||||
if #available(iOS 15.0, *) {
|
if #available(iOS 15.0, *) {
|
||||||
removeObserver(self, forKeyPath: #keyPath(WKWebView.cameraCaptureState))
|
removeObserver(self, forKeyPath: #keyPath(WKWebView.cameraCaptureState))
|
||||||
removeObserver(self, forKeyPath: #keyPath(WKWebView.microphoneCaptureState))
|
removeObserver(self, forKeyPath: #keyPath(WKWebView.microphoneCaptureState))
|
||||||
// removeObserver(self, forKeyPath: #keyPath(WKWebView.fullscreenState))
|
|
||||||
}
|
}
|
||||||
|
// TODO: Still not working on iOS 16.0!
|
||||||
|
// if #available(iOS 16.0, *) {
|
||||||
|
// removeObserver(self, forKeyPath: #keyPath(WKWebView.fullscreenState))
|
||||||
|
// }
|
||||||
scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.contentOffset))
|
scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.contentOffset))
|
||||||
scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.zoomScale))
|
scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.zoomScale))
|
||||||
resumeTimers()
|
resumeTimers()
|
||||||
|
@ -3044,6 +3057,8 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
|
||||||
disablePullToRefresh()
|
disablePullToRefresh()
|
||||||
pullToRefreshControl?.dispose()
|
pullToRefreshControl?.dispose()
|
||||||
pullToRefreshControl = nil
|
pullToRefreshControl = nil
|
||||||
|
findInteractionController?.dispose()
|
||||||
|
findInteractionController = nil
|
||||||
uiDelegate = nil
|
uiDelegate = nil
|
||||||
navigationDelegate = nil
|
navigationDelegate = nil
|
||||||
scrollView.delegate = nil
|
scrollView.delegate = nil
|
||||||
|
|
|
@ -74,6 +74,8 @@ public class InAppWebViewSettings: ISettings<InAppWebView> {
|
||||||
var isTextInteractionEnabled = true
|
var isTextInteractionEnabled = true
|
||||||
var isSiteSpecificQuirksModeEnabled = true
|
var isSiteSpecificQuirksModeEnabled = true
|
||||||
var upgradeKnownHostsToHTTPS = true
|
var upgradeKnownHostsToHTTPS = true
|
||||||
|
var isElementFullscreenEnabled = true
|
||||||
|
var isFindInteractionEnabled = false
|
||||||
|
|
||||||
override init(){
|
override init(){
|
||||||
super.init()
|
super.init()
|
||||||
|
@ -146,6 +148,10 @@ public class InAppWebViewSettings: ISettings<InAppWebView> {
|
||||||
}
|
}
|
||||||
if #available(iOS 15.4, *) {
|
if #available(iOS 15.4, *) {
|
||||||
realSettings["isSiteSpecificQuirksModeEnabled"] = configuration.preferences.isSiteSpecificQuirksModeEnabled
|
realSettings["isSiteSpecificQuirksModeEnabled"] = configuration.preferences.isSiteSpecificQuirksModeEnabled
|
||||||
|
realSettings["isElementFullscreenEnabled"] = configuration.preferences.isElementFullscreenEnabled
|
||||||
|
}
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
realSettings["isFindInteractionEnabled"] = webView.isFindInteractionEnabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return realSettings
|
return realSettings
|
||||||
|
|
|
@ -19,17 +19,22 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||||
let arguments = call.arguments as? NSDictionary
|
let arguments = call.arguments as? NSDictionary
|
||||||
|
|
||||||
switch call.method {
|
guard let method = WebViewChannelDelegateMethods.init(rawValue: call.method) else {
|
||||||
case "getUrl":
|
result(FlutterMethodNotImplemented)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch method {
|
||||||
|
case .getUrl:
|
||||||
result(webView?.url?.absoluteString)
|
result(webView?.url?.absoluteString)
|
||||||
break
|
break
|
||||||
case "getTitle":
|
case .getTitle:
|
||||||
result(webView?.title)
|
result(webView?.title)
|
||||||
break
|
break
|
||||||
case "getProgress":
|
case .getProgress:
|
||||||
result( (webView != nil) ? Int(webView!.estimatedProgress * 100) : nil )
|
result( (webView != nil) ? Int(webView!.estimatedProgress * 100) : nil )
|
||||||
break
|
break
|
||||||
case "loadUrl":
|
case .loadUrl:
|
||||||
let urlRequest = arguments!["urlRequest"] as! [String:Any?]
|
let urlRequest = arguments!["urlRequest"] as! [String:Any?]
|
||||||
let allowingReadAccessTo = arguments!["allowingReadAccessTo"] as? String
|
let allowingReadAccessTo = arguments!["allowingReadAccessTo"] as? String
|
||||||
var allowingReadAccessToURL: URL? = nil
|
var allowingReadAccessToURL: URL? = nil
|
||||||
|
@ -39,7 +44,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
webView?.loadUrl(urlRequest: URLRequest.init(fromPluginMap: urlRequest), allowingReadAccessTo: allowingReadAccessToURL)
|
webView?.loadUrl(urlRequest: URLRequest.init(fromPluginMap: urlRequest), allowingReadAccessTo: allowingReadAccessToURL)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "postUrl":
|
case .postUrl:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
let url = arguments!["url"] as! String
|
let url = arguments!["url"] as! String
|
||||||
let postData = arguments!["postData"] as! FlutterStandardTypedData
|
let postData = arguments!["postData"] as! FlutterStandardTypedData
|
||||||
|
@ -47,7 +52,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
}
|
}
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "loadData":
|
case .loadData:
|
||||||
let data = arguments!["data"] as! String
|
let data = arguments!["data"] as! String
|
||||||
let mimeType = arguments!["mimeType"] as! String
|
let mimeType = arguments!["mimeType"] as! String
|
||||||
let encoding = arguments!["encoding"] as! String
|
let encoding = arguments!["encoding"] as! String
|
||||||
|
@ -60,7 +65,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
webView?.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl, allowingReadAccessTo: allowingReadAccessToURL)
|
webView?.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl, allowingReadAccessTo: allowingReadAccessToURL)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "loadFile":
|
case .loadFile:
|
||||||
let assetFilePath = arguments!["assetFilePath"] as! String
|
let assetFilePath = arguments!["assetFilePath"] as! String
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -72,7 +77,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
}
|
}
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "evaluateJavascript":
|
case .evaluateJavascript:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
let source = arguments!["source"] as! String
|
let source = arguments!["source"] as! String
|
||||||
let contentWorldMap = arguments!["contentWorld"] as? [String:Any?]
|
let contentWorldMap = arguments!["contentWorld"] as? [String:Any?]
|
||||||
|
@ -91,58 +96,58 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "injectJavascriptFileFromUrl":
|
case .injectJavascriptFileFromUrl:
|
||||||
let urlFile = arguments!["urlFile"] as! String
|
let urlFile = arguments!["urlFile"] as! String
|
||||||
let scriptHtmlTagAttributes = arguments!["scriptHtmlTagAttributes"] as? [String:Any?]
|
let scriptHtmlTagAttributes = arguments!["scriptHtmlTagAttributes"] as? [String:Any?]
|
||||||
webView?.injectJavascriptFileFromUrl(urlFile: urlFile, scriptHtmlTagAttributes: scriptHtmlTagAttributes)
|
webView?.injectJavascriptFileFromUrl(urlFile: urlFile, scriptHtmlTagAttributes: scriptHtmlTagAttributes)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "injectCSSCode":
|
case .injectCSSCode:
|
||||||
let source = arguments!["source"] as! String
|
let source = arguments!["source"] as! String
|
||||||
webView?.injectCSSCode(source: source)
|
webView?.injectCSSCode(source: source)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "injectCSSFileFromUrl":
|
case .injectCSSFileFromUrl:
|
||||||
let urlFile = arguments!["urlFile"] as! String
|
let urlFile = arguments!["urlFile"] as! String
|
||||||
let cssLinkHtmlTagAttributes = arguments!["cssLinkHtmlTagAttributes"] as? [String:Any?]
|
let cssLinkHtmlTagAttributes = arguments!["cssLinkHtmlTagAttributes"] as? [String:Any?]
|
||||||
webView?.injectCSSFileFromUrl(urlFile: urlFile, cssLinkHtmlTagAttributes: cssLinkHtmlTagAttributes)
|
webView?.injectCSSFileFromUrl(urlFile: urlFile, cssLinkHtmlTagAttributes: cssLinkHtmlTagAttributes)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "reload":
|
case .reload:
|
||||||
webView?.reload()
|
webView?.reload()
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "goBack":
|
case .goBack:
|
||||||
webView?.goBack()
|
webView?.goBack()
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "canGoBack":
|
case .canGoBack:
|
||||||
result(webView?.canGoBack ?? false)
|
result(webView?.canGoBack ?? false)
|
||||||
break
|
break
|
||||||
case "goForward":
|
case .goForward:
|
||||||
webView?.goForward()
|
webView?.goForward()
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "canGoForward":
|
case .canGoForward:
|
||||||
result(webView?.canGoForward ?? false)
|
result(webView?.canGoForward ?? false)
|
||||||
break
|
break
|
||||||
case "goBackOrForward":
|
case .goBackOrForward:
|
||||||
let steps = arguments!["steps"] as! Int
|
let steps = arguments!["steps"] as! Int
|
||||||
webView?.goBackOrForward(steps: steps)
|
webView?.goBackOrForward(steps: steps)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "canGoBackOrForward":
|
case .canGoBackOrForward:
|
||||||
let steps = arguments!["steps"] as! Int
|
let steps = arguments!["steps"] as! Int
|
||||||
result(webView?.canGoBackOrForward(steps: steps) ?? false)
|
result(webView?.canGoBackOrForward(steps: steps) ?? false)
|
||||||
break
|
break
|
||||||
case "stopLoading":
|
case .stopLoading:
|
||||||
webView?.stopLoading()
|
webView?.stopLoading()
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "isLoading":
|
case .isLoading:
|
||||||
result(webView?.isLoading ?? false)
|
result(webView?.isLoading ?? false)
|
||||||
break
|
break
|
||||||
case "takeScreenshot":
|
case .takeScreenshot:
|
||||||
if let webView = webView, #available(iOS 11.0, *) {
|
if let webView = webView, #available(iOS 11.0, *) {
|
||||||
let screenshotConfiguration = arguments!["screenshotConfiguration"] as? [String: Any?]
|
let screenshotConfiguration = arguments!["screenshotConfiguration"] as? [String: Any?]
|
||||||
webView.takeScreenshot(with: screenshotConfiguration, completionHandler: { (screenshot) -> Void in
|
webView.takeScreenshot(with: screenshotConfiguration, completionHandler: { (screenshot) -> Void in
|
||||||
|
@ -153,7 +158,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "setSettings":
|
case .setSettings:
|
||||||
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
||||||
let inAppBrowserSettings = InAppBrowserSettings()
|
let inAppBrowserSettings = InAppBrowserSettings()
|
||||||
let inAppBrowserSettingsMap = arguments!["settings"] as! [String: Any]
|
let inAppBrowserSettingsMap = arguments!["settings"] as! [String: Any]
|
||||||
|
@ -167,14 +172,14 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
}
|
}
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "getSettings":
|
case .getSettings:
|
||||||
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
||||||
result(iabController.getSettings())
|
result(iabController.getSettings())
|
||||||
} else {
|
} else {
|
||||||
result(webView?.getSettings())
|
result(webView?.getSettings())
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "close":
|
case .close:
|
||||||
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
||||||
iabController.close {
|
iabController.close {
|
||||||
result(true)
|
result(true)
|
||||||
|
@ -183,7 +188,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(FlutterMethodNotImplemented)
|
result(FlutterMethodNotImplemented)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "show":
|
case .show:
|
||||||
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
||||||
iabController.show {
|
iabController.show {
|
||||||
result(true)
|
result(true)
|
||||||
|
@ -192,7 +197,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(FlutterMethodNotImplemented)
|
result(FlutterMethodNotImplemented)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "hide":
|
case .hide:
|
||||||
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
||||||
iabController.hide {
|
iabController.hide {
|
||||||
result(true)
|
result(true)
|
||||||
|
@ -201,13 +206,13 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(FlutterMethodNotImplemented)
|
result(FlutterMethodNotImplemented)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "getCopyBackForwardList":
|
case .getCopyBackForwardList:
|
||||||
result(webView?.getCopyBackForwardList())
|
result(webView?.getCopyBackForwardList())
|
||||||
break
|
break
|
||||||
case "findAllAsync":
|
case .findAllAsync:
|
||||||
if let webView = webView {
|
if let webView = webView, let findInteractionController = webView.findInteractionController {
|
||||||
let find = arguments!["find"] as! String
|
let find = arguments!["find"] as! String
|
||||||
webView.findAllAsync(find: find, completionHandler: {(value, error) in
|
findInteractionController.findAllAsync(find: find, completionHandler: {(value, error) in
|
||||||
if error != nil {
|
if error != nil {
|
||||||
result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil))
|
result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil))
|
||||||
return
|
return
|
||||||
|
@ -218,10 +223,10 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "findNext":
|
case .findNext:
|
||||||
if let webView = webView {
|
if let webView = webView, let findInteractionController = webView.findInteractionController {
|
||||||
let forward = arguments!["forward"] as! Bool
|
let forward = arguments!["forward"] as! Bool
|
||||||
webView.findNext(forward: forward, completionHandler: {(value, error) in
|
findInteractionController.findNext(forward: forward, completionHandler: {(value, error) in
|
||||||
if error != nil {
|
if error != nil {
|
||||||
result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil))
|
result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil))
|
||||||
return
|
return
|
||||||
|
@ -232,9 +237,9 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "clearMatches":
|
case .clearMatches:
|
||||||
if let webView = webView {
|
if let webView = webView, let findInteractionController = webView.findInteractionController {
|
||||||
webView.clearMatches(completionHandler: {(value, error) in
|
findInteractionController.clearMatches(completionHandler: {(value, error) in
|
||||||
if error != nil {
|
if error != nil {
|
||||||
result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil))
|
result(FlutterError(code: "WebViewChannelDelegate", message: error?.localizedDescription, details: nil))
|
||||||
return
|
return
|
||||||
|
@ -245,33 +250,33 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "clearCache":
|
case .clearCache:
|
||||||
webView?.clearCache()
|
webView?.clearCache()
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "scrollTo":
|
case .scrollTo:
|
||||||
let x = arguments!["x"] as! Int
|
let x = arguments!["x"] as! Int
|
||||||
let y = arguments!["y"] as! Int
|
let y = arguments!["y"] as! Int
|
||||||
let animated = arguments!["animated"] as! Bool
|
let animated = arguments!["animated"] as! Bool
|
||||||
webView?.scrollTo(x: x, y: y, animated: animated)
|
webView?.scrollTo(x: x, y: y, animated: animated)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "scrollBy":
|
case .scrollBy:
|
||||||
let x = arguments!["x"] as! Int
|
let x = arguments!["x"] as! Int
|
||||||
let y = arguments!["y"] as! Int
|
let y = arguments!["y"] as! Int
|
||||||
let animated = arguments!["animated"] as! Bool
|
let animated = arguments!["animated"] as! Bool
|
||||||
webView?.scrollBy(x: x, y: y, animated: animated)
|
webView?.scrollBy(x: x, y: y, animated: animated)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "pauseTimers":
|
case .pauseTimers:
|
||||||
webView?.pauseTimers()
|
webView?.pauseTimers()
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "resumeTimers":
|
case .resumeTimers:
|
||||||
webView?.resumeTimers()
|
webView?.resumeTimers()
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "printCurrentPage":
|
case .printCurrentPage:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
let settings = PrintJobSettings()
|
let settings = PrintJobSettings()
|
||||||
if let settingsMap = arguments!["settings"] as? [String: Any?] {
|
if let settingsMap = arguments!["settings"] as? [String: Any?] {
|
||||||
|
@ -282,29 +287,29 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "getContentHeight":
|
case .getContentHeight:
|
||||||
result(webView?.getContentHeight())
|
result(webView?.getContentHeight())
|
||||||
break
|
break
|
||||||
case "zoomBy":
|
case .zoomBy:
|
||||||
let zoomFactor = (arguments!["zoomFactor"] as! NSNumber).floatValue
|
let zoomFactor = (arguments!["zoomFactor"] as! NSNumber).floatValue
|
||||||
let animated = arguments!["animated"] as! Bool
|
let animated = arguments!["animated"] as! Bool
|
||||||
webView?.zoomBy(zoomFactor: zoomFactor, animated: animated)
|
webView?.zoomBy(zoomFactor: zoomFactor, animated: animated)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "reloadFromOrigin":
|
case .reloadFromOrigin:
|
||||||
webView?.reloadFromOrigin()
|
webView?.reloadFromOrigin()
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "getOriginalUrl":
|
case .getOriginalUrl:
|
||||||
result(webView?.getOriginalUrl()?.absoluteString)
|
result(webView?.getOriginalUrl()?.absoluteString)
|
||||||
break
|
break
|
||||||
case "getZoomScale":
|
case .getZoomScale:
|
||||||
result(webView?.getZoomScale())
|
result(webView?.getZoomScale())
|
||||||
break
|
break
|
||||||
case "hasOnlySecureContent":
|
case .hasOnlySecureContent:
|
||||||
result(webView?.hasOnlySecureContent ?? false)
|
result(webView?.hasOnlySecureContent ?? false)
|
||||||
break
|
break
|
||||||
case "getSelectedText":
|
case .getSelectedText:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
webView.getSelectedText { (value, error) in
|
webView.getSelectedText { (value, error) in
|
||||||
if let err = error {
|
if let err = error {
|
||||||
|
@ -319,7 +324,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "getHitTestResult":
|
case .getHitTestResult:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
webView.getHitTestResult { (hitTestResult) in
|
webView.getHitTestResult { (hitTestResult) in
|
||||||
result(hitTestResult.toMap())
|
result(hitTestResult.toMap())
|
||||||
|
@ -329,11 +334,11 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "clearFocus":
|
case .clearFocus:
|
||||||
webView?.clearFocus()
|
webView?.clearFocus()
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "setContextMenu":
|
case .setContextMenu:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
let contextMenu = arguments!["contextMenu"] as? [String: Any]
|
let contextMenu = arguments!["contextMenu"] as? [String: Any]
|
||||||
webView.contextMenu = contextMenu
|
webView.contextMenu = contextMenu
|
||||||
|
@ -342,7 +347,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "requestFocusNodeHref":
|
case .requestFocusNodeHref:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
webView.requestFocusNodeHref { (value, error) in
|
webView.requestFocusNodeHref { (value, error) in
|
||||||
if let err = error {
|
if let err = error {
|
||||||
|
@ -356,7 +361,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "requestImageRef":
|
case .requestImageRef:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
webView.requestImageRef { (value, error) in
|
webView.requestImageRef { (value, error) in
|
||||||
if let err = error {
|
if let err = error {
|
||||||
|
@ -370,24 +375,24 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "getScrollX":
|
case .getScrollX:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
result(Int(webView.scrollView.contentOffset.x))
|
result(Int(webView.scrollView.contentOffset.x))
|
||||||
} else {
|
} else {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "getScrollY":
|
case .getScrollY:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
result(Int(webView.scrollView.contentOffset.y))
|
result(Int(webView.scrollView.contentOffset.y))
|
||||||
} else {
|
} else {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "getCertificate":
|
case .getCertificate:
|
||||||
result(webView?.getCertificate()?.toMap())
|
result(webView?.getCertificate()?.toMap())
|
||||||
break
|
break
|
||||||
case "addUserScript":
|
case .addUserScript:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
let userScriptMap = arguments!["userScript"] as! [String: Any?]
|
let userScriptMap = arguments!["userScript"] as! [String: Any?]
|
||||||
let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView.windowId)!
|
let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView.windowId)!
|
||||||
|
@ -396,23 +401,23 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
}
|
}
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "removeUserScript":
|
case .removeUserScript:
|
||||||
let index = arguments!["index"] as! Int
|
let index = arguments!["index"] as! Int
|
||||||
let userScriptMap = arguments!["userScript"] as! [String: Any?]
|
let userScriptMap = arguments!["userScript"] as! [String: Any?]
|
||||||
let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView?.windowId)!
|
let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView?.windowId)!
|
||||||
webView?.configuration.userContentController.removeUserOnlyScript(at: index, injectionTime: userScript.injectionTime)
|
webView?.configuration.userContentController.removeUserOnlyScript(at: index, injectionTime: userScript.injectionTime)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "removeUserScriptsByGroupName":
|
case .removeUserScriptsByGroupName:
|
||||||
let groupName = arguments!["groupName"] as! String
|
let groupName = arguments!["groupName"] as! String
|
||||||
webView?.configuration.userContentController.removeUserOnlyScripts(with: groupName)
|
webView?.configuration.userContentController.removeUserOnlyScripts(with: groupName)
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "removeAllUserScripts":
|
case .removeAllUserScripts:
|
||||||
webView?.configuration.userContentController.removeAllUserOnlyScripts()
|
webView?.configuration.userContentController.removeAllUserOnlyScripts()
|
||||||
result(true)
|
result(true)
|
||||||
break
|
break
|
||||||
case "callAsyncJavaScript":
|
case .callAsyncJavaScript:
|
||||||
if let webView = webView, #available(iOS 10.3, *) {
|
if let webView = webView, #available(iOS 10.3, *) {
|
||||||
if #available(iOS 14.0, *) {
|
if #available(iOS 14.0, *) {
|
||||||
let functionBody = arguments!["functionBody"] as! String
|
let functionBody = arguments!["functionBody"] as! String
|
||||||
|
@ -436,7 +441,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "createPdf":
|
case .createPdf:
|
||||||
if let webView = webView, #available(iOS 14.0, *) {
|
if let webView = webView, #available(iOS 14.0, *) {
|
||||||
let configuration = arguments!["pdfConfiguration"] as? [String: Any?]
|
let configuration = arguments!["pdfConfiguration"] as? [String: Any?]
|
||||||
webView.createPdf(configuration: configuration, completionHandler: { (pdf) -> Void in
|
webView.createPdf(configuration: configuration, completionHandler: { (pdf) -> Void in
|
||||||
|
@ -447,7 +452,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "createWebArchiveData":
|
case .createWebArchiveData:
|
||||||
if let webView = webView, #available(iOS 14.0, *) {
|
if let webView = webView, #available(iOS 14.0, *) {
|
||||||
webView.createWebArchiveData(dataCompletionHandler: { (webArchiveData) -> Void in
|
webView.createWebArchiveData(dataCompletionHandler: { (webArchiveData) -> Void in
|
||||||
result(webArchiveData)
|
result(webArchiveData)
|
||||||
|
@ -457,7 +462,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "saveWebArchive":
|
case .saveWebArchive:
|
||||||
if let webView = webView, #available(iOS 14.0, *) {
|
if let webView = webView, #available(iOS 14.0, *) {
|
||||||
let filePath = arguments!["filePath"] as! String
|
let filePath = arguments!["filePath"] as! String
|
||||||
let autoname = arguments!["autoname"] as! Bool
|
let autoname = arguments!["autoname"] as! Bool
|
||||||
|
@ -469,7 +474,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "isSecureContext":
|
case .isSecureContext:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
webView.isSecureContext(completionHandler: { (isSecureContext) in
|
webView.isSecureContext(completionHandler: { (isSecureContext) in
|
||||||
result(isSecureContext)
|
result(isSecureContext)
|
||||||
|
@ -479,7 +484,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "createWebMessageChannel":
|
case .createWebMessageChannel:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
let _ = webView.createWebMessageChannel { (webMessageChannel) in
|
let _ = webView.createWebMessageChannel { (webMessageChannel) in
|
||||||
result(webMessageChannel.toMap())
|
result(webMessageChannel.toMap())
|
||||||
|
@ -488,7 +493,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "postWebMessage":
|
case .postWebMessage:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
let message = arguments!["message"] as! [String: Any?]
|
let message = arguments!["message"] as! [String: Any?]
|
||||||
let targetOrigin = arguments!["targetOrigin"] as! String
|
let targetOrigin = arguments!["targetOrigin"] as! String
|
||||||
|
@ -516,7 +521,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "addWebMessageListener":
|
case .addWebMessageListener:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
let webMessageListenerMap = arguments!["webMessageListener"] as! [String: Any?]
|
let webMessageListenerMap = arguments!["webMessageListener"] as! [String: Any?]
|
||||||
let webMessageListener = WebMessageListener.fromMap(map: webMessageListenerMap)!
|
let webMessageListener = WebMessageListener.fromMap(map: webMessageListenerMap)!
|
||||||
|
@ -530,21 +535,21 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "canScrollVertically":
|
case .canScrollVertically:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
result(webView.canScrollVertically())
|
result(webView.canScrollVertically())
|
||||||
} else {
|
} else {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "canScrollHorizontally":
|
case .canScrollHorizontally:
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
result(webView.canScrollHorizontally())
|
result(webView.canScrollHorizontally())
|
||||||
} else {
|
} else {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "pauseAllMediaPlayback":
|
case .pauseAllMediaPlayback:
|
||||||
if let webView = webView, #available(iOS 15.0, *) {
|
if let webView = webView, #available(iOS 15.0, *) {
|
||||||
webView.pauseAllMediaPlayback(completionHandler: { () -> Void in
|
webView.pauseAllMediaPlayback(completionHandler: { () -> Void in
|
||||||
result(true)
|
result(true)
|
||||||
|
@ -553,7 +558,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "setAllMediaPlaybackSuspended":
|
case .setAllMediaPlaybackSuspended:
|
||||||
if let webView = webView, #available(iOS 15.0, *) {
|
if let webView = webView, #available(iOS 15.0, *) {
|
||||||
let suspended = arguments!["suspended"] as! Bool
|
let suspended = arguments!["suspended"] as! Bool
|
||||||
webView.setAllMediaPlaybackSuspended(suspended, completionHandler: { () -> Void in
|
webView.setAllMediaPlaybackSuspended(suspended, completionHandler: { () -> Void in
|
||||||
|
@ -563,7 +568,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "closeAllMediaPresentations":
|
case .closeAllMediaPresentations:
|
||||||
if let webView = self.webView, #available(iOS 14.5, *) {
|
if let webView = self.webView, #available(iOS 14.5, *) {
|
||||||
// closeAllMediaPresentations with completionHandler v15.0 makes the app crash
|
// closeAllMediaPresentations with completionHandler v15.0 makes the app crash
|
||||||
// with error EXC_BAD_ACCESS, so use closeAllMediaPresentations v14.5
|
// with error EXC_BAD_ACCESS, so use closeAllMediaPresentations v14.5
|
||||||
|
@ -573,7 +578,7 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "requestMediaPlaybackState":
|
case .requestMediaPlaybackState:
|
||||||
if let webView = webView, #available(iOS 15.0, *) {
|
if let webView = webView, #available(iOS 15.0, *) {
|
||||||
webView.requestMediaPlaybackState(completionHandler: { (state) -> Void in
|
webView.requestMediaPlaybackState(completionHandler: { (state) -> Void in
|
||||||
result(state.rawValue)
|
result(state.rawValue)
|
||||||
|
@ -582,32 +587,33 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "getMetaThemeColor":
|
case .getMetaThemeColor:
|
||||||
if let webView = webView, #available(iOS 15.0, *) {
|
if let webView = webView, #available(iOS 15.0, *) {
|
||||||
result(webView.themeColor?.hexString)
|
result(webView.themeColor?.hexString)
|
||||||
} else {
|
} else {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "isInFullscreen":
|
case .isInFullscreen:
|
||||||
// if let webView = webView, #available(iOS 15.0, *) {
|
|
||||||
// result(webView.fullscreenState == .inFullscreen)
|
|
||||||
// }
|
|
||||||
if let webView = webView {
|
if let webView = webView {
|
||||||
result(webView.inFullscreen)
|
if #available(iOS 16.0, *) {
|
||||||
|
result(webView.fullscreenState == .inFullscreen)
|
||||||
|
} else {
|
||||||
|
result(webView.inFullscreen)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "getCameraCaptureState":
|
case .getCameraCaptureState:
|
||||||
if let webView = webView, #available(iOS 15.0, *) {
|
if let webView = webView, #available(iOS 15.0, *) {
|
||||||
result(webView.cameraCaptureState.rawValue)
|
result(webView.cameraCaptureState.rawValue)
|
||||||
} else {
|
} else {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "setCameraCaptureState":
|
case .setCameraCaptureState:
|
||||||
if let webView = webView, #available(iOS 15.0, *) {
|
if let webView = webView, #available(iOS 15.0, *) {
|
||||||
let state = WKMediaCaptureState.init(rawValue: arguments!["state"] as! Int) ?? WKMediaCaptureState.none
|
let state = WKMediaCaptureState.init(rawValue: arguments!["state"] as! Int) ?? WKMediaCaptureState.none
|
||||||
webView.setCameraCaptureState(state) {
|
webView.setCameraCaptureState(state) {
|
||||||
|
@ -617,14 +623,14 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "getMicrophoneCaptureState":
|
case .getMicrophoneCaptureState:
|
||||||
if let webView = webView, #available(iOS 15.0, *) {
|
if let webView = webView, #available(iOS 15.0, *) {
|
||||||
result(webView.microphoneCaptureState.rawValue)
|
result(webView.microphoneCaptureState.rawValue)
|
||||||
} else {
|
} else {
|
||||||
result(nil)
|
result(nil)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "setMicrophoneCaptureState":
|
case .setMicrophoneCaptureState:
|
||||||
if let webView = webView, #available(iOS 15.0, *) {
|
if let webView = webView, #available(iOS 15.0, *) {
|
||||||
let state = WKMediaCaptureState.init(rawValue: arguments!["state"] as! Int) ?? WKMediaCaptureState.none
|
let state = WKMediaCaptureState.init(rawValue: arguments!["state"] as! Int) ?? WKMediaCaptureState.none
|
||||||
webView.setMicrophoneCaptureState(state) {
|
webView.setMicrophoneCaptureState(state) {
|
||||||
|
@ -634,12 +640,10 @@ public class WebViewChannelDelegate : ChannelDelegate {
|
||||||
result(false)
|
result(false)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
default:
|
|
||||||
result(FlutterMethodNotImplemented)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, deprecated, message: "Use FindInteractionChannelDelegate.onFindResultReceived instead.")
|
||||||
public func onFindResultReceived(activeMatchOrdinal: Int, numberOfMatches: Int, isDoneCounting: Bool) {
|
public func onFindResultReceived(activeMatchOrdinal: Int, numberOfMatches: Int, isDoneCounting: Bool) {
|
||||||
let arguments: [String : Any?] = [
|
let arguments: [String : Any?] = [
|
||||||
"activeMatchOrdinal": activeMatchOrdinal,
|
"activeMatchOrdinal": activeMatchOrdinal,
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
//
|
||||||
|
// WebViewChannelDelegateMethods.swift
|
||||||
|
// flutter_inappwebview
|
||||||
|
//
|
||||||
|
// Created by Lorenzo Pichilli on 08/10/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public enum WebViewChannelDelegateMethods: String {
|
||||||
|
case getUrl = "getUrl"
|
||||||
|
case getTitle = "getTitle"
|
||||||
|
case getProgress = "getProgress"
|
||||||
|
case loadUrl = "loadUrl"
|
||||||
|
case postUrl = "postUrl"
|
||||||
|
case loadData = "loadData"
|
||||||
|
case loadFile = "loadFile"
|
||||||
|
case evaluateJavascript = "evaluateJavascript"
|
||||||
|
case injectJavascriptFileFromUrl = "injectJavascriptFileFromUrl"
|
||||||
|
case injectCSSCode = "injectCSSCode"
|
||||||
|
case injectCSSFileFromUrl = "injectCSSFileFromUrl"
|
||||||
|
case reload = "reload"
|
||||||
|
case goBack = "goBack"
|
||||||
|
case canGoBack = "canGoBack"
|
||||||
|
case goForward = "goForward"
|
||||||
|
case canGoForward = "canGoForward"
|
||||||
|
case goBackOrForward = "goBackOrForward"
|
||||||
|
case canGoBackOrForward = "canGoBackOrForward"
|
||||||
|
case stopLoading = "stopLoading"
|
||||||
|
case isLoading = "isLoading"
|
||||||
|
case takeScreenshot = "takeScreenshot"
|
||||||
|
case setSettings = "setSettings"
|
||||||
|
case getSettings = "getSettings"
|
||||||
|
case close = "close"
|
||||||
|
case show = "show"
|
||||||
|
case hide = "hide"
|
||||||
|
case getCopyBackForwardList = "getCopyBackForwardList"
|
||||||
|
@available(*, deprecated, message: "Use FindInteractionController.findAllAsync instead.")
|
||||||
|
case findAllAsync = "findAllAsync"
|
||||||
|
@available(*, deprecated, message: "Use FindInteractionController.findNext instead.")
|
||||||
|
case findNext = "findNext"
|
||||||
|
@available(*, deprecated, message: "Use FindInteractionController.clearMatches instead.")
|
||||||
|
case clearMatches = "clearMatches"
|
||||||
|
case clearCache = "clearCache"
|
||||||
|
case scrollTo = "scrollTo"
|
||||||
|
case scrollBy = "scrollBy"
|
||||||
|
case pauseTimers = "pauseTimers"
|
||||||
|
case resumeTimers = "resumeTimers"
|
||||||
|
case printCurrentPage = "printCurrentPage"
|
||||||
|
case getContentHeight = "getContentHeight"
|
||||||
|
case zoomBy = "zoomBy"
|
||||||
|
case reloadFromOrigin = "reloadFromOrigin"
|
||||||
|
case getOriginalUrl = "getOriginalUrl"
|
||||||
|
case getZoomScale = "getZoomScale"
|
||||||
|
case hasOnlySecureContent = "hasOnlySecureContent"
|
||||||
|
case getSelectedText = "getSelectedText"
|
||||||
|
case getHitTestResult = "getHitTestResult"
|
||||||
|
case clearFocus = "clearFocus"
|
||||||
|
case setContextMenu = "setContextMenu"
|
||||||
|
case requestFocusNodeHref = "requestFocusNodeHref"
|
||||||
|
case requestImageRef = "requestImageRef"
|
||||||
|
case getScrollX = "getScrollX"
|
||||||
|
case getScrollY = "getScrollY"
|
||||||
|
case getCertificate = "getCertificate"
|
||||||
|
case addUserScript = "addUserScript"
|
||||||
|
case removeUserScript = "removeUserScript"
|
||||||
|
case removeUserScriptsByGroupName = "removeUserScriptsByGroupName"
|
||||||
|
case removeAllUserScripts = "removeAllUserScripts"
|
||||||
|
case callAsyncJavaScript = "callAsyncJavaScript"
|
||||||
|
case createPdf = "createPdf"
|
||||||
|
case createWebArchiveData = "createWebArchiveData"
|
||||||
|
case saveWebArchive = "saveWebArchive"
|
||||||
|
case isSecureContext = "isSecureContext"
|
||||||
|
case createWebMessageChannel = "createWebMessageChannel"
|
||||||
|
case postWebMessage = "postWebMessage"
|
||||||
|
case addWebMessageListener = "addWebMessageListener"
|
||||||
|
case canScrollVertically = "canScrollVertically"
|
||||||
|
case canScrollHorizontally = "canScrollHorizontally"
|
||||||
|
case pauseAllMediaPlayback = "pauseAllMediaPlayback"
|
||||||
|
case setAllMediaPlaybackSuspended = "setAllMediaPlaybackSuspended"
|
||||||
|
case closeAllMediaPresentations = "closeAllMediaPresentations"
|
||||||
|
case requestMediaPlaybackState = "requestMediaPlaybackState"
|
||||||
|
case getMetaThemeColor = "getMetaThemeColor"
|
||||||
|
case isInFullscreen = "isInFullscreen"
|
||||||
|
case getCameraCaptureState = "getCameraCaptureState"
|
||||||
|
case setCameraCaptureState = "setCameraCaptureState"
|
||||||
|
case getMicrophoneCaptureState = "getMicrophoneCaptureState"
|
||||||
|
case setMicrophoneCaptureState = "setMicrophoneCaptureState"
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ window.\(JAVASCRIPT_BRIDGE_NAME)._findAllAsyncForElement = function(element, key
|
||||||
|
|
||||||
span.setAttribute(
|
span.setAttribute(
|
||||||
"id",
|
"id",
|
||||||
"WKWEBVIEW_SEARCH_WORD_" + \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE)
|
"\(JAVASCRIPT_BRIDGE_NAME)_SEARCH_WORD_" + \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE)
|
||||||
);
|
);
|
||||||
span.setAttribute("class", "\(JAVASCRIPT_BRIDGE_NAME)_Highlight");
|
span.setAttribute("class", "\(JAVASCRIPT_BRIDGE_NAME)_Highlight");
|
||||||
var backgroundColor = \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE) == 0 ? "#FF9732" : "#FFFF00";
|
var backgroundColor = \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE) == 0 ? "#FF9732" : "#FFFF00";
|
||||||
|
|
|
@ -28,17 +28,17 @@ public class PullToRefreshControl : UIRefreshControl, Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func prepare() {
|
public func prepare() {
|
||||||
if let options = settings {
|
if let settings = settings {
|
||||||
if options.enabled {
|
if settings.enabled {
|
||||||
delegate?.enablePullToRefresh()
|
delegate?.enablePullToRefresh()
|
||||||
}
|
}
|
||||||
if let color = options.color, !color.isEmpty {
|
if let color = settings.color, !color.isEmpty {
|
||||||
tintColor = UIColor(hexString: color)
|
tintColor = UIColor(hexString: color)
|
||||||
}
|
}
|
||||||
if let backgroundTintColor = options.backgroundColor, !backgroundTintColor.isEmpty {
|
if let backgroundTintColor = settings.backgroundColor, !backgroundTintColor.isEmpty {
|
||||||
backgroundColor = UIColor(hexString: backgroundTintColor)
|
backgroundColor = UIColor(hexString: backgroundTintColor)
|
||||||
}
|
}
|
||||||
if let attributedTitleMap = options.attributedTitle {
|
if let attributedTitleMap = settings.attributedTitle {
|
||||||
attributedTitle = NSAttributedString.fromMap(map: attributedTitleMap)
|
attributedTitle = NSAttributedString.fromMap(map: attributedTitleMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
//
|
||||||
|
// UIFindSession.swift
|
||||||
|
// flutter_inappwebview
|
||||||
|
//
|
||||||
|
// Created by Lorenzo Pichilli on 07/10/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@available(iOS 16.0, *)
|
||||||
|
extension UIFindSession {
|
||||||
|
public func toMap () -> [String:Any?] {
|
||||||
|
return [
|
||||||
|
"resultCount": resultCount,
|
||||||
|
"highlightedResultIndex": highlightedResultIndex,
|
||||||
|
"searchResultDisplayStyle": searchResultDisplayStyle.rawValue
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,6 +62,10 @@ class WebViewFeature {
|
||||||
static const PROXY_OVERRIDE =
|
static const PROXY_OVERRIDE =
|
||||||
WebViewFeature._internal('PROXY_OVERRIDE', 'PROXY_OVERRIDE');
|
WebViewFeature._internal('PROXY_OVERRIDE', 'PROXY_OVERRIDE');
|
||||||
|
|
||||||
|
///This feature covers [ProxySettings.reverseBypassEnabled].
|
||||||
|
static const PROXY_OVERRIDE_REVERSE_BYPASS = WebViewFeature._internal(
|
||||||
|
'PROXY_OVERRIDE_REVERSE_BYPASS', 'PROXY_OVERRIDE_REVERSE_BYPASS');
|
||||||
|
|
||||||
///
|
///
|
||||||
static const RECEIVE_HTTP_ERROR =
|
static const RECEIVE_HTTP_ERROR =
|
||||||
WebViewFeature._internal('RECEIVE_HTTP_ERROR', 'RECEIVE_HTTP_ERROR');
|
WebViewFeature._internal('RECEIVE_HTTP_ERROR', 'RECEIVE_HTTP_ERROR');
|
||||||
|
@ -223,6 +227,7 @@ class WebViewFeature {
|
||||||
WebViewFeature.OFF_SCREEN_PRERASTER,
|
WebViewFeature.OFF_SCREEN_PRERASTER,
|
||||||
WebViewFeature.POST_WEB_MESSAGE,
|
WebViewFeature.POST_WEB_MESSAGE,
|
||||||
WebViewFeature.PROXY_OVERRIDE,
|
WebViewFeature.PROXY_OVERRIDE,
|
||||||
|
WebViewFeature.PROXY_OVERRIDE_REVERSE_BYPASS,
|
||||||
WebViewFeature.RECEIVE_HTTP_ERROR,
|
WebViewFeature.RECEIVE_HTTP_ERROR,
|
||||||
WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR,
|
WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR,
|
||||||
WebViewFeature.SAFE_BROWSING_ALLOWLIST,
|
WebViewFeature.SAFE_BROWSING_ALLOWLIST,
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
import 'dart:developer' as developer;
|
||||||
|
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import '../in_app_webview/in_app_webview_settings.dart';
|
||||||
|
import '../debug_logging_settings.dart';
|
||||||
|
import '../types/main.dart';
|
||||||
|
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
|
class FindInteractionController {
|
||||||
|
MethodChannel? _channel;
|
||||||
|
|
||||||
|
///Debug settings.
|
||||||
|
static DebugLoggingSettings debugLoggingSettings = DebugLoggingSettings();
|
||||||
|
|
||||||
|
///Event fired as find-on-page operations progress.
|
||||||
|
///The listener may be notified multiple times while the operation is underway, and the [numberOfMatches] value should not be considered final unless [isDoneCounting] is true.
|
||||||
|
///
|
||||||
|
///[activeMatchOrdinal] represents the zero-based ordinal of the currently selected match.
|
||||||
|
///
|
||||||
|
///[numberOfMatches] represents how many matches have been found.
|
||||||
|
///
|
||||||
|
///[isDoneCounting] whether the find operation has actually completed.
|
||||||
|
///
|
||||||
|
///**NOTE**: on iOS, if [InAppWebViewSettings.isFindInteractionEnabled] is `true`, this event will not be called.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView ([Official API - WebView.FindListener.onFindResultReceived](https://developer.android.com/reference/android/webkit/WebView.FindListener#onFindResultReceived(int,%20int,%20boolean)))
|
||||||
|
///- iOS
|
||||||
|
final void Function(
|
||||||
|
FindInteractionController controller,
|
||||||
|
int activeMatchOrdinal,
|
||||||
|
int numberOfMatches,
|
||||||
|
bool isDoneCounting)? onFindResultReceived;
|
||||||
|
|
||||||
|
FindInteractionController({this.onFindResultReceived}) {}
|
||||||
|
|
||||||
|
void initMethodChannel(dynamic id) {
|
||||||
|
this._channel = MethodChannel(
|
||||||
|
'com.pichillilorenzo/flutter_inappwebview_find_interaction_$id');
|
||||||
|
|
||||||
|
this._channel?.setMethodCallHandler((call) async {
|
||||||
|
try {
|
||||||
|
return await _handleMethod(call);
|
||||||
|
} on Error catch (e) {
|
||||||
|
print(e);
|
||||||
|
print(e.stackTrace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_debugLog(String method, dynamic args) {
|
||||||
|
if (FindInteractionController.debugLoggingSettings.enabled) {
|
||||||
|
for (var regExp
|
||||||
|
in FindInteractionController.debugLoggingSettings.excludeFilter) {
|
||||||
|
if (regExp.hasMatch(method)) return;
|
||||||
|
}
|
||||||
|
var maxLogMessageLength =
|
||||||
|
FindInteractionController.debugLoggingSettings.maxLogMessageLength;
|
||||||
|
String message = "FindInteractionController " +
|
||||||
|
" calling \"" +
|
||||||
|
method.toString() +
|
||||||
|
"\" using " +
|
||||||
|
args.toString();
|
||||||
|
if (maxLogMessageLength >= 0 && message.length > maxLogMessageLength) {
|
||||||
|
message = message.substring(0, maxLogMessageLength) + "...";
|
||||||
|
}
|
||||||
|
if (!FindInteractionController.debugLoggingSettings.usePrint) {
|
||||||
|
developer.log(message, name: this.runtimeType.toString());
|
||||||
|
} else {
|
||||||
|
print("[${this.runtimeType.toString()}] $message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> _handleMethod(MethodCall call) async {
|
||||||
|
_debugLog(call.method, call.arguments);
|
||||||
|
|
||||||
|
switch (call.method) {
|
||||||
|
case "onFindResultReceived":
|
||||||
|
if (onFindResultReceived != null) {
|
||||||
|
int activeMatchOrdinal = call.arguments["activeMatchOrdinal"];
|
||||||
|
int numberOfMatches = call.arguments["numberOfMatches"];
|
||||||
|
bool isDoneCounting = call.arguments["isDoneCounting"];
|
||||||
|
onFindResultReceived!(
|
||||||
|
this, activeMatchOrdinal, numberOfMatches, isDoneCounting);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw UnimplementedError("Unimplemented ${call.method} method");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Finds all instances of find on the page and highlights them. Notifies [FindInteractionController.onFindResultReceived] listener.
|
||||||
|
///
|
||||||
|
///[find] represents the string to find.
|
||||||
|
///
|
||||||
|
///**NOTE**: on Android native WebView, it finds all instances asynchronously. Successive calls to this will cancel any pending searches.
|
||||||
|
///
|
||||||
|
///**NOTE**: on iOS, if [InAppWebViewSettings.isFindInteractionEnabled] is `true`,
|
||||||
|
///it uses the built-in find interaction native UI,
|
||||||
|
///otherwise this is implemented using CSS and Javascript.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView ([Official API - WebView.findAllAsync](https://developer.android.com/reference/android/webkit/WebView#findAllAsync(java.lang.String)))
|
||||||
|
///- iOS (if [InAppWebViewSettings.isFindInteractionEnabled] is `true`: [Official API - UIFindInteraction.presentFindNavigator](https://developer.apple.com/documentation/uikit/uifindinteraction/3975832-presentfindnavigator?changes=_2) with [Official API - UIFindInteraction.searchText](https://developer.apple.com/documentation/uikit/uifindinteraction/3975834-searchtext?changes=_2))
|
||||||
|
Future<void> findAllAsync({required String find}) async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
args.putIfAbsent('find', () => find);
|
||||||
|
await _channel?.invokeMethod('findAllAsync', args);
|
||||||
|
}
|
||||||
|
|
||||||
|
///Highlights and scrolls to the next match found by [findAllAsync]. Notifies [FindInteractionController.onFindResultReceived] listener.
|
||||||
|
///
|
||||||
|
///[forward] represents the direction to search.
|
||||||
|
///
|
||||||
|
///**NOTE**: on iOS, if [InAppWebViewSettings.isFindInteractionEnabled] is `true`,
|
||||||
|
///it uses the built-in find interaction native UI,
|
||||||
|
///otherwise this is implemented using CSS and Javascript.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView ([Official API - WebView.findNext](https://developer.android.com/reference/android/webkit/WebView#findNext(boolean)))
|
||||||
|
///- iOS (if [InAppWebViewSettings.isFindInteractionEnabled] is `true`: [Official API - UIFindInteraction.findNext](https://developer.apple.com/documentation/uikit/uifindinteraction/3975829-findnext?changes=_2) and ([Official API - UIFindInteraction.findPrevious](https://developer.apple.com/documentation/uikit/uifindinteraction/3975830-findprevious?changes=_2)))
|
||||||
|
Future<void> findNext({required bool forward}) async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
args.putIfAbsent('forward', () => forward);
|
||||||
|
await _channel?.invokeMethod('findNext', args);
|
||||||
|
}
|
||||||
|
|
||||||
|
///Clears the highlighting surrounding text matches created by [findAllAsync].
|
||||||
|
///
|
||||||
|
///**NOTE**: on iOS, if [InAppWebViewSettings.isFindInteractionEnabled] is `true`,
|
||||||
|
///it uses the built-in find interaction native UI,
|
||||||
|
///otherwise this is implemented using CSS and Javascript.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView ([Official API - WebView.clearMatches](https://developer.android.com/reference/android/webkit/WebView#clearMatches()))
|
||||||
|
///- iOS (if [InAppWebViewSettings.isFindInteractionEnabled] is `true`: [Official API - UIFindInteraction.dismissFindNavigator](https://developer.apple.com/documentation/uikit/uifindinteraction/3975827-dismissfindnavigator?changes=_2))
|
||||||
|
Future<void> clearMatches() async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
await _channel?.invokeMethod('clearMatches', args);
|
||||||
|
}
|
||||||
|
|
||||||
|
///Pre-populate the system find panel's search text field with a search query.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only on iOS and only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- iOS ([Official API - UIFindInteraction.searchText](https://developer.apple.com/documentation/uikit/uifindinteraction/3975834-searchtext?changes=_2))
|
||||||
|
Future<void> setSearchText(String? searchText) async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
args.putIfAbsent('searchText', () => searchText);
|
||||||
|
await _channel?.invokeMethod('setSearchText', args);
|
||||||
|
}
|
||||||
|
|
||||||
|
///Get the system find panel's search text field value.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only on iOS and only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- iOS ([Official API - UIFindInteraction.searchText](https://developer.apple.com/documentation/uikit/uifindinteraction/3975834-searchtext?changes=_2))
|
||||||
|
Future<String?> getSearchText() async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
return await _channel?.invokeMethod('getSearchText', args);
|
||||||
|
}
|
||||||
|
|
||||||
|
///A Boolean value that indicates when the find panel displays onscreen.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only on iOS and only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- iOS ([Official API - UIFindInteraction.isFindNavigatorVisible](https://developer.apple.com/documentation/uikit/uifindinteraction/3975828-isfindnavigatorvisible?changes=_2))
|
||||||
|
Future<bool?> isFindNavigatorVisible() async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
return await _channel?.invokeMethod('isFindNavigatorVisible', args);
|
||||||
|
}
|
||||||
|
|
||||||
|
///Updates the results the interface displays for the active search.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only on iOS and only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- iOS ([Official API - UIFindInteraction.updateResultCount](https://developer.apple.com/documentation/uikit/uifindinteraction/3975835-updateresultcount?changes=_2))
|
||||||
|
Future<void> updateResultCount() async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
await _channel?.invokeMethod('updateResultCount', args);
|
||||||
|
}
|
||||||
|
|
||||||
|
///Begins a search, displaying the find panel.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only on iOS and only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- iOS ([Official API - UIFindInteraction.presentFindNavigator](https://developer.apple.com/documentation/uikit/uifindinteraction/3975832-presentfindnavigator?changes=_2))
|
||||||
|
Future<void> presentFindNavigator() async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
await _channel?.invokeMethod('presentFindNavigator', args);
|
||||||
|
}
|
||||||
|
|
||||||
|
///Dismisses the find panel, if present.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only on iOS and only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- iOS ([Official API - UIFindInteraction.dismissFindNavigator](https://developer.apple.com/documentation/uikit/uifindinteraction/3975827-dismissfindnavigator?changes=_2))
|
||||||
|
Future<void> dismissFindNavigator() async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
await _channel?.invokeMethod('dismissFindNavigator', args);
|
||||||
|
}
|
||||||
|
|
||||||
|
///If there's a currently active find session (implying [isFindNavigatorVisible] is `true`), returns the active find session.
|
||||||
|
///
|
||||||
|
///**NOTE**: available only on iOS and only if [InAppWebViewSettings.isFindInteractionEnabled] is `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- iOS ([Official API - UIFindInteraction.activeFindSession](https://developer.apple.com/documentation/uikit/uifindinteraction/3975825-activefindsession?changes=_7____4_8&language=objc))
|
||||||
|
Future<FindSession?> getActiveFindSession() async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
Map<String, dynamic>? result =
|
||||||
|
(await _channel?.invokeMethod('getActiveFindSession', args))
|
||||||
|
?.cast<String, dynamic>();
|
||||||
|
return FindSession.fromMap(result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export 'find_interaction_controller.dart';
|
|
@ -6,6 +6,7 @@ import 'dart:developer' as developer;
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import '../context_menu.dart';
|
import '../context_menu.dart';
|
||||||
|
import '../find_interaction/find_interaction_controller.dart';
|
||||||
import '../pull_to_refresh/main.dart';
|
import '../pull_to_refresh/main.dart';
|
||||||
import '../types/main.dart';
|
import '../types/main.dart';
|
||||||
|
|
||||||
|
@ -60,6 +61,9 @@ class InAppBrowser {
|
||||||
///Represents the pull-to-refresh feature controller.
|
///Represents the pull-to-refresh feature controller.
|
||||||
PullToRefreshController? pullToRefreshController;
|
PullToRefreshController? pullToRefreshController;
|
||||||
|
|
||||||
|
///Represents the find interaction feature controller.
|
||||||
|
FindInteractionController? findInteractionController;
|
||||||
|
|
||||||
///Initial list of user scripts to be loaded at start or end of a page loading.
|
///Initial list of user scripts to be loaded at start or end of a page loading.
|
||||||
final UnmodifiableListView<UserScript>? initialUserScripts;
|
final UnmodifiableListView<UserScript>? initialUserScripts;
|
||||||
|
|
||||||
|
@ -129,6 +133,7 @@ class InAppBrowser {
|
||||||
_debugLog(call.method, call.arguments);
|
_debugLog(call.method, call.arguments);
|
||||||
this._isOpened = true;
|
this._isOpened = true;
|
||||||
this.pullToRefreshController?.initMethodChannel(id);
|
this.pullToRefreshController?.initMethodChannel(id);
|
||||||
|
this.findInteractionController?.initMethodChannel(id);
|
||||||
onBrowserCreated();
|
onBrowserCreated();
|
||||||
break;
|
break;
|
||||||
case "onExit":
|
case "onExit":
|
||||||
|
@ -662,18 +667,8 @@ class InAppBrowser {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Event fired as find-on-page operations progress.
|
///Use [FindInteractionController.onFindResultReceived] instead.
|
||||||
///The listener may be notified multiple times while the operation is underway, and the [numberOfMatches] value should not be considered final unless [isDoneCounting] is true.
|
@Deprecated('Use FindInteractionController.onFindResultReceived instead')
|
||||||
///
|
|
||||||
///[activeMatchOrdinal] represents the zero-based ordinal of the currently selected match.
|
|
||||||
///
|
|
||||||
///[numberOfMatches] represents how many matches have been found.
|
|
||||||
///
|
|
||||||
///[isDoneCounting] whether the find operation has actually completed.
|
|
||||||
///
|
|
||||||
///**Supported Platforms/Implementations**:
|
|
||||||
///- Android native WebView ([Official API - WebView.FindListener.onFindResultReceived](https://developer.android.com/reference/android/webkit/WebView.FindListener#onFindResultReceived(int,%20int,%20boolean)))
|
|
||||||
///- iOS
|
|
||||||
void onFindResultReceived(
|
void onFindResultReceived(
|
||||||
int activeMatchOrdinal, int numberOfMatches, bool isDoneCounting) {}
|
int activeMatchOrdinal, int numberOfMatches, bool isDoneCounting) {}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_inappwebview/src/util.dart';
|
import 'package:flutter_inappwebview/src/util.dart';
|
||||||
|
|
||||||
import '../context_menu.dart';
|
import '../context_menu.dart';
|
||||||
|
import '../find_interaction/find_interaction_controller.dart';
|
||||||
import '../types/main.dart';
|
import '../types/main.dart';
|
||||||
import '../print_job/main.dart';
|
import '../print_job/main.dart';
|
||||||
import 'webview.dart';
|
import 'webview.dart';
|
||||||
|
@ -61,6 +62,7 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
||||||
this.contextMenu,
|
this.contextMenu,
|
||||||
this.initialUserScripts,
|
this.initialUserScripts,
|
||||||
this.pullToRefreshController,
|
this.pullToRefreshController,
|
||||||
|
this.findInteractionController,
|
||||||
this.implementation = WebViewImplementation.NATIVE,
|
this.implementation = WebViewImplementation.NATIVE,
|
||||||
this.onWebViewCreated,
|
this.onWebViewCreated,
|
||||||
this.onLoadStart,
|
this.onLoadStart,
|
||||||
|
@ -87,6 +89,7 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
||||||
this.onReceivedHttpAuthRequest,
|
this.onReceivedHttpAuthRequest,
|
||||||
this.onReceivedServerTrustAuthRequest,
|
this.onReceivedServerTrustAuthRequest,
|
||||||
this.onReceivedClientCertRequest,
|
this.onReceivedClientCertRequest,
|
||||||
|
@Deprecated('Use FindInteractionController.onFindResultReceived instead')
|
||||||
this.onFindResultReceived,
|
this.onFindResultReceived,
|
||||||
this.shouldInterceptAjaxRequest,
|
this.shouldInterceptAjaxRequest,
|
||||||
this.onAjaxReadyStateChange,
|
this.onAjaxReadyStateChange,
|
||||||
|
@ -173,6 +176,7 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
||||||
switch (call.method) {
|
switch (call.method) {
|
||||||
case "onWebViewCreated":
|
case "onWebViewCreated":
|
||||||
pullToRefreshController?.initMethodChannel(id);
|
pullToRefreshController?.initMethodChannel(id);
|
||||||
|
findInteractionController?.initMethodChannel(id);
|
||||||
if (onWebViewCreated != null) {
|
if (onWebViewCreated != null) {
|
||||||
onWebViewCreated!(webViewController);
|
onWebViewCreated!(webViewController);
|
||||||
}
|
}
|
||||||
|
@ -323,6 +327,9 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
||||||
@override
|
@override
|
||||||
final PullToRefreshController? pullToRefreshController;
|
final PullToRefreshController? pullToRefreshController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final FindInteractionController? findInteractionController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final WebViewImplementation implementation;
|
final WebViewImplementation implementation;
|
||||||
|
|
||||||
|
@ -422,6 +429,8 @@ class HeadlessInAppWebView implements WebView, Disposable {
|
||||||
void Function(InAppWebViewController controller,
|
void Function(InAppWebViewController controller,
|
||||||
DownloadStartRequest downloadStartRequest)? onDownloadStartRequest;
|
DownloadStartRequest downloadStartRequest)? onDownloadStartRequest;
|
||||||
|
|
||||||
|
///Use [FindInteractionController.onFindResultReceived] instead.
|
||||||
|
@Deprecated('Use FindInteractionController.onFindResultReceived instead')
|
||||||
@override
|
@override
|
||||||
void Function(InAppWebViewController controller, int activeMatchOrdinal,
|
void Function(InAppWebViewController controller, int activeMatchOrdinal,
|
||||||
int numberOfMatches, bool isDoneCounting)? onFindResultReceived;
|
int numberOfMatches, bool isDoneCounting)? onFindResultReceived;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
|
|
||||||
|
import '../find_interaction/find_interaction_controller.dart';
|
||||||
import '../web/web_platform_manager.dart';
|
import '../web/web_platform_manager.dart';
|
||||||
|
|
||||||
import '../context_menu.dart';
|
import '../context_menu.dart';
|
||||||
|
@ -50,6 +51,7 @@ class InAppWebView extends StatefulWidget implements WebView {
|
||||||
this.initialSettings,
|
this.initialSettings,
|
||||||
this.initialUserScripts,
|
this.initialUserScripts,
|
||||||
this.pullToRefreshController,
|
this.pullToRefreshController,
|
||||||
|
this.findInteractionController,
|
||||||
this.implementation = WebViewImplementation.NATIVE,
|
this.implementation = WebViewImplementation.NATIVE,
|
||||||
this.contextMenu,
|
this.contextMenu,
|
||||||
this.onWebViewCreated,
|
this.onWebViewCreated,
|
||||||
|
@ -77,6 +79,7 @@ class InAppWebView extends StatefulWidget implements WebView {
|
||||||
this.onReceivedHttpAuthRequest,
|
this.onReceivedHttpAuthRequest,
|
||||||
this.onReceivedServerTrustAuthRequest,
|
this.onReceivedServerTrustAuthRequest,
|
||||||
this.onReceivedClientCertRequest,
|
this.onReceivedClientCertRequest,
|
||||||
|
@Deprecated('Use FindInteractionController.onFindResultReceived instead')
|
||||||
this.onFindResultReceived,
|
this.onFindResultReceived,
|
||||||
this.shouldInterceptAjaxRequest,
|
this.shouldInterceptAjaxRequest,
|
||||||
this.onAjaxReadyStateChange,
|
this.onAjaxReadyStateChange,
|
||||||
|
@ -206,6 +209,9 @@ class InAppWebView extends StatefulWidget implements WebView {
|
||||||
@override
|
@override
|
||||||
final PullToRefreshController? pullToRefreshController;
|
final PullToRefreshController? pullToRefreshController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final FindInteractionController? findInteractionController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final ContextMenu? contextMenu;
|
final ContextMenu? contextMenu;
|
||||||
|
|
||||||
|
@ -294,6 +300,8 @@ class InAppWebView extends StatefulWidget implements WebView {
|
||||||
final void Function(InAppWebViewController controller,
|
final void Function(InAppWebViewController controller,
|
||||||
DownloadStartRequest downloadStartRequest)? onDownloadStartRequest;
|
DownloadStartRequest downloadStartRequest)? onDownloadStartRequest;
|
||||||
|
|
||||||
|
///Use [FindInteractionController.onFindResultReceived] instead.
|
||||||
|
@Deprecated('Use FindInteractionController.onFindResultReceived instead')
|
||||||
@override
|
@override
|
||||||
final void Function(InAppWebViewController controller, int activeMatchOrdinal,
|
final void Function(InAppWebViewController controller, int activeMatchOrdinal,
|
||||||
int numberOfMatches, bool isDoneCounting)? onFindResultReceived;
|
int numberOfMatches, bool isDoneCounting)? onFindResultReceived;
|
||||||
|
@ -725,6 +733,7 @@ class _InAppWebViewState extends State<InAppWebView> {
|
||||||
void _onPlatformViewCreated(int id) {
|
void _onPlatformViewCreated(int id) {
|
||||||
_controller = InAppWebViewController(id, widget);
|
_controller = InAppWebViewController(id, widget);
|
||||||
widget.pullToRefreshController?.initMethodChannel(id);
|
widget.pullToRefreshController?.initMethodChannel(id);
|
||||||
|
widget.findInteractionController?.initMethodChannel(id);
|
||||||
if (widget.onWebViewCreated != null) {
|
if (widget.onWebViewCreated != null) {
|
||||||
widget.onWebViewCreated!(_controller!);
|
widget.onWebViewCreated!(_controller!);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import 'webview.dart';
|
||||||
import '_static_channel.dart';
|
import '_static_channel.dart';
|
||||||
|
|
||||||
import '../print_job/main.dart';
|
import '../print_job/main.dart';
|
||||||
|
import '../find_interaction/main.dart';
|
||||||
|
|
||||||
///List of forbidden names for JavaScript handlers.
|
///List of forbidden names for JavaScript handlers.
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
|
@ -804,17 +805,34 @@ class InAppWebViewController {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "onFindResultReceived":
|
case "onFindResultReceived":
|
||||||
if ((_webview != null && _webview!.onFindResultReceived != null) ||
|
if ((_webview != null && (_webview!.onFindResultReceived != null ||
|
||||||
|
(_webview!.findInteractionController != null && _webview!.findInteractionController!.onFindResultReceived != null))) ||
|
||||||
_inAppBrowser != null) {
|
_inAppBrowser != null) {
|
||||||
int activeMatchOrdinal = call.arguments["activeMatchOrdinal"];
|
int activeMatchOrdinal = call.arguments["activeMatchOrdinal"];
|
||||||
int numberOfMatches = call.arguments["numberOfMatches"];
|
int numberOfMatches = call.arguments["numberOfMatches"];
|
||||||
bool isDoneCounting = call.arguments["isDoneCounting"];
|
bool isDoneCounting = call.arguments["isDoneCounting"];
|
||||||
if (_webview != null && _webview!.onFindResultReceived != null)
|
if (_webview != null) {
|
||||||
_webview!.onFindResultReceived!(
|
if (_webview!.findInteractionController != null &&
|
||||||
|
_webview!.findInteractionController!.onFindResultReceived !=
|
||||||
|
null)
|
||||||
|
_webview!.findInteractionController!.onFindResultReceived!(
|
||||||
|
_webview!.findInteractionController!, activeMatchOrdinal,
|
||||||
|
numberOfMatches, isDoneCounting);
|
||||||
|
else
|
||||||
|
_webview!.onFindResultReceived!(
|
||||||
this, activeMatchOrdinal, numberOfMatches, isDoneCounting);
|
this, activeMatchOrdinal, numberOfMatches, isDoneCounting);
|
||||||
else
|
}
|
||||||
_inAppBrowser!.onFindResultReceived(
|
else {
|
||||||
activeMatchOrdinal, numberOfMatches, isDoneCounting);
|
if (_inAppBrowser!.findInteractionController != null &&
|
||||||
|
_inAppBrowser!.findInteractionController!
|
||||||
|
.onFindResultReceived != null)
|
||||||
|
_inAppBrowser!.findInteractionController!.onFindResultReceived!(
|
||||||
|
_webview!.findInteractionController!, activeMatchOrdinal,
|
||||||
|
numberOfMatches, isDoneCounting);
|
||||||
|
else
|
||||||
|
_inAppBrowser!.onFindResultReceived(
|
||||||
|
activeMatchOrdinal, numberOfMatches, isDoneCounting);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "onPermissionRequest":
|
case "onPermissionRequest":
|
||||||
|
@ -2159,45 +2177,24 @@ class InAppWebViewController {
|
||||||
await _channel.invokeMethod('clearCache', args);
|
await _channel.invokeMethod('clearCache', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
///Finds all instances of find on the page and highlights them. Notifies [WebView.onFindResultReceived] listener.
|
///Use [FindInteractionController.findAllAsync] instead.
|
||||||
///
|
@Deprecated("Use FindInteractionController.findAllAsync instead")
|
||||||
///[find] represents the string to find.
|
|
||||||
///
|
|
||||||
///**NOTE**: on Android native WebView, it finds all instances asynchronously. Successive calls to this will cancel any pending searches.
|
|
||||||
///
|
|
||||||
///**NOTE**: on iOS, this is implemented using CSS and Javascript.
|
|
||||||
///
|
|
||||||
///**Supported Platforms/Implementations**:
|
|
||||||
///- Android native WebView ([Official API - WebView.findAllAsync](https://developer.android.com/reference/android/webkit/WebView#findAllAsync(java.lang.String)))
|
|
||||||
///- iOS
|
|
||||||
Future<void> findAllAsync({required String find}) async {
|
Future<void> findAllAsync({required String find}) async {
|
||||||
Map<String, dynamic> args = <String, dynamic>{};
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
args.putIfAbsent('find', () => find);
|
args.putIfAbsent('find', () => find);
|
||||||
await _channel.invokeMethod('findAllAsync', args);
|
await _channel.invokeMethod('findAllAsync', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
///Highlights and scrolls to the next match found by [findAllAsync]. Notifies [WebView.onFindResultReceived] listener.
|
///Use [FindInteractionController.findNext] instead.
|
||||||
///
|
@Deprecated("Use FindInteractionController.findNext instead")
|
||||||
///[forward] represents the direction to search.
|
|
||||||
///
|
|
||||||
///**NOTE**: on iOS, this is implemented using CSS and Javascript.
|
|
||||||
///
|
|
||||||
///**Supported Platforms/Implementations**:
|
|
||||||
///- Android native WebView ([Official API - WebView.findNext](https://developer.android.com/reference/android/webkit/WebView#findNext(boolean)))
|
|
||||||
///- iOS
|
|
||||||
Future<void> findNext({required bool forward}) async {
|
Future<void> findNext({required bool forward}) async {
|
||||||
Map<String, dynamic> args = <String, dynamic>{};
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
args.putIfAbsent('forward', () => forward);
|
args.putIfAbsent('forward', () => forward);
|
||||||
await _channel.invokeMethod('findNext', args);
|
await _channel.invokeMethod('findNext', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
///Clears the highlighting surrounding text matches created by [findAllAsync()].
|
///Use [FindInteractionController.clearMatches] instead.
|
||||||
///
|
@Deprecated("Use FindInteractionController.clearMatches instead")
|
||||||
///**NOTE**: on iOS, this is implemented using CSS and Javascript.
|
|
||||||
///
|
|
||||||
///**Supported Platforms/Implementations**:
|
|
||||||
///- Android native WebView ([Official API - WebView.clearMatches](https://developer.android.com/reference/android/webkit/WebView#clearMatches()))
|
|
||||||
///- iOS
|
|
||||||
Future<void> clearMatches() async {
|
Future<void> clearMatches() async {
|
||||||
Map<String, dynamic> args = <String, dynamic>{};
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
await _channel.invokeMethod('clearMatches', args);
|
await _channel.invokeMethod('clearMatches', args);
|
||||||
|
|
|
@ -1057,6 +1057,26 @@ class InAppWebViewSettings {
|
||||||
///- iOS
|
///- iOS
|
||||||
bool upgradeKnownHostsToHTTPS;
|
bool upgradeKnownHostsToHTTPS;
|
||||||
|
|
||||||
|
///Sets whether fullscreen API is enabled or not.
|
||||||
|
///
|
||||||
|
///The default value is `true`.
|
||||||
|
///
|
||||||
|
///**NOTE**: available on iOS 15.4+.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- iOS
|
||||||
|
bool isElementFullscreenEnabled;
|
||||||
|
|
||||||
|
///Sets whether the web view's built-in find interaction native UI is enabled or not.
|
||||||
|
///
|
||||||
|
///The default value is `false`.
|
||||||
|
///
|
||||||
|
///**NOTE**: available on iOS 16.0+.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- iOS
|
||||||
|
bool isFindInteractionEnabled;
|
||||||
|
|
||||||
///Specifies a feature policy for the `<iframe>`.
|
///Specifies a feature policy for the `<iframe>`.
|
||||||
///The policy defines what features are available to the `<iframe>` based on the origin of the request
|
///The policy defines what features are available to the `<iframe>` based on the origin of the request
|
||||||
///(e.g. access to the microphone, camera, battery, web-share API, etc.).
|
///(e.g. access to the microphone, camera, battery, web-share API, etc.).
|
||||||
|
@ -1220,6 +1240,8 @@ class InAppWebViewSettings {
|
||||||
this.isTextInteractionEnabled = true,
|
this.isTextInteractionEnabled = true,
|
||||||
this.isSiteSpecificQuirksModeEnabled = true,
|
this.isSiteSpecificQuirksModeEnabled = true,
|
||||||
this.upgradeKnownHostsToHTTPS = true,
|
this.upgradeKnownHostsToHTTPS = true,
|
||||||
|
this.isElementFullscreenEnabled = true,
|
||||||
|
this.isFindInteractionEnabled = false,
|
||||||
this.iframeAllow,
|
this.iframeAllow,
|
||||||
this.iframeAllowFullscreen,
|
this.iframeAllowFullscreen,
|
||||||
this.iframeSandbox,
|
this.iframeSandbox,
|
||||||
|
@ -1373,6 +1395,8 @@ class InAppWebViewSettings {
|
||||||
"isTextInteractionEnabled": isTextInteractionEnabled,
|
"isTextInteractionEnabled": isTextInteractionEnabled,
|
||||||
"isSiteSpecificQuirksModeEnabled": isSiteSpecificQuirksModeEnabled,
|
"isSiteSpecificQuirksModeEnabled": isSiteSpecificQuirksModeEnabled,
|
||||||
"upgradeKnownHostsToHTTPS": upgradeKnownHostsToHTTPS,
|
"upgradeKnownHostsToHTTPS": upgradeKnownHostsToHTTPS,
|
||||||
|
"isElementFullscreenEnabled": isElementFullscreenEnabled,
|
||||||
|
"isFindInteractionEnabled": isFindInteractionEnabled,
|
||||||
"iframeAllow": iframeAllow,
|
"iframeAllow": iframeAllow,
|
||||||
"iframeAllowFullscreen": iframeAllowFullscreen,
|
"iframeAllowFullscreen": iframeAllowFullscreen,
|
||||||
"iframeSandbox": iframeSandbox?.map((e) => e.toNativeValue()).toList(),
|
"iframeSandbox": iframeSandbox?.map((e) => e.toNativeValue()).toList(),
|
||||||
|
@ -1576,6 +1600,8 @@ class InAppWebViewSettings {
|
||||||
settings.isSiteSpecificQuirksModeEnabled =
|
settings.isSiteSpecificQuirksModeEnabled =
|
||||||
map["isSiteSpecificQuirksModeEnabled"];
|
map["isSiteSpecificQuirksModeEnabled"];
|
||||||
settings.upgradeKnownHostsToHTTPS = map["upgradeKnownHostsToHTTPS"];
|
settings.upgradeKnownHostsToHTTPS = map["upgradeKnownHostsToHTTPS"];
|
||||||
|
settings.isElementFullscreenEnabled = map["isElementFullscreenEnabled"];
|
||||||
|
settings.isFindInteractionEnabled = map["isFindInteractionEnabled"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return settings;
|
return settings;
|
||||||
|
|
|
@ -4,4 +4,5 @@ export 'in_app_webview_controller.dart';
|
||||||
export 'in_app_webview_settings.dart';
|
export 'in_app_webview_settings.dart';
|
||||||
export 'headless_in_app_webview.dart';
|
export 'headless_in_app_webview.dart';
|
||||||
export 'android/main.dart';
|
export 'android/main.dart';
|
||||||
export 'apple/main.dart';
|
export 'apple/main.dart';
|
||||||
|
export '../find_interaction/find_interaction_controller.dart';
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import '../find_interaction/find_interaction_controller.dart';
|
||||||
import '../pull_to_refresh/pull_to_refresh_controller.dart';
|
import '../pull_to_refresh/pull_to_refresh_controller.dart';
|
||||||
|
|
||||||
import '../context_menu.dart';
|
import '../context_menu.dart';
|
||||||
|
@ -333,18 +334,8 @@ abstract class WebView {
|
||||||
InAppWebViewController controller, ClientCertChallenge challenge)?
|
InAppWebViewController controller, ClientCertChallenge challenge)?
|
||||||
onReceivedClientCertRequest;
|
onReceivedClientCertRequest;
|
||||||
|
|
||||||
///Event fired as find-on-page operations progress.
|
///Use [FindInteractionController.onFindResultReceived] instead.
|
||||||
///The listener may be notified multiple times while the operation is underway, and the [numberOfMatches] value should not be considered final unless [isDoneCounting] is true.
|
@Deprecated('Use FindInteractionController.onFindResultReceived instead')
|
||||||
///
|
|
||||||
///[activeMatchOrdinal] represents the zero-based ordinal of the currently selected match.
|
|
||||||
///
|
|
||||||
///[numberOfMatches] represents how many matches have been found.
|
|
||||||
///
|
|
||||||
///[isDoneCounting] whether the find operation has actually completed.
|
|
||||||
///
|
|
||||||
///**Supported Platforms/Implementations**:
|
|
||||||
///- Android native WebView ([Official API - WebView.FindListener.onFindResultReceived](https://developer.android.com/reference/android/webkit/WebView.FindListener#onFindResultReceived(int,%20int,%20boolean)))
|
|
||||||
///- iOS
|
|
||||||
final void Function(InAppWebViewController controller, int activeMatchOrdinal,
|
final void Function(InAppWebViewController controller, int activeMatchOrdinal,
|
||||||
int numberOfMatches, bool isDoneCounting)? onFindResultReceived;
|
int numberOfMatches, bool isDoneCounting)? onFindResultReceived;
|
||||||
|
|
||||||
|
@ -960,6 +951,13 @@ abstract class WebView {
|
||||||
///- iOS
|
///- iOS
|
||||||
final PullToRefreshController? pullToRefreshController;
|
final PullToRefreshController? pullToRefreshController;
|
||||||
|
|
||||||
|
///Represents the find interaction feature controller.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
|
final FindInteractionController? findInteractionController;
|
||||||
|
|
||||||
///Represents the WebView native implementation to be used.
|
///Represents the WebView native implementation to be used.
|
||||||
///The default value is [WebViewImplementation.NATIVE].
|
///The default value is [WebViewImplementation.NATIVE].
|
||||||
final WebViewImplementation implementation;
|
final WebViewImplementation implementation;
|
||||||
|
@ -994,6 +992,7 @@ abstract class WebView {
|
||||||
this.onReceivedHttpAuthRequest,
|
this.onReceivedHttpAuthRequest,
|
||||||
this.onReceivedServerTrustAuthRequest,
|
this.onReceivedServerTrustAuthRequest,
|
||||||
this.onReceivedClientCertRequest,
|
this.onReceivedClientCertRequest,
|
||||||
|
@Deprecated('Use FindInteractionController.onFindResultReceived instead')
|
||||||
this.onFindResultReceived,
|
this.onFindResultReceived,
|
||||||
this.shouldInterceptAjaxRequest,
|
this.shouldInterceptAjaxRequest,
|
||||||
this.onAjaxReadyStateChange,
|
this.onAjaxReadyStateChange,
|
||||||
|
@ -1076,5 +1075,6 @@ abstract class WebView {
|
||||||
this.contextMenu,
|
this.contextMenu,
|
||||||
this.initialUserScripts,
|
this.initialUserScripts,
|
||||||
this.pullToRefreshController,
|
this.pullToRefreshController,
|
||||||
|
this.findInteractionController,
|
||||||
this.implementation = WebViewImplementation.NATIVE});
|
this.implementation = WebViewImplementation.NATIVE});
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,3 +17,4 @@ export 'web_message/main.dart';
|
||||||
export 'web_authentication_session/main.dart';
|
export 'web_authentication_session/main.dart';
|
||||||
export 'print_job/main.dart';
|
export 'print_job/main.dart';
|
||||||
export 'debug_logging_settings.dart';
|
export 'debug_logging_settings.dart';
|
||||||
|
export 'find_interaction/main.dart';
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
import 'dart:developer' as developer;
|
||||||
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import '../in_app_webview/webview.dart';
|
import '../in_app_webview/webview.dart';
|
||||||
|
@ -7,6 +8,7 @@ import '../util.dart';
|
||||||
import '../types/main.dart';
|
import '../types/main.dart';
|
||||||
import '../in_app_webview/in_app_webview_settings.dart';
|
import '../in_app_webview/in_app_webview_settings.dart';
|
||||||
import 'pull_to_refresh_settings.dart';
|
import 'pull_to_refresh_settings.dart';
|
||||||
|
import '../debug_logging_settings.dart';
|
||||||
|
|
||||||
///A standard controller that can initiate the refreshing of a scroll view’s contents.
|
///A standard controller that can initiate the refreshing of a scroll view’s contents.
|
||||||
///This should be used whenever the user can refresh the contents of a WebView via a vertical swipe gesture.
|
///This should be used whenever the user can refresh the contents of a WebView via a vertical swipe gesture.
|
||||||
|
@ -26,6 +28,9 @@ class PullToRefreshController {
|
||||||
late PullToRefreshSettings settings;
|
late PullToRefreshSettings settings;
|
||||||
MethodChannel? _channel;
|
MethodChannel? _channel;
|
||||||
|
|
||||||
|
///Debug settings.
|
||||||
|
static DebugLoggingSettings debugLoggingSettings = DebugLoggingSettings();
|
||||||
|
|
||||||
///Event called when a swipe gesture triggers a refresh.
|
///Event called when a swipe gesture triggers a refresh.
|
||||||
final void Function()? onRefresh;
|
final void Function()? onRefresh;
|
||||||
|
|
||||||
|
@ -40,7 +45,46 @@ class PullToRefreshController {
|
||||||
this.settings = settings ?? PullToRefreshSettings();
|
this.settings = settings ?? PullToRefreshSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initMethodChannel(dynamic id) {
|
||||||
|
this._channel = MethodChannel(
|
||||||
|
'com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_$id');
|
||||||
|
this._channel?.setMethodCallHandler((call) async {
|
||||||
|
try {
|
||||||
|
return await _handleMethod(call);
|
||||||
|
} on Error catch (e) {
|
||||||
|
print(e);
|
||||||
|
print(e.stackTrace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_debugLog(String method, dynamic args) {
|
||||||
|
if (PullToRefreshController.debugLoggingSettings.enabled) {
|
||||||
|
for (var regExp
|
||||||
|
in PullToRefreshController.debugLoggingSettings.excludeFilter) {
|
||||||
|
if (regExp.hasMatch(method)) return;
|
||||||
|
}
|
||||||
|
var maxLogMessageLength =
|
||||||
|
PullToRefreshController.debugLoggingSettings.maxLogMessageLength;
|
||||||
|
String message = "PullToRefreshController " +
|
||||||
|
" calling \"" +
|
||||||
|
method.toString() +
|
||||||
|
"\" using " +
|
||||||
|
args.toString();
|
||||||
|
if (maxLogMessageLength >= 0 && message.length > maxLogMessageLength) {
|
||||||
|
message = message.substring(0, maxLogMessageLength) + "...";
|
||||||
|
}
|
||||||
|
if (!PullToRefreshController.debugLoggingSettings.usePrint) {
|
||||||
|
developer.log(message, name: this.runtimeType.toString());
|
||||||
|
} else {
|
||||||
|
print("[${this.runtimeType.toString()}] $message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<dynamic> _handleMethod(MethodCall call) async {
|
Future<dynamic> _handleMethod(MethodCall call) async {
|
||||||
|
_debugLog(call.method, call.arguments);
|
||||||
|
|
||||||
switch (call.method) {
|
switch (call.method) {
|
||||||
case "onRefresh":
|
case "onRefresh":
|
||||||
if (onRefresh != null) onRefresh!();
|
if (onRefresh != null) onRefresh!();
|
||||||
|
@ -162,17 +206,4 @@ class PullToRefreshController {
|
||||||
args.putIfAbsent('attributedTitle', () => attributedTitle.toMap());
|
args.putIfAbsent('attributedTitle', () => attributedTitle.toMap());
|
||||||
await _channel?.invokeMethod('setStyledTitle', args);
|
await _channel?.invokeMethod('setStyledTitle', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initMethodChannel(dynamic id) {
|
|
||||||
this._channel = MethodChannel(
|
|
||||||
'com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_$id');
|
|
||||||
this._channel?.setMethodCallHandler((call) async {
|
|
||||||
try {
|
|
||||||
return await _handleMethod(call);
|
|
||||||
} on Error catch (e) {
|
|
||||||
print(e);
|
|
||||||
print(e.stackTrace);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart';
|
||||||
|
|
||||||
|
import 'search_result_display_style.dart';
|
||||||
|
|
||||||
|
part 'find_session.g.dart';
|
||||||
|
|
||||||
|
@ExchangeableObject()
|
||||||
|
class FindSession_ {
|
||||||
|
///Returns the total number of results.
|
||||||
|
int resultCount;
|
||||||
|
|
||||||
|
///Returns the index of the currently highlighted result.
|
||||||
|
///If no result is currently highlighted.
|
||||||
|
int highlightedResultIndex;
|
||||||
|
|
||||||
|
/// Defines how results are reported through the find panel's UI.
|
||||||
|
SearchResultDisplayStyle_ searchResultDisplayStyle;
|
||||||
|
|
||||||
|
FindSession_({
|
||||||
|
required this.resultCount,
|
||||||
|
required this.highlightedResultIndex,
|
||||||
|
required this.searchResultDisplayStyle
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'find_session.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// ExchangeableObjectGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class FindSession {
|
||||||
|
///Returns the total number of results.
|
||||||
|
int resultCount;
|
||||||
|
|
||||||
|
///Returns the index of the currently highlighted result.
|
||||||
|
///If no result is currently highlighted.
|
||||||
|
int highlightedResultIndex;
|
||||||
|
|
||||||
|
/// Defines how results are reported through the find panel's UI.
|
||||||
|
SearchResultDisplayStyle searchResultDisplayStyle;
|
||||||
|
FindSession(
|
||||||
|
{required this.resultCount,
|
||||||
|
required this.highlightedResultIndex,
|
||||||
|
required this.searchResultDisplayStyle});
|
||||||
|
|
||||||
|
///Gets a possible [FindSession] instance from a [Map] value.
|
||||||
|
static FindSession? fromMap(Map<String, dynamic>? map) {
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final instance = FindSession(
|
||||||
|
resultCount: map['resultCount'],
|
||||||
|
highlightedResultIndex: map['highlightedResultIndex'],
|
||||||
|
searchResultDisplayStyle: SearchResultDisplayStyle.fromNativeValue(
|
||||||
|
map['searchResultDisplayStyle'])!,
|
||||||
|
);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Converts instance to a map.
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
"resultCount": resultCount,
|
||||||
|
"highlightedResultIndex": highlightedResultIndex,
|
||||||
|
"searchResultDisplayStyle": searchResultDisplayStyle.toNativeValue(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
///Converts instance to a map.
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return toMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'FindSession{resultCount: $resultCount, highlightedResultIndex: $highlightedResultIndex, searchResultDisplayStyle: $searchResultDisplayStyle}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -161,3 +161,5 @@ export 'webview_package_info.dart' show WebViewPackageInfo, AndroidWebViewPackag
|
||||||
export 'webview_render_process_action.dart' show WebViewRenderProcessAction;
|
export 'webview_render_process_action.dart' show WebViewRenderProcessAction;
|
||||||
export 'window_features.dart' show WindowFeatures, IOSWKWindowFeatures;
|
export 'window_features.dart' show WindowFeatures, IOSWKWindowFeatures;
|
||||||
export 'requested_with_header_mode.dart' show RequestedWithHeaderMode;
|
export 'requested_with_header_mode.dart' show RequestedWithHeaderMode;
|
||||||
|
export 'find_session.dart' show FindSession;
|
||||||
|
export 'search_result_display_style.dart' show SearchResultDisplayStyle;
|
|
@ -0,0 +1,20 @@
|
||||||
|
import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart';
|
||||||
|
|
||||||
|
part 'search_result_display_style.g.dart';
|
||||||
|
|
||||||
|
///Constants that describe the results summary the find panel UI includes.
|
||||||
|
@ExchangeableEnum()
|
||||||
|
class SearchResultDisplayStyle_ {
|
||||||
|
// ignore: unused_field
|
||||||
|
final int _value;
|
||||||
|
const SearchResultDisplayStyle_._internal(this._value);
|
||||||
|
|
||||||
|
///The find panel includes the total number of results the session reports and the index of the target result.
|
||||||
|
static const CURRENT_AND_TOTAL = const SearchResultDisplayStyle_._internal(0);
|
||||||
|
|
||||||
|
///The find panel includes the total number of results the session reports.
|
||||||
|
static const TOTAL = const SearchResultDisplayStyle_._internal(1);
|
||||||
|
|
||||||
|
///The find panel doesn’t include the number of results the session reports.
|
||||||
|
static const NONE = const SearchResultDisplayStyle_._internal(2);
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'search_result_display_style.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// ExchangeableEnumGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
///Constants that describe the results summary the find panel UI includes.
|
||||||
|
class SearchResultDisplayStyle {
|
||||||
|
final int _value;
|
||||||
|
final int _nativeValue;
|
||||||
|
const SearchResultDisplayStyle._internal(this._value, this._nativeValue);
|
||||||
|
// ignore: unused_element
|
||||||
|
factory SearchResultDisplayStyle._internalMultiPlatform(
|
||||||
|
int value, Function nativeValue) =>
|
||||||
|
SearchResultDisplayStyle._internal(value, nativeValue());
|
||||||
|
|
||||||
|
///The find panel includes the total number of results the session reports and the index of the target result.
|
||||||
|
static const CURRENT_AND_TOTAL = SearchResultDisplayStyle._internal(0, 0);
|
||||||
|
|
||||||
|
///The find panel includes the total number of results the session reports.
|
||||||
|
static const TOTAL = SearchResultDisplayStyle._internal(1, 1);
|
||||||
|
|
||||||
|
///The find panel doesn’t include the number of results the session reports.
|
||||||
|
static const NONE = SearchResultDisplayStyle._internal(2, 2);
|
||||||
|
|
||||||
|
///Set of all values of [SearchResultDisplayStyle].
|
||||||
|
static final Set<SearchResultDisplayStyle> values = [
|
||||||
|
SearchResultDisplayStyle.CURRENT_AND_TOTAL,
|
||||||
|
SearchResultDisplayStyle.TOTAL,
|
||||||
|
SearchResultDisplayStyle.NONE,
|
||||||
|
].toSet();
|
||||||
|
|
||||||
|
///Gets a possible [SearchResultDisplayStyle] instance from [int] value.
|
||||||
|
static SearchResultDisplayStyle? fromValue(int? value) {
|
||||||
|
if (value != null) {
|
||||||
|
try {
|
||||||
|
return SearchResultDisplayStyle.values
|
||||||
|
.firstWhere((element) => element.toValue() == value);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Gets a possible [SearchResultDisplayStyle] instance from a native value.
|
||||||
|
static SearchResultDisplayStyle? fromNativeValue(int? value) {
|
||||||
|
if (value != null) {
|
||||||
|
try {
|
||||||
|
return SearchResultDisplayStyle.values
|
||||||
|
.firstWhere((element) => element.toNativeValue() == value);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Gets [int] value.
|
||||||
|
int toValue() => _value;
|
||||||
|
|
||||||
|
///Gets [int] native value.
|
||||||
|
int toNativeValue() => _nativeValue;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => _value.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(value) => value == _value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
switch (_value) {
|
||||||
|
case 0:
|
||||||
|
return 'CURRENT_AND_TOTAL';
|
||||||
|
case 1:
|
||||||
|
return 'TOTAL';
|
||||||
|
case 2:
|
||||||
|
return 'NONE';
|
||||||
|
}
|
||||||
|
return _value.toString();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue