diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 8a3b8482..f2e059fd 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -15,43 +15,31 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+
+
+
+
@@ -74,48 +62,44 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
@@ -123,11 +107,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
@@ -147,11 +161,6 @@
- cordova
- onDownloadStart
- platfor
- DATAAAAAA
- defaultTargetPlatform
test
WebResourceResponse
onCUstom
@@ -177,6 +186,11 @@
_throwIsNotOpened
_hand
_ChannelManager
+ onDo
+ options
+ initialData
+ assert
+ Level
activity.getPreferences(0)
@@ -196,8 +210,6 @@
@@ -262,6 +276,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -302,39 +359,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -485,11 +509,10 @@
-
-
+
-
-
+
+
@@ -499,19 +522,19 @@
-
+
-
+
-
+
-
+
-
+
@@ -535,20 +558,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -610,23 +619,9 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -721,18 +716,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
@@ -743,67 +726,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -814,9 +736,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -824,55 +763,131 @@
-
+
-
-
-
-
-
-
+
+
-
-
-
-
-
+
-
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
+
+
-
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 97d162e1..22a157d5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,9 +9,17 @@
- Merge "migrating to swift 5.0" [#162](https://github.com/pichillilorenzo/flutter_inappbrowser/pull/162) (thanks to [fattiger00](https://github.com/fattiger00))
- Merge "Update readme example" [#178](https://github.com/pichillilorenzo/flutter_inappbrowser/pull/178) (thanks to [SebastienBtr](https://github.com/SebastienBtr))
- Added `horizontalScrollBarEnabled` and `verticalScrollBarEnabled` options to enable/disable the corresponding scrollbar of the WebView [#165](https://github.com/pichillilorenzo/flutter_inappbrowser/issues/165)
-- Added `onDownloadStart` event: event fires when the WebView recognizes and starts a downloadable file.
+- Added `onDownloadStart` event and `useOnDownloadStart` option: event fires when the WebView recognizes and starts a downloadable file.
- Added `onLoadResourceCustomScheme` event and `resourceCustomSchemes` option to set custom schemes that WebView must handle to load resources
- Added `onTargetBlank` event and `useOnTargetBlank` option to manage links with `target="_blank"`
+- Added `ContentBlocker`, `ContentBlockerTrigger` and `ContentBlockerAction` classes and the `contentBlockers` option that allows to define a set of rules to use to block content in the WebView
+
+### BREAKING CHANGES
+- Deleted `WebResourceRequest` class
+- Updated `WebResourceResponse` class
+- Updated `onLoadResource` event
+- WebView options are now available with the new corresponding classes: `InAppWebViewOptions`, `AndroidInAppWebViewOptions`, `iOSInAppWebViewOptions`, `InAppBrowserOptions`, `AndroidInAppBrowserOptions`, `iOSInAppBrowserOptions`, `AndroidChromeCustomTabsOptions` and `iOSChromeCustomTabsOptions`
+
## 1.2.1
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlocker.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlocker.java
new file mode 100644
index 00000000..2007dac5
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlocker.java
@@ -0,0 +1,171 @@
+package com.pichillilorenzo.flutter_inappbrowser.ContentBlocker;
+
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.webkit.WebResourceResponse;
+
+import com.pichillilorenzo.flutter_inappbrowser.InAppWebView.InAppWebView;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class ContentBlocker {
+ protected static final String LOG_TAG = "ContentBlocker";
+
+ public static WebResourceResponse checkUrl(final InAppWebView webView, String url, ContentBlockerTriggerResourceType responseResourceType) {
+ if (webView.options.contentBlockers == null)
+ return null;
+
+ for (Map> contentBlocker : webView.options.contentBlockers) {
+ ContentBlockerTrigger trigger = ContentBlockerTrigger.fromMap(contentBlocker.get("trigger"));
+ List resourceTypes = trigger.resourceType;
+
+ ContentBlockerAction action = ContentBlockerAction.fromMap(contentBlocker.get("action"));
+
+ Pattern mPattern = Pattern.compile(trigger.urlFilter);
+ Matcher m = mPattern.matcher(url);
+
+ if (m.matches()) {
+ Log.d(LOG_TAG, url);
+ Log.d(LOG_TAG, responseResourceType.toString());
+ Log.d(LOG_TAG, resourceTypes.toString());
+
+ if (resourceTypes != null && resourceTypes.size() > 0 && !resourceTypes.contains(responseResourceType)) {
+ return null;
+ }
+ switch (action.type) {
+
+ case BLOCK:
+ return new WebResourceResponse("", "", null);
+
+ case CSS_DISPLAY_NONE:
+ final String jsScript = "function hide () { document.querySelectorAll('" + action.selector + "').forEach(function (item, index) { item.style.display = \"none\"; }); }; hide(); document.addEventListener(\"DOMContentLoaded\", function(event) { hide(); });";
+ final Handler handler = new Handler(Looper.getMainLooper());
+ Log.d(LOG_TAG, jsScript);
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ webView.evaluateJavascript(jsScript, null);
+ } else {
+ webView.loadUrl("javascript:" + jsScript);
+ }
+ }
+ });
+ break;
+
+ case MAKE_HTTPS:
+ if (url.startsWith("http://")) {
+ String urlHttps = url.replace("http://", "https://");
+
+ Request mRequest = new Request.Builder().url(urlHttps).build();
+ Response response = null;
+
+ try {
+
+ response = webView.httpClient.newCall(mRequest).execute();
+ byte[] dataBytes = response.body().bytes();
+ InputStream dataStream = new ByteArrayInputStream(dataBytes);
+
+ String[] contentTypeSplitted = response.header("content-type", "text/plain").split(";");
+
+ String contentType = contentTypeSplitted[0].trim();
+ String encoding = (contentTypeSplitted.length > 1 && contentTypeSplitted[1].contains("charset="))
+ ? contentTypeSplitted[1].replace("charset=", "").trim()
+ : "utf-8";
+
+ response.close();
+
+ return new WebResourceResponse(contentType, encoding, dataStream);
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ if (response != null) {
+ response.close();
+ }
+ Log.e(LOG_TAG, e.getMessage());
+ }
+ }
+ break;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static WebResourceResponse checkUrl(final InAppWebView webView, String url) {
+ ContentBlockerTriggerResourceType responseResourceType = getResourceTypeFromUrl(webView, url);
+ return checkUrl(webView, url, responseResourceType);
+ }
+
+ public static WebResourceResponse checkUrl(final InAppWebView webView, String url, String contentType) {
+ ContentBlockerTriggerResourceType responseResourceType = getResourceTypeFromContentType(contentType);
+ return checkUrl(webView, url, responseResourceType);
+ }
+
+
+ public static ContentBlockerTriggerResourceType getResourceTypeFromUrl(InAppWebView webView, String url) {
+ ContentBlockerTriggerResourceType responseResourceType = ContentBlockerTriggerResourceType.RAW;
+
+ // make an HTTP "HEAD" request to the server for that URL. This will not return the full content of the URL.
+ if (url.startsWith("http://") || url.startsWith("https://")) {
+ Request mRequest = new Request.Builder().url(url).head().build();
+ Response response = null;
+ try {
+ response = webView.httpClient.newCall(mRequest).execute();
+
+ if (response.header("content-type") != null) {
+ String[] contentTypeSplitted = response.header("content-type").split(";");
+
+ String contentType = contentTypeSplitted[0].trim();
+ String encoding = (contentTypeSplitted.length > 1 && contentTypeSplitted[1].contains("charset="))
+ ? contentTypeSplitted[1].replace("charset=", "").trim()
+ : "utf-8";
+
+ response.close();
+ responseResourceType = getResourceTypeFromContentType(contentType);
+ }
+
+ } catch (IOException e) {
+ if (response != null) {
+ response.close();
+ }
+ e.printStackTrace();
+ }
+ }
+ return responseResourceType;
+ }
+
+ public static ContentBlockerTriggerResourceType getResourceTypeFromContentType(String contentType) {
+ ContentBlockerTriggerResourceType responseResourceType = ContentBlockerTriggerResourceType.RAW;
+
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
+ if (contentType.equals("text/css")) {
+ responseResourceType = ContentBlockerTriggerResourceType.STYLE_SHEET;
+ } else if (contentType.equals("image/svg+xml")) {
+ responseResourceType = ContentBlockerTriggerResourceType.SVG_DOCUMENT;
+ } else if (contentType.startsWith("image/")) {
+ responseResourceType = ContentBlockerTriggerResourceType.IMAGE;
+ } else if (contentType.startsWith("font/")) {
+ responseResourceType = ContentBlockerTriggerResourceType.FONT;
+ } else if (contentType.startsWith("audio/") || contentType.startsWith("video/") || contentType.equals("application/ogg")) {
+ responseResourceType = ContentBlockerTriggerResourceType.MEDIA;
+ } else if (contentType.endsWith("javascript")) {
+ responseResourceType = ContentBlockerTriggerResourceType.SCRIPT;
+ } else if (contentType.startsWith("text/")) {
+ responseResourceType = ContentBlockerTriggerResourceType.DOCUMENT;
+ }
+
+ return responseResourceType;
+ }
+}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerAction.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerAction.java
new file mode 100644
index 00000000..150eb6f8
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerAction.java
@@ -0,0 +1,22 @@
+package com.pichillilorenzo.flutter_inappbrowser.ContentBlocker;
+
+import java.util.Map;
+
+public class ContentBlockerAction {
+ ContentBlockerActionType type;
+ String selector;
+
+ ContentBlockerAction(ContentBlockerActionType type, String selector) {
+ this.type = type;
+ if (this.type.equals(ContentBlockerActionType.CSS_DISPLAY_NONE)) {
+ assert(selector != null);
+ }
+ this.selector = selector;
+ }
+
+ public static ContentBlockerAction fromMap(Map map) {
+ ContentBlockerActionType type = ContentBlockerActionType.fromValue((String) map.get("type"));
+ String selector = (String) map.get("selector");
+ return new ContentBlockerAction(type, selector);
+ }
+}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerActionType.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerActionType.java
new file mode 100644
index 00000000..cd24b2df
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerActionType.java
@@ -0,0 +1,29 @@
+package com.pichillilorenzo.flutter_inappbrowser.ContentBlocker;
+
+public enum ContentBlockerActionType {
+ BLOCK ("block"),
+ CSS_DISPLAY_NONE ("css-display-none"),
+ MAKE_HTTPS ("make-https");
+
+ private final String value;
+
+ private ContentBlockerActionType(String value) {
+ this.value = value;
+ }
+
+ public boolean equalsValue(String otherValue) {
+ return value.equals(otherValue);
+ }
+
+ public static ContentBlockerActionType fromValue(String value) {
+ for( ContentBlockerActionType type : ContentBlockerActionType.values()) {
+ if(value.equals(type.value))
+ return type;
+ }
+ throw new IllegalArgumentException("No enum constant: " + value);
+ }
+
+ public String toString() {
+ return this.value;
+ }
+}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerTrigger.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerTrigger.java
new file mode 100644
index 00000000..99f22015
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerTrigger.java
@@ -0,0 +1,27 @@
+package com.pichillilorenzo.flutter_inappbrowser.ContentBlocker;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class ContentBlockerTrigger {
+
+ public String urlFilter;
+ List resourceType = new ArrayList<>();
+
+ public ContentBlockerTrigger(String urlFilter, List resourceType) {
+ this.urlFilter = urlFilter;
+ this.resourceType = resourceType != null ? resourceType : this.resourceType;
+ }
+
+ public static ContentBlockerTrigger fromMap(Map map) {
+ String urlFilter = (String) map.get("url-filter");
+ List resourceTypeStringList = (List) map.get("resource-type");
+ List resourceType = new ArrayList<>();
+ for (String type : resourceTypeStringList) {
+ resourceType.add(ContentBlockerTriggerResourceType.fromValue(type));
+ }
+ return new ContentBlockerTrigger(urlFilter, resourceType);
+ }
+
+}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerTriggerResourceType.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerTriggerResourceType.java
new file mode 100644
index 00000000..c96192e6
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerTriggerResourceType.java
@@ -0,0 +1,34 @@
+package com.pichillilorenzo.flutter_inappbrowser.ContentBlocker;
+
+public enum ContentBlockerTriggerResourceType {
+ DOCUMENT ("document"),
+ IMAGE ("image"),
+ STYLE_SHEET ("style-sheet"),
+ SCRIPT ("script"),
+ FONT ("font"),
+ SVG_DOCUMENT ("svg-document"),
+ MEDIA ("media"),
+ RAW ("raw");
+
+ private final String value;
+
+ private ContentBlockerTriggerResourceType(String value) {
+ this.value = value;
+ }
+
+ public boolean equalsValue(String otherValue) {
+ return value.equals(otherValue);
+ }
+
+ public static ContentBlockerTriggerResourceType fromValue(String value) {
+ for( ContentBlockerTriggerResourceType type : ContentBlockerTriggerResourceType.values()) {
+ if(value.equals(type.value))
+ return type;
+ }
+ throw new IllegalArgumentException("No enum constant: " + value);
+ }
+
+ public String toString() {
+ return this.value;
+ }
+}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java
index 21c4e419..dc5e78f0 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java
@@ -1,6 +1,5 @@
package com.pichillilorenzo.flutter_inappbrowser.InAppWebView;
-import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
@@ -23,7 +22,6 @@ import com.pichillilorenzo.flutter_inappbrowser.FlutterWebView;
import com.pichillilorenzo.flutter_inappbrowser.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappbrowser.InAppBrowserFlutterPlugin;
import com.pichillilorenzo.flutter_inappbrowser.JavaScriptBridgeInterface;
-import com.pichillilorenzo.flutter_inappbrowser.RequestPermissionHandler;
import com.pichillilorenzo.flutter_inappbrowser.Util;
import java.io.ByteArrayOutputStream;
@@ -47,11 +45,11 @@ public class InAppWebView extends WebView {
public InAppBrowserActivity inAppBrowserActivity;
public FlutterWebView flutterWebView;
public int id;
- InAppWebViewClient inAppWebViewClient;
- InAppWebChromeClient inAppWebChromeClient;
+ public InAppWebViewClient inAppWebViewClient;
+ public InAppWebChromeClient inAppWebChromeClient;
public InAppWebViewOptions options;
public boolean isLoading = false;
- OkHttpClient httpClient;
+ public OkHttpClient httpClient;
int okHttpClientCacheSize = 10 * 1024 * 1024; // 10MB
static final String consoleLogJS = "(function() {" +
@@ -80,6 +78,15 @@ public class InAppWebView extends WebView {
" }" +
"})();";
+ static final String resourceObserverJS = "(function() {" +
+ " var observer = new PerformanceObserver(function(list) {" +
+ " list.getEntries().forEach(function(entry) {" +
+ " window." + JavaScriptBridgeInterface.name + "._resourceLoaded(JSON.stringify(entry));" +
+ " });" +
+ " });" +
+ " observer.observe({entryTypes: ['resource']});" +
+ "})();";
+
static final String platformReadyJS = "window.dispatchEvent(new Event('flutterInAppBrowserPlatformReady'));";
public InAppWebView(Context context) {
@@ -117,7 +124,8 @@ public class InAppWebView extends WebView {
boolean isFromInAppBrowserActivity = inAppBrowserActivity != null;
- httpClient = new OkHttpClient().newBuilder().cache(new Cache(getContext().getCacheDir(), okHttpClientCacheSize)).build();
+ //httpClient = new OkHttpClient().newBuilder().cache(new Cache(getContext().getCacheDir(), okHttpClientCacheSize)).build();
+ httpClient = new OkHttpClient().newBuilder().build();
addJavascriptInterface(new JavaScriptBridgeInterface((isFromInAppBrowserActivity) ? inAppBrowserActivity : flutterWebView), JavaScriptBridgeInterface.name);
@@ -127,23 +135,8 @@ public class InAppWebView extends WebView {
inAppWebViewClient = new InAppWebViewClient((isFromInAppBrowserActivity) ? inAppBrowserActivity : flutterWebView);
setWebViewClient(inAppWebViewClient);
- setDownloadListener(new DownloadListener() {
- @Override
- public void onDownloadStart(final String url, final String userAgent,
- final String contentDisposition, final String mimetype,
- final long contentLength) {
- RequestPermissionHandler.checkAndRun(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE, RequestPermissionHandler.REQUEST_CODE_WRITE_EXTERNAL_STORAGE, new Runnable(){
- @Override
- public void run(){
- Map obj = new HashMap<>();
- if (inAppBrowserActivity != null)
- obj.put("uuid", inAppBrowserActivity.uuid);
- obj.put("url", url);
- getChannel().invokeMethod("onDownloadStart", obj);
- }
- });
- }
- });
+ if (options.useOnDownloadStart)
+ setDownloadListener(new DownloadStartListener());
WebSettings settings = getSettings();
@@ -396,6 +389,14 @@ public class InAppWebView extends WebView {
if (newOptionsMap.get("useOnTargetBlank") != null && options.useOnTargetBlank != newOptions.useOnTargetBlank)
settings.setSupportMultipleWindows(newOptions.useOnTargetBlank);
+ if (newOptionsMap.get("useOnDownloadStart") != null && options.useOnDownloadStart != newOptions.useOnDownloadStart) {
+ if (newOptions.useOnDownloadStart) {
+ setDownloadListener(new DownloadStartListener());
+ } else {
+ setDownloadListener(null);
+ }
+ }
+
options = newOptions;
}
@@ -534,6 +535,17 @@ public class InAppWebView extends WebView {
return (inAppBrowserActivity != null) ? InAppBrowserFlutterPlugin.instance.channel : flutterWebView.channel;
}
+ class DownloadStartListener implements DownloadListener {
+ @Override
+ public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
+ Map obj = new HashMap<>();
+ if (inAppBrowserActivity != null)
+ obj.put("uuid", inAppBrowserActivity.uuid);
+ obj.put("url", url);
+ getChannel().invokeMethod("onDownloadStart", obj);
+ }
+ }
+
@Override
public void destroy() {
super.destroy();
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java
index 5b31347b..d40c6492 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java
@@ -5,10 +5,6 @@ import android.graphics.Bitmap;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
-import androidx.annotation.RequiresApi;
-
-import android.os.Handler;
-import android.os.Looper;
import android.util.Base64;
import android.util.Log;
import android.webkit.CookieManager;
@@ -21,6 +17,9 @@ import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
+import androidx.annotation.RequiresApi;
+
+import com.pichillilorenzo.flutter_inappbrowser.ContentBlocker.ContentBlocker;
import com.pichillilorenzo.flutter_inappbrowser.FlutterWebView;
import com.pichillilorenzo.flutter_inappbrowser.InAppBrowserActivity;
import com.pichillilorenzo.flutter_inappbrowser.InAppBrowserFlutterPlugin;
@@ -28,15 +27,10 @@ import com.pichillilorenzo.flutter_inappbrowser.JavaScriptBridgeInterface;
import com.pichillilorenzo.flutter_inappbrowser.Util;
import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
-import okhttp3.Request;
-import okhttp3.Response;
public class InAppWebViewClient extends WebViewClient {
@@ -185,12 +179,16 @@ public class InAppWebViewClient extends WebViewClient {
*/
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
+
+ InAppWebView webView = (InAppWebView) view;
+
+ if (webView.options.useOnLoadResource)
+ webView.loadUrl("javascript:" + webView.resourceObserverJS.replaceAll("[\r\n]+", ""));
+
super.onPageStarted(view, url, favicon);
startPageTime = System.currentTimeMillis();
-
- ((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView).isLoading = true;
-
+ webView.isLoading = true;
if (inAppBrowserActivity != null && inAppBrowserActivity.searchView != null && !url.equals(inAppBrowserActivity.searchView.getQuery().toString())) {
inAppBrowserActivity.searchView.setQuery(url, false);
}
@@ -204,9 +202,11 @@ public class InAppWebViewClient extends WebViewClient {
public void onPageFinished(final WebView view, String url) {
+ InAppWebView webView = (InAppWebView) view;
+
super.onPageFinished(view, url);
- ((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView).isLoading = false;
+ webView.isLoading = false;
// CB-10395 InAppBrowserFlutterPlugin's WebView not storing cookies reliable to local device storage
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@@ -305,7 +305,7 @@ public class InAppWebViewClient extends WebViewClient {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
- InAppWebView webView = (InAppWebView) view;
+ final InAppWebView webView = (InAppWebView) view;
final String url = request.getUrl().toString();
String scheme = request.getUrl().getScheme();
@@ -324,105 +324,16 @@ public class InAppWebViewClient extends WebViewClient {
}
else if (flutterResult.result != null) {
Map res = (Map) flutterResult.result;
+ WebResourceResponse response = ContentBlocker.checkUrl(webView, url, res.get("content-type"));
+ if (response != null)
+ return response;
byte[] data = Base64.decode(res.get("base64data"), Base64.DEFAULT);
return new WebResourceResponse(res.get("content-type"), res.get("content-encoding"), new ByteArrayInputStream(data));
}
}
- if (!request.getMethod().toLowerCase().equals("get") ||
- !(((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView).options.useOnLoadResource)) {
- return null;
- }
-
- try {
- Request mRequest = new Request.Builder().url(url).build();
-
- long startResourceTime = System.currentTimeMillis();
- Response response = ((inAppBrowserActivity != null) ? inAppBrowserActivity.webView : flutterWebView.webView).httpClient.newCall(mRequest).execute();
- long startTime = startResourceTime - startPageTime;
- startTime = (startTime < 0) ? 0 : startTime;
- long duration = System.currentTimeMillis() - startResourceTime;
-
- if (response.cacheResponse() != null) {
- duration = 0;
- }
-
- String reasonPhrase = response.message();
- if (reasonPhrase.equals("")) {
- reasonPhrase = statusCodeMapping.get(response.code());
- }
- reasonPhrase = (reasonPhrase.equals("") || reasonPhrase == null) ? "OK" : reasonPhrase;
-
- Map headersResponse = new HashMap();
- for (Map.Entry> entry : response.headers().toMultimap().entrySet()) {
- StringBuilder value = new StringBuilder();
- for (String val : entry.getValue()) {
- value.append((value.toString().isEmpty()) ? val : "; " + val);
- }
- headersResponse.put(entry.getKey().toLowerCase(), value.toString());
- }
-
- Map headersRequest = new HashMap();
- for (Map.Entry> entry : mRequest.headers().toMultimap().entrySet()) {
- StringBuilder value = new StringBuilder();
- for (String val : entry.getValue()) {
- value.append((value.toString().isEmpty()) ? val : "; " + val);
- }
- headersRequest.put(entry.getKey().toLowerCase(), value.toString());
- }
-
- final Map obj = new HashMap<>();
- Map res = new HashMap<>();
- Map req = new HashMap<>();
-
- if (inAppBrowserActivity != null)
- obj.put("uuid", inAppBrowserActivity.uuid);
-
- byte[] dataBytes = response.body().bytes();
- InputStream dataStream = new ByteArrayInputStream(dataBytes);
-
- res.put("url", url);
- res.put("statusCode", response.code());
- res.put("headers", headersResponse);
- res.put("startTime", startTime);
- res.put("duration", duration);
- res.put("data", dataBytes);
-
- req.put("url", url);
- req.put("headers", headersRequest);
- req.put("method", mRequest.method());
-
- obj.put("response", res);
- obj.put("request", req);
-
- // java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread.
- // https://github.com/pichillilorenzo/flutter_inappbrowser/issues/98
- final Handler handler = new Handler(Looper.getMainLooper());
- handler.post(new Runnable() {
- @Override
- public void run() {
- getChannel().invokeMethod("onLoadResource", obj);
- }
- });
-
- // this return is not working (it blocks some resources), so return null
-// return new WebResourceResponse(
-// response.header("content-type", "text/plain").split(";")[0].trim(),
-// response.header("content-encoding", "utf-8"),
-// response.code(),
-// reasonPhrase,
-// headersResponse,
-// dataStream
-// );
- } catch (IOException e) {
- e.printStackTrace();
- Log.d(LOG_TAG, e.getMessage());
- } catch (Exception e) {
- e.printStackTrace();
- Log.d(LOG_TAG, e.getMessage());
- }
-
- return null;
+ WebResourceResponse response = ContentBlocker.checkUrl(webView, url);
+ return response;
}
private MethodChannel getChannel() {
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java
index 46184daf..0aac1f38 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java
@@ -4,6 +4,7 @@ import com.pichillilorenzo.flutter_inappbrowser.Options;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
public class InAppWebViewOptions extends Options {
@@ -11,6 +12,7 @@ public class InAppWebViewOptions extends Options {
public boolean useShouldOverrideUrlLoading = false;
public boolean useOnLoadResource = false;
+ public boolean useOnDownloadStart = false;
public boolean useOnTargetBlank = false;
public boolean clearCache = false;
public String userAgent = "";
@@ -21,6 +23,7 @@ public class InAppWebViewOptions extends Options {
public boolean verticalScrollBarEnabled = true;
public boolean horizontalScrollBarEnabled = true;
public List resourceCustomSchemes = new ArrayList<>();
+ public List