diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebViewFactory.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebViewFactory.java index 597e7538..bc9a325b 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebViewFactory.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebViewFactory.java @@ -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; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java index d9442e68..4fbbb1dd 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java @@ -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; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewMethodHandler.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewMethodHandler.java deleted file mode 100644 index 4ebf9b46..00000000 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewMethodHandler.java +++ /dev/null @@ -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 urlRequest = (Map) 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 contentWorldMap = (Map) call.argument("contentWorld"); - ContentWorld contentWorld = ContentWorld.fromMap(contentWorldMap); - webView.evaluateJavascript(source, contentWorld, new ValueCallback() { - @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 scriptHtmlTagAttributes = (Map) 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 cssLinkHtmlTagAttributes = (Map) 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 screenshotConfiguration = (Map) 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 inAppBrowserSettingsMap = (HashMap) call.argument("settings"); - inAppBrowserSettings.parse(inAppBrowserSettingsMap); - inAppBrowserActivity.setSettings(inAppBrowserSettings, inAppBrowserSettingsMap); - } else if (webView != null) { - InAppWebViewSettings inAppWebViewSettings = new InAppWebViewSettings(); - HashMap inAppWebViewSettingsMap = (HashMap) 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() { - @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() { - @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() { - @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 contextMenu = (Map) 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 userScriptMap = (Map) 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 userScriptMap = (Map) 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 functionArguments = (Map) call.argument("arguments"); - Map contentWorldMap = (Map) call.argument("contentWorld"); - ContentWorld contentWorld = ContentWorld.fromMap(contentWorldMap); - webView.callAsyncJavaScript(functionBody, functionArguments, contentWorld, new ValueCallback() { - @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() { - @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 message = (Map) call.argument("message"); - String targetOrigin = (String) call.argument("targetOrigin"); - List compatPorts = new ArrayList<>(); - List ports = new ArrayList<>(); - List> portsMap = (List>) message.get("ports"); - if (portsMap != null) { - for (Map 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 webMessageListenerMap = (Map) 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; - } -} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java index c57d21ca..6b263e92 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java @@ -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; } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyCookieManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyCookieManager.java index 5ed98435..adde338a 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyCookieManager.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyCookieManager.java @@ -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; } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyWebStorage.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyWebStorage.java index 413da60c..285fba54 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyWebStorage.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyWebStorage.java @@ -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; } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/PlatformUtil.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/PlatformUtil.java index 8be52b35..0437a2f1 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/PlatformUtil.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/PlatformUtil.java @@ -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; } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/ServiceWorkerManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/ServiceWorkerManager.java deleted file mode 100755 index f0fcab94..00000000 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/ServiceWorkerManager.java +++ /dev/null @@ -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) flutterResult.result); - if (response != null) { - String contentType = response.getContentType(); - String contentEncoding = response.getContentEncoding(); - byte[] data = response.getData(); - Map 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; - } -} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/Util.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/Util.java index 6f4330cc..ad70ead6 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/Util.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/Util.java @@ -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 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 invokeMethodAndWaitResult(final @NonNull MethodChannel channel, final @NonNull String method, final @Nullable Object arguments, final @NonNull SyncBaseCallbackResultImpl 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, diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/WebViewFeatureManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/WebViewFeatureManager.java index 3e98b427..1df294b4 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/WebViewFeatureManager.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/WebViewFeatureManager.java @@ -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; } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ActionBroadcastReceiver.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ActionBroadcastReceiver.java index 1d3bb700..6a4b182b 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ActionBroadcastReceiver.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ActionBroadcastReceiver.java @@ -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 obj = new HashMap<>(); obj.put("url", url); obj.put("title", title); diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java index fd2f0003..6cccda5b 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java @@ -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 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 obj = new HashMap<>(); - channel.invokeMethod("onChromeSafariBrowserOpened", obj); + if (channelDelegate != null) { + channelDelegate.onChromeSafariBrowserOpened(); + } } if (navigationEvent == NAVIGATION_FINISHED && !onChromeSafariBrowserCompletedInitialLoad) { onChromeSafariBrowserCompletedInitialLoad = true; - Map 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 obj = new HashMap<>(); - channel.invokeMethod("onChromeSafariBrowserClosed", obj); + if (channelDelegate != null) { + channelDelegate.onChromeSafariBrowserClosed(); + } } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java new file mode 100644 index 00000000..97335dba --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java @@ -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 obj = new HashMap<>(); + channel.invokeMethod("onChromeSafariBrowserOpened", obj); + } + + public void onChromeSafariBrowserCompletedInitialLoad() { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + channel.invokeMethod("onChromeSafariBrowserCompletedInitialLoad", obj); + } + + public void onChromeSafariBrowserClosed() { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + channel.invokeMethod("onChromeSafariBrowserClosed", obj); + } + + @Override + public void dispose() { + super.dispose(); + chromeCustomTabsActivity = null; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeSafariBrowserManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeSafariBrowserManager.java index e60cdc13..2af399ee 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeSafariBrowserManager.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeSafariBrowserManager.java @@ -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 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; } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/content_blocker/ContentBlockerHandler.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/content_blocker/ContentBlockerHandler.java index 22c6709b..07ed019c 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/content_blocker/ContentBlockerHandler.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/content_blocker/ContentBlockerHandler.java @@ -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; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/credential_database/CredentialDatabaseHandler.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/credential_database/CredentialDatabaseHandler.java index 801a4568..851f0648 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/credential_database/CredentialDatabaseHandler.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/credential_database/CredentialDatabaseHandler.java @@ -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; } - } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebView.java index 315db61b..091d2e6f 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebView.java @@ -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 sizeMap = (Map) 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 obj = new HashMap<>(); - channel.invokeMethod("onWebViewCreated", obj); + if (channelDelegate != null) { + channelDelegate.onWebViewCreated(); + } } public void prepare(Map 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 initialSize = (Map) 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); + if (contentView != null) { + ViewGroup mainView = (ViewGroup) (contentView).getChildAt(0); + if (mainView != null && flutterWebView != null) { + View view = flutterWebView.getView(); + final Map initialSize = (Map) 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); + } } } } @@ -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); } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebViewManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebViewManager.java index ea796641..eeb9183b 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebViewManager.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebViewManager.java @@ -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 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 headlessInAppWebViews = webViews.values(); for (HeadlessInAppWebView headlessInAppWebView : headlessInAppWebViews) { if (headlessInAppWebView != null) { diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessWebViewChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessWebViewChannelDelegate.java new file mode 100644 index 00000000..5a31ff3f --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessWebViewChannelDelegate.java @@ -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 sizeMap = (Map) 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 obj = new HashMap<>(); + channel.invokeMethod("onWebViewCreated", obj); + } + + @Override + public void dispose() { + super.dispose(); + headlessWebView = null; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserActivity.java index 93ac8388..d8126de2 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserActivity.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserActivity.java @@ -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 { - - static final String LOG_TAG = "InAppBrowserActivity"; - public MethodChannel channel; +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_"; + + @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 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 pullToRefreshInitialSettings = (Map) 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 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 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 getCustomSettings() { - Map webViewSettingsMap = webView.getCustomSettings(); + Map 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); diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserChannelDelegate.java new file mode 100644 index 00000000..0febcb77 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserChannelDelegate.java @@ -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 obj = new HashMap<>(); + channel.invokeMethod("onBrowserCreated", obj); + } + + public void onExit() { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + channel.invokeMethod("onExit", obj); + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java index b1a70b3a..0e73319c 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java @@ -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 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; } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/EventChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/EventChannelDelegate.java deleted file mode 100644 index e199049e..00000000 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/EventChannelDelegate.java +++ /dev/null @@ -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 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 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 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 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 obj = new HashMap<>(); - channel.invokeMethod("onHideContextMenu", obj); - } - - public void onEnterFullscreen() { - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onEnterFullscreen", obj); - } - - public void onExitFullscreen() { - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onExitFullscreen", obj); - } - - public static class JsAlertCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public JsAlertResponse decodeResult(@Nullable Object obj) { - return JsAlertResponse.fromMap((Map) obj); - } - } - - public void onJsAlert(String url, String message, Boolean isMainFrame, @NonNull JsAlertCallback callback) { - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map 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 { - @Nullable - @Override - public JsConfirmResponse decodeResult(@Nullable Object obj) { - return JsConfirmResponse.fromMap((Map) obj); - } - } - - public void onJsConfirm(String url, String message, Boolean isMainFrame, @NonNull JsConfirmCallback callback) { - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map 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 { - @Nullable - @Override - public JsPromptResponse decodeResult(@Nullable Object obj) { - return JsPromptResponse.fromMap((Map) obj); - } - } - - public void onJsPrompt(String url, String message, String defaultValue, Boolean isMainFrame, @NonNull JsPromptCallback callback) { - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map 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 { - @Nullable - @Override - public JsBeforeUnloadResponse decodeResult(@Nullable Object obj) { - return JsBeforeUnloadResponse.fromMap((Map) obj); - } - } - - public void onJsBeforeUnload(String url, String message, @NonNull JsBeforeUnloadCallback callback) { - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("message", message); - channel.invokeMethod("onJsBeforeUnload", obj, callback); - } - - public static class CreateWindowCallback extends BaseCallbackResultImpl { - @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 obj = new HashMap<>(); - channel.invokeMethod("onCloseWindow", obj); - } - - public static class GeolocationPermissionsShowPromptCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public GeolocationPermissionShowPromptResponse decodeResult(@Nullable Object obj) { - return GeolocationPermissionShowPromptResponse.fromMap((Map) obj); - } - } - - public void onGeolocationPermissionsShowPrompt(String origin, @NonNull GeolocationPermissionsShowPromptCallback callback) { - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("origin", origin); - channel.invokeMethod("onGeolocationPermissionsShowPrompt", obj, callback); - } - - public void onGeolocationPermissionsHidePrompt() { - if (channel == null) return; - Map obj = new HashMap<>(); - channel.invokeMethod("onGeolocationPermissionsHidePrompt", obj); - } - - public void onConsoleMessage(String message, int messageLevel) { - if (channel == null) return; - Map 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 obj = new HashMap<>(); - obj.put("progress", progress); - channel.invokeMethod("onProgressChanged", obj); - } - - public void onTitleChanged(String title) { - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("title", title); - channel.invokeMethod("onTitleChanged", obj); - } - - public void onReceivedIcon(byte[] icon) { - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("icon", icon); - channel.invokeMethod("onReceivedIcon", obj); - } - - public void onReceivedTouchIconUrl(String url, boolean precomposed) { - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("precomposed", precomposed); - channel.invokeMethod("onReceivedTouchIconUrl", obj); - } - - public static class PermissionRequestCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public PermissionResponse decodeResult(@Nullable Object obj) { - return PermissionResponse.fromMap((Map) obj); - } - } - - public void onPermissionRequest(String origin, List resources, Object frame, @NonNull PermissionRequestCallback callback) { - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map 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 { - @Nullable - @Override - public NavigationActionPolicy decodeResult(@Nullable Object obj) { - Integer action = Util.getOrDefault((Map) 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 obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onLoadStart", obj); - } - - public void onLoadStop(String url) { - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onLoadStop", obj); - } - - public void onUpdateVisitedHistory(String url, boolean isReload) { - if (channel == null) return; - Map 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 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 obj = new HashMap<>(); - obj.put("request", request.toMap()); - obj.put("errorResponse", errorResponse.toMap()); - channel.invokeMethod("onReceivedHttpError", obj); - } - - public static class ReceivedHttpAuthRequestCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public HttpAuthResponse decodeResult(@Nullable Object obj) { - return HttpAuthResponse.fromMap((Map) 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 { - @Nullable - @Override - public ServerTrustAuthResponse decodeResult(@Nullable Object obj) { - return ServerTrustAuthResponse.fromMap((Map) 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 { - @Nullable - @Override - public ClientCertResponse decodeResult(@Nullable Object obj) { - return ClientCertResponse.fromMap((Map) 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 obj = new HashMap<>(); - obj.put("oldScale", oldScale); - obj.put("newScale", newScale); - channel.invokeMethod("onZoomScaleChanged", obj); - } - - public static class SafeBrowsingHitCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public SafeBrowsingResponse decodeResult(@Nullable Object obj) { - return SafeBrowsingResponse.fromMap((Map) obj); - } - } - - public void onSafeBrowsingHit(String url, int threatType, @NonNull SafeBrowsingHitCallback callback) { - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("threatType", threatType); - channel.invokeMethod("onSafeBrowsingHit", obj, callback); - } - - public static class FormResubmissionCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public Integer decodeResult(@Nullable Object obj) { - return obj != null ? (Integer) ((Map) obj).get("action") : null; - } - } - - public void onFormResubmission(String url, @NonNull FormResubmissionCallback callback) { - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onFormResubmission", obj, callback); - } - - public void onPageCommitVisible(String url) { - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onPageCommitVisible", obj); - } - - public void onRenderProcessGone(boolean didCrash, int rendererPriorityAtExit) { - if (channel == null) return; - Map 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 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 { - @Nullable - @Override - public CustomSchemeResponse decodeResult(@Nullable Object obj) { - return CustomSchemeResponse.fromMap((Map) obj); - } - } - - public void onLoadResourceCustomScheme(String url, @NonNull LoadResourceCustomSchemeCallback callback) { - if (channel == null) return; - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onLoadResourceCustomScheme", obj, callback); - } - - public static class SyncLoadResourceCustomSchemeCallback extends SyncBaseCallbackResultImpl { - @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 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 { - @Nullable - @Override - public WebResourceResponseExt decodeResult(@Nullable Object obj) { - return WebResourceResponseExt.fromMap((Map) 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 { - @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 { - @Nullable - @Override - public Integer decodeResult(@Nullable Object obj) { - return obj != null ? (Integer) ((Map) obj).get("action") : null; - } - } - - public void onRenderProcessUnresponsive(String url, @NonNull RenderProcessUnresponsiveCallback callback) { - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onRenderProcessUnresponsive", obj, callback); - } - - public static class RenderProcessResponsiveCallback extends BaseCallbackResultImpl { - @Nullable - @Override - public Integer decodeResult(@Nullable Object obj) { - return obj != null ? (Integer) ((Map) obj).get("action") : null; - } - } - - public void onRenderProcessResponsive(String url, @NonNull RenderProcessResponsiveCallback callback) { - if (channel == null) { - callback.defaultBehaviour(null); - return; - } - Map obj = new HashMap<>(); - obj.put("url", url); - channel.invokeMethod("onRenderProcessResponsive", obj, callback); - } - - public void dispose() { - channel = null; - } -} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/proxy/ProxyManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/proxy/ProxyManager.java index 5a5556c2..2d49f1c8 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/proxy/ProxyManager.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/proxy/ProxyManager.java @@ -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() { diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshChannelDelegate.java new file mode 100644 index 00000000..592869ea --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshChannelDelegate.java @@ -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 obj = new HashMap<>(); + channel.invokeMethod("onRefresh", obj); + } + + @Override + public void dispose() { + super.dispose(); + pullToRefreshView = null; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshLayout.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshLayout.java index 8a53df17..0ddbf175 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshLayout.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshLayout.java @@ -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 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(); } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshSettings.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshSettings.java index 479a9697..7a256b9a 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshSettings.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshSettings.java @@ -22,8 +22,8 @@ public class PullToRefreshSettings implements ISettings { @Nullable public Integer size; - public PullToRefreshSettings parse(Map options) { - for (Map.Entry pair : options.entrySet()) { + public PullToRefreshSettings parse(Map settings) { + for (Map.Entry pair : settings.entrySet()) { String key = pair.getKey(); Object value = pair.getValue(); if (value == null) { diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/service_worker/ServiceWorkerChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/service_worker/ServiceWorkerChannelDelegate.java new file mode 100755 index 00000000..ec52036e --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/service_worker/ServiceWorkerChannelDelegate.java @@ -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 { + @Nullable + @Override + public WebResourceResponseExt decodeResult(@Nullable Object obj) { + return WebResourceResponseExt.fromMap((Map) 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 { + @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; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/service_worker/ServiceWorkerManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/service_worker/ServiceWorkerManager.java new file mode 100755 index 00000000..c2d7ae4d --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/service_worker/ServiceWorkerManager.java @@ -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 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; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/ChannelDelegateImpl.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/ChannelDelegateImpl.java new file mode 100644 index 00000000..adeada5c --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/ChannelDelegateImpl.java @@ -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) { + + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/Disposable.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/Disposable.java new file mode 100644 index 00000000..468ee1a5 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/Disposable.java @@ -0,0 +1,5 @@ +package com.pichillilorenzo.flutter_inappwebview.types; + +public interface Disposable { + void dispose(); +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/IChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/IChannelDelegate.java new file mode 100644 index 00000000..3de75d6f --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/IChannelDelegate.java @@ -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(); +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessagePort.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessagePort.java index f3c07d2b..2684fd39 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessagePort.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessagePort.java @@ -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; } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/ContextMenuSettings.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/ContextMenuSettings.java similarity index 94% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/ContextMenuSettings.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/ContextMenuSettings.java index cbbafe5d..46db0b16 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/ContextMenuSettings.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/ContextMenuSettings.java @@ -1,4 +1,4 @@ -package com.pichillilorenzo.flutter_inappwebview.in_app_webview; +package com.pichillilorenzo.flutter_inappwebview.webview; import com.pichillilorenzo.flutter_inappwebview.ISettings; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/InAppWebViewInterface.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/InAppWebViewInterface.java similarity index 85% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/InAppWebViewInterface.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/InAppWebViewInterface.java index 24e0a88d..877ac0b5 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/InAppWebViewInterface.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/InAppWebViewInterface.java @@ -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); } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/JavaScriptBridgeInterface.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/JavaScriptBridgeInterface.java similarity index 64% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/JavaScriptBridgeInterface.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/JavaScriptBridgeInterface.java index 9556cd52..586d622e 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/JavaScriptBridgeInterface.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/JavaScriptBridgeInterface.java @@ -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 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) 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) 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() { - - } - }); + }); + } } }); } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/PlatformWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/PlatformWebView.java similarity index 76% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/PlatformWebView.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/PlatformWebView.java index 260f87d4..a756ec4b 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/PlatformWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/PlatformWebView.java @@ -1,4 +1,4 @@ -package com.pichillilorenzo.flutter_inappwebview.types; +package com.pichillilorenzo.flutter_inappwebview.webview; import java.util.HashMap; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/WebViewChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/WebViewChannelDelegate.java new file mode 100644 index 00000000..aea0b5f5 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/WebViewChannelDelegate.java @@ -0,0 +1,1232 @@ +package com.pichillilorenzo.flutter_inappwebview.webview; + +import android.net.Uri; +import android.os.Build; +import android.webkit.ValueCallback; +import android.webkit.WebView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.webkit.WebMessageCompat; +import androidx.webkit.WebMessagePortCompat; +import androidx.webkit.WebViewCompat; +import androidx.webkit.WebViewFeature; + +import com.pichillilorenzo.flutter_inappwebview.Util; +import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserActivity; +import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserSettings; +import com.pichillilorenzo.flutter_inappwebview.types.BaseCallbackResultImpl; +import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; +import com.pichillilorenzo.flutter_inappwebview.types.ClientCertChallenge; +import com.pichillilorenzo.flutter_inappwebview.types.ClientCertResponse; +import com.pichillilorenzo.flutter_inappwebview.types.ContentWorld; +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.SslCertificateExt; +import com.pichillilorenzo.flutter_inappwebview.types.SyncBaseCallbackResultImpl; +import com.pichillilorenzo.flutter_inappwebview.types.URLRequest; +import com.pichillilorenzo.flutter_inappwebview.types.UserScript; +import com.pichillilorenzo.flutter_inappwebview.types.WebMessagePort; +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.in_app_webview.InAppWebView; +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.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 WebViewChannelDelegate extends ChannelDelegateImpl { + static final String LOG_TAG = "WebViewChannelDelegate"; + + @Nullable + private InAppWebViewInterface webView; + + public WebViewChannelDelegate(@NonNull InAppWebViewInterface webView, @NonNull MethodChannel channel) { + super(channel); + 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 urlRequest = (Map) 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 contentWorldMap = (Map) call.argument("contentWorld"); + ContentWorld contentWorld = ContentWorld.fromMap(contentWorldMap); + webView.evaluateJavascript(source, contentWorld, new ValueCallback() { + @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 scriptHtmlTagAttributes = (Map) 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 cssLinkHtmlTagAttributes = (Map) 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 screenshotConfiguration = (Map) call.argument("screenshotConfiguration"); + webView.takeScreenshot(screenshotConfiguration, result); + } + else + result.success(null); + break; + case "setSettings": + if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) { + InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate(); + InAppBrowserSettings inAppBrowserSettings = new InAppBrowserSettings(); + HashMap inAppBrowserSettingsMap = (HashMap) call.argument("settings"); + inAppBrowserSettings.parse(inAppBrowserSettingsMap); + inAppBrowserActivity.setSettings(inAppBrowserSettings, inAppBrowserSettingsMap); + } else if (webView != null) { + InAppWebViewSettings inAppWebViewSettings = new InAppWebViewSettings(); + HashMap inAppWebViewSettingsMap = (HashMap) call.argument("settings"); + inAppWebViewSettings.parse(inAppWebViewSettingsMap); + webView.setSettings(inAppWebViewSettings, inAppWebViewSettingsMap); + } + result.success(true); + break; + case "getSettings": + if (webView != 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() instanceof InAppBrowserActivity) { + InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate(); + inAppBrowserActivity.close(result); + } else { + result.notImplemented(); + } + break; + case "show": + if (webView != 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() 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() { + @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() { + @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() { + @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 contextMenu = (Map) 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 userScriptMap = (Map) 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 userScriptMap = (Map) 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 functionArguments = (Map) call.argument("arguments"); + Map contentWorldMap = (Map) call.argument("contentWorld"); + ContentWorld contentWorld = ContentWorld.fromMap(contentWorldMap); + webView.callAsyncJavaScript(functionBody, functionArguments, contentWorld, new ValueCallback() { + @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() { + @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 message = (Map) call.argument("message"); + String targetOrigin = (String) call.argument("targetOrigin"); + List compatPorts = new ArrayList<>(); + List ports = new ArrayList<>(); + List> portsMap = (List>) message.get("ports"); + if (portsMap != null) { + for (Map 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 webMessageListenerMap = (Map) 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 onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("activeMatchOrdinal", activeMatchOrdinal); + obj.put("numberOfMatches", numberOfMatches); + obj.put("isDoneCounting", isDoneCounting); + channel.invokeMethod("onFindResultReceived", obj); + } + + public void onLongPressHitTestResult(HitTestResult hitTestResult) { + MethodChannel channel = getChannel(); + if (channel == null) return; + channel.invokeMethod("onLongPressHitTestResult", hitTestResult.toMap()); + } + + public void onScrollChanged(int x, int y) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("x", x); + obj.put("y", y); + channel.invokeMethod("onScrollChanged", obj); + } + + public void onDownloadStartRequest(DownloadStartRequest downloadStartRequest) { + MethodChannel channel = getChannel(); + if (channel == null) return; + channel.invokeMethod("onDownloadStartRequest", downloadStartRequest.toMap()); + } + + public void onCreateContextMenu(HitTestResult hitTestResult) { + MethodChannel channel = getChannel(); + if (channel == null) return; + channel.invokeMethod("onCreateContextMenu", hitTestResult.toMap()); + } + + public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map 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) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map 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() { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + channel.invokeMethod("onHideContextMenu", obj); + } + + public void onEnterFullscreen() { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + channel.invokeMethod("onEnterFullscreen", obj); + } + + public void onExitFullscreen() { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + channel.invokeMethod("onExitFullscreen", obj); + } + + public static class JsAlertCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public JsAlertResponse decodeResult(@Nullable Object obj) { + return JsAlertResponse.fromMap((Map) obj); + } + } + + public void onJsAlert(String url, String message, Boolean isMainFrame, @NonNull JsAlertCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + Map 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 { + @Nullable + @Override + public JsConfirmResponse decodeResult(@Nullable Object obj) { + return JsConfirmResponse.fromMap((Map) obj); + } + } + + public void onJsConfirm(String url, String message, Boolean isMainFrame, @NonNull JsConfirmCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + Map 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 { + @Nullable + @Override + public JsPromptResponse decodeResult(@Nullable Object obj) { + return JsPromptResponse.fromMap((Map) obj); + } + } + + public void onJsPrompt(String url, String message, String defaultValue, Boolean isMainFrame, @NonNull JsPromptCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + Map 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 { + @Nullable + @Override + public JsBeforeUnloadResponse decodeResult(@Nullable Object obj) { + return JsBeforeUnloadResponse.fromMap((Map) obj); + } + } + + public void onJsBeforeUnload(String url, String message, @NonNull JsBeforeUnloadCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + Map obj = new HashMap<>(); + obj.put("url", url); + obj.put("message", message); + channel.invokeMethod("onJsBeforeUnload", obj, callback); + } + + public static class CreateWindowCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public Boolean decodeResult(@Nullable Object obj) { + return (obj instanceof Boolean) && (boolean) obj; + } + } + + public void onCreateWindow(CreateWindowAction createWindowAction, @NonNull CreateWindowCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + channel.invokeMethod("onCreateWindow", createWindowAction.toMap(), callback); + } + + public void onCloseWindow() { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + channel.invokeMethod("onCloseWindow", obj); + } + + public static class GeolocationPermissionsShowPromptCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public GeolocationPermissionShowPromptResponse decodeResult(@Nullable Object obj) { + return GeolocationPermissionShowPromptResponse.fromMap((Map) obj); + } + } + + public void onGeolocationPermissionsShowPrompt(String origin, @NonNull GeolocationPermissionsShowPromptCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + Map obj = new HashMap<>(); + obj.put("origin", origin); + channel.invokeMethod("onGeolocationPermissionsShowPrompt", obj, callback); + } + + public void onGeolocationPermissionsHidePrompt() { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + channel.invokeMethod("onGeolocationPermissionsHidePrompt", obj); + } + + public void onConsoleMessage(String message, int messageLevel) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("message", message); + obj.put("messageLevel", messageLevel); + channel.invokeMethod("onConsoleMessage", obj); + } + + public void onProgressChanged(int progress) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("progress", progress); + channel.invokeMethod("onProgressChanged", obj); + } + + public void onTitleChanged(String title) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("title", title); + channel.invokeMethod("onTitleChanged", obj); + } + + public void onReceivedIcon(byte[] icon) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("icon", icon); + channel.invokeMethod("onReceivedIcon", obj); + } + + public void onReceivedTouchIconUrl(String url, boolean precomposed) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("url", url); + obj.put("precomposed", precomposed); + channel.invokeMethod("onReceivedTouchIconUrl", obj); + } + + public static class PermissionRequestCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public PermissionResponse decodeResult(@Nullable Object obj) { + return PermissionResponse.fromMap((Map) obj); + } + } + + public void onPermissionRequest(String origin, List resources, Object frame, @NonNull PermissionRequestCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + Map 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 { + @Nullable + @Override + public NavigationActionPolicy decodeResult(@Nullable Object obj) { + Integer action = Util.getOrDefault((Map) obj, + "action", NavigationActionPolicy.CANCEL.rawValue()); + return NavigationActionPolicy.fromValue(action); + } + } + + public void shouldOverrideUrlLoading(NavigationAction navigationAction, @NonNull ShouldOverrideUrlLoadingCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + channel.invokeMethod("shouldOverrideUrlLoading", navigationAction.toMap(), callback); + } + + public void onLoadStart(String url) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("url", url); + channel.invokeMethod("onLoadStart", obj); + } + + public void onLoadStop(String url) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("url", url); + channel.invokeMethod("onLoadStop", obj); + } + + public void onUpdateVisitedHistory(String url, boolean isReload) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("url", url); + obj.put("isReload", isReload); + channel.invokeMethod("onUpdateVisitedHistory", obj); + } + + public void onReceivedError(WebResourceRequestExt request, WebResourceErrorExt error) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("request", request.toMap()); + obj.put("error", error.toMap()); + channel.invokeMethod("onReceivedError", obj); + } + + public void onReceivedHttpError(WebResourceRequestExt request, WebResourceResponseExt errorResponse) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("request", request.toMap()); + obj.put("errorResponse", errorResponse.toMap()); + channel.invokeMethod("onReceivedHttpError", obj); + } + + public static class ReceivedHttpAuthRequestCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public HttpAuthResponse decodeResult(@Nullable Object obj) { + return HttpAuthResponse.fromMap((Map) obj); + } + } + + public void onReceivedHttpAuthRequest(HttpAuthenticationChallenge challenge, @NonNull ReceivedHttpAuthRequestCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + channel.invokeMethod("onReceivedHttpAuthRequest", challenge.toMap(), callback); + } + + public static class ReceivedServerTrustAuthRequestCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public ServerTrustAuthResponse decodeResult(@Nullable Object obj) { + return ServerTrustAuthResponse.fromMap((Map) obj); + } + } + + public void onReceivedServerTrustAuthRequest(ServerTrustChallenge challenge, @NonNull ReceivedServerTrustAuthRequestCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + channel.invokeMethod("onReceivedServerTrustAuthRequest", challenge.toMap(), callback); + } + + public static class ReceivedClientCertRequestCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public ClientCertResponse decodeResult(@Nullable Object obj) { + return ClientCertResponse.fromMap((Map) obj); + } + } + + public void onReceivedClientCertRequest(ClientCertChallenge challenge, @NonNull ReceivedClientCertRequestCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + channel.invokeMethod("onReceivedClientCertRequest", challenge.toMap(), callback); + } + + public void onZoomScaleChanged(float oldScale, float newScale) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("oldScale", oldScale); + obj.put("newScale", newScale); + channel.invokeMethod("onZoomScaleChanged", obj); + } + + public static class SafeBrowsingHitCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public SafeBrowsingResponse decodeResult(@Nullable Object obj) { + return SafeBrowsingResponse.fromMap((Map) obj); + } + } + + public void onSafeBrowsingHit(String url, int threatType, @NonNull SafeBrowsingHitCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + Map obj = new HashMap<>(); + obj.put("url", url); + obj.put("threatType", threatType); + channel.invokeMethod("onSafeBrowsingHit", obj, callback); + } + + public static class FormResubmissionCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public Integer decodeResult(@Nullable Object obj) { + return obj != null ? (Integer) ((Map) obj).get("action") : null; + } + } + + public void onFormResubmission(String url, @NonNull FormResubmissionCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + Map obj = new HashMap<>(); + obj.put("url", url); + channel.invokeMethod("onFormResubmission", obj, callback); + } + + public void onPageCommitVisible(String url) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("url", url); + channel.invokeMethod("onPageCommitVisible", obj); + } + + public void onRenderProcessGone(boolean didCrash, int rendererPriorityAtExit) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("didCrash", didCrash); + obj.put("rendererPriorityAtExit", rendererPriorityAtExit); + channel.invokeMethod("onRenderProcessGone", obj); + } + + public void onReceivedLoginRequest(String realm, String account, String args) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map 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 { + @Nullable + @Override + public CustomSchemeResponse decodeResult(@Nullable Object obj) { + return CustomSchemeResponse.fromMap((Map) obj); + } + } + + public void onLoadResourceCustomScheme(String url, @NonNull LoadResourceCustomSchemeCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("url", url); + channel.invokeMethod("onLoadResourceCustomScheme", obj, callback); + } + + public static class SyncLoadResourceCustomSchemeCallback extends SyncBaseCallbackResultImpl { + @Nullable + @Override + public CustomSchemeResponse decodeResult(@Nullable Object obj) { + return (new LoadResourceCustomSchemeCallback()).decodeResult(obj); + } + } + + @Nullable + public CustomSchemeResponse onLoadResourceCustomScheme(String url) throws InterruptedException { + MethodChannel channel = getChannel(); + if (channel == null) return null; + final Map 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 { + @Nullable + @Override + public WebResourceResponseExt decodeResult(@Nullable Object obj) { + return WebResourceResponseExt.fromMap((Map) obj); + } + } + + public void shouldInterceptRequest(WebResourceRequestExt request, @NonNull ShouldInterceptRequestCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) return; + channel.invokeMethod("shouldInterceptRequest", request.toMap(), callback); + } + + public static class SyncShouldInterceptRequestCallback extends SyncBaseCallbackResultImpl { + @Nullable + @Override + public WebResourceResponseExt decodeResult(@Nullable Object obj) { + return (new ShouldInterceptRequestCallback()).decodeResult(obj); + } + } + + @Nullable + public WebResourceResponseExt shouldInterceptRequest(WebResourceRequestExt request) throws InterruptedException { + MethodChannel channel = getChannel(); + if (channel == null) return null; + final SyncShouldInterceptRequestCallback callback = new SyncShouldInterceptRequestCallback(); + return Util.invokeMethodAndWaitResult(channel, "shouldInterceptRequest", request.toMap(), callback); + } + + public static class RenderProcessUnresponsiveCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public Integer decodeResult(@Nullable Object obj) { + return obj != null ? (Integer) ((Map) obj).get("action") : null; + } + } + + public void onRenderProcessUnresponsive(String url, @NonNull RenderProcessUnresponsiveCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + Map obj = new HashMap<>(); + obj.put("url", url); + channel.invokeMethod("onRenderProcessUnresponsive", obj, callback); + } + + public static class RenderProcessResponsiveCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public Integer decodeResult(@Nullable Object obj) { + return obj != null ? (Integer) ((Map) obj).get("action") : null; + } + } + + public void onRenderProcessResponsive(String url, @NonNull RenderProcessResponsiveCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + Map obj = new HashMap<>(); + obj.put("url", url); + channel.invokeMethod("onRenderProcessResponsive", obj, callback); + } + + public static class CallJsHandlerCallback extends BaseCallbackResultImpl { + @Nullable + @Override + public Object decodeResult(@Nullable Object obj) { + return obj; + } + } + + public void onCallJsHandler(String handlerName, String args, @NonNull CallJsHandlerCallback callback) { + MethodChannel channel = getChannel(); + if (channel == null) { + callback.defaultBehaviour(null); + return; + } + Map obj = new HashMap<>(); + obj.put("handlerName", handlerName); + obj.put("args", args); + channel.invokeMethod("onCallJsHandler", obj, callback); + } + + @Override + public void dispose() { + super.dispose(); + webView = null; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/DisplayListenerProxy.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/DisplayListenerProxy.java similarity index 98% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/DisplayListenerProxy.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/DisplayListenerProxy.java index 50bd2e4b..eb92c83f 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/DisplayListenerProxy.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/DisplayListenerProxy.java @@ -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; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/FlutterWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/FlutterWebView.java similarity index 80% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/FlutterWebView.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/FlutterWebView.java index a874a51f..55464317 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/FlutterWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/FlutterWebView.java @@ -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 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> initialUserScripts = (List>) params.get("initialUserScripts"); Map pullToRefreshInitialSettings = (Map) 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(); diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebView.java similarity index 97% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebView.java index ef80b301..4082226b 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebView.java @@ -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 contextMenu, View containerView, List 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(); } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewChromeClient.java similarity index 91% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewChromeClient.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewChromeClient.java index 56e905d7..0efc3549 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewChromeClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewChromeClient.java @@ -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); diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewClient.java similarity index 89% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewClient.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewClient.java index 1aab666c..ec952190 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewClient.java @@ -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); } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewRenderProcessClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewRenderProcessClient.java similarity index 78% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewRenderProcessClient.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewRenderProcessClient.java index 174c647c..4db53aa1 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewRenderProcessClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewRenderProcessClient.java @@ -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); } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewSettings.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewSettings.java similarity index 99% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewSettings.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewSettings.java index 8d0c2fef..56057ec3 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewSettings.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewSettings.java @@ -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; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InputAwareWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InputAwareWebView.java similarity index 95% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InputAwareWebView.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InputAwareWebView.java index e67c0e5d..0613f133 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InputAwareWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InputAwareWebView.java @@ -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. diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/ThreadedInputConnectionProxyAdapterView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/ThreadedInputConnectionProxyAdapterView.java similarity index 91% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/ThreadedInputConnectionProxyAdapterView.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/ThreadedInputConnectionProxyAdapterView.java index d0d71692..bf401488 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/ThreadedInputConnectionProxyAdapterView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/ThreadedInputConnectionProxyAdapterView.java @@ -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; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessageChannel.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageChannel.java similarity index 65% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessageChannel.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageChannel.java index c2b24b8b..ce465be5 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessageChannel.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageChannel.java @@ -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 compatPorts; public final List 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<>(); @@ -59,54 +65,18 @@ public class WebMessageChannel implements MethodChannel.MethodCallHandler { callback.onReceiveValue(this); } } - - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - switch (call.method) { - case "setWebMessageCallback": - if (webView instanceof InAppWebView) { - final Integer index = (Integer) call.argument("index"); - setWebMessageCallbackForInAppWebView(index, result); - } else { - result.success(true); - } - break; - case "postMessage": - if (webView instanceof InAppWebView) { - final Integer index = (Integer) call.argument("index"); - Map message = (Map) 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 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 message, @NonNull MethodChannel.Result result) { + public void postMessageForInAppWebView(final Integer index, Map 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 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 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; } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageChannelChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageChannelChannelDelegate.java new file mode 100644 index 00000000..630f50c6 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageChannelChannelDelegate.java @@ -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 message = (Map) 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 obj = new HashMap<>(); + obj.put("index", index); + obj.put("message", message ); + channel.invokeMethod("onMessage", obj); + } + + @Override + public void dispose() { + super.dispose(); + webMessageChannel = null; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessageListener.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageListener.java similarity index 79% rename from android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessageListener.java rename to android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageListener.java index ded33592..48291605 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessageListener.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageListener.java @@ -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 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 allowedOriginRules) { + public WebMessageListener(@NonNull InAppWebViewInterface webView, @NonNull BinaryMessenger messenger, + @NonNull String jsObjectName, @NonNull Set 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); } @@ -218,19 +213,14 @@ public class WebMessageListener implements MethodChannel.MethodCallHandler { } return false; } - - public void onPostMessage(String message, Uri sourceOrigin, boolean isMainFrame) { - Map 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; } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageListenerChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageListenerChannelDelegate.java new file mode 100644 index 00000000..d37b4a95 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/web_message/WebMessageListenerChannelDelegate.java @@ -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 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; + } +} diff --git a/android/src/main/res/layout/activity_web_view.xml b/android/src/main/res/layout/activity_web_view.xml index 04d0d54d..7dcc1374 100755 --- a/android/src/main/res/layout/activity_web_view.xml +++ b/android/src/main/res/layout/activity_web_view.xml @@ -14,7 +14,7 @@ android:id="@+id/pullToRefresh" android:layout_width="match_parent" android:layout_height="match_parent"> -