added andrioid custom ChannelDelegate implementation

This commit is contained in:
Lorenzo Pichilli 2022-05-04 23:30:34 +02:00
parent 55f3b64a24
commit 92abeea57f
52 changed files with 2527 additions and 2053 deletions

View File

@ -2,8 +2,8 @@ package com.pichillilorenzo.flutter_inappwebview;
import android.content.Context; import android.content.Context;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.FlutterWebView; import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.types.PlatformWebView; import com.pichillilorenzo.flutter_inappwebview.webview.PlatformWebView;
import com.pichillilorenzo.flutter_inappwebview.types.WebViewImplementation; import com.pichillilorenzo.flutter_inappwebview.types.WebViewImplementation;
import java.util.HashMap; import java.util.HashMap;

View File

@ -13,6 +13,7 @@ import com.pichillilorenzo.flutter_inappwebview.credential_database.CredentialDa
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserManager; import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserManager;
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebViewManager; import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebViewManager;
import com.pichillilorenzo.flutter_inappwebview.proxy.ProxyManager; import com.pichillilorenzo.flutter_inappwebview.proxy.ProxyManager;
import com.pichillilorenzo.flutter_inappwebview.service_worker.ServiceWorkerManager;
import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;

View File

@ -1,616 +0,0 @@
package com.pichillilorenzo.flutter_inappwebview;
import android.net.Uri;
import android.os.Build;
import android.webkit.ValueCallback;
import android.webkit.WebView;
import androidx.annotation.NonNull;
import androidx.webkit.WebMessageCompat;
import androidx.webkit.WebMessagePortCompat;
import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature;
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_webview.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebViewSettings;
import com.pichillilorenzo.flutter_inappwebview.types.ContentWorld;
import com.pichillilorenzo.flutter_inappwebview.types.HitTestResult;
import com.pichillilorenzo.flutter_inappwebview.types.InAppWebViewInterface;
import com.pichillilorenzo.flutter_inappwebview.types.SslCertificateExt;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
import com.pichillilorenzo.flutter_inappwebview.types.UserScript;
import com.pichillilorenzo.flutter_inappwebview.types.WebMessageChannel;
import com.pichillilorenzo.flutter_inappwebview.types.WebMessageListener;
import com.pichillilorenzo.flutter_inappwebview.types.WebMessagePort;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandler {
static final String LOG_TAG = "IAWMethodHandler";
public InAppWebViewInterface webView;
public InAppWebViewMethodHandler(InAppWebViewInterface webView) {
this.webView = webView;
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) {
switch (call.method) {
case "getUrl":
result.success((webView != null) ? webView.getUrl() : null);
break;
case "getTitle":
result.success((webView != null) ? webView.getTitle() : null);
break;
case "getProgress":
result.success((webView != null) ? webView.getProgress() : null);
break;
case "loadUrl":
if (webView != null) {
Map<String, Object> urlRequest = (Map<String, Object>) call.argument("urlRequest");
webView.loadUrl(URLRequest.fromMap(urlRequest));
}
result.success(true);
break;
case "postUrl":
if (webView != null) {
String url = (String) call.argument("url");
byte[] postData = (byte[]) call.argument("postData");
webView.postUrl(url, postData);
}
result.success(true);
break;
case "loadData":
if (webView != null) {
String data = (String) call.argument("data");
String mimeType = (String) call.argument("mimeType");
String encoding = (String) call.argument("encoding");
String baseUrl = (String) call.argument("baseUrl");
String historyUrl = (String) call.argument("historyUrl");
webView.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
}
result.success(true);
break;
case "loadFile":
if (webView != null) {
String assetFilePath = (String) call.argument("assetFilePath");
try {
webView.loadFile(assetFilePath);
} catch (IOException e) {
e.printStackTrace();
result.error(LOG_TAG, e.getMessage(), null);
return;
}
}
result.success(true);
break;
case "evaluateJavascript":
if (webView != null) {
String source = (String) call.argument("source");
Map<String, Object> contentWorldMap = (Map<String, Object>) call.argument("contentWorld");
ContentWorld contentWorld = ContentWorld.fromMap(contentWorldMap);
webView.evaluateJavascript(source, contentWorld, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
result.success(value);
}
});
}
else {
result.success(null);
}
break;
case "injectJavascriptFileFromUrl":
if (webView != null) {
String urlFile = (String) call.argument("urlFile");
Map<String, Object> scriptHtmlTagAttributes = (Map<String, Object>) call.argument("scriptHtmlTagAttributes");
webView.injectJavascriptFileFromUrl(urlFile, scriptHtmlTagAttributes);
}
result.success(true);
break;
case "injectCSSCode":
if (webView != null) {
String source = (String) call.argument("source");
webView.injectCSSCode(source);
}
result.success(true);
break;
case "injectCSSFileFromUrl":
if (webView != null) {
String urlFile = (String) call.argument("urlFile");
Map<String, Object> cssLinkHtmlTagAttributes = (Map<String, Object>) call.argument("cssLinkHtmlTagAttributes");
webView.injectCSSFileFromUrl(urlFile, cssLinkHtmlTagAttributes);
}
result.success(true);
break;
case "reload":
if (webView != null)
webView.reload();
result.success(true);
break;
case "goBack":
if (webView != null)
webView.goBack();
result.success(true);
break;
case "canGoBack":
result.success((webView != null) && webView.canGoBack());
break;
case "goForward":
if (webView != null)
webView.goForward();
result.success(true);
break;
case "canGoForward":
result.success((webView != null) && webView.canGoForward());
break;
case "goBackOrForward":
if (webView != null)
webView.goBackOrForward((Integer) call.argument("steps"));
result.success(true);
break;
case "canGoBackOrForward":
result.success((webView != null) && webView.canGoBackOrForward((Integer) call.argument("steps")));
break;
case "stopLoading":
if (webView != null)
webView.stopLoading();
result.success(true);
break;
case "isLoading":
result.success((webView != null) && webView.isLoading());
break;
case "takeScreenshot":
if (webView != null) {
Map<String, Object> screenshotConfiguration = (Map<String, Object>) call.argument("screenshotConfiguration");
webView.takeScreenshot(screenshotConfiguration, result);
}
else
result.success(null);
break;
case "setSettings":
if (webView != null && webView.getInAppBrowserDelegate() != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
InAppBrowserSettings inAppBrowserSettings = new InAppBrowserSettings();
HashMap<String, Object> inAppBrowserSettingsMap = (HashMap<String, Object>) call.argument("settings");
inAppBrowserSettings.parse(inAppBrowserSettingsMap);
inAppBrowserActivity.setSettings(inAppBrowserSettings, inAppBrowserSettingsMap);
} else if (webView != null) {
InAppWebViewSettings inAppWebViewSettings = new InAppWebViewSettings();
HashMap<String, Object> inAppWebViewSettingsMap = (HashMap<String, Object>) call.argument("settings");
inAppWebViewSettings.parse(inAppWebViewSettingsMap);
webView.setSettings(inAppWebViewSettings, inAppWebViewSettingsMap);
}
result.success(true);
break;
case "getSettings":
if (webView != null && webView.getInAppBrowserDelegate() != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
result.success(inAppBrowserActivity.getCustomSettings());
} else {
result.success((webView != null) ? webView.getCustomSettings() : null);
}
break;
case "close":
if (webView != null && webView.getInAppBrowserDelegate() != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
inAppBrowserActivity.close(result);
} else {
result.notImplemented();
}
break;
case "show":
if (webView != null && webView.getInAppBrowserDelegate() != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
inAppBrowserActivity.show();
result.success(true);
} else {
result.notImplemented();
}
break;
case "hide":
if (webView != null && webView.getInAppBrowserDelegate() != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) {
InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate();
inAppBrowserActivity.hide();
result.success(true);
} else {
result.notImplemented();
}
break;
case "getCopyBackForwardList":
result.success((webView != null) ? webView.getCopyBackForwardList() : null);
break;
case "startSafeBrowsing":
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) {
WebViewCompat.startSafeBrowsing(webView.getContext(), new ValueCallback<Boolean>() {
@Override
public void onReceiveValue(Boolean success) {
result.success(success);
}
});
}
else {
result.success(false);
}
break;
case "clearCache":
if (webView != null)
webView.clearAllCache();
result.success(true);
break;
case "clearSslPreferences":
if (webView != null)
webView.clearSslPreferences();
result.success(true);
break;
case "findAllAsync":
if (webView != null) {
String find = (String) call.argument("find");
webView.findAllAsync(find);
}
result.success(true);
break;
case "findNext":
if (webView != null) {
Boolean forward = (Boolean) call.argument("forward");
webView.findNext(forward);
}
result.success(true);
break;
case "clearMatches":
if (webView != null) {
webView.clearMatches();
}
result.success(true);
break;
case "scrollTo":
if (webView != null) {
Integer x = (Integer) call.argument("x");
Integer y = (Integer) call.argument("y");
Boolean animated = (Boolean) call.argument("animated");
webView.scrollTo(x, y, animated);
}
result.success(true);
break;
case "scrollBy":
if (webView != null) {
Integer x = (Integer) call.argument("x");
Integer y = (Integer) call.argument("y");
Boolean animated = (Boolean) call.argument("animated");
webView.scrollBy(x, y, animated);
}
result.success(true);
break;
case "pause":
if (webView != null) {
webView.onPause();
}
result.success(true);
break;
case "resume":
if (webView != null) {
webView.onResume();
}
result.success(true);
break;
case "pauseTimers":
if (webView != null) {
webView.pauseTimers();
}
result.success(true);
break;
case "resumeTimers":
if (webView != null) {
webView.resumeTimers();
}
result.success(true);
break;
case "printCurrentPage":
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webView.printCurrentPage();
}
result.success(true);
break;
case "getContentHeight":
if (webView instanceof InAppWebView) {
result.success(webView.getContentHeight());
} else {
result.success(null);
}
break;
case "zoomBy":
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
double zoomFactor = (double) call.argument("zoomFactor");
webView.zoomBy((float) zoomFactor);
}
result.success(true);
break;
case "getOriginalUrl":
result.success((webView != null) ? webView.getOriginalUrl() : null);
break;
case "getZoomScale":
if (webView instanceof InAppWebView) {
result.success(webView.getZoomScale());
} else {
result.success(null);
}
break;
case "getSelectedText":
if ((webView instanceof InAppWebView && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)) {
webView.getSelectedText(new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
result.success(value);
}
});
} else {
result.success(null);
}
break;
case "getHitTestResult":
if (webView instanceof InAppWebView) {
result.success(HitTestResult.fromWebViewHitTestResult(webView.getHitTestResult()).toMap());
} else {
result.success(null);
}
break;
case "pageDown":
if (webView != null) {
boolean bottom = (boolean) call.argument("bottom");
result.success(webView.pageDown(bottom));
} else {
result.success(false);
}
break;
case "pageUp":
if (webView != null) {
boolean top = (boolean) call.argument("top");
result.success(webView.pageUp(top));
} else {
result.success(false);
}
break;
case "saveWebArchive":
if (webView != null) {
String filePath = (String) call.argument("filePath");
boolean autoname = (boolean) call.argument("autoname");
webView.saveWebArchive(filePath, autoname, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
result.success(value);
}
});
} else {
result.success(null);
}
break;
case "zoomIn":
if (webView != null) {
result.success(webView.zoomIn());
} else {
result.success(false);
}
break;
case "zoomOut":
if (webView != null) {
result.success(webView.zoomOut());
} else {
result.success(false);
}
break;
case "clearFocus":
if (webView != null) {
webView.clearFocus();
}
result.success(true);
break;
case "setContextMenu":
if (webView != null) {
Map<String, Object> contextMenu = (Map<String, Object>) call.argument("contextMenu");
webView.setContextMenu(contextMenu);
}
result.success(true);
break;
case "requestFocusNodeHref":
if (webView != null) {
result.success(webView.requestFocusNodeHref());
} else {
result.success(null);
}
break;
case "requestImageRef":
if (webView != null) {
result.success(webView.requestImageRef());
} else {
result.success(null);
}
break;
case "getScrollX":
if (webView != null) {
result.success(webView.getScrollX());
} else {
result.success(null);
}
break;
case "getScrollY":
if (webView != null) {
result.success(webView.getScrollY());
} else {
result.success(null);
}
break;
case "getCertificate":
if (webView != null) {
result.success(SslCertificateExt.toMap(webView.getCertificate()));
} else {
result.success(null);
}
break;
case "clearHistory":
if (webView != null) {
webView.clearHistory();
}
result.success(true);
break;
case "addUserScript":
if (webView != null && webView.getUserContentController() != null) {
Map<String, Object> userScriptMap = (Map<String, Object>) call.argument("userScript");
UserScript userScript = UserScript.fromMap(userScriptMap);
result.success(webView.getUserContentController().addUserOnlyScript(userScript));
} else {
result.success(false);
}
break;
case "removeUserScript":
if (webView != null && webView.getUserContentController() != null) {
Integer index = (Integer) call.argument("index");
Map<String, Object> userScriptMap = (Map<String, Object>) call.argument("userScript");
UserScript userScript = UserScript.fromMap(userScriptMap);
result.success(webView.getUserContentController().removeUserOnlyScriptAt(index, userScript.getInjectionTime()));
} else {
result.success(false);
}
break;
case "removeUserScriptsByGroupName":
if (webView != null && webView.getUserContentController() != null) {
String groupName = (String) call.argument("groupName");
webView.getUserContentController().removeUserOnlyScriptsByGroupName(groupName);
}
result.success(true);
break;
case "removeAllUserScripts":
if (webView != null && webView.getUserContentController() != null) {
webView.getUserContentController().removeAllUserOnlyScripts();
}
result.success(true);
break;
case "callAsyncJavaScript":
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
String functionBody = (String) call.argument("functionBody");
Map<String, Object> functionArguments = (Map<String, Object>) call.argument("arguments");
Map<String, Object> contentWorldMap = (Map<String, Object>) call.argument("contentWorld");
ContentWorld contentWorld = ContentWorld.fromMap(contentWorldMap);
webView.callAsyncJavaScript(functionBody, functionArguments, contentWorld, new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
result.success(value);
}
});
}
else {
result.success(null);
}
break;
case "isSecureContext":
if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webView.isSecureContext(new ValueCallback<Boolean>() {
@Override
public void onReceiveValue(Boolean value) {
result.success(value);
}
});
} else {
result.success(false);
}
break;
case "createWebMessageChannel":
if (webView != null) {
if (webView instanceof InAppWebView && WebViewFeature.isFeatureSupported(WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL)) {
result.success(webView.createCompatWebMessageChannel().toMap());
} else {
result.success(null);
}
} else {
result.success(null);
}
break;
case "postWebMessage":
if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.POST_WEB_MESSAGE)) {
Map<String, Object> message = (Map<String, Object>) call.argument("message");
String targetOrigin = (String) call.argument("targetOrigin");
List<WebMessagePortCompat> compatPorts = new ArrayList<>();
List<WebMessagePort> ports = new ArrayList<>();
List<Map<String, Object>> portsMap = (List<Map<String, Object>>) message.get("ports");
if (portsMap != null) {
for (Map<String, Object> portMap : portsMap) {
String webMessageChannelId = (String) portMap.get("webMessageChannelId");
Integer index = (Integer) portMap.get("index");
WebMessageChannel webMessageChannel = webView.getWebMessageChannels().get(webMessageChannelId);
if (webMessageChannel != null) {
if (webView instanceof InAppWebView) {
compatPorts.add(webMessageChannel.compatPorts.get(index));
}
}
}
}
if (webView instanceof InAppWebView) {
WebMessageCompat webMessage = new WebMessageCompat((String) message.get("data"), compatPorts.toArray(new WebMessagePortCompat[0]));
try {
WebViewCompat.postWebMessage((WebView) webView, webMessage, Uri.parse(targetOrigin));
result.success(true);
} catch (Exception e) {
result.error(LOG_TAG, e.getMessage(), null);
}
}
} else {
result.success(true);
}
break;
case "addWebMessageListener":
if (webView != null) {
Map<String, Object> webMessageListenerMap = (Map<String, Object>) call.argument("webMessageListener");
WebMessageListener webMessageListener = WebMessageListener.fromMap(webView, webView.getPlugin().messenger, webMessageListenerMap);
if (webView instanceof InAppWebView && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
try {
webView.addWebMessageListener(webMessageListener);
result.success(true);
} catch (Exception e) {
result.error(LOG_TAG, e.getMessage(), null);
}
} else {
result.success(true);
}
} else {
result.success(true);
}
break;
case "canScrollVertically":
if (webView != null) {
result.success(webView.canScrollVertically());
} else {
result.success(false);
}
break;
case "canScrollHorizontally":
if (webView != null) {
result.success(webView.canScrollHorizontally());
} else {
result.success(false);
}
break;
case "isInFullscreen":
if (webView != null) {
result.success(webView.isInFullscreen());
} else {
result.success(false);
}
break;
default:
result.notImplemented();
}
}
public void dispose() {
webView = null;
}
}

View File

@ -6,10 +6,14 @@ import android.webkit.ValueCallback;
import android.webkit.WebSettings; import android.webkit.WebSettings;
import android.webkit.WebView; import android.webkit.WebView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.webkit.WebViewCompat; import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature; import androidx.webkit.WebViewFeature;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -20,21 +24,20 @@ import java.util.Set;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class InAppWebViewStatic implements MethodChannel.MethodCallHandler { public class InAppWebViewStatic extends ChannelDelegateImpl implements Disposable {
protected static final String LOG_TAG = "InAppWebViewStatic"; protected static final String LOG_TAG = "InAppWebViewStatic";
public MethodChannel channel; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static";
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
public InAppWebViewStatic(final InAppWebViewFlutterPlugin plugin) { public InAppWebViewStatic(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin; this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_static");
channel.setMethodCallHandler(this);
} }
@Override @Override
public void onMethodCall(MethodCall call, final MethodChannel.Result result) { public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) {
switch (call.method) { switch (call.method) {
case "getDefaultUserAgent": case "getDefaultUserAgent":
result.success(WebSettings.getDefaultUserAgent(plugin.applicationContext)); result.success(WebSettings.getDefaultUserAgent(plugin.applicationContext));
@ -124,8 +127,9 @@ public class InAppWebViewStatic implements MethodChannel.MethodCallHandler {
return webViewPackageInfoMap; return webViewPackageInfoMap;
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); super.dispose();
plugin = null; plugin = null;
} }
} }

View File

@ -5,8 +5,12 @@ import android.webkit.CookieManager;
import android.webkit.CookieSyncManager; import android.webkit.CookieSyncManager;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -19,24 +23,22 @@ import java.util.TimeZone;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class MyCookieManager implements MethodChannel.MethodCallHandler { public class MyCookieManager extends ChannelDelegateImpl implements Disposable {
protected static final String LOG_TAG = "MyCookieManager";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager";
static final String LOG_TAG = "MyCookieManager";
public MethodChannel channel;
public static CookieManager cookieManager; public static CookieManager cookieManager;
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
public MyCookieManager(final InAppWebViewFlutterPlugin plugin) { public MyCookieManager(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin; this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_cookiemanager");
channel.setMethodCallHandler(this);
cookieManager = getCookieManager(); cookieManager = getCookieManager();
} }
@Override @Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) { public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) { switch (call.method) {
case "setCookie": case "setCookie":
{ {
@ -299,8 +301,9 @@ public class MyCookieManager implements MethodChannel.MethodCallHandler {
return sdf.format(new Date(timestamp)); return sdf.format(new Date(timestamp));
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); super.dispose();
plugin = null; plugin = null;
} }
} }

View File

@ -3,8 +3,12 @@ package com.pichillilorenzo.flutter_inappwebview;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import android.webkit.WebStorage; import android.webkit.WebStorage;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -13,24 +17,22 @@ import java.util.Map;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class MyWebStorage implements MethodChannel.MethodCallHandler { public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
protected static final String LOG_TAG = "MyWebStorage";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager";
static final String LOG_TAG = "MyWebStorage";
public MethodChannel channel;
public static WebStorage webStorageManager; public static WebStorage webStorageManager;
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
public MyWebStorage(final InAppWebViewFlutterPlugin plugin) { public MyWebStorage(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin; this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_webstoragemanager");
channel.setMethodCallHandler(this);
webStorageManager = WebStorage.getInstance(); webStorageManager = WebStorage.getInstance();
} }
@Override @Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) { public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) { switch (call.method) {
case "getOrigins": case "getOrigins":
getOrigins(result); getOrigins(result);
@ -101,8 +103,9 @@ public class MyWebStorage implements MethodChannel.MethodCallHandler {
}); });
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); super.dispose();
plugin = null; plugin = null;
} }
} }

View File

@ -2,32 +2,34 @@ package com.pichillilorenzo.flutter_inappwebview;
import android.os.Build; import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class PlatformUtil implements MethodChannel.MethodCallHandler { public class PlatformUtil extends ChannelDelegateImpl implements Disposable {
protected static final String LOG_TAG = "PlatformUtil"; protected static final String LOG_TAG = "PlatformUtil";
public MethodChannel channel; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil";
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
public PlatformUtil(final InAppWebViewFlutterPlugin plugin) { public PlatformUtil(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin; this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_platformutil");
channel.setMethodCallHandler(this);
} }
@Override @Override
public void onMethodCall(MethodCall call, final MethodChannel.Result result) { public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) {
switch (call.method) { switch (call.method) {
case "getSystemVersion": case "getSystemVersion":
result.success(String.valueOf(Build.VERSION.SDK_INT)); result.success(String.valueOf(Build.VERSION.SDK_INT));
@ -64,8 +66,9 @@ public class PlatformUtil implements MethodChannel.MethodCallHandler {
return sdf.format(new Date(date)); return sdf.format(new Date(date));
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); super.dispose();
plugin = null; plugin = null;
} }
} }

View File

@ -1,185 +0,0 @@
package com.pichillilorenzo.flutter_inappwebview;
import android.os.Build;
import android.util.Log;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.webkit.ServiceWorkerClientCompat;
import androidx.webkit.ServiceWorkerControllerCompat;
import androidx.webkit.ServiceWorkerWebSettingsCompat;
import androidx.webkit.WebViewFeature;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceRequestExt;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceResponseExt;
import java.io.ByteArrayInputStream;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
@RequiresApi(api = Build.VERSION_CODES.N)
public class ServiceWorkerManager implements MethodChannel.MethodCallHandler {
static final String LOG_TAG = "ServiceWorkerManager";
public MethodChannel channel;
@Nullable
public static ServiceWorkerControllerCompat serviceWorkerController;
@Nullable
public InAppWebViewFlutterPlugin plugin;
public ServiceWorkerManager(final InAppWebViewFlutterPlugin plugin) {
this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_serviceworkercontroller");
channel.setMethodCallHandler(this);
if (WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_BASIC_USAGE)) {
serviceWorkerController = ServiceWorkerControllerCompat.getInstance();
} else {
serviceWorkerController = null;
}
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
ServiceWorkerWebSettingsCompat serviceWorkerWebSettings = (serviceWorkerController != null) ? serviceWorkerController.getServiceWorkerWebSettings() : null;
switch (call.method) {
case "setServiceWorkerClient":
{
Boolean isNull = (Boolean) call.argument("isNull");
setServiceWorkerClient(isNull);
}
result.success(true);
break;
case "getAllowContentAccess":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS)) {
result.success(serviceWorkerWebSettings.getAllowContentAccess());
} else {
result.success(false);
}
break;
case "getAllowFileAccess":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_FILE_ACCESS)) {
result.success(serviceWorkerWebSettings.getAllowFileAccess());
} else {
result.success(false);
}
break;
case "getBlockNetworkLoads":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS)) {
result.success(serviceWorkerWebSettings.getBlockNetworkLoads());
} else {
result.success(false);
}
break;
case "getCacheMode":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CACHE_MODE)) {
result.success(serviceWorkerWebSettings.getCacheMode());
} else {
result.success(null);
}
break;
case "setAllowContentAccess":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS)) {
Boolean allow = (Boolean) call.argument("allow");
serviceWorkerWebSettings.setAllowContentAccess(allow);
}
result.success(true);
break;
case "setAllowFileAccess":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_FILE_ACCESS)) {
Boolean allow = (Boolean) call.argument("allow");
serviceWorkerWebSettings.setAllowFileAccess(allow);
}
result.success(true);
break;
case "setBlockNetworkLoads":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS)) {
Boolean flag = (Boolean) call.argument("flag");
serviceWorkerWebSettings.setBlockNetworkLoads(flag);
}
result.success(true);
break;
case "setCacheMode":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CACHE_MODE)) {
Integer mode = (Integer) call.argument("mode");
serviceWorkerWebSettings.setCacheMode(mode);
}
result.success(true);
break;
default:
result.notImplemented();
}
}
private void setServiceWorkerClient(Boolean isNull) {
if (serviceWorkerController != null) {
// set ServiceWorkerClient as null makes the app crashes, so just set a dummy ServiceWorkerClientCompat.
// https://github.com/pichillilorenzo/flutter_inappwebview/issues/1151
serviceWorkerController.setServiceWorkerClient(isNull ? dummyServiceWorkerClientCompat() : new ServiceWorkerClientCompat() {
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(@NonNull WebResourceRequest request) {
WebResourceRequestExt requestExt = WebResourceRequestExt.fromWebResourceRequest(request);
Util.WaitFlutterResult flutterResult;
try {
flutterResult = Util.invokeMethodAndWait(channel, "shouldInterceptRequest", requestExt.toMap());
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
if (flutterResult.error != null) {
Log.e(LOG_TAG, flutterResult.error);
}
else if (flutterResult.result != null) {
WebResourceResponseExt response = WebResourceResponseExt.fromMap((Map<String, Object>) flutterResult.result);
if (response != null) {
String contentType = response.getContentType();
String contentEncoding = response.getContentEncoding();
byte[] data = response.getData();
Map<String, String> responseHeaders = response.getHeaders();
Integer statusCode = response.getStatusCode();
String reasonPhrase = response.getReasonPhrase();
ByteArrayInputStream inputStream = (data != null) ? new ByteArrayInputStream(data) : null;
if (statusCode != null && reasonPhrase != null) {
return new WebResourceResponse(contentType, contentEncoding, statusCode, reasonPhrase, responseHeaders, inputStream);
} else {
return new WebResourceResponse(contentType, contentEncoding, inputStream);
}
}
}
return null;
}
});
}
}
private ServiceWorkerClientCompat dummyServiceWorkerClientCompat() {
return new ServiceWorkerClientCompat() {
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(@NonNull WebResourceRequest request) {
return null;
}
};
}
public void dispose() {
channel.setMethodCallHandler(null);
if (serviceWorkerController != null) {
serviceWorkerController.setServiceWorkerClient(dummyServiceWorkerClientCompat());
serviceWorkerController = null;
}
plugin = null;
}
}

View File

@ -92,44 +92,6 @@ public class Util {
return mg.open(key); return mg.open(key);
} }
public static WaitFlutterResult invokeMethodAndWait(final MethodChannel channel, final String method, final Object arguments) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
final Map<String, Object> flutterResultMap = new HashMap<>();
flutterResultMap.put("result", null);
flutterResultMap.put("error", null);
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
channel.invokeMethod(method, arguments, new MethodChannel.Result() {
@Override
public void success(Object result) {
flutterResultMap.put("result", result);
latch.countDown();
}
@Override
public void error(String s, String s1, Object o) {
flutterResultMap.put("error", "ERROR: " + s + " " + s1);
flutterResultMap.put("result", o);
latch.countDown();
}
@Override
public void notImplemented() {
latch.countDown();
}
});
}
});
latch.await();
return new WaitFlutterResult(flutterResultMap.get("result"), (String) flutterResultMap.get("error"));
}
public static <T> T invokeMethodAndWaitResult(final @NonNull MethodChannel channel, public static <T> T invokeMethodAndWaitResult(final @NonNull MethodChannel channel,
final @NonNull String method, final @Nullable Object arguments, final @NonNull String method, final @Nullable Object arguments,
final @NonNull SyncBaseCallbackResultImpl<T> callback) throws InterruptedException { final @NonNull SyncBaseCallbackResultImpl<T> callback) throws InterruptedException {
@ -144,16 +106,6 @@ public class Util {
return callback.result; return callback.result;
} }
public static class WaitFlutterResult {
public Object result;
public String error;
public WaitFlutterResult(Object r, String e) {
result = r;
error = e;
}
}
@Nullable @Nullable
public static PrivateKeyAndCertificates loadPrivateKeyAndCertificate(@NonNull InAppWebViewFlutterPlugin plugin, public static PrivateKeyAndCertificates loadPrivateKeyAndCertificate(@NonNull InAppWebViewFlutterPlugin plugin,
@NonNull String certificatePath, @NonNull String certificatePath,

View File

@ -1,28 +1,29 @@
package com.pichillilorenzo.flutter_inappwebview; package com.pichillilorenzo.flutter_inappwebview;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.webkit.WebViewFeature; import androidx.webkit.WebViewFeature;
import io.flutter.plugin.common.BinaryMessenger; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class WebViewFeatureManager implements MethodChannel.MethodCallHandler { public class WebViewFeatureManager extends ChannelDelegateImpl implements Disposable {
protected static final String LOG_TAG = "WebViewFeatureManager";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webviewfeature";
static final String LOG_TAG = "WebViewFeatureManager";
public MethodChannel channel;
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
public WebViewFeatureManager(final InAppWebViewFlutterPlugin plugin) { public WebViewFeatureManager(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin; this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_webviewfeature");
channel.setMethodCallHandler(this);
} }
@Override @Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) { public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) { switch (call.method) {
case "isFeatureSupported": case "isFeatureSupported":
String feature = (String) call.argument("feature"); String feature = (String) call.argument("feature");
@ -33,8 +34,9 @@ public class WebViewFeatureManager implements MethodChannel.MethodCallHandler {
} }
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); super.dispose();
plugin = null; plugin = null;
} }
} }

View File

@ -29,7 +29,7 @@ public class ActionBroadcastReceiver extends BroadcastReceiver {
String managerId = b.getString(CHROME_MANAGER_ID); String managerId = b.getString(CHROME_MANAGER_ID);
ChromeSafariBrowserManager manager = (ChromeSafariBrowserManager) ChromeSafariBrowserManager.shared.get(managerId); ChromeSafariBrowserManager manager = (ChromeSafariBrowserManager) ChromeSafariBrowserManager.shared.get(managerId);
MethodChannel channel = new MethodChannel(manager.plugin.messenger, "com.pichillilorenzo/flutter_chromesafaribrowser_" + viewId); MethodChannel channel = new MethodChannel(manager.plugin.messenger, ChromeCustomTabsActivity.METHOD_CHANNEL_NAME_PREFIX + viewId);
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("url", url); obj.put("url", url);
obj.put("title", title); obj.put("title", title);

View File

@ -10,6 +10,7 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabColorSchemeParams; import androidx.browser.customtabs.CustomTabColorSchemeParams;
import androidx.browser.customtabs.CustomTabsCallback; import androidx.browser.customtabs.CustomTabsCallback;
@ -20,6 +21,7 @@ import androidx.browser.customtabs.CustomTabsSession;
import com.pichillilorenzo.flutter_inappwebview.R; import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsActionButton; import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsActionButton;
import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsMenuItem; import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsMenuItem;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -29,13 +31,14 @@ import java.util.Map;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class ChromeCustomTabsActivity extends Activity implements MethodChannel.MethodCallHandler { public class ChromeCustomTabsActivity extends Activity implements Disposable {
protected static final String LOG_TAG = "CustomTabsActivity"; protected static final String LOG_TAG = "CustomTabsActivity";
public MethodChannel channel; public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_chromesafaribrowser_";
public String id; public String id;
@Nullable
public CustomTabsIntent.Builder builder; public CustomTabsIntent.Builder builder;
public ChromeCustomTabsSettings customSettings; public ChromeCustomTabsSettings customSettings = new ChromeCustomTabsSettings();
public CustomTabActivityHelper customTabActivityHelper = new CustomTabActivityHelper(); public CustomTabActivityHelper customTabActivityHelper = new CustomTabActivityHelper();
@Nullable @Nullable
public CustomTabsSession customTabsSession; public CustomTabsSession customTabsSession;
@ -48,6 +51,8 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
public List<CustomTabsMenuItem> menuItems = new ArrayList<>(); public List<CustomTabsMenuItem> menuItems = new ArrayList<>();
@Nullable @Nullable
public CustomTabsActionButton actionButton; public CustomTabsActionButton actionButton;
@Nullable
public ChromeCustomTabsChannelDelegate channelDelegate;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -64,8 +69,8 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
manager = ChromeSafariBrowserManager.shared.get(managerId); manager = ChromeSafariBrowserManager.shared.get(managerId);
if (manager == null || manager.plugin == null|| manager.plugin.messenger == null) return; if (manager == null || manager.plugin == null|| manager.plugin.messenger == null) return;
channel = new MethodChannel(manager.plugin.messenger, "com.pichillilorenzo/flutter_chromesafaribrowser_" + id); MethodChannel channel = new MethodChannel(manager.plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
channel.setMethodCallHandler(this); channelDelegate = new ChromeCustomTabsChannelDelegate(this, channel);
initialUrl = b.getString("url"); initialUrl = b.getString("url");
@ -97,14 +102,16 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
public void onNavigationEvent(int navigationEvent, Bundle extras) { public void onNavigationEvent(int navigationEvent, Bundle extras) {
if (navigationEvent == TAB_SHOWN && !onChromeSafariBrowserOpened) { if (navigationEvent == TAB_SHOWN && !onChromeSafariBrowserOpened) {
onChromeSafariBrowserOpened = true; onChromeSafariBrowserOpened = true;
Map<String, Object> obj = new HashMap<>(); if (channelDelegate != null) {
channel.invokeMethod("onChromeSafariBrowserOpened", obj); channelDelegate.onChromeSafariBrowserOpened();
}
} }
if (navigationEvent == NAVIGATION_FINISHED && !onChromeSafariBrowserCompletedInitialLoad) { if (navigationEvent == NAVIGATION_FINISHED && !onChromeSafariBrowserCompletedInitialLoad) {
onChromeSafariBrowserCompletedInitialLoad = true; onChromeSafariBrowserCompletedInitialLoad = true;
Map<String, Object> obj = new HashMap<>(); if (channelDelegate != null) {
channel.invokeMethod("onChromeSafariBrowserCompletedInitialLoad", obj); channelDelegate.onChromeSafariBrowserCompletedInitialLoad();
}
} }
} }
@ -131,31 +138,6 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
}); });
} }
@Override
public void onMethodCall(final MethodCall call, final MethodChannel.Result result) {
switch (call.method) {
case "close":
this.onStop();
this.onDestroy();
this.close();
if (manager != null && manager.plugin != null && manager.plugin.activity != null) {
// https://stackoverflow.com/a/41596629/4637638
Intent myIntent = new Intent(manager.plugin.activity, manager.plugin.activity.getClass());
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
manager.plugin.activity.startActivity(myIntent);
}
dispose();
result.success(true);
break;
default:
result.notImplemented();
}
}
public void customTabsConnected() { public void customTabsConnected() {
customTabsSession = customTabActivityHelper.getSession(); customTabsSession = customTabActivityHelper.getSession();
Uri uri = Uri.parse(initialUrl); Uri uri = Uri.parse(initialUrl);
@ -229,6 +211,11 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
customTabActivityHelper.unbindCustomTabsService(this); customTabActivityHelper.unbindCustomTabsService(this);
} }
@Override
public void onDestroy() {
super.onDestroy();
}
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CHROME_CUSTOM_TAB_REQUEST_CODE) { if (requestCode == CHROME_CUSTOM_TAB_REQUEST_CODE) {
@ -255,15 +242,20 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
} }
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); if (channelDelegate != null) {
channelDelegate.dispose();
channelDelegate = null;
}
manager = null; manager = null;
} }
public void close() { public void close() {
customTabsSession = null; customTabsSession = null;
finish(); finish();
Map<String, Object> obj = new HashMap<>(); if (channelDelegate != null) {
channel.invokeMethod("onChromeSafariBrowserClosed", obj); channelDelegate.onChromeSafariBrowserClosed();
}
} }
} }

View File

@ -0,0 +1,83 @@
package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs;
import android.app.Activity;
import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebView;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl {
@Nullable
private ChromeCustomTabsActivity chromeCustomTabsActivity;
public ChromeCustomTabsChannelDelegate(@NonNull ChromeCustomTabsActivity chromeCustomTabsActivity, @NonNull MethodChannel channel) {
super(channel);
this.chromeCustomTabsActivity = chromeCustomTabsActivity;
}
@Override
public void onMethodCall(@NonNull final MethodCall call, @NonNull final MethodChannel.Result result) {
switch (call.method) {
case "close":
if (chromeCustomTabsActivity != null) {
chromeCustomTabsActivity.onStop();
chromeCustomTabsActivity.onDestroy();
chromeCustomTabsActivity.close();
if (chromeCustomTabsActivity.manager != null && chromeCustomTabsActivity.manager.plugin != null &&
chromeCustomTabsActivity.manager.plugin.activity != null) {
Activity activity = chromeCustomTabsActivity.manager.plugin.activity;
// https://stackoverflow.com/a/41596629/4637638
Intent myIntent = new Intent(activity, activity.getClass());
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
activity.startActivity(myIntent);
}
chromeCustomTabsActivity.dispose();
result.success(true);
} else {
result.success(false);
}
break;
default:
result.notImplemented();
}
}
public void onChromeSafariBrowserOpened() {
MethodChannel channel = getChannel();
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onChromeSafariBrowserOpened", obj);
}
public void onChromeSafariBrowserCompletedInitialLoad() {
MethodChannel channel = getChannel();
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onChromeSafariBrowserCompletedInitialLoad", obj);
}
public void onChromeSafariBrowserClosed() {
MethodChannel channel = getChannel();
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onChromeSafariBrowserClosed", obj);
}
@Override
public void dispose() {
super.dispose();
chromeCustomTabsActivity = null;
}
}

View File

@ -8,6 +8,8 @@ import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.Util; import com.pichillilorenzo.flutter_inappwebview.Util;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
@ -18,20 +20,19 @@ import java.util.UUID;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandler { public class ChromeSafariBrowserManager extends ChannelDelegateImpl implements Disposable {
protected static final String LOG_TAG = "ChromeBrowserManager"; protected static final String LOG_TAG = "ChromeBrowserManager";
public MethodChannel channel; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser";
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
public String id; public String id;
public static final Map<String, ChromeSafariBrowserManager> shared = new HashMap<>(); public static final Map<String, ChromeSafariBrowserManager> shared = new HashMap<>();
public ChromeSafariBrowserManager(final InAppWebViewFlutterPlugin plugin) { public ChromeSafariBrowserManager(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.id = UUID.randomUUID().toString(); this.id = UUID.randomUUID().toString();
this.plugin = plugin; this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_chromesafaribrowser");
channel.setMethodCallHandler(this);
shared.put(this.id, this); shared.put(this.id, this);
} }
@ -96,8 +97,9 @@ public class ChromeSafariBrowserManager implements MethodChannel.MethodCallHandl
result.error(LOG_TAG, "ChromeCustomTabs is not available!", null); result.error(LOG_TAG, "ChromeCustomTabs is not available!", null);
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); super.dispose();
shared.remove(this.id); shared.remove(this.id);
plugin = null; plugin = null;
} }

View File

@ -7,7 +7,7 @@ import android.webkit.WebResourceResponse;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView; import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.Util; import com.pichillilorenzo.flutter_inappwebview.Util;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;

View File

@ -8,6 +8,8 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.types.URLCredential; import com.pichillilorenzo.flutter_inappwebview.types.URLCredential;
import com.pichillilorenzo.flutter_inappwebview.types.URLProtectionSpace; import com.pichillilorenzo.flutter_inappwebview.types.URLProtectionSpace;
@ -20,24 +22,22 @@ import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
@RequiresApi(api = Build.VERSION_CODES.O) @RequiresApi(api = Build.VERSION_CODES.O)
public class CredentialDatabaseHandler implements MethodChannel.MethodCallHandler { public class CredentialDatabaseHandler extends ChannelDelegateImpl implements Disposable {
protected static final String LOG_TAG = "CredentialDatabaseHandler";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database";
static final String LOG_TAG = "CredentialDatabaseHandler";
public MethodChannel channel;
public static CredentialDatabase credentialDatabase; public static CredentialDatabase credentialDatabase;
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
public CredentialDatabaseHandler(final InAppWebViewFlutterPlugin plugin) { public CredentialDatabaseHandler(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin; this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_credential_database");
channel.setMethodCallHandler(this);
credentialDatabase = CredentialDatabase.getInstance(plugin.applicationContext); credentialDatabase = CredentialDatabase.getInstance(plugin.applicationContext);
} }
@Override @Override
public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) { public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) { switch (call.method) {
case "getAllAuthCredentials": case "getAllAuthCredentials":
{ {
@ -122,9 +122,9 @@ public class CredentialDatabaseHandler implements MethodChannel.MethodCallHandle
} }
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); super.dispose();
plugin = null; plugin = null;
} }
} }

View File

@ -9,21 +9,23 @@ import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.Util; import com.pichillilorenzo.flutter_inappwebview.Util;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.FlutterWebView; import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.types.Size2D; import com.pichillilorenzo.flutter_inappwebview.types.Size2D;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class HeadlessInAppWebView implements MethodChannel.MethodCallHandler { public class HeadlessInAppWebView implements Disposable {
protected static final String LOG_TAG = "HeadlessInAppWebView"; protected static final String LOG_TAG = "HeadlessInAppWebView";
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_headless_inappwebview_";
@NonNull @NonNull
public final String id; public final String id;
public final MethodChannel channel; @Nullable
public HeadlessWebViewChannelDelegate channelDelegate;
@Nullable @Nullable
public FlutterWebView flutterWebView; public FlutterWebView flutterWebView;
@Nullable @Nullable
@ -33,40 +35,14 @@ public class HeadlessInAppWebView implements MethodChannel.MethodCallHandler {
this.id = id; this.id = id;
this.plugin = plugin; this.plugin = plugin;
this.flutterWebView = flutterWebView; this.flutterWebView = flutterWebView;
this.channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_headless_inappwebview_" + id); final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
channel.setMethodCallHandler(this); this.channelDelegate = new HeadlessWebViewChannelDelegate(this, channel);
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) {
case "dispose":
dispose();
result.success(true);
break;
case "setSize":
{
Map<String, Object> sizeMap = (Map<String, Object>) call.argument("size");
Size2D size = Size2D.fromMap(sizeMap);
if (size != null)
setSize(size);
}
result.success(true);
break;
case "getSize":
{
Size2D size = getSize();
result.success(size != null ? size.toMap() : null);
}
break;
default:
result.notImplemented();
}
} }
public void onWebViewCreated() { public void onWebViewCreated() {
Map<String, Object> obj = new HashMap<>(); if (channelDelegate != null) {
channel.invokeMethod("onWebViewCreated", obj); channelDelegate.onWebViewCreated();
}
} }
public void prepare(Map<String, Object> params) { public void prepare(Map<String, Object> params) {
@ -74,18 +50,20 @@ public class HeadlessInAppWebView implements MethodChannel.MethodCallHandler {
// Add the headless WebView to the view hierarchy. // Add the headless WebView to the view hierarchy.
// This way is also possible to take screenshots. // This way is also possible to take screenshots.
ViewGroup contentView = (ViewGroup) plugin.activity.findViewById(android.R.id.content); ViewGroup contentView = (ViewGroup) plugin.activity.findViewById(android.R.id.content);
ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0); if (contentView != null) {
if (mainView != null && flutterWebView != null) { ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0);
View view = flutterWebView.getView(); if (mainView != null && flutterWebView != null) {
final Map<String, Object> initialSize = (Map<String, Object>) params.get("initialSize"); View view = flutterWebView.getView();
Size2D size = Size2D.fromMap(initialSize); final Map<String, Object> initialSize = (Map<String, Object>) params.get("initialSize");
if (size != null) { Size2D size = Size2D.fromMap(initialSize);
setSize(size); if (size != null) {
} else { setSize(size);
view.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } else {
} view.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
mainView.addView(view, 0); }
view.setVisibility(View.INVISIBLE); mainView.addView(view, 0);
view.setVisibility(View.INVISIBLE);
}
} }
} }
} }
@ -110,7 +88,10 @@ public class HeadlessInAppWebView implements MethodChannel.MethodCallHandler {
} }
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); if (channelDelegate != null) {
channelDelegate.dispose();
channelDelegate = null;
}
if (HeadlessInAppWebViewManager.webViews.containsKey(id)) { if (HeadlessInAppWebViewManager.webViews.containsKey(id)) {
HeadlessInAppWebViewManager.webViews.put(id, null); HeadlessInAppWebViewManager.webViews.put(id, null);
} }

View File

@ -25,29 +25,29 @@ import androidx.annotation.Nullable;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.FlutterWebView; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.MethodChannel.Result;
public class HeadlessInAppWebViewManager implements MethodChannel.MethodCallHandler { public class HeadlessInAppWebViewManager extends ChannelDelegateImpl implements Disposable {
protected static final String LOG_TAG = "HeadlessInAppWebViewManager"; protected static final String LOG_TAG = "HeadlessInAppWebViewManager";
public MethodChannel channel; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview";
public static final Map<String, HeadlessInAppWebView> webViews = new HashMap<>(); public static final Map<String, HeadlessInAppWebView> webViews = new HashMap<>();
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
public HeadlessInAppWebViewManager(final InAppWebViewFlutterPlugin plugin) { public HeadlessInAppWebViewManager(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin; this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_headless_inappwebview");
channel.setMethodCallHandler(this);
} }
@Override @Override
@ -79,8 +79,9 @@ public class HeadlessInAppWebViewManager implements MethodChannel.MethodCallHand
flutterWebView.makeInitialLoad(params); flutterWebView.makeInitialLoad(params);
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); super.dispose();
Collection<HeadlessInAppWebView> headlessInAppWebViews = webViews.values(); Collection<HeadlessInAppWebView> headlessInAppWebViews = webViews.values();
for (HeadlessInAppWebView headlessInAppWebView : headlessInAppWebViews) { for (HeadlessInAppWebView headlessInAppWebView : headlessInAppWebViews) {
if (headlessInAppWebView != null) { if (headlessInAppWebView != null) {

View File

@ -0,0 +1,71 @@
package com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Size2D;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class HeadlessWebViewChannelDelegate extends ChannelDelegateImpl {
@Nullable
private HeadlessInAppWebView headlessWebView;
public HeadlessWebViewChannelDelegate(@NonNull HeadlessInAppWebView headlessWebView, @NonNull MethodChannel channel) {
super(channel);
this.headlessWebView = headlessWebView;
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) {
case "dispose":
if (headlessWebView != null) {
headlessWebView.dispose();
result.success(true);
} else {
result.success(false);
}
break;
case "setSize":
if (headlessWebView != null) {
Map<String, Object> sizeMap = (Map<String, Object>) call.argument("size");
Size2D size = Size2D.fromMap(sizeMap);
if (size != null)
headlessWebView.setSize(size);
result.success(true);
} else {
result.success(false);
}
break;
case "getSize":
if (headlessWebView != null) {
Size2D size = headlessWebView.getSize();
result.success(size != null ? size.toMap() : null);
} else {
result.success(null);
}
break;
default:
result.notImplemented();
}
}
public void onWebViewCreated() {
MethodChannel channel = getChannel();
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onWebViewCreated", obj);
}
@Override
public void dispose() {
super.dispose();
headlessWebView = null;
}
}

View File

@ -24,12 +24,14 @@ 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.InAppWebViewMethodHandler; 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;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView; import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshChannelDelegate;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebViewChromeClient; import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebViewSettings; import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebViewChromeClient;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebViewSettings;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
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;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest; import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
@ -43,25 +45,34 @@ import java.util.Map;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class InAppBrowserActivity extends AppCompatActivity implements InAppBrowserDelegate { public class InAppBrowserActivity extends AppCompatActivity implements InAppBrowserDelegate, Disposable {
protected static final String LOG_TAG = "InAppBrowserActivity";
static final String LOG_TAG = "InAppBrowserActivity"; public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappbrowser_";
public MethodChannel channel;
@Nullable
public Integer windowId; public Integer windowId;
public String id; public String id;
@Nullable
public InAppWebView webView; public InAppWebView webView;
@Nullable
public PullToRefreshLayout pullToRefreshLayout; public PullToRefreshLayout pullToRefreshLayout;
@Nullable @Nullable
public ActionBar actionBar; public ActionBar actionBar;
@Nullable
public Menu menu; public Menu menu;
@Nullable
public SearchView searchView; public SearchView searchView;
public InAppBrowserSettings customSettings = new InAppBrowserSettings(); public InAppBrowserSettings customSettings = new InAppBrowserSettings();
@Nullable
public ProgressBar progressBar; public ProgressBar progressBar;
public boolean isHidden = false; public boolean isHidden = false;
@Nullable
public String fromActivity; public String fromActivity;
private List<ActivityResultListener> activityResultListeners = new ArrayList<>(); private List<ActivityResultListener> activityResultListeners = new ArrayList<>();
public InAppWebViewMethodHandler methodCallDelegate; @Nullable
public InAppBrowserManager manager; public InAppBrowserManager manager;
@Nullable
public InAppBrowserChannelDelegate channelDelegate;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -81,27 +92,25 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
windowId = b.getInt("windowId"); windowId = b.getInt("windowId");
channel = new MethodChannel(manager.plugin.messenger, "com.pichillilorenzo/flutter_inappbrowser_" + id);
setContentView(R.layout.activity_web_view); setContentView(R.layout.activity_web_view);
Map<String, Object> pullToRefreshInitialSettings = (Map<String, Object>) b.getSerializable("pullToRefreshInitialSettings"); Map<String, Object> pullToRefreshInitialSettings = (Map<String, Object>) b.getSerializable("pullToRefreshInitialSettings");
MethodChannel pullToRefreshLayoutChannel = new MethodChannel(manager.plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_" + id); MethodChannel pullToRefreshLayoutChannel = new MethodChannel(manager.plugin.messenger, PullToRefreshLayout.METHOD_CHANNEL_NAME_PREFIX + id);
PullToRefreshSettings pullToRefreshSettings = new PullToRefreshSettings(); PullToRefreshSettings pullToRefreshSettings = new PullToRefreshSettings();
pullToRefreshSettings.parse(pullToRefreshInitialSettings); pullToRefreshSettings.parse(pullToRefreshInitialSettings);
pullToRefreshLayout = findViewById(R.id.pullToRefresh); pullToRefreshLayout = findViewById(R.id.pullToRefresh);
pullToRefreshLayout.channel = pullToRefreshLayoutChannel; pullToRefreshLayout.channelDelegate = new PullToRefreshChannelDelegate(pullToRefreshLayout, pullToRefreshLayoutChannel);
pullToRefreshLayout.options = pullToRefreshSettings; pullToRefreshLayout.settings = pullToRefreshSettings;
pullToRefreshLayout.prepare(); pullToRefreshLayout.prepare();
webView = findViewById(R.id.webView); webView = findViewById(R.id.webView);
webView.windowId = windowId; webView.windowId = windowId;
webView.inAppBrowserDelegate = this; webView.inAppBrowserDelegate = this;
webView.channel = channel;
webView.plugin = manager.plugin; webView.plugin = manager.plugin;
methodCallDelegate = new InAppWebViewMethodHandler(webView); final MethodChannel channel = new MethodChannel(manager.plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
channel.setMethodCallHandler(methodCallDelegate); channelDelegate = new InAppBrowserChannelDelegate(channel);
webView.channelDelegate = new WebViewChannelDelegate(webView, channel);
fromActivity = b.getString("fromActivity"); fromActivity = b.getString("fromActivity");
@ -153,21 +162,22 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
} }
else if (initialUrlRequest != null) { else if (initialUrlRequest != null) {
URLRequest urlRequest = URLRequest.fromMap(initialUrlRequest); URLRequest urlRequest = URLRequest.fromMap(initialUrlRequest);
webView.loadUrl(urlRequest); if (urlRequest != null) {
webView.loadUrl(urlRequest);
}
} }
} }
onBrowserCreated(); if (channelDelegate != null) {
} channelDelegate.onBrowserCreated();
}
public void onBrowserCreated() {
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onBrowserCreated", obj);
} }
private void prepareView() { private void prepareView() {
webView.prepare(); if (webView != null) {
webView.prepare();
}
if (customSettings.hidden) if (customSettings.hidden)
hide(); hide();
@ -199,6 +209,12 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
public boolean onCreateOptionsMenu(Menu m) { public boolean onCreateOptionsMenu(Menu m) {
menu = m; menu = m;
if (actionBar != null && (customSettings.toolbarTopFixedTitle == null || customSettings.toolbarTopFixedTitle.isEmpty()))
actionBar.setTitle(webView != null ? webView.getTitle() : "");
if (menu == null)
return super.onCreateOptionsMenu(m);
MenuInflater inflater = getMenuInflater(); MenuInflater inflater = getMenuInflater();
// Inflate menu to add items to action bar if it is present. // Inflate menu to add items to action bar if it is present.
inflater.inflate(R.menu.menu_main, menu); inflater.inflate(R.menu.menu_main, menu);
@ -209,10 +225,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
if (customSettings.hideUrlBar) if (customSettings.hideUrlBar)
menu.findItem(R.id.menu_search).setVisible(false); menu.findItem(R.id.menu_search).setVisible(false);
searchView.setQuery(webView.getUrl(), false); searchView.setQuery(webView != null ? webView.getUrl() : "", false);
if (actionBar != null && (customSettings.toolbarTopFixedTitle == null || customSettings.toolbarTopFixedTitle.isEmpty()))
actionBar.setTitle(webView.getTitle());
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override @Override
@ -276,8 +289,9 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
} }
public void close(final MethodChannel.Result result) { public void close(final MethodChannel.Result result) {
Map<String, Object> obj = new HashMap<>(); if (channelDelegate != null) {
channel.invokeMethod("onExit", obj); channelDelegate.onExit();
}
dispose(); dispose();
@ -314,14 +328,16 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
} }
public void hide() { public void hide() {
try { if (fromActivity != null) {
isHidden = true; try {
Intent openActivity = new Intent(this, Class.forName(fromActivity)); isHidden = true;
openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); Intent openActivity = new Intent(this, Class.forName(fromActivity));
startActivityIfNeeded(openActivity, 0); openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
} catch (ClassNotFoundException e) { startActivityIfNeeded(openActivity, 0);
e.printStackTrace(); } catch (ClassNotFoundException e) {
Log.d(LOG_TAG, e.getMessage()); e.printStackTrace();
Log.d(LOG_TAG, e.getMessage());
}
} }
} }
@ -343,7 +359,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
public void shareButtonClicked(MenuItem item) { public void shareButtonClicked(MenuItem item) {
Intent share = new Intent(Intent.ACTION_SEND); Intent share = new Intent(Intent.ACTION_SEND);
share.setType("text/plain"); share.setType("text/plain");
share.putExtra(Intent.EXTRA_TEXT, webView.getUrl()); share.putExtra(Intent.EXTRA_TEXT, webView != null ? webView.getUrl() : "");
startActivity(Intent.createChooser(share, "Share")); startActivity(Intent.createChooser(share, "Share"));
} }
@ -359,7 +375,9 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
InAppWebViewSettings newInAppWebViewSettings = new InAppWebViewSettings(); InAppWebViewSettings newInAppWebViewSettings = new InAppWebViewSettings();
newInAppWebViewSettings.parse(newSettingsMap); newInAppWebViewSettings.parse(newSettingsMap);
webView.setSettings(newInAppWebViewSettings, newSettingsMap); if (webView != null) {
webView.setSettings(newInAppWebViewSettings, newSettingsMap);
}
if (newSettingsMap.get("hidden") != null && customSettings.hidden != newSettings.hidden) { if (newSettingsMap.get("hidden") != null && customSettings.hidden != newSettings.hidden) {
if (newSettings.hidden) if (newSettings.hidden)
@ -387,15 +405,15 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
if (actionBar != null && newSettingsMap.get("toolbarTopBackgroundColor") != null && if (actionBar != null && newSettingsMap.get("toolbarTopBackgroundColor") != null &&
!Util.objEquals(customSettings.toolbarTopBackgroundColor, newSettings.toolbarTopBackgroundColor) && !Util.objEquals(customSettings.toolbarTopBackgroundColor, newSettings.toolbarTopBackgroundColor) &&
!newSettings.toolbarTopBackgroundColor.isEmpty()) newSettings.toolbarTopBackgroundColor != null && !newSettings.toolbarTopBackgroundColor.isEmpty())
actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(newSettings.toolbarTopBackgroundColor))); actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(newSettings.toolbarTopBackgroundColor)));
if (actionBar != null && newSettingsMap.get("toolbarTopFixedTitle") != null && if (actionBar != null && newSettingsMap.get("toolbarTopFixedTitle") != null &&
!Util.objEquals(customSettings.toolbarTopFixedTitle, newSettings.toolbarTopFixedTitle) && !Util.objEquals(customSettings.toolbarTopFixedTitle, newSettings.toolbarTopFixedTitle) &&
!newSettings.toolbarTopFixedTitle.isEmpty()) newSettings.toolbarTopFixedTitle != null && !newSettings.toolbarTopFixedTitle.isEmpty())
actionBar.setTitle(newSettings.toolbarTopFixedTitle); actionBar.setTitle(newSettings.toolbarTopFixedTitle);
if (newSettingsMap.get("hideUrlBar") != null && customSettings.hideUrlBar != newSettings.hideUrlBar) { if (menu != null && newSettingsMap.get("hideUrlBar") != null && customSettings.hideUrlBar != newSettings.hideUrlBar) {
if (newSettings.hideUrlBar) if (newSettings.hideUrlBar)
menu.findItem(R.id.menu_search).setVisible(false); menu.findItem(R.id.menu_search).setVisible(false);
else else
@ -406,7 +424,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
} }
public Map<String, Object> getCustomSettings() { public Map<String, Object> getCustomSettings() {
Map<String, Object> webViewSettingsMap = webView.getCustomSettings(); Map<String, Object> webViewSettingsMap = webView != null ? webView.getCustomSettings() : null;
if (customSettings == null || webViewSettingsMap == null) if (customSettings == null || webViewSettingsMap == null)
return null; return null;
@ -492,17 +510,21 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); if (channelDelegate != null) {
activityResultListeners.clear(); channelDelegate.dispose();
if (methodCallDelegate != null) { channelDelegate = null;
methodCallDelegate.dispose();
methodCallDelegate = null;
} }
activityResultListeners.clear();
if (webView != null) { if (webView != null) {
if (manager != null && manager.plugin != null && manager.plugin.activityPluginBinding != null) { if (manager != null && manager.plugin != null &&
manager.plugin.activityPluginBinding != null && webView.inAppWebViewChromeClient != null) {
manager.plugin.activityPluginBinding.removeActivityResultListener(webView.inAppWebViewChromeClient); manager.plugin.activityPluginBinding.removeActivityResultListener(webView.inAppWebViewChromeClient);
} }
if (webView.channelDelegate != null) {
webView.channelDelegate.dispose();
}
ViewGroup vg = (ViewGroup) (webView.getParent()); ViewGroup vg = (ViewGroup) (webView.getParent());
if (vg != null) { if (vg != null) {
vg.removeView(webView); vg.removeView(webView);

View File

@ -0,0 +1,30 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_browser;
import androidx.annotation.NonNull;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
public class InAppBrowserChannelDelegate extends ChannelDelegateImpl {
public InAppBrowserChannelDelegate(@NonNull MethodChannel channel) {
super(channel);
}
public void onBrowserCreated() {
MethodChannel channel = getChannel();
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onBrowserCreated", obj);
}
public void onExit() {
MethodChannel channel = getChannel();
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onExit", obj);
}
}

View File

@ -36,6 +36,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
@ -51,20 +53,19 @@ import io.flutter.plugin.common.MethodChannel.Result;
/** /**
* InAppBrowserManager * InAppBrowserManager
*/ */
public class InAppBrowserManager implements MethodChannel.MethodCallHandler { public class InAppBrowserManager extends ChannelDelegateImpl implements Disposable {
protected static final String LOG_TAG = "InAppBrowserManager"; protected static final String LOG_TAG = "InAppBrowserManager";
public MethodChannel channel; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappbrowser";
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
public String id; public String id;
public static final Map<String, InAppBrowserManager> shared = new HashMap<>(); public static final Map<String, InAppBrowserManager> shared = new HashMap<>();
public InAppBrowserManager(final InAppWebViewFlutterPlugin plugin) { public InAppBrowserManager(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.id = UUID.randomUUID().toString(); this.id = UUID.randomUUID().toString();
this.plugin = plugin; this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappbrowser");
channel.setMethodCallHandler(this);
shared.put(this.id, this); shared.put(this.id, this);
} }
@ -208,8 +209,9 @@ public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
activity.startActivity(intent); activity.startActivity(intent);
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); super.dispose();
shared.remove(this.id); shared.remove(this.id);
plugin = null; plugin = null;
} }

View File

@ -1,571 +0,0 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_webview;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.Util;
import com.pichillilorenzo.flutter_inappwebview.types.BaseCallbackResultImpl;
import com.pichillilorenzo.flutter_inappwebview.types.ClientCertChallenge;
import com.pichillilorenzo.flutter_inappwebview.types.ClientCertResponse;
import com.pichillilorenzo.flutter_inappwebview.types.CreateWindowAction;
import com.pichillilorenzo.flutter_inappwebview.types.CustomSchemeResponse;
import com.pichillilorenzo.flutter_inappwebview.types.DownloadStartRequest;
import com.pichillilorenzo.flutter_inappwebview.types.GeolocationPermissionShowPromptResponse;
import com.pichillilorenzo.flutter_inappwebview.types.HitTestResult;
import com.pichillilorenzo.flutter_inappwebview.types.HttpAuthResponse;
import com.pichillilorenzo.flutter_inappwebview.types.HttpAuthenticationChallenge;
import com.pichillilorenzo.flutter_inappwebview.types.JsAlertResponse;
import com.pichillilorenzo.flutter_inappwebview.types.JsBeforeUnloadResponse;
import com.pichillilorenzo.flutter_inappwebview.types.JsConfirmResponse;
import com.pichillilorenzo.flutter_inappwebview.types.JsPromptResponse;
import com.pichillilorenzo.flutter_inappwebview.types.NavigationAction;
import com.pichillilorenzo.flutter_inappwebview.types.NavigationActionPolicy;
import com.pichillilorenzo.flutter_inappwebview.types.PermissionResponse;
import com.pichillilorenzo.flutter_inappwebview.types.SafeBrowsingResponse;
import com.pichillilorenzo.flutter_inappwebview.types.ServerTrustAuthResponse;
import com.pichillilorenzo.flutter_inappwebview.types.ServerTrustChallenge;
import com.pichillilorenzo.flutter_inappwebview.types.SyncBaseCallbackResultImpl;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceErrorExt;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceRequestExt;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceResponseExt;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
public class EventChannelDelegate {
@Nullable
private MethodChannel channel;
public EventChannelDelegate(@Nullable MethodChannel channel) {
this.channel = channel;
}
public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) {
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);
}
public void onLongPressHitTestResult(HitTestResult hitTestResult) {
if (channel == null) return;
channel.invokeMethod("onLongPressHitTestResult", hitTestResult.toMap());
}
public void onScrollChanged(int x, int y) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("x", x);
obj.put("y", y);
channel.invokeMethod("onScrollChanged", obj);
}
public void onDownloadStartRequest(DownloadStartRequest downloadStartRequest) {
if (channel == null) return;
channel.invokeMethod("onDownloadStartRequest", downloadStartRequest.toMap());
}
public void onCreateContextMenu(HitTestResult hitTestResult) {
if (channel == null) return;
channel.invokeMethod("onCreateContextMenu", hitTestResult.toMap());
}
public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("x", scrollX);
obj.put("y", scrollY);
obj.put("clampedX", clampedX);
obj.put("clampedY", clampedY);
channel.invokeMethod("onOverScrolled", obj);
}
public void onContextMenuActionItemClicked(int itemId, String itemTitle) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("id", itemId);
obj.put("androidId", itemId);
obj.put("iosId", null);
obj.put("title", itemTitle);
channel.invokeMethod("onContextMenuActionItemClicked", obj);
}
public void onHideContextMenu() {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onHideContextMenu", obj);
}
public void onEnterFullscreen() {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onEnterFullscreen", obj);
}
public void onExitFullscreen() {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onExitFullscreen", obj);
}
public static class JsAlertCallback extends BaseCallbackResultImpl<JsAlertResponse> {
@Nullable
@Override
public JsAlertResponse decodeResult(@Nullable Object obj) {
return JsAlertResponse.fromMap((Map<String, Object>) obj);
}
}
public void onJsAlert(String url, String message, Boolean isMainFrame, @NonNull JsAlertCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
obj.put("message", message);
obj.put("isMainFrame", isMainFrame);
channel.invokeMethod("onJsAlert", obj, callback);
}
public static class JsConfirmCallback extends BaseCallbackResultImpl<JsConfirmResponse> {
@Nullable
@Override
public JsConfirmResponse decodeResult(@Nullable Object obj) {
return JsConfirmResponse.fromMap((Map<String, Object>) obj);
}
}
public void onJsConfirm(String url, String message, Boolean isMainFrame, @NonNull JsConfirmCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
obj.put("message", message);
obj.put("isMainFrame", isMainFrame);
channel.invokeMethod("onJsConfirm", obj, callback);
}
public static class JsPromptCallback extends BaseCallbackResultImpl<JsPromptResponse> {
@Nullable
@Override
public JsPromptResponse decodeResult(@Nullable Object obj) {
return JsPromptResponse.fromMap((Map<String, Object>) obj);
}
}
public void onJsPrompt(String url, String message, String defaultValue, Boolean isMainFrame, @NonNull JsPromptCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
obj.put("message", message);
obj.put("defaultValue", defaultValue);
obj.put("isMainFrame", isMainFrame);
channel.invokeMethod("onJsPrompt", obj, callback);
}
public static class JsBeforeUnloadCallback extends BaseCallbackResultImpl<JsBeforeUnloadResponse> {
@Nullable
@Override
public JsBeforeUnloadResponse decodeResult(@Nullable Object obj) {
return JsBeforeUnloadResponse.fromMap((Map<String, Object>) obj);
}
}
public void onJsBeforeUnload(String url, String message, @NonNull JsBeforeUnloadCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
obj.put("message", message);
channel.invokeMethod("onJsBeforeUnload", obj, callback);
}
public static class CreateWindowCallback extends BaseCallbackResultImpl<Boolean> {
@Nullable
@Override
public Boolean decodeResult(@Nullable Object obj) {
return (obj instanceof Boolean) && (boolean) obj;
}
}
public void onCreateWindow(CreateWindowAction createWindowAction, @NonNull CreateWindowCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
channel.invokeMethod("onCreateWindow", createWindowAction.toMap(), callback);
}
public void onCloseWindow() {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onCloseWindow", obj);
}
public static class GeolocationPermissionsShowPromptCallback extends BaseCallbackResultImpl<GeolocationPermissionShowPromptResponse> {
@Nullable
@Override
public GeolocationPermissionShowPromptResponse decodeResult(@Nullable Object obj) {
return GeolocationPermissionShowPromptResponse.fromMap((Map<String, Object>) obj);
}
}
public void onGeolocationPermissionsShowPrompt(String origin, @NonNull GeolocationPermissionsShowPromptCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
Map<String, Object> obj = new HashMap<>();
obj.put("origin", origin);
channel.invokeMethod("onGeolocationPermissionsShowPrompt", obj, callback);
}
public void onGeolocationPermissionsHidePrompt() {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onGeolocationPermissionsHidePrompt", obj);
}
public void onConsoleMessage(String message, int messageLevel) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("message", message);
obj.put("messageLevel", messageLevel);
channel.invokeMethod("onConsoleMessage", obj);
}
public void onProgressChanged(int progress) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("progress", progress);
channel.invokeMethod("onProgressChanged", obj);
}
public void onTitleChanged(String title) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("title", title);
channel.invokeMethod("onTitleChanged", obj);
}
public void onReceivedIcon(byte[] icon) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("icon", icon);
channel.invokeMethod("onReceivedIcon", obj);
}
public void onReceivedTouchIconUrl(String url, boolean precomposed) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
obj.put("precomposed", precomposed);
channel.invokeMethod("onReceivedTouchIconUrl", obj);
}
public static class PermissionRequestCallback extends BaseCallbackResultImpl<PermissionResponse> {
@Nullable
@Override
public PermissionResponse decodeResult(@Nullable Object obj) {
return PermissionResponse.fromMap((Map<String, Object>) obj);
}
}
public void onPermissionRequest(String origin, List<String> resources, Object frame, @NonNull PermissionRequestCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
Map<String, Object> obj = new HashMap<>();
obj.put("origin", origin);
obj.put("resources", resources);
obj.put("frame", frame);
channel.invokeMethod("onPermissionRequest", obj, callback);
}
public static class ShouldOverrideUrlLoadingCallback extends BaseCallbackResultImpl<NavigationActionPolicy> {
@Nullable
@Override
public NavigationActionPolicy decodeResult(@Nullable Object obj) {
Integer action = Util.<Integer>getOrDefault((Map<String, Object>) obj,
"action", NavigationActionPolicy.CANCEL.rawValue());
return NavigationActionPolicy.fromValue(action);
}
}
public void shouldOverrideUrlLoading(NavigationAction navigationAction, @NonNull ShouldOverrideUrlLoadingCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
channel.invokeMethod("shouldOverrideUrlLoading", navigationAction.toMap(), callback);
}
public void onLoadStart(String url) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
channel.invokeMethod("onLoadStart", obj);
}
public void onLoadStop(String url) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
channel.invokeMethod("onLoadStop", obj);
}
public void onUpdateVisitedHistory(String url, boolean isReload) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
obj.put("isReload", isReload);
channel.invokeMethod("onUpdateVisitedHistory", obj);
}
public void onReceivedError(WebResourceRequestExt request, WebResourceErrorExt error) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("request", request.toMap());
obj.put("error", error.toMap());
channel.invokeMethod("onReceivedError", obj);
}
public void onReceivedHttpError(WebResourceRequestExt request, WebResourceResponseExt errorResponse) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("request", request.toMap());
obj.put("errorResponse", errorResponse.toMap());
channel.invokeMethod("onReceivedHttpError", obj);
}
public static class ReceivedHttpAuthRequestCallback extends BaseCallbackResultImpl<HttpAuthResponse> {
@Nullable
@Override
public HttpAuthResponse decodeResult(@Nullable Object obj) {
return HttpAuthResponse.fromMap((Map<String, Object>) obj);
}
}
public void onReceivedHttpAuthRequest(HttpAuthenticationChallenge challenge, @NonNull ReceivedHttpAuthRequestCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
channel.invokeMethod("onReceivedHttpAuthRequest", challenge.toMap(), callback);
}
public static class ReceivedServerTrustAuthRequestCallback extends BaseCallbackResultImpl<ServerTrustAuthResponse> {
@Nullable
@Override
public ServerTrustAuthResponse decodeResult(@Nullable Object obj) {
return ServerTrustAuthResponse.fromMap((Map<String, Object>) obj);
}
}
public void onReceivedServerTrustAuthRequest(ServerTrustChallenge challenge, @NonNull ReceivedServerTrustAuthRequestCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
channel.invokeMethod("onReceivedServerTrustAuthRequest", challenge.toMap(), callback);
}
public static class ReceivedClientCertRequestCallback extends BaseCallbackResultImpl<ClientCertResponse> {
@Nullable
@Override
public ClientCertResponse decodeResult(@Nullable Object obj) {
return ClientCertResponse.fromMap((Map<String, Object>) obj);
}
}
public void onReceivedClientCertRequest(ClientCertChallenge challenge, @NonNull ReceivedClientCertRequestCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
channel.invokeMethod("onReceivedClientCertRequest", challenge.toMap(), callback);
}
public void onZoomScaleChanged(float oldScale, float newScale) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("oldScale", oldScale);
obj.put("newScale", newScale);
channel.invokeMethod("onZoomScaleChanged", obj);
}
public static class SafeBrowsingHitCallback extends BaseCallbackResultImpl<SafeBrowsingResponse> {
@Nullable
@Override
public SafeBrowsingResponse decodeResult(@Nullable Object obj) {
return SafeBrowsingResponse.fromMap((Map<String, Object>) obj);
}
}
public void onSafeBrowsingHit(String url, int threatType, @NonNull SafeBrowsingHitCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
obj.put("threatType", threatType);
channel.invokeMethod("onSafeBrowsingHit", obj, callback);
}
public static class FormResubmissionCallback extends BaseCallbackResultImpl<Integer> {
@Nullable
@Override
public Integer decodeResult(@Nullable Object obj) {
return obj != null ? (Integer) ((Map<String, Object>) obj).get("action") : null;
}
}
public void onFormResubmission(String url, @NonNull FormResubmissionCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
channel.invokeMethod("onFormResubmission", obj, callback);
}
public void onPageCommitVisible(String url) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
channel.invokeMethod("onPageCommitVisible", obj);
}
public void onRenderProcessGone(boolean didCrash, int rendererPriorityAtExit) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("didCrash", didCrash);
obj.put("rendererPriorityAtExit", rendererPriorityAtExit);
channel.invokeMethod("onRenderProcessGone", obj);
}
public void onReceivedLoginRequest(String realm, String account, String args) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("realm", realm);
obj.put("account", account);
obj.put("args", args);
channel.invokeMethod("onReceivedLoginRequest", obj);
}
public static class LoadResourceCustomSchemeCallback extends BaseCallbackResultImpl<CustomSchemeResponse> {
@Nullable
@Override
public CustomSchemeResponse decodeResult(@Nullable Object obj) {
return CustomSchemeResponse.fromMap((Map<String, Object>) obj);
}
}
public void onLoadResourceCustomScheme(String url, @NonNull LoadResourceCustomSchemeCallback callback) {
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
channel.invokeMethod("onLoadResourceCustomScheme", obj, callback);
}
public static class SyncLoadResourceCustomSchemeCallback extends SyncBaseCallbackResultImpl<CustomSchemeResponse> {
@Nullable
@Override
public CustomSchemeResponse decodeResult(@Nullable Object obj) {
return (new LoadResourceCustomSchemeCallback()).decodeResult(obj);
}
}
@Nullable
public CustomSchemeResponse onLoadResourceCustomScheme(String url) throws InterruptedException {
if (channel == null) return null;
final Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
final SyncLoadResourceCustomSchemeCallback callback = new SyncLoadResourceCustomSchemeCallback();
return Util.invokeMethodAndWaitResult(channel, "onLoadResourceCustomScheme", obj, callback);
}
public static class ShouldInterceptRequestCallback extends BaseCallbackResultImpl<WebResourceResponseExt> {
@Nullable
@Override
public WebResourceResponseExt decodeResult(@Nullable Object obj) {
return WebResourceResponseExt.fromMap((Map<String, Object>) obj);
}
}
public void shouldInterceptRequest(WebResourceRequestExt request, @NonNull ShouldInterceptRequestCallback callback) {
if (channel == null) return;
channel.invokeMethod("shouldInterceptRequest", request.toMap(), callback);
}
public static class SyncShouldInterceptRequestCallback extends SyncBaseCallbackResultImpl<WebResourceResponseExt> {
@Nullable
@Override
public WebResourceResponseExt decodeResult(@Nullable Object obj) {
return (new ShouldInterceptRequestCallback()).decodeResult(obj);
}
}
@Nullable
public WebResourceResponseExt shouldInterceptRequest(WebResourceRequestExt request) throws InterruptedException {
if (channel == null) return null;
final SyncShouldInterceptRequestCallback callback = new SyncShouldInterceptRequestCallback();
return Util.invokeMethodAndWaitResult(channel, "shouldInterceptRequest", request.toMap(), callback);
}
public static class RenderProcessUnresponsiveCallback extends BaseCallbackResultImpl<Integer> {
@Nullable
@Override
public Integer decodeResult(@Nullable Object obj) {
return obj != null ? (Integer) ((Map<String, Object>) obj).get("action") : null;
}
}
public void onRenderProcessUnresponsive(String url, @NonNull RenderProcessUnresponsiveCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
channel.invokeMethod("onRenderProcessUnresponsive", obj, callback);
}
public static class RenderProcessResponsiveCallback extends BaseCallbackResultImpl<Integer> {
@Nullable
@Override
public Integer decodeResult(@Nullable Object obj) {
return obj != null ? (Integer) ((Map<String, Object>) obj).get("action") : null;
}
}
public void onRenderProcessResponsive(String url, @NonNull RenderProcessResponsiveCallback callback) {
if (channel == null) {
callback.defaultBehaviour(null);
return;
}
Map<String, Object> obj = new HashMap<>();
obj.put("url", url);
channel.invokeMethod("onRenderProcessResponsive", obj, callback);
}
public void dispose() {
channel = null;
}
}

View File

@ -7,29 +7,28 @@ import androidx.webkit.ProxyController;
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.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.types.ProxyRuleExt; import com.pichillilorenzo.flutter_inappwebview.types.ProxyRuleExt;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class ProxyManager implements MethodChannel.MethodCallHandler { public class ProxyManager extends ChannelDelegateImpl implements Disposable {
protected static final String LOG_TAG = "ProxyManager";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_proxycontroller";
static final String LOG_TAG = "ProxyManager";
public MethodChannel channel;
@Nullable @Nullable
public static ProxyController proxyController; public static ProxyController proxyController;
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
public ProxyManager(final InAppWebViewFlutterPlugin plugin) { public ProxyManager(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin; this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_proxycontroller");
channel.setMethodCallHandler(this);
if (WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) { if (WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) {
proxyController = ProxyController.getInstance(); proxyController = ProxyController.getInstance();
} else { } else {
@ -116,8 +115,9 @@ public class ProxyManager implements MethodChannel.MethodCallHandler {
} }
} }
@Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null); super.dispose();
if (proxyController != null) { if (proxyController != null) {
// Clears the proxy settings // Clears the proxy settings
proxyController.clearProxyOverride(new Executor() { proxyController.clearProxyOverride(new Executor() {

View File

@ -0,0 +1,115 @@
package com.pichillilorenzo.flutter_inappwebview.pull_to_refresh;
import android.graphics.Color;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
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 PullToRefreshChannelDelegate extends ChannelDelegateImpl {
@Nullable
private PullToRefreshLayout pullToRefreshView;
public PullToRefreshChannelDelegate(@NonNull PullToRefreshLayout pullToRefreshView, @NonNull MethodChannel channel) {
super(channel);
this.pullToRefreshView = pullToRefreshView;
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) {
switch (call.method) {
case "setEnabled":
if (pullToRefreshView != null) {
Boolean enabled = (Boolean) call.argument("enabled");
pullToRefreshView.setEnabled(enabled);
result.success(true);
} else {
result.success(false);
}
break;
case "setRefreshing":
if (pullToRefreshView != null) {
Boolean refreshing = (Boolean) call.argument("refreshing");
pullToRefreshView.setRefreshing(refreshing);
result.success(true);
} else {
result.success(false);
}
break;
case "isRefreshing":
result.success(pullToRefreshView != null && pullToRefreshView.isRefreshing());
break;
case "setColor":
if (pullToRefreshView != null) {
String color = (String) call.argument("color");
pullToRefreshView.setColorSchemeColors(Color.parseColor(color));
result.success(true);
} else {
result.success(false);
}
break;
case "setBackgroundColor":
if (pullToRefreshView != null) {
String color = (String) call.argument("color");
pullToRefreshView.setProgressBackgroundColorSchemeColor(Color.parseColor(color));
result.success(true);
} else {
result.success(false);
}
break;
case "setDistanceToTriggerSync":
if (pullToRefreshView != null) {
Integer distanceToTriggerSync = (Integer) call.argument("distanceToTriggerSync");
pullToRefreshView.setDistanceToTriggerSync(distanceToTriggerSync);
result.success(true);
} else {
result.success(false);
}
break;
case "setSlingshotDistance":
if (pullToRefreshView != null) {
Integer slingshotDistance = (Integer) call.argument("slingshotDistance");
pullToRefreshView.setSlingshotDistance(slingshotDistance);
result.success(true);
} else {
result.success(false);
}
break;
case "getDefaultSlingshotDistance":
result.success(SwipeRefreshLayout.DEFAULT_SLINGSHOT_DISTANCE);
break;
case "setSize":
if (pullToRefreshView != null) {
Integer size = (Integer) call.argument("size");
pullToRefreshView.setSize(size);
result.success(true);
} else {
result.success(false);
}
break;
default:
result.notImplemented();
}
}
public void onRefresh() {
MethodChannel channel = getChannel();
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onRefresh", obj);
}
@Override
public void dispose() {
super.dispose();
pullToRefreshView = null;
}
}

View File

@ -9,46 +9,40 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class PullToRefreshLayout extends SwipeRefreshLayout implements MethodChannel.MethodCallHandler { public class PullToRefreshLayout extends SwipeRefreshLayout implements Disposable {
static final String LOG_TAG = "PullToRefreshLayout"; static final String LOG_TAG = "PullToRefreshLayout";
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_";
public MethodChannel channel; @Nullable
public PullToRefreshSettings options; public PullToRefreshChannelDelegate channelDelegate;
public PullToRefreshSettings settings = new PullToRefreshSettings();
public PullToRefreshLayout(@NonNull Context context, @NonNull MethodChannel channel, @NonNull PullToRefreshSettings options) { public PullToRefreshLayout(@NonNull Context context, @NonNull InAppWebViewFlutterPlugin plugin,
@NonNull Object id, @NonNull PullToRefreshSettings settings) {
super(context); super(context);
this.channel = channel; this.settings = settings;
this.options = options; final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
this.channelDelegate = new PullToRefreshChannelDelegate(this, channel);
} }
public PullToRefreshLayout(@NonNull Context context) { public PullToRefreshLayout(@NonNull Context context) {
super(context); super(context);
this.channel = null;
this.options = null;
} }
public PullToRefreshLayout(@NonNull Context context, @Nullable AttributeSet attrs) { public PullToRefreshLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs); super(context, attrs);
this.channel = null;
this.options = null;
} }
public void prepare() { public void prepare() {
final PullToRefreshLayout self = this; final PullToRefreshLayout self = this;
if (channel != null) { setEnabled(settings.enabled);
this.channel.setMethodCallHandler(this);
}
setEnabled(options.enabled);
setOnChildScrollUpCallback(new OnChildScrollUpCallback() { setOnChildScrollUpCallback(new OnChildScrollUpCallback() {
@Override @Override
public boolean canChildScrollUp(@NonNull SwipeRefreshLayout parent, @Nullable View child) { public boolean canChildScrollUp(@NonNull SwipeRefreshLayout parent, @Nullable View child) {
@ -63,93 +57,30 @@ public class PullToRefreshLayout extends SwipeRefreshLayout implements MethodCha
setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override @Override
public void onRefresh() { public void onRefresh() {
if (channel == null) { if (channelDelegate == null) {
self.setRefreshing(false); self.setRefreshing(false);
return; return;
} }
Map<String, Object> obj = new HashMap<>(); channelDelegate.onRefresh();
channel.invokeMethod("onRefresh", obj);
} }
}); });
if (options.color != null) if (settings.color != null)
setColorSchemeColors(Color.parseColor(options.color)); setColorSchemeColors(Color.parseColor(settings.color));
if (options.backgroundColor != null) if (settings.backgroundColor != null)
setProgressBackgroundColorSchemeColor(Color.parseColor(options.backgroundColor)); setProgressBackgroundColorSchemeColor(Color.parseColor(settings.backgroundColor));
if (options.distanceToTriggerSync != null) if (settings.distanceToTriggerSync != null)
setDistanceToTriggerSync(options.distanceToTriggerSync); setDistanceToTriggerSync(settings.distanceToTriggerSync);
if (options.slingshotDistance != null) if (settings.slingshotDistance != null)
setSlingshotDistance(options.slingshotDistance); setSlingshotDistance(settings.slingshotDistance);
if (options.size != null) if (settings.size != null)
setSize(options.size); setSize(settings.size);
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) {
switch (call.method) {
case "setEnabled":
{
Boolean enabled = (Boolean) call.argument("enabled");
setEnabled(enabled);
}
result.success(true);
break;
case "setRefreshing":
{
Boolean refreshing = (Boolean) call.argument("refreshing");
setRefreshing(refreshing);
}
result.success(true);
break;
case "isRefreshing":
result.success(isRefreshing());
break;
case "setColor":
{
String color = (String) call.argument("color");
setColorSchemeColors(Color.parseColor(color));
}
result.success(true);
break;
case "setBackgroundColor":
{
String color = (String) call.argument("color");
setProgressBackgroundColorSchemeColor(Color.parseColor(color));
}
result.success(true);
break;
case "setDistanceToTriggerSync":
{
Integer distanceToTriggerSync = (Integer) call.argument("distanceToTriggerSync");
setDistanceToTriggerSync(distanceToTriggerSync);
}
result.success(true);
break;
case "setSlingshotDistance":
{
Integer slingshotDistance = (Integer) call.argument("slingshotDistance");
setSlingshotDistance(slingshotDistance);
}
result.success(true);
break;
case "getDefaultSlingshotDistance":
result.success(SwipeRefreshLayout.DEFAULT_SLINGSHOT_DISTANCE);
break;
case "setSize":
{
Integer size = (Integer) call.argument("size");
setSize(size);
}
result.success(true);
break;
default:
result.notImplemented();
}
} }
public void dispose() { public void dispose() {
removeAllViews(); if (channelDelegate != null) {
if (channel != null) { channelDelegate.dispose();
channel.setMethodCallHandler(null); channelDelegate = null;
} }
removeAllViews();
} }
} }

View File

@ -22,8 +22,8 @@ public class PullToRefreshSettings implements ISettings<PullToRefreshLayout> {
@Nullable @Nullable
public Integer size; public Integer size;
public PullToRefreshSettings parse(Map<String, Object> options) { public PullToRefreshSettings parse(Map<String, Object> settings) {
for (Map.Entry<String, Object> pair : options.entrySet()) { for (Map.Entry<String, Object> pair : settings.entrySet()) {
String key = pair.getKey(); String key = pair.getKey();
Object value = pair.getValue(); Object value = pair.getValue();
if (value == null) { if (value == null) {

View File

@ -0,0 +1,150 @@
package com.pichillilorenzo.flutter_inappwebview.service_worker;
import android.os.Build;
import android.webkit.ServiceWorkerController;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.webkit.ServiceWorkerControllerCompat;
import androidx.webkit.ServiceWorkerWebSettingsCompat;
import androidx.webkit.WebViewFeature;
import com.pichillilorenzo.flutter_inappwebview.Util;
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebView;
import com.pichillilorenzo.flutter_inappwebview.types.BaseCallbackResultImpl;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.types.SyncBaseCallbackResultImpl;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceRequestExt;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceResponseExt;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
@RequiresApi(api = Build.VERSION_CODES.N)
public class ServiceWorkerChannelDelegate extends ChannelDelegateImpl {
@Nullable
private ServiceWorkerManager serviceWorkerManager;
public ServiceWorkerChannelDelegate(@NonNull ServiceWorkerManager serviceWorkerManager, @NonNull MethodChannel channel) {
super(channel);
this.serviceWorkerManager = serviceWorkerManager;
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
ServiceWorkerControllerCompat serviceWorkerController = ServiceWorkerManager.serviceWorkerController;
ServiceWorkerWebSettingsCompat serviceWorkerWebSettings = (serviceWorkerController != null) ?
serviceWorkerController.getServiceWorkerWebSettings() : null;
switch (call.method) {
case "setServiceWorkerClient":
if (serviceWorkerManager != null) {
Boolean isNull = (Boolean) call.argument("isNull");
serviceWorkerManager.setServiceWorkerClient(isNull);
result.success(true);
} else {
result.success(false);
}
break;
case "getAllowContentAccess":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS)) {
result.success(serviceWorkerWebSettings.getAllowContentAccess());
} else {
result.success(false);
}
break;
case "getAllowFileAccess":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_FILE_ACCESS)) {
result.success(serviceWorkerWebSettings.getAllowFileAccess());
} else {
result.success(false);
}
break;
case "getBlockNetworkLoads":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS)) {
result.success(serviceWorkerWebSettings.getBlockNetworkLoads());
} else {
result.success(false);
}
break;
case "getCacheMode":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CACHE_MODE)) {
result.success(serviceWorkerWebSettings.getCacheMode());
} else {
result.success(null);
}
break;
case "setAllowContentAccess":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS)) {
Boolean allow = (Boolean) call.argument("allow");
serviceWorkerWebSettings.setAllowContentAccess(allow);
}
result.success(true);
break;
case "setAllowFileAccess":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_FILE_ACCESS)) {
Boolean allow = (Boolean) call.argument("allow");
serviceWorkerWebSettings.setAllowFileAccess(allow);
}
result.success(true);
break;
case "setBlockNetworkLoads":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS)) {
Boolean flag = (Boolean) call.argument("flag");
serviceWorkerWebSettings.setBlockNetworkLoads(flag);
}
result.success(true);
break;
case "setCacheMode":
if (serviceWorkerWebSettings != null && WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_CACHE_MODE)) {
Integer mode = (Integer) call.argument("mode");
serviceWorkerWebSettings.setCacheMode(mode);
}
result.success(true);
break;
default:
result.notImplemented();
}
}
public static class ShouldInterceptRequestCallback extends BaseCallbackResultImpl<WebResourceResponseExt> {
@Nullable
@Override
public WebResourceResponseExt decodeResult(@Nullable Object obj) {
return WebResourceResponseExt.fromMap((Map<String, Object>) obj);
}
}
public void shouldInterceptRequest(WebResourceRequestExt request, @NonNull WebViewChannelDelegate.ShouldInterceptRequestCallback callback) {
MethodChannel channel = getChannel();
if (channel == null) return;
channel.invokeMethod("shouldInterceptRequest", request.toMap(), callback);
}
public static class SyncShouldInterceptRequestCallback extends SyncBaseCallbackResultImpl<WebResourceResponseExt> {
@Nullable
@Override
public WebResourceResponseExt decodeResult(@Nullable Object obj) {
return (new WebViewChannelDelegate.ShouldInterceptRequestCallback()).decodeResult(obj);
}
}
@Nullable
public WebResourceResponseExt shouldInterceptRequest(WebResourceRequestExt request) throws InterruptedException {
MethodChannel channel = getChannel();
if (channel == null) return null;
final WebViewChannelDelegate.SyncShouldInterceptRequestCallback callback = new WebViewChannelDelegate.SyncShouldInterceptRequestCallback();
return Util.invokeMethodAndWaitResult(channel, "shouldInterceptRequest", request.toMap(), callback);
}
@Override
public void dispose() {
super.dispose();
serviceWorkerManager = null;
}
}

View File

@ -0,0 +1,112 @@
package com.pichillilorenzo.flutter_inappwebview.service_worker;
import android.os.Build;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.webkit.ServiceWorkerClientCompat;
import androidx.webkit.ServiceWorkerControllerCompat;
import androidx.webkit.WebViewFeature;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceRequestExt;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceResponseExt;
import java.io.ByteArrayInputStream;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
@RequiresApi(api = Build.VERSION_CODES.N)
public class ServiceWorkerManager implements Disposable {
protected static final String LOG_TAG = "ServiceWorkerManager";
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_serviceworkercontroller";
@Nullable
public ServiceWorkerChannelDelegate channelDelegate;
@Nullable
public static ServiceWorkerControllerCompat serviceWorkerController;
@Nullable
public InAppWebViewFlutterPlugin plugin;
public ServiceWorkerManager(final InAppWebViewFlutterPlugin plugin) {
this.plugin = plugin;
final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME);
this.channelDelegate = new ServiceWorkerChannelDelegate(this, channel);
if (WebViewFeature.isFeatureSupported(WebViewFeature.SERVICE_WORKER_BASIC_USAGE)) {
serviceWorkerController = ServiceWorkerControllerCompat.getInstance();
} else {
serviceWorkerController = null;
}
}
public void setServiceWorkerClient(Boolean isNull) {
if (serviceWorkerController != null) {
// set ServiceWorkerClient as null makes the app crashes, so just set a dummy ServiceWorkerClientCompat.
// https://github.com/pichillilorenzo/flutter_inappwebview/issues/1151
serviceWorkerController.setServiceWorkerClient(isNull ? dummyServiceWorkerClientCompat() : new ServiceWorkerClientCompat() {
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(@NonNull WebResourceRequest request) {
WebResourceRequestExt requestExt = WebResourceRequestExt.fromWebResourceRequest(request);
WebResourceResponseExt response = null;
if (channelDelegate != null) {
try {
response = channelDelegate.shouldInterceptRequest(requestExt);
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
if (response != null) {
String contentType = response.getContentType();
String contentEncoding = response.getContentEncoding();
byte[] data = response.getData();
Map<String, String> responseHeaders = response.getHeaders();
Integer statusCode = response.getStatusCode();
String reasonPhrase = response.getReasonPhrase();
ByteArrayInputStream inputStream = (data != null) ? new ByteArrayInputStream(data) : null;
if (statusCode != null && reasonPhrase != null) {
return new WebResourceResponse(contentType, contentEncoding, statusCode, reasonPhrase, responseHeaders, inputStream);
} else {
return new WebResourceResponse(contentType, contentEncoding, inputStream);
}
}
return null;
}
});
}
}
private ServiceWorkerClientCompat dummyServiceWorkerClientCompat() {
return new ServiceWorkerClientCompat() {
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(@NonNull WebResourceRequest request) {
return null;
}
};
}
@Override
public void dispose() {
if (channelDelegate != null) {
channelDelegate.dispose();
channelDelegate = null;
}
if (serviceWorkerController != null) {
serviceWorkerController.setServiceWorkerClient(dummyServiceWorkerClientCompat());
serviceWorkerController = null;
}
plugin = null;
}
}

View File

@ -0,0 +1,37 @@
package com.pichillilorenzo.flutter_inappwebview.types;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class ChannelDelegateImpl implements IChannelDelegate {
@Nullable
private MethodChannel channel;
public ChannelDelegateImpl(@NonNull MethodChannel channel) {
this.channel = channel;
this.channel.setMethodCallHandler(this);
}
@Override
@Nullable
public MethodChannel getChannel() {
return channel;
}
@CallSuper
public void dispose() {
if (channel != null) {
channel.setMethodCallHandler(null);
channel = null;
}
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
}
}

View File

@ -0,0 +1,5 @@
package com.pichillilorenzo.flutter_inappwebview.types;
public interface Disposable {
void dispose();
}

View File

@ -0,0 +1,11 @@
package com.pichillilorenzo.flutter_inappwebview.types;
import androidx.annotation.Nullable;
import io.flutter.plugin.common.MethodChannel;
public interface IChannelDelegate extends MethodChannel.MethodCallHandler {
@Nullable
MethodChannel getChannel();
void dispose();
}

View File

@ -3,7 +3,12 @@ package com.pichillilorenzo.flutter_inappwebview.types;
import android.text.TextUtils; import android.text.TextUtils;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.Util; import com.pichillilorenzo.flutter_inappwebview.Util;
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
import com.pichillilorenzo.flutter_inappwebview.webview.web_message.WebMessageChannel;
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS; import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
import java.util.ArrayList; import java.util.ArrayList;
@ -11,12 +16,13 @@ import java.util.List;
public class WebMessagePort { public class WebMessagePort {
public String name; public String name;
@Nullable
public WebMessageChannel webMessageChannel; public WebMessageChannel webMessageChannel;
public boolean isClosed = false; public boolean isClosed = false;
public boolean isTransferred = false; public boolean isTransferred = false;
public boolean isStarted = false; public boolean isStarted = false;
public WebMessagePort(String name, WebMessageChannel webMessageChannel) { public WebMessagePort(String name, @NonNull WebMessageChannel webMessageChannel) {
this.name = name; this.name = name;
this.webMessageChannel = webMessageChannel; this.webMessageChannel = webMessageChannel;
} }

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_webview; package com.pichillilorenzo.flutter_inappwebview.webview;
import com.pichillilorenzo.flutter_inappwebview.ISettings; import com.pichillilorenzo.flutter_inappwebview.ISettings;

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.types; package com.pichillilorenzo.flutter_inappwebview.webview;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
@ -12,8 +12,13 @@ import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserDelegate; import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserDelegate;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebViewSettings; import com.pichillilorenzo.flutter_inappwebview.types.ContentWorld;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.EventChannelDelegate; import com.pichillilorenzo.flutter_inappwebview.types.HitTestResult;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
import com.pichillilorenzo.flutter_inappwebview.types.UserContentController;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebViewSettings;
import com.pichillilorenzo.flutter_inappwebview.webview.web_message.WebMessageChannel;
import com.pichillilorenzo.flutter_inappwebview.webview.web_message.WebMessageListener;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@ -106,6 +111,6 @@ public interface InAppWebViewInterface {
boolean isInFullscreen(); boolean isInFullscreen();
void setInFullscreen(boolean inFullscreen); void setInFullscreen(boolean inFullscreen);
@Nullable @Nullable
EventChannelDelegate getEventChannelDelegate(); WebViewChannelDelegate getChannelDelegate();
void setEventChannelDelegate(@Nullable EventChannelDelegate eventChannelDelegate); void setChannelDelegate(@Nullable WebViewChannelDelegate eventWebViewChannelDelegate);
} }

View File

@ -1,32 +1,27 @@
package com.pichillilorenzo.flutter_inappwebview; package com.pichillilorenzo.flutter_inappwebview.webview;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import android.util.Log; import android.util.Log;
import android.webkit.JavascriptInterface; import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView; import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS; import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
public class JavaScriptBridgeInterface { public class JavaScriptBridgeInterface {
private static final String LOG_TAG = "JSBridgeInterface"; private static final String LOG_TAG = "JSBridgeInterface";
private InAppWebView inAppWebView; private InAppWebView inAppWebView;
private final MethodChannel channel;
public JavaScriptBridgeInterface(InAppWebView inAppWebView) { public JavaScriptBridgeInterface(InAppWebView inAppWebView) {
this.inAppWebView = inAppWebView; this.inAppWebView = inAppWebView;
this.channel = this.inAppWebView.channel;
} }
@JavascriptInterface @JavascriptInterface
@ -52,10 +47,6 @@ public class JavaScriptBridgeInterface {
return; return;
} }
final Map<String, Object> obj = new HashMap<>();
obj.put("handlerName", handlerName);
obj.put("args", args);
// java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread. // java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread.
// https://github.com/pichillilorenzo/flutter_inappwebview/issues/98 // https://github.com/pichillilorenzo/flutter_inappwebview/issues/98
final Handler handler = new Handler(inAppWebView.getWebViewLooper()); final Handler handler = new Handler(inAppWebView.getWebViewLooper());
@ -99,32 +90,33 @@ public class JavaScriptBridgeInterface {
return; return;
} }
// invoke flutter javascript handler and send back flutter data as a JSON Object to javascript if (inAppWebView.channelDelegate != null) {
channel.invokeMethod("onCallJsHandler", obj, new MethodChannel.Result() { // invoke flutter javascript handler and send back flutter data as a JSON Object to javascript
@Override inAppWebView.channelDelegate.onCallJsHandler(handlerName, args, new WebViewChannelDelegate.CallJsHandlerCallback() {
public void success(Object json) { @Override
if (inAppWebView == null) { public void defaultBehaviour(@Nullable Object json) {
// The webview has already been disposed, ignore. if (inAppWebView == null) {
return; // The webview has already been disposed, ignore.
return;
}
String sourceCode = "if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "] != null) { " +
"window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "](" + json + "); " +
"delete window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "]; " +
"}";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
inAppWebView.evaluateJavascript(sourceCode, (ValueCallback<String>) null);
}
else {
inAppWebView.loadUrl("javascript:" + sourceCode);
}
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
inAppWebView.evaluateJavascript("if(window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "] != null) {window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "](" + json + "); delete window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "];}", (ValueCallback<String>) null); @Override
public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) {
Log.e(LOG_TAG, errorCode + ", " + ((errorMessage != null) ? errorMessage : ""));
} }
else { });
inAppWebView.loadUrl("javascript:if(window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "] != null) {window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "](" + json + "); delete window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "];}"); }
}
}
@Override
public void error(String s, String s1, Object o) {
Log.d(LOG_TAG, "ERROR: " + s + " " + s1);
}
@Override
public void notImplemented() {
}
});
} }
}); });
} }

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.types; package com.pichillilorenzo.flutter_inappwebview.webview;
import java.util.HashMap; import java.util.HashMap;

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_webview; package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
import static android.hardware.display.DisplayManager.DisplayListener; import static android.hardware.display.DisplayManager.DisplayListener;

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_webview; package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
import android.content.Context; import android.content.Context;
import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager;
@ -14,15 +14,15 @@ import android.webkit.WebViewClient;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.webkit.WebViewCompat; 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.InAppWebViewMethodHandler;
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;
import com.pichillilorenzo.flutter_inappwebview.types.PlatformWebView; import com.pichillilorenzo.flutter_inappwebview.webview.PlatformWebView;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest; import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
import com.pichillilorenzo.flutter_inappwebview.types.UserScript; import com.pichillilorenzo.flutter_inappwebview.types.UserScript;
@ -32,21 +32,17 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
public class FlutterWebView implements PlatformWebView { public class FlutterWebView implements PlatformWebView {
static final String LOG_TAG = "IAWFlutterWebView"; static final String LOG_TAG = "IAWFlutterWebView";
@Nullable
public InAppWebView webView; public InAppWebView webView;
public final MethodChannel channel; @Nullable
public InAppWebViewMethodHandler methodCallDelegate;
public PullToRefreshLayout pullToRefreshLayout; public PullToRefreshLayout pullToRefreshLayout;
public FlutterWebView(final InAppWebViewFlutterPlugin plugin, final Context context, Object id, public FlutterWebView(final InAppWebViewFlutterPlugin plugin, final Context context, Object id,
HashMap<String, Object> params) { HashMap<String, Object> params) {
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_" + id);
DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy(); DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy();
DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
displayListenerProxy.onPreWebViewInitialization(displayManager); displayListenerProxy.onPreWebViewInitialization(displayManager);
@ -57,8 +53,8 @@ public class FlutterWebView implements PlatformWebView {
List<Map<String, Object>> initialUserScripts = (List<Map<String, Object>>) params.get("initialUserScripts"); List<Map<String, Object>> initialUserScripts = (List<Map<String, Object>>) params.get("initialUserScripts");
Map<String, Object> pullToRefreshInitialSettings = (Map<String, Object>) params.get("pullToRefreshSettings"); Map<String, Object> pullToRefreshInitialSettings = (Map<String, Object>) params.get("pullToRefreshSettings");
InAppWebViewSettings options = new InAppWebViewSettings(); InAppWebViewSettings customSettings = new InAppWebViewSettings();
options.parse(initialSettings); customSettings.parse(initialSettings);
if (plugin == null || plugin.activity == null) { if (plugin == null || plugin.activity == null) {
Log.e(LOG_TAG, "\n\n\nERROR: You need to upgrade your Flutter project to use the new Java Embedding API:\n\n" + Log.e(LOG_TAG, "\n\n\nERROR: You need to upgrade your Flutter project to use the new Java Embedding API:\n\n" +
@ -74,23 +70,20 @@ public class FlutterWebView implements PlatformWebView {
} }
} }
webView = new InAppWebView(context, plugin, channel, id, windowId, options, contextMenu, options.useHybridComposition ? null : plugin.flutterView, userScripts); webView = new InAppWebView(context, plugin, id, windowId, customSettings, contextMenu,
customSettings.useHybridComposition ? null : plugin.flutterView, userScripts);
displayListenerProxy.onPostWebViewInitialization(displayManager); displayListenerProxy.onPostWebViewInitialization(displayManager);
if (options.useHybridComposition) { if (customSettings.useHybridComposition) {
// set MATCH_PARENT layout params to the WebView, otherwise it won't take all the available space! // set MATCH_PARENT layout params to the WebView, otherwise it won't take all the available space!
webView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); webView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
MethodChannel pullToRefreshLayoutChannel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_" + id);
PullToRefreshSettings pullToRefreshSettings = new PullToRefreshSettings(); PullToRefreshSettings pullToRefreshSettings = new PullToRefreshSettings();
pullToRefreshSettings.parse(pullToRefreshInitialSettings); pullToRefreshSettings.parse(pullToRefreshInitialSettings);
pullToRefreshLayout = new PullToRefreshLayout(context, pullToRefreshLayoutChannel, pullToRefreshSettings); pullToRefreshLayout = new PullToRefreshLayout(context, plugin, id, pullToRefreshSettings);
pullToRefreshLayout.addView(webView); pullToRefreshLayout.addView(webView);
pullToRefreshLayout.prepare(); pullToRefreshLayout.prepare();
} }
methodCallDelegate = new InAppWebViewMethodHandler(webView);
channel.setMethodCallHandler(methodCallDelegate);
webView.prepare(); webView.prepare();
} }
@ -130,19 +123,19 @@ public class FlutterWebView implements PlatformWebView {
} }
else if (initialUrlRequest != null) { else if (initialUrlRequest != null) {
URLRequest urlRequest = URLRequest.fromMap(initialUrlRequest); URLRequest urlRequest = URLRequest.fromMap(initialUrlRequest);
webView.loadUrl(urlRequest); if (urlRequest != null) {
webView.loadUrl(urlRequest);
}
} }
} }
} }
@Override @Override
public void dispose() { public void dispose() {
channel.setMethodCallHandler(null);
if (methodCallDelegate != null) {
methodCallDelegate.dispose();
methodCallDelegate = null;
}
if (webView != null) { if (webView != null) {
if (webView.channelDelegate != null) {
webView.channelDelegate.dispose();
}
webView.removeJavascriptInterface(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME); webView.removeJavascriptInterface(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE)) {
WebViewCompat.setWebViewRenderProcessClient(webView, null); WebViewCompat.setWebViewRenderProcessClient(webView, null);
@ -154,13 +147,20 @@ public class FlutterWebView implements PlatformWebView {
if (webView.inAppWebViewRenderProcessClient != null) { if (webView.inAppWebViewRenderProcessClient != null) {
webView.inAppWebViewRenderProcessClient.dispose(); webView.inAppWebViewRenderProcessClient.dispose();
} }
webView.eventChannelDelegate.dispose(); if (webView.inAppWebViewChromeClient != null) {
webView.inAppWebViewChromeClient.dispose(); webView.inAppWebViewChromeClient.dispose();
webView.inAppWebViewClient.dispose(); }
webView.javaScriptBridgeInterface.dispose(); if (webView.inAppWebViewClient != null) {
webView.dispose(); webView.inAppWebViewClient.dispose();
webView.destroy(); }
webView = null; if (webView.javaScriptBridgeInterface != null) {
webView.javaScriptBridgeInterface.dispose();
}
if (webView != null) {
webView.dispose();
webView.destroy();
webView = null;
}
if (pullToRefreshLayout != null) { if (pullToRefreshLayout != null) {
pullToRefreshLayout.dispose(); pullToRefreshLayout.dispose();

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_webview; package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder; import android.animation.PropertyValuesHolder;
@ -55,7 +55,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.JavaScriptBridgeInterface; import com.pichillilorenzo.flutter_inappwebview.webview.JavaScriptBridgeInterface;
import com.pichillilorenzo.flutter_inappwebview.R; import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Util; import com.pichillilorenzo.flutter_inappwebview.Util;
import com.pichillilorenzo.flutter_inappwebview.content_blocker.ContentBlocker; import com.pichillilorenzo.flutter_inappwebview.content_blocker.ContentBlocker;
@ -76,14 +76,16 @@ import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.PromisePolyfil
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshLayout; import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshLayout;
import com.pichillilorenzo.flutter_inappwebview.types.ContentWorld; import com.pichillilorenzo.flutter_inappwebview.types.ContentWorld;
import com.pichillilorenzo.flutter_inappwebview.types.DownloadStartRequest; import com.pichillilorenzo.flutter_inappwebview.types.DownloadStartRequest;
import com.pichillilorenzo.flutter_inappwebview.types.InAppWebViewInterface; import com.pichillilorenzo.flutter_inappwebview.webview.ContextMenuSettings;
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript; import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
import com.pichillilorenzo.flutter_inappwebview.types.PreferredContentModeOptionType; import com.pichillilorenzo.flutter_inappwebview.types.PreferredContentModeOptionType;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest; import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
import com.pichillilorenzo.flutter_inappwebview.types.UserContentController; import com.pichillilorenzo.flutter_inappwebview.types.UserContentController;
import com.pichillilorenzo.flutter_inappwebview.types.UserScript; import com.pichillilorenzo.flutter_inappwebview.types.UserScript;
import com.pichillilorenzo.flutter_inappwebview.types.WebMessageChannel; import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
import com.pichillilorenzo.flutter_inappwebview.types.WebMessageListener; import com.pichillilorenzo.flutter_inappwebview.webview.web_message.WebMessageChannel;
import com.pichillilorenzo.flutter_inappwebview.webview.web_message.WebMessageListener;
import org.json.JSONObject; import org.json.JSONObject;
@ -104,14 +106,13 @@ import static android.content.Context.INPUT_METHOD_SERVICE;
import static com.pichillilorenzo.flutter_inappwebview.types.PreferredContentModeOptionType.fromValue; import static com.pichillilorenzo.flutter_inappwebview.types.PreferredContentModeOptionType.fromValue;
final public class InAppWebView extends InputAwareWebView implements InAppWebViewInterface { final public class InAppWebView extends InputAwareWebView implements InAppWebViewInterface {
protected static final String LOG_TAG = "InAppWebView";
static final String LOG_TAG = "InAppWebView"; public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_";
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
@Nullable @Nullable
public InAppBrowserDelegate inAppBrowserDelegate; public InAppBrowserDelegate inAppBrowserDelegate;
public MethodChannel channel;
public Object id; public Object id;
@Nullable @Nullable
public Integer windowId; public Integer windowId;
@ -122,10 +123,10 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
@Nullable @Nullable
public InAppWebViewRenderProcessClient inAppWebViewRenderProcessClient; public InAppWebViewRenderProcessClient inAppWebViewRenderProcessClient;
@Nullable @Nullable
public EventChannelDelegate eventChannelDelegate; public WebViewChannelDelegate channelDelegate;
@Nullable @Nullable
public JavaScriptBridgeInterface javaScriptBridgeInterface; public JavaScriptBridgeInterface javaScriptBridgeInterface;
public InAppWebViewSettings customSettings; public InAppWebViewSettings customSettings = new InAppWebViewSettings();
public boolean isLoading = false; public boolean isLoading = false;
private boolean inFullscreen = false; private boolean inFullscreen = false;
public OkHttpClient httpClient; public OkHttpClient httpClient;
@ -169,15 +170,15 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
super(context, attrs, defaultStyle); super(context, attrs, defaultStyle);
} }
public InAppWebView(Context context, InAppWebViewFlutterPlugin plugin, public InAppWebView(Context context, @NonNull InAppWebViewFlutterPlugin plugin,
MethodChannel channel, Object id, @NonNull Object id, @Nullable Integer windowId, InAppWebViewSettings customSettings,
@Nullable Integer windowId, InAppWebViewSettings customSettings,
@Nullable Map<String, Object> contextMenu, View containerView, @Nullable Map<String, Object> contextMenu, View containerView,
List<UserScript> userScripts) { List<UserScript> userScripts) {
super(context, containerView, customSettings.useHybridComposition); super(context, containerView, customSettings.useHybridComposition);
this.plugin = plugin; this.plugin = plugin;
this.channel = channel;
this.id = id; this.id = id;
final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
this.channelDelegate = new WebViewChannelDelegate(this, channel);
this.windowId = windowId; this.windowId = windowId;
this.customSettings = customSettings; this.customSettings = customSettings;
this.contextMenu = contextMenu; this.contextMenu = contextMenu;
@ -190,8 +191,6 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
public void prepare() { public void prepare() {
httpClient = new OkHttpClient().newBuilder().build(); httpClient = new OkHttpClient().newBuilder().build();
eventChannelDelegate = new EventChannelDelegate(channel);
javaScriptBridgeInterface = new JavaScriptBridgeInterface(this); javaScriptBridgeInterface = new JavaScriptBridgeInterface(this);
addJavascriptInterface(javaScriptBridgeInterface, JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME); addJavascriptInterface(javaScriptBridgeInterface, JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME);
@ -397,7 +396,7 @@ 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 (eventChannelDelegate != null) eventChannelDelegate.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting); if (channelDelegate != null) channelDelegate.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting);
} }
}); });
@ -493,7 +492,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
public boolean onLongClick(View v) { public boolean onLongClick(View v) {
com.pichillilorenzo.flutter_inappwebview.types.HitTestResult hitTestResult = com.pichillilorenzo.flutter_inappwebview.types.HitTestResult hitTestResult =
com.pichillilorenzo.flutter_inappwebview.types.HitTestResult.fromWebViewHitTestResult(getHitTestResult()); com.pichillilorenzo.flutter_inappwebview.types.HitTestResult.fromWebViewHitTestResult(getHitTestResult());
if (eventChannelDelegate != null) eventChannelDelegate.onLongPressHitTestResult(hitTestResult); if (channelDelegate != null) channelDelegate.onLongPressHitTestResult(hitTestResult);
return false; return false;
} }
}); });
@ -1194,7 +1193,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
floatingContextMenu.setVisibility(View.GONE); floatingContextMenu.setVisibility(View.GONE);
} }
if (eventChannelDelegate != null) eventChannelDelegate.onScrollChanged(x, y); if (channelDelegate != null) channelDelegate.onScrollChanged(x, y);
} }
public void scrollTo(Integer x, Integer y, Boolean animated) { public void scrollTo(Integer x, Integer y, Boolean animated) {
@ -1231,7 +1230,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
URLUtil.guessFileName(url, contentDisposition, mimeType), URLUtil.guessFileName(url, contentDisposition, mimeType),
null null
); );
if (eventChannelDelegate != null) eventChannelDelegate.onDownloadStartRequest(downloadStartRequest); if (channelDelegate != null) channelDelegate.onDownloadStartRequest(downloadStartRequest);
} }
} }
@ -1282,7 +1281,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
private void sendOnCreateContextMenuEvent() { private void sendOnCreateContextMenuEvent() {
com.pichillilorenzo.flutter_inappwebview.types.HitTestResult hitTestResult = com.pichillilorenzo.flutter_inappwebview.types.HitTestResult hitTestResult =
com.pichillilorenzo.flutter_inappwebview.types.HitTestResult.fromWebViewHitTestResult(getHitTestResult()); com.pichillilorenzo.flutter_inappwebview.types.HitTestResult.fromWebViewHitTestResult(getHitTestResult());
if (eventChannelDelegate != null) eventChannelDelegate.onCreateContextMenu(hitTestResult); if (channelDelegate != null) channelDelegate.onCreateContextMenu(hitTestResult);
} }
private Point contextMenuPoint = new Point(0, 0); private Point contextMenuPoint = new Point(0, 0);
@ -1315,13 +1314,13 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
PullToRefreshLayout pullToRefreshLayout = (PullToRefreshLayout) parent; PullToRefreshLayout pullToRefreshLayout = (PullToRefreshLayout) parent;
// change over scroll mode to OVER_SCROLL_NEVER in order to disable temporarily the glow effect // change over scroll mode to OVER_SCROLL_NEVER in order to disable temporarily the glow effect
setOverScrollMode(OVER_SCROLL_NEVER); setOverScrollMode(OVER_SCROLL_NEVER);
pullToRefreshLayout.setEnabled(pullToRefreshLayout.options.enabled); pullToRefreshLayout.setEnabled(pullToRefreshLayout.settings.enabled);
// reset over scroll mode // reset over scroll mode
setOverScrollMode(customSettings.overScrollMode); setOverScrollMode(customSettings.overScrollMode);
} }
if (overScrolledHorizontally || overScrolledVertically) { if (overScrolledHorizontally || overScrolledVertically) {
if (eventChannelDelegate != null) eventChannelDelegate.onOverScrolled(scrollX, scrollY, overScrolledHorizontally, overScrolledVertically); if (channelDelegate != null) channelDelegate.onOverScrolled(scrollX, scrollY, overScrolledHorizontally, overScrolledVertically);
} }
} }
@ -1428,13 +1427,13 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
TextView text = (TextView) LayoutInflater.from(this.getContext()) TextView text = (TextView) LayoutInflater.from(this.getContext())
.inflate(R.layout.floating_action_mode_item, this, false); .inflate(R.layout.floating_action_mode_item, this, false);
text.setText(itemTitle); text.setText(itemTitle);
text.setOnClickListener(new OnClickListener() { text.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
hideContextMenu(); hideContextMenu();
callback.onActionItemClicked(actionMode, menuItem); callback.onActionItemClicked(actionMode, menuItem);
if (eventChannelDelegate != null) eventChannelDelegate.onContextMenuActionItemClicked(itemId, itemTitle); if (channelDelegate != null) channelDelegate.onContextMenuActionItemClicked(itemId, itemTitle);
} }
}); });
if (floatingContextMenu != null) { if (floatingContextMenu != null) {
@ -1454,12 +1453,11 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
public void onClick(View v) { public void onClick(View v) {
hideContextMenu(); hideContextMenu();
if (eventChannelDelegate != null) eventChannelDelegate.onContextMenuActionItemClicked(itemId, itemTitle); if (channelDelegate != null) channelDelegate.onContextMenuActionItemClicked(itemId, itemTitle);
} }
}); });
if (floatingContextMenu != null) { if (floatingContextMenu != null) {
menuItemListLayout.addView(text); menuItemListLayout.addView(text);
} }
} }
@ -1531,7 +1529,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
removeView(floatingContextMenu); removeView(floatingContextMenu);
floatingContextMenu = null; floatingContextMenu = null;
if (eventChannelDelegate != null) eventChannelDelegate.onHideContextMenu(); if (channelDelegate != null) channelDelegate.onHideContextMenu();
} }
public void onScrollStopped() { public void onScrollStopped() {
@ -1794,13 +1792,13 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
@Nullable @Nullable
@Override @Override
public EventChannelDelegate getEventChannelDelegate() { public WebViewChannelDelegate getChannelDelegate() {
return eventChannelDelegate; return channelDelegate;
} }
@Override @Override
public void setEventChannelDelegate(@Nullable EventChannelDelegate eventChannelDelegate) { public void setChannelDelegate(@Nullable WebViewChannelDelegate channelDelegate) {
this.eventChannelDelegate = eventChannelDelegate; this.channelDelegate = channelDelegate;
} }
@Override @Override
@ -1824,7 +1822,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
inAppWebViewClient = null; inAppWebViewClient = null;
javaScriptBridgeInterface = null; javaScriptBridgeInterface = null;
inAppWebViewRenderProcessClient = null; inAppWebViewRenderProcessClient = null;
eventChannelDelegate = null; channelDelegate = null;
plugin = null; plugin = null;
super.dispose(); super.dispose();
} }

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_webview; package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
import android.Manifest; import android.Manifest;
import android.annotation.TargetApi; import android.annotation.TargetApi;
@ -53,6 +53,7 @@ import com.pichillilorenzo.flutter_inappwebview.types.JsConfirmResponse;
import com.pichillilorenzo.flutter_inappwebview.types.JsPromptResponse; import com.pichillilorenzo.flutter_inappwebview.types.JsPromptResponse;
import com.pichillilorenzo.flutter_inappwebview.types.PermissionResponse; import com.pichillilorenzo.flutter_inappwebview.types.PermissionResponse;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest; import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@ -62,7 +63,6 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugin.common.PluginRegistry;
import static android.app.Activity.RESULT_OK; import static android.app.Activity.RESULT_OK;
@ -150,9 +150,9 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
if (inAppWebView != null) { if (inAppWebView != null) {
EventChannelDelegate eventChannelDelegate = inAppWebView.eventChannelDelegate; WebViewChannelDelegate eventWebViewChannelDelegate = inAppWebView.channelDelegate;
if (eventChannelDelegate != null) if (eventWebViewChannelDelegate != null)
eventChannelDelegate.onExitFullscreen(); eventWebViewChannelDelegate.onExitFullscreen();
inAppWebView.setInFullscreen(false); inAppWebView.setInFullscreen(false);
} }
} }
@ -188,9 +188,9 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
((FrameLayout) decorView).addView(this.mCustomView, FULLSCREEN_LAYOUT_PARAMS); ((FrameLayout) decorView).addView(this.mCustomView, FULLSCREEN_LAYOUT_PARAMS);
if (inAppWebView != null) { if (inAppWebView != null) {
EventChannelDelegate eventChannelDelegate = inAppWebView.eventChannelDelegate; WebViewChannelDelegate eventWebViewChannelDelegate = inAppWebView.channelDelegate;
if (eventChannelDelegate != null) if (eventWebViewChannelDelegate != null)
eventChannelDelegate.onEnterFullscreen(); eventWebViewChannelDelegate.onEnterFullscreen();
inAppWebView.setInFullscreen(true); inAppWebView.setInFullscreen(true);
} }
} }
@ -198,8 +198,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override @Override
public boolean onJsAlert(final WebView view, String url, final String message, public boolean onJsAlert(final WebView view, String url, final String message,
final JsResult result) { final JsResult result) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) { if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.eventChannelDelegate.onJsAlert(url, message, null, new EventChannelDelegate.JsAlertCallback() { inAppWebView.channelDelegate.onJsAlert(url, message, null, new WebViewChannelDelegate.JsAlertCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull JsAlertResponse response) { public boolean nonNullSuccess(@NonNull JsAlertResponse response) {
if (response.isHandledByClient()) { if (response.isHandledByClient()) {
@ -226,7 +226,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
responseMessage = response.getMessage(); responseMessage = response.getMessage();
confirmButtonTitle = response.getConfirmButtonTitle(); confirmButtonTitle = response.getConfirmButtonTitle();
} }
createAlertDialog(view, message, result, responseMessage, confirmButtonTitle); createAlertDialog(message, result, responseMessage, confirmButtonTitle);
} }
@Override @Override
@ -242,7 +242,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
return false; return false;
} }
public void createAlertDialog(WebView view, String message, final JsResult result, String responseMessage, String confirmButtonTitle) { public void createAlertDialog(String message, final JsResult result, String responseMessage, String confirmButtonTitle) {
String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message; String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message;
DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() { DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
@ -281,8 +281,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override @Override
public boolean onJsConfirm(final WebView view, String url, final String message, public boolean onJsConfirm(final WebView view, String url, final String message,
final JsResult result) { final JsResult result) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) { if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.eventChannelDelegate.onJsConfirm(url, message, null, new EventChannelDelegate.JsConfirmCallback() { inAppWebView.channelDelegate.onJsConfirm(url, message, null, new WebViewChannelDelegate.JsConfirmCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull JsConfirmResponse response) { public boolean nonNullSuccess(@NonNull JsConfirmResponse response) {
if (response.isHandledByClient()) { if (response.isHandledByClient()) {
@ -311,7 +311,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
confirmButtonTitle = response.getConfirmButtonTitle(); confirmButtonTitle = response.getConfirmButtonTitle();
cancelButtonTitle = response.getCancelButtonTitle(); cancelButtonTitle = response.getCancelButtonTitle();
} }
createConfirmDialog(view, message, result, responseMessage, confirmButtonTitle, cancelButtonTitle); createConfirmDialog(message, result, responseMessage, confirmButtonTitle, cancelButtonTitle);
} }
@Override @Override
@ -327,7 +327,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
return false; return false;
} }
public void createConfirmDialog(WebView view, String message, final JsResult result, String responseMessage, String confirmButtonTitle, String cancelButtonTitle) { public void createConfirmDialog(String message, final JsResult result, String responseMessage, String confirmButtonTitle, String cancelButtonTitle) {
String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message; String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message;
DialogInterface.OnClickListener confirmClickListener = new DialogInterface.OnClickListener() { DialogInterface.OnClickListener confirmClickListener = new DialogInterface.OnClickListener() {
@Override @Override
@ -377,8 +377,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override @Override
public boolean onJsPrompt(final WebView view, String url, final String message, public boolean onJsPrompt(final WebView view, String url, final String message,
final String defaultValue, final JsPromptResult result) { final String defaultValue, final JsPromptResult result) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) { if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.eventChannelDelegate.onJsPrompt(url, message, defaultValue, null, new EventChannelDelegate.JsPromptCallback() { inAppWebView.channelDelegate.onJsPrompt(url, message, defaultValue, null, new WebViewChannelDelegate.JsPromptCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull JsPromptResponse response) { public boolean nonNullSuccess(@NonNull JsPromptResponse response) {
if (response.isHandledByClient()) { if (response.isHandledByClient()) {
@ -494,8 +494,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override @Override
public boolean onJsBeforeUnload(final WebView view, String url, final String message, public boolean onJsBeforeUnload(final WebView view, String url, final String message,
final JsResult result) { final JsResult result) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) { if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.eventChannelDelegate.onJsBeforeUnload(url, message, new EventChannelDelegate.JsBeforeUnloadCallback() { inAppWebView.channelDelegate.onJsBeforeUnload(url, message, new WebViewChannelDelegate.JsBeforeUnloadCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull JsBeforeUnloadResponse response) { public boolean nonNullSuccess(@NonNull JsBeforeUnloadResponse response) {
if (response.isHandledByClient()) { if (response.isHandledByClient()) {
@ -524,7 +524,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
confirmButtonTitle = response.getConfirmButtonTitle(); confirmButtonTitle = response.getConfirmButtonTitle();
cancelButtonTitle = response.getCancelButtonTitle(); cancelButtonTitle = response.getCancelButtonTitle();
} }
createBeforeUnloadDialog(view, message, result, responseMessage, confirmButtonTitle, cancelButtonTitle); createBeforeUnloadDialog(message, result, responseMessage, confirmButtonTitle, cancelButtonTitle);
} }
@Override @Override
@ -540,7 +540,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
return false; return false;
} }
public void createBeforeUnloadDialog(WebView view, String message, final JsResult result, String responseMessage, String confirmButtonTitle, String cancelButtonTitle) { public void createBeforeUnloadDialog(String message, final JsResult result, String responseMessage, String confirmButtonTitle, String cancelButtonTitle) {
String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message; String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message;
DialogInterface.OnClickListener confirmClickListener = new DialogInterface.OnClickListener() { DialogInterface.OnClickListener confirmClickListener = new DialogInterface.OnClickListener() {
@Override @Override
@ -620,8 +620,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
windowWebViewMessages.put(windowId, resultMsg); windowWebViewMessages.put(windowId, resultMsg);
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) { if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.eventChannelDelegate.onCreateWindow(createWindowAction, new EventChannelDelegate.CreateWindowCallback() { inAppWebView.channelDelegate.onCreateWindow(createWindowAction, new WebViewChannelDelegate.CreateWindowCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull Boolean handledByClient) { public boolean nonNullSuccess(@NonNull Boolean handledByClient) {
return !handledByClient; return !handledByClient;
@ -647,8 +647,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override @Override
public void onCloseWindow(WebView window) { public void onCloseWindow(WebView window) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) { if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.eventChannelDelegate.onCloseWindow(); inAppWebView.channelDelegate.onCloseWindow();
} }
super.onCloseWindow(window); super.onCloseWindow(window);
@ -656,7 +656,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override @Override
public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) { public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) {
final EventChannelDelegate.GeolocationPermissionsShowPromptCallback resultCallback = new EventChannelDelegate.GeolocationPermissionsShowPromptCallback() { final WebViewChannelDelegate.GeolocationPermissionsShowPromptCallback resultCallback = new WebViewChannelDelegate.GeolocationPermissionsShowPromptCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull GeolocationPermissionShowPromptResponse response) { public boolean nonNullSuccess(@NonNull GeolocationPermissionShowPromptResponse response) {
callback.invoke(response.getOrigin(), response.isAllow(), response.isRetain()); callback.invoke(response.getOrigin(), response.isAllow(), response.isRetain());
@ -675,8 +675,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
}; };
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) { if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.eventChannelDelegate.onGeolocationPermissionsShowPrompt(origin, resultCallback); inAppWebView.channelDelegate.onGeolocationPermissionsShowPrompt(origin, resultCallback);
} else { } else {
resultCallback.defaultBehaviour(null); resultCallback.defaultBehaviour(null);
} }
@ -684,15 +684,15 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override @Override
public void onGeolocationPermissionsHidePrompt() { public void onGeolocationPermissionsHidePrompt() {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) { if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.eventChannelDelegate.onGeolocationPermissionsHidePrompt(); inAppWebView.channelDelegate.onGeolocationPermissionsHidePrompt();
} }
} }
@Override @Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) { public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) { if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.eventChannelDelegate.onConsoleMessage( inAppWebView.channelDelegate.onConsoleMessage(
consoleMessage.message(), consoleMessage.message(),
consoleMessage.messageLevel().ordinal()); consoleMessage.messageLevel().ordinal());
} }
@ -714,8 +714,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
webView.inAppWebViewClient.loadCustomJavaScriptOnPageStarted(view); webView.inAppWebViewClient.loadCustomJavaScriptOnPageStarted(view);
} }
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onProgressChanged(progress); webView.channelDelegate.onProgressChanged(progress);
} }
} }
@ -729,8 +729,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
InAppWebView webView = (InAppWebView) view; InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onTitleChanged(title); webView.channelDelegate.onTitleChanged(title);
} }
} }
@ -752,8 +752,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
icon.recycle(); icon.recycle();
InAppWebView webView = (InAppWebView) view; InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onReceivedIcon(byteArrayOutputStream.toByteArray()); webView.channelDelegate.onReceivedIcon(byteArrayOutputStream.toByteArray());
} }
} }
@ -764,8 +764,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
super.onReceivedTouchIconUrl(view, url, precomposed); super.onReceivedTouchIconUrl(view, url, precomposed);
InAppWebView webView = (InAppWebView) view; InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onReceivedTouchIconUrl(url, precomposed); webView.channelDelegate.onReceivedTouchIconUrl(url, precomposed);
} }
} }
@ -1157,7 +1157,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override @Override
public void onPermissionRequest(final PermissionRequest request) { public void onPermissionRequest(final PermissionRequest request) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final EventChannelDelegate.PermissionRequestCallback callback = new EventChannelDelegate.PermissionRequestCallback() { final WebViewChannelDelegate.PermissionRequestCallback callback = new WebViewChannelDelegate.PermissionRequestCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull PermissionResponse response) { public boolean nonNullSuccess(@NonNull PermissionResponse response) {
Integer action = response.getAction(); Integer action = response.getAction();
@ -1189,8 +1189,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
}; };
if(inAppWebView != null && inAppWebView.eventChannelDelegate != null) { if(inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.eventChannelDelegate.onPermissionRequest(request.getOrigin().toString(), inAppWebView.channelDelegate.onPermissionRequest(request.getOrigin().toString(),
Arrays.asList(request.getResources()), null, callback); Arrays.asList(request.getResources()), null, callback);
} else { } else {
callback.defaultBehaviour(null); callback.defaultBehaviour(null);

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_webview; package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -47,6 +47,7 @@ import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceErrorExt; import com.pichillilorenzo.flutter_inappwebview.types.WebResourceErrorExt;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceRequestExt; import com.pichillilorenzo.flutter_inappwebview.types.WebResourceRequestExt;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceResponseExt; import com.pichillilorenzo.flutter_inappwebview.types.WebResourceResponseExt;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.net.URI; import java.net.URI;
@ -133,7 +134,7 @@ public class InAppWebViewClient extends WebViewClient {
isRedirect isRedirect
); );
final EventChannelDelegate.ShouldOverrideUrlLoadingCallback callback = new EventChannelDelegate.ShouldOverrideUrlLoadingCallback() { final WebViewChannelDelegate.ShouldOverrideUrlLoadingCallback callback = new WebViewChannelDelegate.ShouldOverrideUrlLoadingCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull NavigationActionPolicy result) { public boolean nonNullSuccess(@NonNull NavigationActionPolicy result) {
switch (result) { switch (result) {
@ -159,8 +160,8 @@ public class InAppWebViewClient extends WebViewClient {
} }
}; };
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.shouldOverrideUrlLoading(navigationAction, callback); webView.channelDelegate.shouldOverrideUrlLoading(navigationAction, callback);
} else { } else {
callback.defaultBehaviour(null); callback.defaultBehaviour(null);
} }
@ -204,12 +205,11 @@ public class InAppWebViewClient extends WebViewClient {
inAppBrowserDelegate.didStartNavigation(url); inAppBrowserDelegate.didStartNavigation(url);
} }
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onLoadStart(url); webView.channelDelegate.onLoadStart(url);
} }
} }
public void onPageFinished(WebView view, String url) { public void onPageFinished(WebView view, String url) {
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
webView.isLoading = false; webView.isLoading = false;
@ -238,8 +238,8 @@ public class InAppWebViewClient extends WebViewClient {
webView.loadUrl("javascript:" + js.replaceAll("[\r\n]+", "")); webView.loadUrl("javascript:" + js.replaceAll("[\r\n]+", ""));
} }
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onLoadStop(url); webView.channelDelegate.onLoadStop(url);
} }
} }
@ -255,8 +255,8 @@ public class InAppWebViewClient extends WebViewClient {
} }
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onUpdateVisitedHistory(url, isReload); webView.channelDelegate.onUpdateVisitedHistory(url, isReload);
} }
} }
@ -280,8 +280,8 @@ public class InAppWebViewClient extends WebViewClient {
} }
} }
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onReceivedError( webView.channelDelegate.onReceivedError(
WebResourceRequestExt.fromWebResourceRequest(request), WebResourceRequestExt.fromWebResourceRequest(request),
WebResourceErrorExt.fromWebResourceError(error)); WebResourceErrorExt.fromWebResourceError(error));
} }
@ -317,8 +317,8 @@ public class InAppWebViewClient extends WebViewClient {
description description
); );
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onReceivedError( webView.channelDelegate.onReceivedError(
request, request,
error); error);
} }
@ -332,8 +332,8 @@ public class InAppWebViewClient extends WebViewClient {
super.onReceivedHttpError(view, request, errorResponse); super.onReceivedHttpError(view, request, errorResponse);
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onReceivedHttpError( webView.channelDelegate.onReceivedHttpError(
WebResourceRequestExt.fromWebResourceRequest(request), WebResourceRequestExt.fromWebResourceRequest(request),
WebResourceResponseExt.fromWebResourceResponse(errorResponse)); WebResourceResponseExt.fromWebResourceResponse(errorResponse));
} }
@ -371,7 +371,7 @@ public class InAppWebViewClient extends WebViewClient {
HttpAuthenticationChallenge challenge = new HttpAuthenticationChallenge(protectionSpace, previousAuthRequestFailureCount, credentialProposed); HttpAuthenticationChallenge challenge = new HttpAuthenticationChallenge(protectionSpace, previousAuthRequestFailureCount, credentialProposed);
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.ReceivedHttpAuthRequestCallback callback = new EventChannelDelegate.ReceivedHttpAuthRequestCallback() { final WebViewChannelDelegate.ReceivedHttpAuthRequestCallback callback = new WebViewChannelDelegate.ReceivedHttpAuthRequestCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull HttpAuthResponse response) { public boolean nonNullSuccess(@NonNull HttpAuthResponse response) {
Integer action = response.getAction(); Integer action = response.getAction();
@ -422,8 +422,8 @@ public class InAppWebViewClient extends WebViewClient {
} }
}; };
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onReceivedHttpAuthRequest(challenge, callback); webView.channelDelegate.onReceivedHttpAuthRequest(challenge, callback);
} else { } else {
callback.defaultBehaviour(null); callback.defaultBehaviour(null);
} }
@ -449,7 +449,7 @@ public class InAppWebViewClient extends WebViewClient {
ServerTrustChallenge challenge = new ServerTrustChallenge(protectionSpace); ServerTrustChallenge challenge = new ServerTrustChallenge(protectionSpace);
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.ReceivedServerTrustAuthRequestCallback callback = new EventChannelDelegate.ReceivedServerTrustAuthRequestCallback() { final WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback callback = new WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull ServerTrustAuthResponse response) { public boolean nonNullSuccess(@NonNull ServerTrustAuthResponse response) {
Integer action = response.getAction(); Integer action = response.getAction();
@ -481,8 +481,8 @@ public class InAppWebViewClient extends WebViewClient {
} }
}; };
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onReceivedServerTrustAuthRequest(challenge, callback); webView.channelDelegate.onReceivedServerTrustAuthRequest(challenge, callback);
} else { } else {
callback.defaultBehaviour(null); callback.defaultBehaviour(null);
} }
@ -509,7 +509,7 @@ public class InAppWebViewClient extends WebViewClient {
ClientCertChallenge challenge = new ClientCertChallenge(protectionSpace, request.getPrincipals(), request.getKeyTypes()); ClientCertChallenge challenge = new ClientCertChallenge(protectionSpace, request.getPrincipals(), request.getKeyTypes());
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.ReceivedClientCertRequestCallback callback = new EventChannelDelegate.ReceivedClientCertRequestCallback() { final WebViewChannelDelegate.ReceivedClientCertRequestCallback callback = new WebViewChannelDelegate.ReceivedClientCertRequestCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull ClientCertResponse response) { public boolean nonNullSuccess(@NonNull ClientCertResponse response) {
Integer action = response.getAction(); Integer action = response.getAction();
@ -555,8 +555,8 @@ public class InAppWebViewClient extends WebViewClient {
} }
}; };
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onReceivedClientCertRequest(challenge, callback); webView.channelDelegate.onReceivedClientCertRequest(challenge, callback);
} else { } else {
callback.defaultBehaviour(null); callback.defaultBehaviour(null);
} }
@ -568,8 +568,8 @@ public class InAppWebViewClient extends WebViewClient {
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
webView.zoomScale = newScale / Util.getPixelDensity(webView.getContext()); webView.zoomScale = newScale / Util.getPixelDensity(webView.getContext());
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onZoomScaleChanged(oldScale, newScale); webView.channelDelegate.onZoomScaleChanged(oldScale, newScale);
} }
} }
@ -577,7 +577,7 @@ public class InAppWebViewClient extends WebViewClient {
@Override @Override
public void onSafeBrowsingHit(final WebView view, final WebResourceRequest request, final int threatType, final SafeBrowsingResponse callback) { public void onSafeBrowsingHit(final WebView view, final WebResourceRequest request, final int threatType, final SafeBrowsingResponse callback) {
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.SafeBrowsingHitCallback resultCallback = new EventChannelDelegate.SafeBrowsingHitCallback() { final WebViewChannelDelegate.SafeBrowsingHitCallback resultCallback = new WebViewChannelDelegate.SafeBrowsingHitCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull com.pichillilorenzo.flutter_inappwebview.types.SafeBrowsingResponse response) { public boolean nonNullSuccess(@NonNull com.pichillilorenzo.flutter_inappwebview.types.SafeBrowsingResponse response) {
Integer action = response.getAction(); Integer action = response.getAction();
@ -613,8 +613,8 @@ public class InAppWebViewClient extends WebViewClient {
} }
}; };
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onSafeBrowsingHit(request.getUrl().toString(), threatType, resultCallback); webView.channelDelegate.onSafeBrowsingHit(request.getUrl().toString(), threatType, resultCallback);
} else { } else {
resultCallback.defaultBehaviour(null); resultCallback.defaultBehaviour(null);
} }
@ -647,9 +647,9 @@ public class InAppWebViewClient extends WebViewClient {
if (webView.customSettings.resourceCustomSchemes != null && webView.customSettings.resourceCustomSchemes.contains(scheme)) { if (webView.customSettings.resourceCustomSchemes != null && webView.customSettings.resourceCustomSchemes.contains(scheme)) {
CustomSchemeResponse customSchemeResponse = null; CustomSchemeResponse customSchemeResponse = null;
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
try { try {
customSchemeResponse = webView.eventChannelDelegate.onLoadResourceCustomScheme(url); customSchemeResponse = webView.channelDelegate.onLoadResourceCustomScheme(url);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
@ -711,9 +711,9 @@ public class InAppWebViewClient extends WebViewClient {
} }
WebResourceResponseExt response = null; WebResourceResponseExt response = null;
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
try { try {
response = webView.eventChannelDelegate.shouldInterceptRequest(requestExt); response = webView.channelDelegate.shouldInterceptRequest(requestExt);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
@ -743,7 +743,7 @@ public class InAppWebViewClient extends WebViewClient {
@Override @Override
public void onFormResubmission(final WebView view, final Message dontResend, final Message resend) { public void onFormResubmission(final WebView view, final Message dontResend, final Message resend) {
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.FormResubmissionCallback callback = new EventChannelDelegate.FormResubmissionCallback() { final WebViewChannelDelegate.FormResubmissionCallback callback = new WebViewChannelDelegate.FormResubmissionCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull Integer action) { public boolean nonNullSuccess(@NonNull Integer action) {
switch (action) { switch (action) {
@ -769,8 +769,8 @@ public class InAppWebViewClient extends WebViewClient {
} }
}; };
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onFormResubmission(webView.getUrl(), callback); webView.channelDelegate.onFormResubmission(webView.getUrl(), callback);
} else { } else {
callback.defaultBehaviour(null); callback.defaultBehaviour(null);
} }
@ -781,8 +781,8 @@ public class InAppWebViewClient extends WebViewClient {
super.onPageCommitVisible(view, url); super.onPageCommitVisible(view, url);
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onPageCommitVisible(url); webView.channelDelegate.onPageCommitVisible(url);
} }
} }
@ -791,10 +791,10 @@ public class InAppWebViewClient extends WebViewClient {
public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
if (webView.customSettings.useOnRenderProcessGone && webView.eventChannelDelegate != null) { if (webView.customSettings.useOnRenderProcessGone && webView.channelDelegate != null) {
boolean didCrash = detail.didCrash(); boolean didCrash = detail.didCrash();
int rendererPriorityAtExit = detail.rendererPriorityAtExit(); int rendererPriorityAtExit = detail.rendererPriorityAtExit();
webView.eventChannelDelegate.onRenderProcessGone(didCrash, rendererPriorityAtExit); webView.channelDelegate.onRenderProcessGone(didCrash, rendererPriorityAtExit);
return true; return true;
} }
@ -804,8 +804,8 @@ public class InAppWebViewClient extends WebViewClient {
@Override @Override
public void onReceivedLoginRequest(WebView view, String realm, String account, String args) { public void onReceivedLoginRequest(WebView view, String realm, String account, String args) {
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onReceivedLoginRequest(realm, account, args); webView.channelDelegate.onReceivedLoginRequest(realm, account, args);
} }
} }

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_webview; package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
import android.util.Log; import android.util.Log;
import android.webkit.WebView; import android.webkit.WebView;
@ -9,6 +9,8 @@ import androidx.webkit.WebViewFeature;
import androidx.webkit.WebViewRenderProcess; import androidx.webkit.WebViewRenderProcess;
import androidx.webkit.WebViewRenderProcessClient; import androidx.webkit.WebViewRenderProcessClient;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient { public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient {
protected static final String LOG_TAG = "IAWRenderProcessClient"; protected static final String LOG_TAG = "IAWRenderProcessClient";
@ -20,7 +22,7 @@ public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient
@Override @Override
public void onRenderProcessUnresponsive(@NonNull WebView view, @Nullable final WebViewRenderProcess renderer) { public void onRenderProcessUnresponsive(@NonNull WebView view, @Nullable final WebViewRenderProcess renderer) {
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.RenderProcessUnresponsiveCallback callback = new EventChannelDelegate.RenderProcessUnresponsiveCallback() { final WebViewChannelDelegate.RenderProcessUnresponsiveCallback callback = new WebViewChannelDelegate.RenderProcessUnresponsiveCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull Integer action) { public boolean nonNullSuccess(@NonNull Integer action) {
if (renderer != null) { if (renderer != null) {
@ -47,8 +49,8 @@ public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient
} }
}; };
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onRenderProcessUnresponsive(webView.getUrl(), callback); webView.channelDelegate.onRenderProcessUnresponsive(webView.getUrl(), callback);
} else { } else {
callback.defaultBehaviour(null); callback.defaultBehaviour(null);
} }
@ -57,7 +59,7 @@ public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient
@Override @Override
public void onRenderProcessResponsive(@NonNull WebView view, @Nullable final WebViewRenderProcess renderer) { public void onRenderProcessResponsive(@NonNull WebView view, @Nullable final WebViewRenderProcess renderer) {
final InAppWebView webView = (InAppWebView) view; final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.RenderProcessResponsiveCallback callback = new EventChannelDelegate.RenderProcessResponsiveCallback() { final WebViewChannelDelegate.RenderProcessResponsiveCallback callback = new WebViewChannelDelegate.RenderProcessResponsiveCallback() {
@Override @Override
public boolean nonNullSuccess(@NonNull Integer action) { public boolean nonNullSuccess(@NonNull Integer action) {
if (renderer != null) { if (renderer != null) {
@ -84,8 +86,8 @@ public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient
} }
}; };
if (webView.eventChannelDelegate != null) { if (webView.channelDelegate != null) {
webView.eventChannelDelegate.onRenderProcessResponsive(webView.getUrl(), callback); webView.channelDelegate.onRenderProcessResponsive(webView.getUrl(), callback);
} else { } else {
callback.defaultBehaviour(null); callback.defaultBehaviour(null);
} }

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_webview; package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
import android.os.Build; import android.os.Build;
import android.view.View; import android.view.View;
@ -9,7 +9,7 @@ import androidx.webkit.WebSettingsCompat;
import androidx.webkit.WebViewFeature; import androidx.webkit.WebViewFeature;
import com.pichillilorenzo.flutter_inappwebview.ISettings; import com.pichillilorenzo.flutter_inappwebview.ISettings;
import com.pichillilorenzo.flutter_inappwebview.types.InAppWebViewInterface; import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
import com.pichillilorenzo.flutter_inappwebview.types.PreferredContentModeOptionType; import com.pichillilorenzo.flutter_inappwebview.types.PreferredContentModeOptionType;
import java.util.ArrayList; import java.util.ArrayList;

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_webview; package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
import static android.content.Context.INPUT_METHOD_SERVICE; import static android.content.Context.INPUT_METHOD_SERVICE;
@ -20,7 +20,7 @@ import androidx.annotation.Nullable;
* *
* These hacks are only needed in Android versions below N and exist to create an InputConnection * These hacks are only needed in Android versions below N and exist to create an InputConnection
* on the WebView's dedicated input, or IME, thread. The majority of this proxying logic is in * on the WebView's dedicated input, or IME, thread. The majority of this proxying logic is in
* https://github.com/flutter/plugins/blob/master/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java * https://github.com/flutter/plugins/blob/main/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java
*/ */
public class InputAwareWebView extends WebView { public class InputAwareWebView extends WebView {
private static final String LOG_TAG = "InputAwareWebView"; private static final String LOG_TAG = "InputAwareWebView";
@ -196,6 +196,13 @@ public class InputAwareWebView extends WebView {
new Runnable() { new Runnable() {
@Override @Override
public void run() { public void run() {
if (containerView == null) {
Log.e(
LOG_TAG,
"Can't set the input connection target because there is no containerView to use as a handler.");
return;
}
InputMethodManager imm = InputMethodManager imm =
(InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE); (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
// This is a hack to make InputMethodManager believe that the target view now has focus. // This is a hack to make InputMethodManager believe that the target view now has focus.

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.in_app_webview; package com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
@ -9,7 +9,7 @@ import android.view.inputmethod.InputConnection;
/** /**
* A fake View only exposed to InputMethodManager. * A fake View only exposed to InputMethodManager.
* *
* https://github.com/flutter/plugins/blob/master/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java * https://github.com/flutter/plugins/blob/main/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java
*/ */
final class ThreadedInputConnectionProxyAdapterView extends View { final class ThreadedInputConnectionProxyAdapterView extends View {
final Handler imeHandler; final Handler imeHandler;

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.types; package com.pichillilorenzo.flutter_inappwebview.webview.web_message;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
@ -9,8 +9,11 @@ import androidx.webkit.WebMessagePortCompat;
import androidx.webkit.WebViewCompat; import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature; import androidx.webkit.WebViewFeature;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS; import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
import com.pichillilorenzo.flutter_inappwebview.types.WebMessagePort;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -21,19 +24,22 @@ import java.util.Map;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class WebMessageChannel implements MethodChannel.MethodCallHandler { public class WebMessageChannel implements Disposable {
static final String LOG_TAG = "WebMessageChannel"; protected static final String LOG_TAG = "WebMessageChannel";
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_channel_";
public String id; public String id;
public MethodChannel channel; @Nullable
public WebMessageChannelChannelDelegate channelDelegate;
public final List<WebMessagePortCompat> compatPorts; public final List<WebMessagePortCompat> compatPorts;
public final List<WebMessagePort> ports; public final List<WebMessagePort> ports;
@Nullable
public InAppWebViewInterface webView; public InAppWebViewInterface webView;
public WebMessageChannel(@NonNull String id, @NonNull InAppWebViewInterface webView) { public WebMessageChannel(@NonNull String id, @NonNull InAppWebViewInterface webView) {
this.id = id; this.id = id;
this.channel = new MethodChannel(webView.getPlugin().messenger, "com.pichillilorenzo/flutter_inappwebview_web_message_channel_" + id); final MethodChannel channel = new MethodChannel(webView.getPlugin().messenger, METHOD_CHANNEL_NAME_PREFIX + id);
this.channel.setMethodCallHandler(this); this.channelDelegate = new WebMessageChannelChannelDelegate(this, channel);
if (webView instanceof InAppWebView) { if (webView instanceof InAppWebView) {
this.compatPorts = new ArrayList<>(Arrays.asList(WebViewCompat.createWebMessageChannel((InAppWebView) webView))); this.compatPorts = new ArrayList<>(Arrays.asList(WebViewCompat.createWebMessageChannel((InAppWebView) webView)));
this.ports = new ArrayList<>(); this.ports = new ArrayList<>();
@ -59,54 +65,18 @@ public class WebMessageChannel implements MethodChannel.MethodCallHandler {
callback.onReceiveValue(this); callback.onReceiveValue(this);
} }
} }
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) {
case "setWebMessageCallback":
if (webView instanceof InAppWebView) {
final Integer index = (Integer) call.argument("index");
setWebMessageCallbackForInAppWebView(index, result);
} else {
result.success(true);
}
break;
case "postMessage":
if (webView instanceof InAppWebView) {
final Integer index = (Integer) call.argument("index");
Map<String, Object> message = (Map<String, Object>) call.argument("message");
postMessageForInAppWebView(index, message, result);
} else {
result.success(true);
}
break;
case "close":
if (webView instanceof InAppWebView) {
Integer index = (Integer) call.argument("index");
closeForInAppWebView(index, result);
} else {
result.success(true);
}
break;
default:
result.notImplemented();
}
}
private void setWebMessageCallbackForInAppWebView(final Integer index, @NonNull MethodChannel.Result result) { public void setWebMessageCallbackForInAppWebView(final int index, @NonNull MethodChannel.Result result) {
if (webView != null && compatPorts.size() > 0 && if (webView != null && compatPorts.size() > 0 &&
WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK)) { WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK)) {
final WebMessagePortCompat webMessagePort = compatPorts.get(index); final WebMessagePortCompat webMessagePort = compatPorts.get(index);
final WebMessageChannel webMessageChannel = this;
try { try {
webMessagePort.setWebMessageCallback(new WebMessagePortCompat.WebMessageCallbackCompat() { webMessagePort.setWebMessageCallback(new WebMessagePortCompat.WebMessageCallbackCompat() {
@Override @Override
public void onMessage(@NonNull WebMessagePortCompat port, @Nullable WebMessageCompat message) { public void onMessage(@NonNull WebMessagePortCompat port, @Nullable WebMessageCompat message) {
super.onMessage(port, message); super.onMessage(port, message);
webMessageChannel.onMessage(index, message != null ? message.getData() : null);
Map<String, Object> obj = new HashMap<>();
obj.put("index", index);
obj.put("message", message != null ? message.getData() : null);
channel.invokeMethod("onMessage", obj);
} }
}); });
result.success(true); result.success(true);
@ -118,7 +88,7 @@ public class WebMessageChannel implements MethodChannel.MethodCallHandler {
} }
} }
private void postMessageForInAppWebView(final Integer index, Map<String, Object> message, @NonNull MethodChannel.Result result) { public void postMessageForInAppWebView(final Integer index, Map<String, Object> message, @NonNull MethodChannel.Result result) {
if (webView != null && compatPorts.size() > 0 && if (webView != null && compatPorts.size() > 0 &&
WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE)) { WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE)) {
WebMessagePortCompat port = compatPorts.get(index); WebMessagePortCompat port = compatPorts.get(index);
@ -146,7 +116,7 @@ public class WebMessageChannel implements MethodChannel.MethodCallHandler {
} }
} }
private void closeForInAppWebView(Integer index, @NonNull MethodChannel.Result result) { public void closeForInAppWebView(Integer index, @NonNull MethodChannel.Result result) {
if (webView != null && compatPorts.size() > 0 && if (webView != null && compatPorts.size() > 0 &&
WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_CLOSE)) { WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_CLOSE)) {
WebMessagePortCompat port = compatPorts.get(index); WebMessagePortCompat port = compatPorts.get(index);
@ -161,11 +131,10 @@ public class WebMessageChannel implements MethodChannel.MethodCallHandler {
} }
} }
public void onMessage(Integer index, String message) { public void onMessage(int index, String message) {
Map<String, Object> obj = new HashMap<>(); if (channelDelegate != null) {
obj.put("index", index); channelDelegate.onMessage(index, message);
obj.put("message", message ); }
channel.invokeMethod("onMessage", obj);
} }
public Map<String, Object> toMap() { public Map<String, Object> toMap() {
@ -182,8 +151,11 @@ public class WebMessageChannel implements MethodChannel.MethodCallHandler {
} catch (Exception ignored) {} } catch (Exception ignored) {}
} }
} }
this.channel.setMethodCallHandler(null); if (channelDelegate != null) {
this.compatPorts.clear(); channelDelegate.dispose();
this.webView = null; channelDelegate = null;
}
compatPorts.clear();
webView = null;
} }
} }

View File

@ -0,0 +1,72 @@
package com.pichillilorenzo.flutter_inappwebview.webview.web_message;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class WebMessageChannelChannelDelegate extends ChannelDelegateImpl {
@Nullable
private WebMessageChannel webMessageChannel;
public WebMessageChannelChannelDelegate(@NonNull WebMessageChannel webMessageChannel, @NonNull MethodChannel channel) {
super(channel);
this.webMessageChannel = webMessageChannel;
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) {
case "setWebMessageCallback":
if (webMessageChannel != null && webMessageChannel.webView instanceof InAppWebView) {
final Integer index = (Integer) call.argument("index");
webMessageChannel.setWebMessageCallbackForInAppWebView(index, result);
} else {
result.success(true);
}
break;
case "postMessage":
if (webMessageChannel != null && webMessageChannel.webView instanceof InAppWebView) {
final Integer index = (Integer) call.argument("index");
Map<String, Object> message = (Map<String, Object>) call.argument("message");
webMessageChannel.postMessageForInAppWebView(index, message, result);
} else {
result.success(true);
}
break;
case "close":
if (webMessageChannel != null && webMessageChannel.webView instanceof InAppWebView) {
Integer index = (Integer) call.argument("index");
webMessageChannel.closeForInAppWebView(index, result);
} else {
result.success(true);
}
break;
default:
result.notImplemented();
}
}
public void onMessage(int index, String message) {
MethodChannel channel = getChannel();
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("index", index);
obj.put("message", message );
channel.invokeMethod("onMessage", obj);
}
@Override
public void dispose() {
super.dispose();
webMessageChannel = null;
}
}

View File

@ -1,8 +1,7 @@
package com.pichillilorenzo.flutter_inappwebview.types; package com.pichillilorenzo.flutter_inappwebview.webview.web_message;
import android.net.Uri; import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import android.webkit.ValueCallback;
import android.webkit.WebView; import android.webkit.WebView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -13,11 +12,14 @@ 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.in_app_webview.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS; import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.JavaScriptBridgeJS;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.webview.InAppWebViewInterface;
import com.pichillilorenzo.flutter_inappwebview.types.PluginScript;
import com.pichillilorenzo.flutter_inappwebview.types.UserScriptInjectionTime;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -27,29 +29,38 @@ import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class WebMessageListener implements MethodChannel.MethodCallHandler { public class WebMessageListener implements Disposable {
static final String LOG_TAG = "WebMessageListener"; protected static final String LOG_TAG = "WebMessageListener";
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_listener_";
public String jsObjectName; public String jsObjectName;
public Set<String> allowedOriginRules; public Set<String> allowedOriginRules;
public WebViewCompat.WebMessageListener listener; public WebViewCompat.WebMessageListener listener;
public JavaScriptReplyProxy replyProxy; public JavaScriptReplyProxy replyProxy;
public MethodChannel channel; @Nullable
public InAppWebViewInterface webView; public InAppWebViewInterface webView;
@Nullable
public WebMessageListenerChannelDelegate channelDelegate;
public WebMessageListener(@NonNull InAppWebViewInterface webView, @NonNull BinaryMessenger messenger, @NonNull String jsObjectName, @NonNull Set<String> allowedOriginRules) { public WebMessageListener(@NonNull InAppWebViewInterface webView, @NonNull BinaryMessenger messenger,
@NonNull String jsObjectName, @NonNull Set<String> allowedOriginRules) {
this.webView = webView; this.webView = webView;
this.jsObjectName = jsObjectName; this.jsObjectName = jsObjectName;
this.allowedOriginRules = allowedOriginRules; this.allowedOriginRules = allowedOriginRules;
this.channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappwebview_web_message_listener_" + this.jsObjectName); final MethodChannel channel = new MethodChannel(messenger, METHOD_CHANNEL_NAME_PREFIX + this.jsObjectName);
this.channel.setMethodCallHandler(this); this.channelDelegate = new WebMessageListenerChannelDelegate(this, channel);
if (this.webView instanceof InAppWebView) { if (this.webView instanceof InAppWebView) {
final WebMessageListener self = this;
this.listener = new WebViewCompat.WebMessageListener() { this.listener = new WebViewCompat.WebMessageListener() {
@Override @Override
public void onPostMessage(@NonNull WebView view, @NonNull WebMessageCompat message, @NonNull Uri sourceOrigin, boolean isMainFrame, @NonNull JavaScriptReplyProxy javaScriptReplyProxy) { public void onPostMessage(@NonNull WebView view, @NonNull WebMessageCompat message, @NonNull Uri sourceOrigin,
boolean isMainFrame, @NonNull JavaScriptReplyProxy javaScriptReplyProxy) {
replyProxy = javaScriptReplyProxy; replyProxy = javaScriptReplyProxy;
self.onPostMessage(message.getData(), sourceOrigin, isMainFrame); if (channelDelegate != null) {
channelDelegate.onPostMessage(message.getData(),
sourceOrigin.toString().equals("null") ? null : sourceOrigin.toString(),
isMainFrame);
}
} }
}; };
} }
@ -103,22 +114,6 @@ public class WebMessageListener implements MethodChannel.MethodCallHandler {
return new WebMessageListener(webView, messenger, jsObjectName, allowedOriginRules); return new WebMessageListener(webView, messenger, jsObjectName, allowedOriginRules);
} }
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) {
case "postMessage":
if (webView instanceof InAppWebView) {
String message = (String) call.argument("message");
postMessageForInAppWebView(message, result);
} else {
result.success(true);
}
break;
default:
result.notImplemented();
}
}
public void assertOriginRulesValid() throws Exception { public void assertOriginRulesValid() throws Exception {
int index = 0; int index = 0;
for (String originRule : allowedOriginRules) { for (String originRule : allowedOriginRules) {
@ -170,7 +165,7 @@ public class WebMessageListener implements MethodChannel.MethodCallHandler {
} }
} }
private void postMessageForInAppWebView(String message, @NonNull MethodChannel.Result result) { public void postMessageForInAppWebView(String message, @NonNull MethodChannel.Result result) {
if (replyProxy != null && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) { if (replyProxy != null && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
replyProxy.postMessage(message); replyProxy.postMessage(message);
} }
@ -218,19 +213,14 @@ public class WebMessageListener implements MethodChannel.MethodCallHandler {
} }
return false; return false;
} }
public void onPostMessage(String message, Uri sourceOrigin, boolean isMainFrame) {
Map<String, Object> obj = new HashMap<>();
obj.put("message", message);
obj.put("sourceOrigin", sourceOrigin.toString().equals("null") ? null : sourceOrigin.toString());
obj.put("isMainFrame", isMainFrame);
channel.invokeMethod("onPostMessage", obj);
}
public void dispose() { public void dispose() {
this.channel.setMethodCallHandler(null); if (channelDelegate != null) {
this.listener = null; channelDelegate.dispose();
this.replyProxy = null; channelDelegate = null;
this.webView = null; }
listener = null;
replyProxy = null;
webView = null;
} }
} }

View File

@ -0,0 +1,57 @@
package com.pichillilorenzo.flutter_inappwebview.webview.web_message;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.headless_in_app_webview.HeadlessInAppWebView;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class WebMessageListenerChannelDelegate extends ChannelDelegateImpl {
@Nullable
private WebMessageListener webMessageListener;
public WebMessageListenerChannelDelegate(@NonNull WebMessageListener webMessageListener, @NonNull MethodChannel channel) {
super(channel);
this.webMessageListener = webMessageListener;
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) {
case "postMessage":
if (webMessageListener != null && webMessageListener.webView instanceof InAppWebView) {
String message = (String) call.argument("message");
webMessageListener.postMessageForInAppWebView(message, result);
} else {
result.success(true);
}
break;
default:
result.notImplemented();
}
}
public void onPostMessage(String message, String sourceOrigin, boolean isMainFrame) {
MethodChannel channel = getChannel();
if (channel == null) return;
Map<String, Object> obj = new HashMap<>();
obj.put("message", message);
obj.put("sourceOrigin", sourceOrigin);
obj.put("isMainFrame", isMainFrame);
channel.invokeMethod("onPostMessage", obj);
}
@Override
public void dispose() {
super.dispose();
webMessageListener = null;
}
}

View File

@ -14,7 +14,7 @@
android:id="@+id/pullToRefresh" android:id="@+id/pullToRefresh"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView <com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView
android:id="@+id/webView" android:id="@+id/webView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />