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 com.pichillilorenzo.flutter_inappwebview.in_app_webview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.types.PlatformWebView;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.FlutterWebView;
import com.pichillilorenzo.flutter_inappwebview.webview.PlatformWebView;
import com.pichillilorenzo.flutter_inappwebview.types.WebViewImplementation;
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.headless_in_app_webview.HeadlessInAppWebViewManager;
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.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.WebView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.webkit.WebViewCompat;
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.util.HashMap;
import java.util.HashSet;
@ -20,21 +24,20 @@ import java.util.Set;
import io.flutter.plugin.common.MethodCall;
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";
public MethodChannel channel;
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static";
@Nullable
public InAppWebViewFlutterPlugin plugin;
public InAppWebViewStatic(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_static");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(MethodCall call, final MethodChannel.Result result) {
public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) {
switch (call.method) {
case "getDefaultUserAgent":
result.success(WebSettings.getDefaultUserAgent(plugin.applicationContext));
@ -124,8 +127,9 @@ public class InAppWebViewStatic implements MethodChannel.MethodCallHandler {
return webViewPackageInfoMap;
}
@Override
public void dispose() {
channel.setMethodCallHandler(null);
super.dispose();
plugin = null;
}
}

View File

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

View File

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

View File

@ -2,32 +2,34 @@ package com.pichillilorenzo.flutter_inappwebview;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
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";
public MethodChannel channel;
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil";
@Nullable
public InAppWebViewFlutterPlugin plugin;
public PlatformUtil(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_platformutil");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(MethodCall call, final MethodChannel.Result result) {
public void onMethodCall(@NonNull MethodCall call, @NonNull final MethodChannel.Result result) {
switch (call.method) {
case "getSystemVersion":
result.success(String.valueOf(Build.VERSION.SDK_INT));
@ -64,8 +66,9 @@ public class PlatformUtil implements MethodChannel.MethodCallHandler {
return sdf.format(new Date(date));
}
@Override
public void dispose() {
channel.setMethodCallHandler(null);
super.dispose();
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);
}
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,
final @NonNull String method, final @Nullable Object arguments,
final @NonNull SyncBaseCallbackResultImpl<T> callback) throws InterruptedException {
@ -144,16 +106,6 @@ public class Util {
return callback.result;
}
public static class WaitFlutterResult {
public Object result;
public String error;
public WaitFlutterResult(Object r, String e) {
result = r;
error = e;
}
}
@Nullable
public static PrivateKeyAndCertificates loadPrivateKeyAndCertificate(@NonNull InAppWebViewFlutterPlugin plugin,
@NonNull String certificatePath,

View File

@ -1,28 +1,29 @@
package com.pichillilorenzo.flutter_inappwebview;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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.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
public InAppWebViewFlutterPlugin plugin;
public WebViewFeatureManager(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_webviewfeature");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) {
case "isFeatureSupported":
String feature = (String) call.argument("feature");
@ -33,8 +34,9 @@ public class WebViewFeatureManager implements MethodChannel.MethodCallHandler {
}
}
@Override
public void dispose() {
channel.setMethodCallHandler(null);
super.dispose();
plugin = null;
}
}

View File

@ -29,7 +29,7 @@ public class ActionBroadcastReceiver extends BroadcastReceiver {
String managerId = b.getString(CHROME_MANAGER_ID);
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<>();
obj.put("url", url);
obj.put("title", title);

View File

@ -10,6 +10,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabColorSchemeParams;
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.types.CustomTabsActionButton;
import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsMenuItem;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.util.ArrayList;
import java.util.HashMap;
@ -29,13 +31,14 @@ import java.util.Map;
import io.flutter.plugin.common.MethodCall;
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";
public MethodChannel channel;
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_chromesafaribrowser_";
public String id;
@Nullable
public CustomTabsIntent.Builder builder;
public ChromeCustomTabsSettings customSettings;
public ChromeCustomTabsSettings customSettings = new ChromeCustomTabsSettings();
public CustomTabActivityHelper customTabActivityHelper = new CustomTabActivityHelper();
@Nullable
public CustomTabsSession customTabsSession;
@ -48,6 +51,8 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
public List<CustomTabsMenuItem> menuItems = new ArrayList<>();
@Nullable
public CustomTabsActionButton actionButton;
@Nullable
public ChromeCustomTabsChannelDelegate channelDelegate;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -64,8 +69,8 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
manager = ChromeSafariBrowserManager.shared.get(managerId);
if (manager == null || manager.plugin == null|| manager.plugin.messenger == null) return;
channel = new MethodChannel(manager.plugin.messenger, "com.pichillilorenzo/flutter_chromesafaribrowser_" + id);
channel.setMethodCallHandler(this);
MethodChannel channel = new MethodChannel(manager.plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
channelDelegate = new ChromeCustomTabsChannelDelegate(this, channel);
initialUrl = b.getString("url");
@ -97,14 +102,16 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
public void onNavigationEvent(int navigationEvent, Bundle extras) {
if (navigationEvent == TAB_SHOWN && !onChromeSafariBrowserOpened) {
onChromeSafariBrowserOpened = true;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onChromeSafariBrowserOpened", obj);
if (channelDelegate != null) {
channelDelegate.onChromeSafariBrowserOpened();
}
}
if (navigationEvent == NAVIGATION_FINISHED && !onChromeSafariBrowserCompletedInitialLoad) {
onChromeSafariBrowserCompletedInitialLoad = true;
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onChromeSafariBrowserCompletedInitialLoad", obj);
if (channelDelegate != null) {
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() {
customTabsSession = customTabActivityHelper.getSession();
Uri uri = Uri.parse(initialUrl);
@ -229,6 +211,11 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
customTabActivityHelper.unbindCustomTabsService(this);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CHROME_CUSTOM_TAB_REQUEST_CODE) {
@ -255,15 +242,20 @@ public class ChromeCustomTabsActivity extends Activity implements MethodChannel.
}
}
@Override
public void dispose() {
channel.setMethodCallHandler(null);
if (channelDelegate != null) {
channelDelegate.dispose();
channelDelegate = null;
}
manager = null;
}
public void close() {
customTabsSession = null;
finish();
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onChromeSafariBrowserClosed", obj);
if (channelDelegate != null) {
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.Util;
import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import java.io.Serializable;
import java.util.HashMap;
@ -18,20 +20,19 @@ import java.util.UUID;
import io.flutter.plugin.common.MethodCall;
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";
public MethodChannel channel;
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser";
@Nullable
public InAppWebViewFlutterPlugin plugin;
public String id;
public static final Map<String, ChromeSafariBrowserManager> shared = new HashMap<>();
public ChromeSafariBrowserManager(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.id = UUID.randomUUID().toString();
this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_chromesafaribrowser");
channel.setMethodCallHandler(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);
}
@Override
public void dispose() {
channel.setMethodCallHandler(null);
super.dispose();
shared.remove(this.id);
plugin = null;
}

View File

@ -7,7 +7,7 @@ import android.webkit.WebResourceResponse;
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 java.io.ByteArrayInputStream;

View File

@ -8,6 +8,8 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
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.URLProtectionSpace;
@ -20,24 +22,22 @@ import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
@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;
@Nullable
public InAppWebViewFlutterPlugin plugin;
public CredentialDatabaseHandler(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_credential_database");
channel.setMethodCallHandler(this);
credentialDatabase = CredentialDatabase.getInstance(plugin.applicationContext);
}
@Override
public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) {
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
switch (call.method) {
case "getAllAuthCredentials":
{
@ -122,9 +122,9 @@ public class CredentialDatabaseHandler implements MethodChannel.MethodCallHandle
}
}
@Override
public void dispose() {
channel.setMethodCallHandler(null);
super.dispose();
plugin = null;
}
}

View File

@ -9,21 +9,23 @@ import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
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 java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class HeadlessInAppWebView implements MethodChannel.MethodCallHandler {
public class HeadlessInAppWebView implements Disposable {
protected static final String LOG_TAG = "HeadlessInAppWebView";
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_headless_inappwebview_";
@NonNull
public final String id;
public final MethodChannel channel;
@Nullable
public HeadlessWebViewChannelDelegate channelDelegate;
@Nullable
public FlutterWebView flutterWebView;
@Nullable
@ -33,40 +35,14 @@ public class HeadlessInAppWebView implements MethodChannel.MethodCallHandler {
this.id = id;
this.plugin = plugin;
this.flutterWebView = flutterWebView;
this.channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_headless_inappwebview_" + id);
channel.setMethodCallHandler(this);
}
@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();
}
final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
this.channelDelegate = new HeadlessWebViewChannelDelegate(this, channel);
}
public void onWebViewCreated() {
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onWebViewCreated", obj);
if (channelDelegate != null) {
channelDelegate.onWebViewCreated();
}
}
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.
// This way is also possible to take screenshots.
ViewGroup contentView = (ViewGroup) plugin.activity.findViewById(android.R.id.content);
ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0);
if (mainView != null && flutterWebView != null) {
View view = flutterWebView.getView();
final Map<String, Object> initialSize = (Map<String, Object>) params.get("initialSize");
Size2D size = Size2D.fromMap(initialSize);
if (size != null) {
setSize(size);
} else {
view.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
if (contentView != null) {
ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0);
if (mainView != null && flutterWebView != null) {
View view = flutterWebView.getView();
final Map<String, Object> initialSize = (Map<String, Object>) params.get("initialSize");
Size2D size = Size2D.fromMap(initialSize);
if (size != null) {
setSize(size);
} 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() {
channel.setMethodCallHandler(null);
if (channelDelegate != null) {
channelDelegate.dispose();
channelDelegate = null;
}
if (HeadlessInAppWebViewManager.webViews.containsKey(id)) {
HeadlessInAppWebViewManager.webViews.put(id, null);
}

View File

@ -25,29 +25,29 @@ import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
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.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
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";
public MethodChannel channel;
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview";
public static final Map<String, HeadlessInAppWebView> webViews = new HashMap<>();
@Nullable
public InAppWebViewFlutterPlugin plugin;
public HeadlessInAppWebViewManager(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_headless_inappwebview");
channel.setMethodCallHandler(this);
}
@Override
@ -79,8 +79,9 @@ public class HeadlessInAppWebViewManager implements MethodChannel.MethodCallHand
flutterWebView.makeInitialLoad(params);
}
@Override
public void dispose() {
channel.setMethodCallHandler(null);
super.dispose();
Collection<HeadlessInAppWebView> headlessInAppWebViews = webViews.values();
for (HeadlessInAppWebView headlessInAppWebView : headlessInAppWebViews) {
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.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.Util;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebViewChromeClient;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebViewSettings;
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshChannelDelegate;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
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.PullToRefreshSettings;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
@ -43,25 +45,34 @@ import java.util.Map;
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";
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappbrowser_";
static final String LOG_TAG = "InAppBrowserActivity";
public MethodChannel channel;
@Nullable
public Integer windowId;
public String id;
@Nullable
public InAppWebView webView;
@Nullable
public PullToRefreshLayout pullToRefreshLayout;
@Nullable
public ActionBar actionBar;
@Nullable
public Menu menu;
@Nullable
public SearchView searchView;
public InAppBrowserSettings customSettings = new InAppBrowserSettings();
@Nullable
public ProgressBar progressBar;
public boolean isHidden = false;
@Nullable
public String fromActivity;
private List<ActivityResultListener> activityResultListeners = new ArrayList<>();
public InAppWebViewMethodHandler methodCallDelegate;
@Nullable
public InAppBrowserManager manager;
@Nullable
public InAppBrowserChannelDelegate channelDelegate;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -81,27 +92,25 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
windowId = b.getInt("windowId");
channel = new MethodChannel(manager.plugin.messenger, "com.pichillilorenzo/flutter_inappbrowser_" + id);
setContentView(R.layout.activity_web_view);
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.parse(pullToRefreshInitialSettings);
pullToRefreshLayout = findViewById(R.id.pullToRefresh);
pullToRefreshLayout.channel = pullToRefreshLayoutChannel;
pullToRefreshLayout.options = pullToRefreshSettings;
pullToRefreshLayout.channelDelegate = new PullToRefreshChannelDelegate(pullToRefreshLayout, pullToRefreshLayoutChannel);
pullToRefreshLayout.settings = pullToRefreshSettings;
pullToRefreshLayout.prepare();
webView = findViewById(R.id.webView);
webView.windowId = windowId;
webView.inAppBrowserDelegate = this;
webView.channel = channel;
webView.plugin = manager.plugin;
methodCallDelegate = new InAppWebViewMethodHandler(webView);
channel.setMethodCallHandler(methodCallDelegate);
final MethodChannel channel = new MethodChannel(manager.plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
channelDelegate = new InAppBrowserChannelDelegate(channel);
webView.channelDelegate = new WebViewChannelDelegate(webView, channel);
fromActivity = b.getString("fromActivity");
@ -153,21 +162,22 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
}
else if (initialUrlRequest != null) {
URLRequest urlRequest = URLRequest.fromMap(initialUrlRequest);
webView.loadUrl(urlRequest);
if (urlRequest != null) {
webView.loadUrl(urlRequest);
}
}
}
onBrowserCreated();
}
public void onBrowserCreated() {
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onBrowserCreated", obj);
if (channelDelegate != null) {
channelDelegate.onBrowserCreated();
}
}
private void prepareView() {
webView.prepare();
if (webView != null) {
webView.prepare();
}
if (customSettings.hidden)
hide();
@ -199,6 +209,12 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
public boolean onCreateOptionsMenu(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();
// Inflate menu to add items to action bar if it is present.
inflater.inflate(R.menu.menu_main, menu);
@ -209,10 +225,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
if (customSettings.hideUrlBar)
menu.findItem(R.id.menu_search).setVisible(false);
searchView.setQuery(webView.getUrl(), false);
if (actionBar != null && (customSettings.toolbarTopFixedTitle == null || customSettings.toolbarTopFixedTitle.isEmpty()))
actionBar.setTitle(webView.getTitle());
searchView.setQuery(webView != null ? webView.getUrl() : "", false);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
@ -276,8 +289,9 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
}
public void close(final MethodChannel.Result result) {
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onExit", obj);
if (channelDelegate != null) {
channelDelegate.onExit();
}
dispose();
@ -314,14 +328,16 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
}
public void hide() {
try {
isHidden = true;
Intent openActivity = new Intent(this, Class.forName(fromActivity));
openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivityIfNeeded(openActivity, 0);
} catch (ClassNotFoundException e) {
e.printStackTrace();
Log.d(LOG_TAG, e.getMessage());
if (fromActivity != null) {
try {
isHidden = true;
Intent openActivity = new Intent(this, Class.forName(fromActivity));
openActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivityIfNeeded(openActivity, 0);
} catch (ClassNotFoundException e) {
e.printStackTrace();
Log.d(LOG_TAG, e.getMessage());
}
}
}
@ -343,7 +359,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
public void shareButtonClicked(MenuItem item) {
Intent share = new Intent(Intent.ACTION_SEND);
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"));
}
@ -359,7 +375,9 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
InAppWebViewSettings newInAppWebViewSettings = new InAppWebViewSettings();
newInAppWebViewSettings.parse(newSettingsMap);
webView.setSettings(newInAppWebViewSettings, newSettingsMap);
if (webView != null) {
webView.setSettings(newInAppWebViewSettings, newSettingsMap);
}
if (newSettingsMap.get("hidden") != null && customSettings.hidden != newSettings.hidden) {
if (newSettings.hidden)
@ -387,15 +405,15 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
if (actionBar != null && newSettingsMap.get("toolbarTopBackgroundColor") != null &&
!Util.objEquals(customSettings.toolbarTopBackgroundColor, newSettings.toolbarTopBackgroundColor) &&
!newSettings.toolbarTopBackgroundColor.isEmpty())
newSettings.toolbarTopBackgroundColor != null && !newSettings.toolbarTopBackgroundColor.isEmpty())
actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(newSettings.toolbarTopBackgroundColor)));
if (actionBar != null && newSettingsMap.get("toolbarTopFixedTitle") != null &&
!Util.objEquals(customSettings.toolbarTopFixedTitle, newSettings.toolbarTopFixedTitle) &&
!newSettings.toolbarTopFixedTitle.isEmpty())
newSettings.toolbarTopFixedTitle != null && !newSettings.toolbarTopFixedTitle.isEmpty())
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)
menu.findItem(R.id.menu_search).setVisible(false);
else
@ -406,7 +424,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
}
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)
return null;
@ -492,17 +510,21 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void dispose() {
channel.setMethodCallHandler(null);
activityResultListeners.clear();
if (methodCallDelegate != null) {
methodCallDelegate.dispose();
methodCallDelegate = null;
if (channelDelegate != null) {
channelDelegate.dispose();
channelDelegate = null;
}
activityResultListeners.clear();
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);
}
if (webView.channelDelegate != null) {
webView.channelDelegate.dispose();
}
ViewGroup vg = (ViewGroup) (webView.getParent());
if (vg != null) {
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 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.util.ArrayList;
@ -51,20 +53,19 @@ import io.flutter.plugin.common.MethodChannel.Result;
/**
* InAppBrowserManager
*/
public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
public class InAppBrowserManager extends ChannelDelegateImpl implements Disposable {
protected static final String LOG_TAG = "InAppBrowserManager";
public MethodChannel channel;
public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappbrowser";
@Nullable
public InAppWebViewFlutterPlugin plugin;
public String id;
public static final Map<String, InAppBrowserManager> shared = new HashMap<>();
public InAppBrowserManager(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.id = UUID.randomUUID().toString();
this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappbrowser");
channel.setMethodCallHandler(this);
shared.put(this.id, this);
}
@ -208,8 +209,9 @@ public class InAppBrowserManager implements MethodChannel.MethodCallHandler {
activity.startActivity(intent);
}
@Override
public void dispose() {
channel.setMethodCallHandler(null);
super.dispose();
shared.remove(this.id);
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 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 java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import io.flutter.plugin.common.MethodCall;
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
public static ProxyController proxyController;
@Nullable
public InAppWebViewFlutterPlugin plugin;
public ProxyManager(final InAppWebViewFlutterPlugin plugin) {
super(new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME));
this.plugin = plugin;
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_proxycontroller");
channel.setMethodCallHandler(this);
if (WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) {
proxyController = ProxyController.getInstance();
} else {
@ -116,8 +115,9 @@ public class ProxyManager implements MethodChannel.MethodCallHandler {
}
}
@Override
public void dispose() {
channel.setMethodCallHandler(null);
super.dispose();
if (proxyController != null) {
// Clears the proxy settings
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.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;
public class PullToRefreshLayout extends SwipeRefreshLayout implements MethodChannel.MethodCallHandler {
public class PullToRefreshLayout extends SwipeRefreshLayout implements Disposable {
static final String LOG_TAG = "PullToRefreshLayout";
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_";
public MethodChannel channel;
public PullToRefreshSettings options;
@Nullable
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);
this.channel = channel;
this.options = options;
this.settings = settings;
final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id);
this.channelDelegate = new PullToRefreshChannelDelegate(this, channel);
}
public PullToRefreshLayout(@NonNull Context context) {
super(context);
this.channel = null;
this.options = null;
}
public PullToRefreshLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.channel = null;
this.options = null;
}
public void prepare() {
final PullToRefreshLayout self = this;
if (channel != null) {
this.channel.setMethodCallHandler(this);
}
setEnabled(options.enabled);
setEnabled(settings.enabled);
setOnChildScrollUpCallback(new OnChildScrollUpCallback() {
@Override
public boolean canChildScrollUp(@NonNull SwipeRefreshLayout parent, @Nullable View child) {
@ -63,93 +57,30 @@ public class PullToRefreshLayout extends SwipeRefreshLayout implements MethodCha
setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
if (channel == null) {
if (channelDelegate == null) {
self.setRefreshing(false);
return;
}
Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onRefresh", obj);
channelDelegate.onRefresh();
}
});
if (options.color != null)
setColorSchemeColors(Color.parseColor(options.color));
if (options.backgroundColor != null)
setProgressBackgroundColorSchemeColor(Color.parseColor(options.backgroundColor));
if (options.distanceToTriggerSync != null)
setDistanceToTriggerSync(options.distanceToTriggerSync);
if (options.slingshotDistance != null)
setSlingshotDistance(options.slingshotDistance);
if (options.size != null)
setSize(options.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();
}
if (settings.color != null)
setColorSchemeColors(Color.parseColor(settings.color));
if (settings.backgroundColor != null)
setProgressBackgroundColorSchemeColor(Color.parseColor(settings.backgroundColor));
if (settings.distanceToTriggerSync != null)
setDistanceToTriggerSync(settings.distanceToTriggerSync);
if (settings.slingshotDistance != null)
setSlingshotDistance(settings.slingshotDistance);
if (settings.size != null)
setSize(settings.size);
}
public void dispose() {
removeAllViews();
if (channel != null) {
channel.setMethodCallHandler(null);
if (channelDelegate != null) {
channelDelegate.dispose();
channelDelegate = null;
}
removeAllViews();
}
}

View File

@ -22,8 +22,8 @@ public class PullToRefreshSettings implements ISettings<PullToRefreshLayout> {
@Nullable
public Integer size;
public PullToRefreshSettings parse(Map<String, Object> options) {
for (Map.Entry<String, Object> pair : options.entrySet()) {
public PullToRefreshSettings parse(Map<String, Object> settings) {
for (Map.Entry<String, Object> pair : settings.entrySet()) {
String key = pair.getKey();
Object value = pair.getValue();
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.webkit.ValueCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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 java.util.ArrayList;
@ -11,12 +16,13 @@ import java.util.List;
public class WebMessagePort {
public String name;
@Nullable
public WebMessageChannel webMessageChannel;
public boolean isClosed = false;
public boolean isTransferred = false;
public boolean isStarted = false;
public WebMessagePort(String name, WebMessageChannel webMessageChannel) {
public WebMessagePort(String name, @NonNull WebMessageChannel webMessageChannel) {
this.name = name;
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;

View File

@ -1,4 +1,4 @@
package com.pichillilorenzo.flutter_inappwebview.types;
package com.pichillilorenzo.flutter_inappwebview.webview;
import android.content.Context;
import android.net.Uri;
@ -12,8 +12,13 @@ import androidx.annotation.Nullable;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserDelegate;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebViewSettings;
import com.pichillilorenzo.flutter_inappwebview.in_app_webview.EventChannelDelegate;
import com.pichillilorenzo.flutter_inappwebview.types.ContentWorld;
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.util.HashMap;
@ -106,6 +111,6 @@ public interface InAppWebViewInterface {
boolean isInFullscreen();
void setInFullscreen(boolean inFullscreen);
@Nullable
EventChannelDelegate getEventChannelDelegate();
void setEventChannelDelegate(@Nullable EventChannelDelegate eventChannelDelegate);
WebViewChannelDelegate getChannelDelegate();
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.Handler;
import android.os.Looper;
import android.util.Log;
import android.webkit.JavascriptInterface;
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 org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
public class JavaScriptBridgeInterface {
private static final String LOG_TAG = "JSBridgeInterface";
private InAppWebView inAppWebView;
private final MethodChannel channel;
public JavaScriptBridgeInterface(InAppWebView inAppWebView) {
this.inAppWebView = inAppWebView;
this.channel = this.inAppWebView.channel;
}
@JavascriptInterface
@ -52,10 +47,6 @@ public class JavaScriptBridgeInterface {
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.
// https://github.com/pichillilorenzo/flutter_inappwebview/issues/98
final Handler handler = new Handler(inAppWebView.getWebViewLooper());
@ -99,32 +90,33 @@ public class JavaScriptBridgeInterface {
return;
}
// invoke flutter javascript handler and send back flutter data as a JSON Object to javascript
channel.invokeMethod("onCallJsHandler", obj, new MethodChannel.Result() {
@Override
public void success(Object json) {
if (inAppWebView == null) {
// The webview has already been disposed, ignore.
return;
if (inAppWebView.channelDelegate != null) {
// invoke flutter javascript handler and send back flutter data as a JSON Object to javascript
inAppWebView.channelDelegate.onCallJsHandler(handlerName, args, new WebViewChannelDelegate.CallJsHandlerCallback() {
@Override
public void defaultBehaviour(@Nullable Object json) {
if (inAppWebView == null) {
// 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;

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;

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.hardware.display.DisplayManager;
@ -14,15 +14,15 @@ import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature;
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.pull_to_refresh.PullToRefreshLayout;
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.UserScript;
@ -32,21 +32,17 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
public class FlutterWebView implements PlatformWebView {
static final String LOG_TAG = "IAWFlutterWebView";
@Nullable
public InAppWebView webView;
public final MethodChannel channel;
public InAppWebViewMethodHandler methodCallDelegate;
@Nullable
public PullToRefreshLayout pullToRefreshLayout;
public FlutterWebView(final InAppWebViewFlutterPlugin plugin, final Context context, Object id,
HashMap<String, Object> params) {
channel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_" + id);
DisplayListenerProxy displayListenerProxy = new DisplayListenerProxy();
DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
displayListenerProxy.onPreWebViewInitialization(displayManager);
@ -57,8 +53,8 @@ public class FlutterWebView implements PlatformWebView {
List<Map<String, Object>> initialUserScripts = (List<Map<String, Object>>) params.get("initialUserScripts");
Map<String, Object> pullToRefreshInitialSettings = (Map<String, Object>) params.get("pullToRefreshSettings");
InAppWebViewSettings options = new InAppWebViewSettings();
options.parse(initialSettings);
InAppWebViewSettings customSettings = new InAppWebViewSettings();
customSettings.parse(initialSettings);
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" +
@ -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);
if (options.useHybridComposition) {
if (customSettings.useHybridComposition) {
// 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));
MethodChannel pullToRefreshLayoutChannel = new MethodChannel(plugin.messenger, "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_" + id);
PullToRefreshSettings pullToRefreshSettings = new PullToRefreshSettings();
pullToRefreshSettings.parse(pullToRefreshInitialSettings);
pullToRefreshLayout = new PullToRefreshLayout(context, pullToRefreshLayoutChannel, pullToRefreshSettings);
pullToRefreshLayout = new PullToRefreshLayout(context, plugin, id, pullToRefreshSettings);
pullToRefreshLayout.addView(webView);
pullToRefreshLayout.prepare();
}
methodCallDelegate = new InAppWebViewMethodHandler(webView);
channel.setMethodCallHandler(methodCallDelegate);
webView.prepare();
}
@ -130,19 +123,19 @@ public class FlutterWebView implements PlatformWebView {
}
else if (initialUrlRequest != null) {
URLRequest urlRequest = URLRequest.fromMap(initialUrlRequest);
webView.loadUrl(urlRequest);
if (urlRequest != null) {
webView.loadUrl(urlRequest);
}
}
}
}
@Override
public void dispose() {
channel.setMethodCallHandler(null);
if (methodCallDelegate != null) {
methodCallDelegate.dispose();
methodCallDelegate = null;
}
if (webView != null) {
if (webView.channelDelegate != null) {
webView.channelDelegate.dispose();
}
webView.removeJavascriptInterface(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE)) {
WebViewCompat.setWebViewRenderProcessClient(webView, null);
@ -154,13 +147,20 @@ public class FlutterWebView implements PlatformWebView {
if (webView.inAppWebViewRenderProcessClient != null) {
webView.inAppWebViewRenderProcessClient.dispose();
}
webView.eventChannelDelegate.dispose();
webView.inAppWebViewChromeClient.dispose();
webView.inAppWebViewClient.dispose();
webView.javaScriptBridgeInterface.dispose();
webView.dispose();
webView.destroy();
webView = null;
if (webView.inAppWebViewChromeClient != null) {
webView.inAppWebViewChromeClient.dispose();
}
if (webView.inAppWebViewClient != null) {
webView.inAppWebViewClient.dispose();
}
if (webView.javaScriptBridgeInterface != null) {
webView.javaScriptBridgeInterface.dispose();
}
if (webView != null) {
webView.dispose();
webView.destroy();
webView = null;
}
if (pullToRefreshLayout != null) {
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.PropertyValuesHolder;
@ -55,7 +55,7 @@ import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature;
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.Util;
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.types.ContentWorld;
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.PreferredContentModeOptionType;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
import com.pichillilorenzo.flutter_inappwebview.types.UserContentController;
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.webview.WebViewChannelDelegate;
import com.pichillilorenzo.flutter_inappwebview.webview.web_message.WebMessageChannel;
import com.pichillilorenzo.flutter_inappwebview.webview.web_message.WebMessageListener;
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;
final public class InAppWebView extends InputAwareWebView implements InAppWebViewInterface {
static final String LOG_TAG = "InAppWebView";
protected static final String LOG_TAG = "InAppWebView";
public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_";
@Nullable
public InAppWebViewFlutterPlugin plugin;
@Nullable
public InAppBrowserDelegate inAppBrowserDelegate;
public MethodChannel channel;
public Object id;
@Nullable
public Integer windowId;
@ -122,10 +123,10 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
@Nullable
public InAppWebViewRenderProcessClient inAppWebViewRenderProcessClient;
@Nullable
public EventChannelDelegate eventChannelDelegate;
public WebViewChannelDelegate channelDelegate;
@Nullable
public JavaScriptBridgeInterface javaScriptBridgeInterface;
public InAppWebViewSettings customSettings;
public InAppWebViewSettings customSettings = new InAppWebViewSettings();
public boolean isLoading = false;
private boolean inFullscreen = false;
public OkHttpClient httpClient;
@ -169,15 +170,15 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
super(context, attrs, defaultStyle);
}
public InAppWebView(Context context, InAppWebViewFlutterPlugin plugin,
MethodChannel channel, Object id,
@Nullable Integer windowId, InAppWebViewSettings customSettings,
public InAppWebView(Context context, @NonNull InAppWebViewFlutterPlugin plugin,
@NonNull Object id, @Nullable Integer windowId, InAppWebViewSettings customSettings,
@Nullable Map<String, Object> contextMenu, View containerView,
List<UserScript> userScripts) {
super(context, containerView, customSettings.useHybridComposition);
this.plugin = plugin;
this.channel = channel;
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.customSettings = customSettings;
this.contextMenu = contextMenu;
@ -190,8 +191,6 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
public void prepare() {
httpClient = new OkHttpClient().newBuilder().build();
eventChannelDelegate = new EventChannelDelegate(channel);
javaScriptBridgeInterface = new JavaScriptBridgeInterface(this);
addJavascriptInterface(javaScriptBridgeInterface, JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME);
@ -397,7 +396,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
setFindListener(new FindListener() {
@Override
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) {
com.pichillilorenzo.flutter_inappwebview.types.HitTestResult hitTestResult =
com.pichillilorenzo.flutter_inappwebview.types.HitTestResult.fromWebViewHitTestResult(getHitTestResult());
if (eventChannelDelegate != null) eventChannelDelegate.onLongPressHitTestResult(hitTestResult);
if (channelDelegate != null) channelDelegate.onLongPressHitTestResult(hitTestResult);
return false;
}
});
@ -1194,7 +1193,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
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) {
@ -1231,7 +1230,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
URLUtil.guessFileName(url, contentDisposition, mimeType),
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() {
com.pichillilorenzo.flutter_inappwebview.types.HitTestResult hitTestResult =
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);
@ -1315,13 +1314,13 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
PullToRefreshLayout pullToRefreshLayout = (PullToRefreshLayout) parent;
// change over scroll mode to OVER_SCROLL_NEVER in order to disable temporarily the glow effect
setOverScrollMode(OVER_SCROLL_NEVER);
pullToRefreshLayout.setEnabled(pullToRefreshLayout.options.enabled);
pullToRefreshLayout.setEnabled(pullToRefreshLayout.settings.enabled);
// reset over scroll mode
setOverScrollMode(customSettings.overScrollMode);
}
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())
.inflate(R.layout.floating_action_mode_item, this, false);
text.setText(itemTitle);
text.setOnClickListener(new OnClickListener() {
text.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
hideContextMenu();
callback.onActionItemClicked(actionMode, menuItem);
if (eventChannelDelegate != null) eventChannelDelegate.onContextMenuActionItemClicked(itemId, itemTitle);
if (channelDelegate != null) channelDelegate.onContextMenuActionItemClicked(itemId, itemTitle);
}
});
if (floatingContextMenu != null) {
@ -1454,12 +1453,11 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
public void onClick(View v) {
hideContextMenu();
if (eventChannelDelegate != null) eventChannelDelegate.onContextMenuActionItemClicked(itemId, itemTitle);
if (channelDelegate != null) channelDelegate.onContextMenuActionItemClicked(itemId, itemTitle);
}
});
if (floatingContextMenu != null) {
menuItemListLayout.addView(text);
}
}
@ -1531,7 +1529,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
removeView(floatingContextMenu);
floatingContextMenu = null;
if (eventChannelDelegate != null) eventChannelDelegate.onHideContextMenu();
if (channelDelegate != null) channelDelegate.onHideContextMenu();
}
public void onScrollStopped() {
@ -1794,13 +1792,13 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
@Nullable
@Override
public EventChannelDelegate getEventChannelDelegate() {
return eventChannelDelegate;
public WebViewChannelDelegate getChannelDelegate() {
return channelDelegate;
}
@Override
public void setEventChannelDelegate(@Nullable EventChannelDelegate eventChannelDelegate) {
this.eventChannelDelegate = eventChannelDelegate;
public void setChannelDelegate(@Nullable WebViewChannelDelegate channelDelegate) {
this.channelDelegate = channelDelegate;
}
@Override
@ -1824,7 +1822,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
inAppWebViewClient = null;
javaScriptBridgeInterface = null;
inAppWebViewRenderProcessClient = null;
eventChannelDelegate = null;
channelDelegate = null;
plugin = null;
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.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.PermissionResponse;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -62,7 +63,6 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
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);
if (inAppWebView != null) {
EventChannelDelegate eventChannelDelegate = inAppWebView.eventChannelDelegate;
if (eventChannelDelegate != null)
eventChannelDelegate.onExitFullscreen();
WebViewChannelDelegate eventWebViewChannelDelegate = inAppWebView.channelDelegate;
if (eventWebViewChannelDelegate != null)
eventWebViewChannelDelegate.onExitFullscreen();
inAppWebView.setInFullscreen(false);
}
}
@ -188,9 +188,9 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
((FrameLayout) decorView).addView(this.mCustomView, FULLSCREEN_LAYOUT_PARAMS);
if (inAppWebView != null) {
EventChannelDelegate eventChannelDelegate = inAppWebView.eventChannelDelegate;
if (eventChannelDelegate != null)
eventChannelDelegate.onEnterFullscreen();
WebViewChannelDelegate eventWebViewChannelDelegate = inAppWebView.channelDelegate;
if (eventWebViewChannelDelegate != null)
eventWebViewChannelDelegate.onEnterFullscreen();
inAppWebView.setInFullscreen(true);
}
}
@ -198,8 +198,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override
public boolean onJsAlert(final WebView view, String url, final String message,
final JsResult result) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) {
inAppWebView.eventChannelDelegate.onJsAlert(url, message, null, new EventChannelDelegate.JsAlertCallback() {
if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.channelDelegate.onJsAlert(url, message, null, new WebViewChannelDelegate.JsAlertCallback() {
@Override
public boolean nonNullSuccess(@NonNull JsAlertResponse response) {
if (response.isHandledByClient()) {
@ -226,7 +226,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
responseMessage = response.getMessage();
confirmButtonTitle = response.getConfirmButtonTitle();
}
createAlertDialog(view, message, result, responseMessage, confirmButtonTitle);
createAlertDialog(message, result, responseMessage, confirmButtonTitle);
}
@Override
@ -242,7 +242,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
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;
DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
@ -281,8 +281,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override
public boolean onJsConfirm(final WebView view, String url, final String message,
final JsResult result) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) {
inAppWebView.eventChannelDelegate.onJsConfirm(url, message, null, new EventChannelDelegate.JsConfirmCallback() {
if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.channelDelegate.onJsConfirm(url, message, null, new WebViewChannelDelegate.JsConfirmCallback() {
@Override
public boolean nonNullSuccess(@NonNull JsConfirmResponse response) {
if (response.isHandledByClient()) {
@ -311,7 +311,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
confirmButtonTitle = response.getConfirmButtonTitle();
cancelButtonTitle = response.getCancelButtonTitle();
}
createConfirmDialog(view, message, result, responseMessage, confirmButtonTitle, cancelButtonTitle);
createConfirmDialog(message, result, responseMessage, confirmButtonTitle, cancelButtonTitle);
}
@Override
@ -327,7 +327,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
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;
DialogInterface.OnClickListener confirmClickListener = new DialogInterface.OnClickListener() {
@Override
@ -377,8 +377,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override
public boolean onJsPrompt(final WebView view, String url, final String message,
final String defaultValue, final JsPromptResult result) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) {
inAppWebView.eventChannelDelegate.onJsPrompt(url, message, defaultValue, null, new EventChannelDelegate.JsPromptCallback() {
if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.channelDelegate.onJsPrompt(url, message, defaultValue, null, new WebViewChannelDelegate.JsPromptCallback() {
@Override
public boolean nonNullSuccess(@NonNull JsPromptResponse response) {
if (response.isHandledByClient()) {
@ -494,8 +494,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override
public boolean onJsBeforeUnload(final WebView view, String url, final String message,
final JsResult result) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) {
inAppWebView.eventChannelDelegate.onJsBeforeUnload(url, message, new EventChannelDelegate.JsBeforeUnloadCallback() {
if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.channelDelegate.onJsBeforeUnload(url, message, new WebViewChannelDelegate.JsBeforeUnloadCallback() {
@Override
public boolean nonNullSuccess(@NonNull JsBeforeUnloadResponse response) {
if (response.isHandledByClient()) {
@ -524,7 +524,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
confirmButtonTitle = response.getConfirmButtonTitle();
cancelButtonTitle = response.getCancelButtonTitle();
}
createBeforeUnloadDialog(view, message, result, responseMessage, confirmButtonTitle, cancelButtonTitle);
createBeforeUnloadDialog(message, result, responseMessage, confirmButtonTitle, cancelButtonTitle);
}
@Override
@ -540,7 +540,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
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;
DialogInterface.OnClickListener confirmClickListener = new DialogInterface.OnClickListener() {
@Override
@ -620,8 +620,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
windowWebViewMessages.put(windowId, resultMsg);
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) {
inAppWebView.eventChannelDelegate.onCreateWindow(createWindowAction, new EventChannelDelegate.CreateWindowCallback() {
if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.channelDelegate.onCreateWindow(createWindowAction, new WebViewChannelDelegate.CreateWindowCallback() {
@Override
public boolean nonNullSuccess(@NonNull Boolean handledByClient) {
return !handledByClient;
@ -647,8 +647,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override
public void onCloseWindow(WebView window) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) {
inAppWebView.eventChannelDelegate.onCloseWindow();
if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.channelDelegate.onCloseWindow();
}
super.onCloseWindow(window);
@ -656,7 +656,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override
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
public boolean nonNullSuccess(@NonNull GeolocationPermissionShowPromptResponse response) {
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) {
inAppWebView.eventChannelDelegate.onGeolocationPermissionsShowPrompt(origin, resultCallback);
if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.channelDelegate.onGeolocationPermissionsShowPrompt(origin, resultCallback);
} else {
resultCallback.defaultBehaviour(null);
}
@ -684,15 +684,15 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override
public void onGeolocationPermissionsHidePrompt() {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) {
inAppWebView.eventChannelDelegate.onGeolocationPermissionsHidePrompt();
if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.channelDelegate.onGeolocationPermissionsHidePrompt();
}
}
@Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
if (inAppWebView != null && inAppWebView.eventChannelDelegate != null) {
inAppWebView.eventChannelDelegate.onConsoleMessage(
if (inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.channelDelegate.onConsoleMessage(
consoleMessage.message(),
consoleMessage.messageLevel().ordinal());
}
@ -714,8 +714,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
webView.inAppWebViewClient.loadCustomJavaScriptOnPageStarted(view);
}
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onProgressChanged(progress);
if (webView.channelDelegate != null) {
webView.channelDelegate.onProgressChanged(progress);
}
}
@ -729,8 +729,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onTitleChanged(title);
if (webView.channelDelegate != null) {
webView.channelDelegate.onTitleChanged(title);
}
}
@ -752,8 +752,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
icon.recycle();
InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onReceivedIcon(byteArrayOutputStream.toByteArray());
if (webView.channelDelegate != null) {
webView.channelDelegate.onReceivedIcon(byteArrayOutputStream.toByteArray());
}
}
@ -764,8 +764,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
super.onReceivedTouchIconUrl(view, url, precomposed);
InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onReceivedTouchIconUrl(url, precomposed);
if (webView.channelDelegate != null) {
webView.channelDelegate.onReceivedTouchIconUrl(url, precomposed);
}
}
@ -1157,7 +1157,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
@Override
public void onPermissionRequest(final PermissionRequest request) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final EventChannelDelegate.PermissionRequestCallback callback = new EventChannelDelegate.PermissionRequestCallback() {
final WebViewChannelDelegate.PermissionRequestCallback callback = new WebViewChannelDelegate.PermissionRequestCallback() {
@Override
public boolean nonNullSuccess(@NonNull PermissionResponse response) {
Integer action = response.getAction();
@ -1189,8 +1189,8 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
};
if(inAppWebView != null && inAppWebView.eventChannelDelegate != null) {
inAppWebView.eventChannelDelegate.onPermissionRequest(request.getOrigin().toString(),
if(inAppWebView != null && inAppWebView.channelDelegate != null) {
inAppWebView.channelDelegate.onPermissionRequest(request.getOrigin().toString(),
Arrays.asList(request.getResources()), null, callback);
} else {
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.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.WebResourceRequestExt;
import com.pichillilorenzo.flutter_inappwebview.types.WebResourceResponseExt;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
import java.io.ByteArrayInputStream;
import java.net.URI;
@ -133,7 +134,7 @@ public class InAppWebViewClient extends WebViewClient {
isRedirect
);
final EventChannelDelegate.ShouldOverrideUrlLoadingCallback callback = new EventChannelDelegate.ShouldOverrideUrlLoadingCallback() {
final WebViewChannelDelegate.ShouldOverrideUrlLoadingCallback callback = new WebViewChannelDelegate.ShouldOverrideUrlLoadingCallback() {
@Override
public boolean nonNullSuccess(@NonNull NavigationActionPolicy result) {
switch (result) {
@ -159,8 +160,8 @@ public class InAppWebViewClient extends WebViewClient {
}
};
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.shouldOverrideUrlLoading(navigationAction, callback);
if (webView.channelDelegate != null) {
webView.channelDelegate.shouldOverrideUrlLoading(navigationAction, callback);
} else {
callback.defaultBehaviour(null);
}
@ -204,12 +205,11 @@ public class InAppWebViewClient extends WebViewClient {
inAppBrowserDelegate.didStartNavigation(url);
}
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onLoadStart(url);
if (webView.channelDelegate != null) {
webView.channelDelegate.onLoadStart(url);
}
}
public void onPageFinished(WebView view, String url) {
final InAppWebView webView = (InAppWebView) view;
webView.isLoading = false;
@ -238,8 +238,8 @@ public class InAppWebViewClient extends WebViewClient {
webView.loadUrl("javascript:" + js.replaceAll("[\r\n]+", ""));
}
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onLoadStop(url);
if (webView.channelDelegate != null) {
webView.channelDelegate.onLoadStop(url);
}
}
@ -255,8 +255,8 @@ public class InAppWebViewClient extends WebViewClient {
}
final InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onUpdateVisitedHistory(url, isReload);
if (webView.channelDelegate != null) {
webView.channelDelegate.onUpdateVisitedHistory(url, isReload);
}
}
@ -280,8 +280,8 @@ public class InAppWebViewClient extends WebViewClient {
}
}
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onReceivedError(
if (webView.channelDelegate != null) {
webView.channelDelegate.onReceivedError(
WebResourceRequestExt.fromWebResourceRequest(request),
WebResourceErrorExt.fromWebResourceError(error));
}
@ -317,8 +317,8 @@ public class InAppWebViewClient extends WebViewClient {
description
);
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onReceivedError(
if (webView.channelDelegate != null) {
webView.channelDelegate.onReceivedError(
request,
error);
}
@ -332,8 +332,8 @@ public class InAppWebViewClient extends WebViewClient {
super.onReceivedHttpError(view, request, errorResponse);
final InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onReceivedHttpError(
if (webView.channelDelegate != null) {
webView.channelDelegate.onReceivedHttpError(
WebResourceRequestExt.fromWebResourceRequest(request),
WebResourceResponseExt.fromWebResourceResponse(errorResponse));
}
@ -371,7 +371,7 @@ public class InAppWebViewClient extends WebViewClient {
HttpAuthenticationChallenge challenge = new HttpAuthenticationChallenge(protectionSpace, previousAuthRequestFailureCount, credentialProposed);
final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.ReceivedHttpAuthRequestCallback callback = new EventChannelDelegate.ReceivedHttpAuthRequestCallback() {
final WebViewChannelDelegate.ReceivedHttpAuthRequestCallback callback = new WebViewChannelDelegate.ReceivedHttpAuthRequestCallback() {
@Override
public boolean nonNullSuccess(@NonNull HttpAuthResponse response) {
Integer action = response.getAction();
@ -422,8 +422,8 @@ public class InAppWebViewClient extends WebViewClient {
}
};
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onReceivedHttpAuthRequest(challenge, callback);
if (webView.channelDelegate != null) {
webView.channelDelegate.onReceivedHttpAuthRequest(challenge, callback);
} else {
callback.defaultBehaviour(null);
}
@ -449,7 +449,7 @@ public class InAppWebViewClient extends WebViewClient {
ServerTrustChallenge challenge = new ServerTrustChallenge(protectionSpace);
final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.ReceivedServerTrustAuthRequestCallback callback = new EventChannelDelegate.ReceivedServerTrustAuthRequestCallback() {
final WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback callback = new WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback() {
@Override
public boolean nonNullSuccess(@NonNull ServerTrustAuthResponse response) {
Integer action = response.getAction();
@ -481,8 +481,8 @@ public class InAppWebViewClient extends WebViewClient {
}
};
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onReceivedServerTrustAuthRequest(challenge, callback);
if (webView.channelDelegate != null) {
webView.channelDelegate.onReceivedServerTrustAuthRequest(challenge, callback);
} else {
callback.defaultBehaviour(null);
}
@ -509,7 +509,7 @@ public class InAppWebViewClient extends WebViewClient {
ClientCertChallenge challenge = new ClientCertChallenge(protectionSpace, request.getPrincipals(), request.getKeyTypes());
final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.ReceivedClientCertRequestCallback callback = new EventChannelDelegate.ReceivedClientCertRequestCallback() {
final WebViewChannelDelegate.ReceivedClientCertRequestCallback callback = new WebViewChannelDelegate.ReceivedClientCertRequestCallback() {
@Override
public boolean nonNullSuccess(@NonNull ClientCertResponse response) {
Integer action = response.getAction();
@ -555,8 +555,8 @@ public class InAppWebViewClient extends WebViewClient {
}
};
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onReceivedClientCertRequest(challenge, callback);
if (webView.channelDelegate != null) {
webView.channelDelegate.onReceivedClientCertRequest(challenge, callback);
} else {
callback.defaultBehaviour(null);
}
@ -568,8 +568,8 @@ public class InAppWebViewClient extends WebViewClient {
final InAppWebView webView = (InAppWebView) view;
webView.zoomScale = newScale / Util.getPixelDensity(webView.getContext());
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onZoomScaleChanged(oldScale, newScale);
if (webView.channelDelegate != null) {
webView.channelDelegate.onZoomScaleChanged(oldScale, newScale);
}
}
@ -577,7 +577,7 @@ public class InAppWebViewClient extends WebViewClient {
@Override
public void onSafeBrowsingHit(final WebView view, final WebResourceRequest request, final int threatType, final SafeBrowsingResponse callback) {
final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.SafeBrowsingHitCallback resultCallback = new EventChannelDelegate.SafeBrowsingHitCallback() {
final WebViewChannelDelegate.SafeBrowsingHitCallback resultCallback = new WebViewChannelDelegate.SafeBrowsingHitCallback() {
@Override
public boolean nonNullSuccess(@NonNull com.pichillilorenzo.flutter_inappwebview.types.SafeBrowsingResponse response) {
Integer action = response.getAction();
@ -613,8 +613,8 @@ public class InAppWebViewClient extends WebViewClient {
}
};
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onSafeBrowsingHit(request.getUrl().toString(), threatType, resultCallback);
if (webView.channelDelegate != null) {
webView.channelDelegate.onSafeBrowsingHit(request.getUrl().toString(), threatType, resultCallback);
} else {
resultCallback.defaultBehaviour(null);
}
@ -647,9 +647,9 @@ public class InAppWebViewClient extends WebViewClient {
if (webView.customSettings.resourceCustomSchemes != null && webView.customSettings.resourceCustomSchemes.contains(scheme)) {
CustomSchemeResponse customSchemeResponse = null;
if (webView.eventChannelDelegate != null) {
if (webView.channelDelegate != null) {
try {
customSchemeResponse = webView.eventChannelDelegate.onLoadResourceCustomScheme(url);
customSchemeResponse = webView.channelDelegate.onLoadResourceCustomScheme(url);
} catch (InterruptedException e) {
e.printStackTrace();
return null;
@ -711,9 +711,9 @@ public class InAppWebViewClient extends WebViewClient {
}
WebResourceResponseExt response = null;
if (webView.eventChannelDelegate != null) {
if (webView.channelDelegate != null) {
try {
response = webView.eventChannelDelegate.shouldInterceptRequest(requestExt);
response = webView.channelDelegate.shouldInterceptRequest(requestExt);
} catch (InterruptedException e) {
e.printStackTrace();
return null;
@ -743,7 +743,7 @@ public class InAppWebViewClient extends WebViewClient {
@Override
public void onFormResubmission(final WebView view, final Message dontResend, final Message resend) {
final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.FormResubmissionCallback callback = new EventChannelDelegate.FormResubmissionCallback() {
final WebViewChannelDelegate.FormResubmissionCallback callback = new WebViewChannelDelegate.FormResubmissionCallback() {
@Override
public boolean nonNullSuccess(@NonNull Integer action) {
switch (action) {
@ -769,8 +769,8 @@ public class InAppWebViewClient extends WebViewClient {
}
};
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onFormResubmission(webView.getUrl(), callback);
if (webView.channelDelegate != null) {
webView.channelDelegate.onFormResubmission(webView.getUrl(), callback);
} else {
callback.defaultBehaviour(null);
}
@ -781,8 +781,8 @@ public class InAppWebViewClient extends WebViewClient {
super.onPageCommitVisible(view, url);
final InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onPageCommitVisible(url);
if (webView.channelDelegate != null) {
webView.channelDelegate.onPageCommitVisible(url);
}
}
@ -791,10 +791,10 @@ public class InAppWebViewClient extends WebViewClient {
public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
final InAppWebView webView = (InAppWebView) view;
if (webView.customSettings.useOnRenderProcessGone && webView.eventChannelDelegate != null) {
if (webView.customSettings.useOnRenderProcessGone && webView.channelDelegate != null) {
boolean didCrash = detail.didCrash();
int rendererPriorityAtExit = detail.rendererPriorityAtExit();
webView.eventChannelDelegate.onRenderProcessGone(didCrash, rendererPriorityAtExit);
webView.channelDelegate.onRenderProcessGone(didCrash, rendererPriorityAtExit);
return true;
}
@ -804,8 +804,8 @@ public class InAppWebViewClient extends WebViewClient {
@Override
public void onReceivedLoginRequest(WebView view, String realm, String account, String args) {
final InAppWebView webView = (InAppWebView) view;
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onReceivedLoginRequest(realm, account, args);
if (webView.channelDelegate != null) {
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.webkit.WebView;
@ -9,6 +9,8 @@ import androidx.webkit.WebViewFeature;
import androidx.webkit.WebViewRenderProcess;
import androidx.webkit.WebViewRenderProcessClient;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient {
protected static final String LOG_TAG = "IAWRenderProcessClient";
@ -20,7 +22,7 @@ public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient
@Override
public void onRenderProcessUnresponsive(@NonNull WebView view, @Nullable final WebViewRenderProcess renderer) {
final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.RenderProcessUnresponsiveCallback callback = new EventChannelDelegate.RenderProcessUnresponsiveCallback() {
final WebViewChannelDelegate.RenderProcessUnresponsiveCallback callback = new WebViewChannelDelegate.RenderProcessUnresponsiveCallback() {
@Override
public boolean nonNullSuccess(@NonNull Integer action) {
if (renderer != null) {
@ -47,8 +49,8 @@ public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient
}
};
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onRenderProcessUnresponsive(webView.getUrl(), callback);
if (webView.channelDelegate != null) {
webView.channelDelegate.onRenderProcessUnresponsive(webView.getUrl(), callback);
} else {
callback.defaultBehaviour(null);
}
@ -57,7 +59,7 @@ public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient
@Override
public void onRenderProcessResponsive(@NonNull WebView view, @Nullable final WebViewRenderProcess renderer) {
final InAppWebView webView = (InAppWebView) view;
final EventChannelDelegate.RenderProcessResponsiveCallback callback = new EventChannelDelegate.RenderProcessResponsiveCallback() {
final WebViewChannelDelegate.RenderProcessResponsiveCallback callback = new WebViewChannelDelegate.RenderProcessResponsiveCallback() {
@Override
public boolean nonNullSuccess(@NonNull Integer action) {
if (renderer != null) {
@ -84,8 +86,8 @@ public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient
}
};
if (webView.eventChannelDelegate != null) {
webView.eventChannelDelegate.onRenderProcessResponsive(webView.getUrl(), callback);
if (webView.channelDelegate != null) {
webView.channelDelegate.onRenderProcessResponsive(webView.getUrl(), callback);
} else {
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.view.View;
@ -9,7 +9,7 @@ import androidx.webkit.WebSettingsCompat;
import androidx.webkit.WebViewFeature;
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 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;
@ -20,7 +20,7 @@ import androidx.annotation.Nullable;
*
* 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
* 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 {
private static final String LOG_TAG = "InputAwareWebView";
@ -196,6 +196,13 @@ public class InputAwareWebView extends WebView {
new Runnable() {
@Override
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) getContext().getSystemService(INPUT_METHOD_SERVICE);
// 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.IBinder;
@ -9,7 +9,7 @@ import android.view.inputmethod.InputConnection;
/**
* 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 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;
@ -9,8 +9,11 @@ import androidx.webkit.WebMessagePortCompat;
import androidx.webkit.WebViewCompat;
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.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.Arrays;
@ -21,19 +24,22 @@ import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class WebMessageChannel implements MethodChannel.MethodCallHandler {
static final String LOG_TAG = "WebMessageChannel";
public class WebMessageChannel implements Disposable {
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 MethodChannel channel;
@Nullable
public WebMessageChannelChannelDelegate channelDelegate;
public final List<WebMessagePortCompat> compatPorts;
public final List<WebMessagePort> ports;
@Nullable
public InAppWebViewInterface webView;
public WebMessageChannel(@NonNull String id, @NonNull InAppWebViewInterface webView) {
this.id = id;
this.channel = new MethodChannel(webView.getPlugin().messenger, "com.pichillilorenzo/flutter_inappwebview_web_message_channel_" + id);
this.channel.setMethodCallHandler(this);
final MethodChannel channel = new MethodChannel(webView.getPlugin().messenger, METHOD_CHANNEL_NAME_PREFIX + id);
this.channelDelegate = new WebMessageChannelChannelDelegate(this, channel);
if (webView instanceof InAppWebView) {
this.compatPorts = new ArrayList<>(Arrays.asList(WebViewCompat.createWebMessageChannel((InAppWebView) webView)));
this.ports = new ArrayList<>();
@ -60,53 +66,17 @@ public class WebMessageChannel implements MethodChannel.MethodCallHandler {
}
}
@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 &&
WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK)) {
final WebMessagePortCompat webMessagePort = compatPorts.get(index);
final WebMessageChannel webMessageChannel = this;
try {
webMessagePort.setWebMessageCallback(new WebMessagePortCompat.WebMessageCallbackCompat() {
@Override
public void onMessage(@NonNull WebMessagePortCompat port, @Nullable WebMessageCompat message) {
super.onMessage(port, message);
Map<String, Object> obj = new HashMap<>();
obj.put("index", index);
obj.put("message", message != null ? message.getData() : null);
channel.invokeMethod("onMessage", obj);
webMessageChannel.onMessage(index, message != null ? message.getData() : null);
}
});
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 &&
WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE)) {
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 &&
WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_PORT_CLOSE)) {
WebMessagePortCompat port = compatPorts.get(index);
@ -161,11 +131,10 @@ public class WebMessageChannel implements MethodChannel.MethodCallHandler {
}
}
public void onMessage(Integer index, String message) {
Map<String, Object> obj = new HashMap<>();
obj.put("index", index);
obj.put("message", message );
channel.invokeMethod("onMessage", obj);
public void onMessage(int index, String message) {
if (channelDelegate != null) {
channelDelegate.onMessage(index, message);
}
}
public Map<String, Object> toMap() {
@ -182,8 +151,11 @@ public class WebMessageChannel implements MethodChannel.MethodCallHandler {
} catch (Exception ignored) {}
}
}
this.channel.setMethodCallHandler(null);
this.compatPorts.clear();
this.webView = null;
if (channelDelegate != null) {
channelDelegate.dispose();
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.text.TextUtils;
import android.webkit.ValueCallback;
import android.webkit.WebView;
import androidx.annotation.NonNull;
@ -13,11 +12,14 @@ import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature;
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.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.HashMap;
import java.util.HashSet;
import java.util.List;
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.MethodChannel;
public class WebMessageListener implements MethodChannel.MethodCallHandler {
static final String LOG_TAG = "WebMessageListener";
public class WebMessageListener implements Disposable {
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 Set<String> allowedOriginRules;
public WebViewCompat.WebMessageListener listener;
public JavaScriptReplyProxy replyProxy;
public MethodChannel channel;
@Nullable
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.jsObjectName = jsObjectName;
this.allowedOriginRules = allowedOriginRules;
this.channel = new MethodChannel(messenger, "com.pichillilorenzo/flutter_inappwebview_web_message_listener_" + this.jsObjectName);
this.channel.setMethodCallHandler(this);
final MethodChannel channel = new MethodChannel(messenger, METHOD_CHANNEL_NAME_PREFIX + this.jsObjectName);
this.channelDelegate = new WebMessageListenerChannelDelegate(this, channel);
if (this.webView instanceof InAppWebView) {
final WebMessageListener self = this;
this.listener = new WebViewCompat.WebMessageListener() {
@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;
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);
}
@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 {
int index = 0;
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)) {
replyProxy.postMessage(message);
}
@ -219,18 +214,13 @@ public class WebMessageListener implements MethodChannel.MethodCallHandler {
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() {
this.channel.setMethodCallHandler(null);
this.listener = null;
this.replyProxy = null;
this.webView = null;
if (channelDelegate != null) {
channelDelegate.dispose();
channelDelegate = 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:layout_width="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:layout_width="match_parent"
android:layout_height="match_parent" />