diff --git a/CHANGELOG.md b/CHANGELOG.md index 8206624c..cd077ece 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,19 @@ - Added Android keyboard workaround to hide the keyboard when clicking other HTML elements, losing the focus on the previous input - Added `onEnterFullscreen`, `onExitFullscreen` webview events [#275](https://github.com/pichillilorenzo/flutter_inappwebview/issues/275) - Added Android support to use camera on HTML inputs that requires it, such as `` [#353](https://github.com/pichillilorenzo/flutter_inappwebview/issues/353) +- Added `overScrollMode`, `networkAvailable`, `scrollBarStyle`, `verticalScrollbarPosition`, `scrollBarDefaultDelayBeforeFade`, `scrollbarFadingEnabled`, `scrollBarFadeDuration`, `rendererPriorityPolicy` webview options on Android +- Added `pageDown`, `pageUp`, `saveWebArchive`, `zoomIn`, `zoomOut` webview methods on Android +- Added `getCurrentWebViewPackage` static webview method on Android +- Added `shouldInterceptRequest`, `onRenderProcessUnresponsive`, `onRenderProcessResponsive`, `onRenderProcessGone`, `onFormResubmission`, `onPageCommitVisible`, `onScaleChanged` Android events - Fixed `Print preview is not working? java.lang.IllegalStateException: Can print only from an activity` [#128](https://github.com/pichillilorenzo/flutter_inappwebview/issues/128) - Fixed `onJsAlert`, `onJsConfirm`, `onJsPrompt` for `InAppBrowser` on Android +- Fixed `onActivityResult` for `InAppBrowser` on Android - Fixed `InAppBrowser.openWithSystemBrowser crash on iOS` [#358](https://github.com/pichillilorenzo/flutter_inappwebview/issues/358) +### BREAKING CHANGES + +- Android `clearClientCertPreferences`, `getSafeBrowsingPrivacyPolicyUrl`, `setSafeBrowsingWhitelist` webview methods are static now + ## 3.2.0 - Added `ContextMenu` and `ContextMenuItem` classes [#235](https://github.com/pichillilorenzo/flutter_inappwebview/issues/235) diff --git a/README.md b/README.md index 914678d4..14dc6338 100755 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ On **Android**, you need to add some additional configurations. Add the following codes inside the `` tag of your `android/app/src/main/AndroidManifest.xml`: ```xml diff --git a/android/build.gradle b/android/build.gradle index b80e9be9..6a0bfcab 100755 --- a/android/build.gradle +++ b/android/build.gradle @@ -45,8 +45,8 @@ android { } } dependencies { - implementation 'androidx.webkit:webkit:1.0.0' - implementation 'androidx.browser:browser:1.0.0' + implementation 'androidx.webkit:webkit:1.2.0' + implementation 'androidx.browser:browser:1.2.0' implementation 'androidx.appcompat:appcompat:1.0.0' implementation 'com.squareup.okhttp3:mockwebserver:3.11.0' } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowser/InAppBrowserActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowser/InAppBrowserActivity.java index c4639daa..d950fb78 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowser/InAppBrowserActivity.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppBrowser/InAppBrowserActivity.java @@ -14,6 +14,7 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; @@ -23,6 +24,8 @@ import android.widget.SearchView; import androidx.annotation.RequiresApi; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; +import androidx.webkit.WebViewCompat; +import androidx.webkit.WebViewFeature; import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebView; import com.pichillilorenzo.flutter_inappwebview.InAppWebView.InAppWebViewOptions; @@ -31,6 +34,7 @@ import com.pichillilorenzo.flutter_inappwebview.Shared; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -52,6 +56,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha public ProgressBar progressBar; public boolean isHidden = false; public String fromActivity; + public List activityResultListeners = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { @@ -256,9 +261,6 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha case "startSafeBrowsing": startSafeBrowsing(result); break; - case "setSafeBrowsingWhitelist": - setSafeBrowsingWhitelist((List) call.argument("hosts"), result); - break; case "clearCache": clearCache(); result.success(true); @@ -267,9 +269,6 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha clearSslPreferences(); result.success(true); break; - case "clearClientCertPreferences": - clearClientCertPreferences(result); - break; case "findAllAsync": String find = (String) call.argument("find"); findAllAsync(find); @@ -726,18 +725,19 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha return null; } - public void startSafeBrowsing(MethodChannel.Result result) { - if (webView != null) - webView.startSafeBrowsing(result); - else - result.success(false); - } - - public void setSafeBrowsingWhitelist(List hosts, MethodChannel.Result result) { - if (webView != null) - webView.setSafeBrowsingWhitelist(hosts, result); - else + public void startSafeBrowsing(final MethodChannel.Result result) { + if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 && + 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); + } } public void clearCache() { @@ -750,19 +750,6 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha webView.clearSslPreferences(); } - public void clearClientCertPreferences(final MethodChannel.Result result) { - if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - webView.clearClientCertPreferences(new Runnable() { - @Override - public void run() { - result.success(true); - } - }); - } - else - result.success(false); - } - public void findAllAsync(String find) { if (webView != null) webView.findAllAsync(find); @@ -867,7 +854,11 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha public void dispose() { channel.setMethodCallHandler(null); + activityResultListeners.clear(); if (webView != null) { + if (Shared.activityPluginBinding != null) { + Shared.activityPluginBinding.removeActivityResultListener(webView.inAppWebViewChromeClient); + } webView.setWebChromeClient(new WebChromeClient()); webView.setWebViewClient(new WebViewClient() { public void onPageFinished(WebView view, String url) { @@ -880,9 +871,26 @@ public class InAppBrowserActivity extends AppCompatActivity implements MethodCha } } + @Override + protected void onActivityResult (int requestCode, + int resultCode, + Intent data) { + for (ActivityResultListener listener : activityResultListeners) { + if (listener.onActivityResult(requestCode, resultCode, data)) { + return; + } + } + super.onActivityResult(requestCode, resultCode, data); + } + @Override public void onDestroy() { dispose(); super.onDestroy(); } + + public interface ActivityResultListener { + /** @return true if the result has been handled. */ + boolean onActivityResult(int requestCode, int resultCode, Intent data); + } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/FlutterWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/FlutterWebView.java index 91cb1a14..439fbc4d 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/FlutterWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/FlutterWebView.java @@ -7,11 +7,15 @@ import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.View; +import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; +import androidx.webkit.WebViewCompat; +import androidx.webkit.WebViewFeature; + import com.pichillilorenzo.flutter_inappwebview.Shared; import com.pichillilorenzo.flutter_inappwebview.Util; @@ -31,7 +35,7 @@ import static io.flutter.plugin.common.MethodChannel.Result; public class FlutterWebView implements PlatformView, MethodCallHandler { - static final String LOG_TAG = "FlutterWebView"; + static final String LOG_TAG = "IAWFlutterWebView"; public InAppWebView webView; public final MethodChannel channel; @@ -253,24 +257,18 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { result.success((webView != null) ? webView.getCopyBackForwardList() : null); break; case "startSafeBrowsing": - if (webView != null) - webView.startSafeBrowsing(result); - else - result.success(false); - break; - case "setSafeBrowsingWhitelist": - if (webView != null) { - List hosts = (List) call.argument("hosts"); - webView.setSafeBrowsingWhitelist(hosts, result); + if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 && + WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) { + WebViewCompat.startSafeBrowsing(webView.getContext(), new ValueCallback() { + @Override + public void onReceiveValue(Boolean success) { + result.success(success); + } + }); } - else + else { result.success(false); - break; - case "getSafeBrowsingPrivacyPolicyUrl": - if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { - result.success(webView.getSafeBrowsingPrivacyPolicyUrl().toString()); - } else - result.success(null); + } break; case "clearCache": if (webView != null) @@ -282,18 +280,6 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { webView.clearSslPreferences(); result.success(true); break; - case "clearClientCertPreferences": - if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - webView.clearClientCertPreferences(new Runnable() { - @Override - public void run() { - result.success(true); - } - }); - } else { - result.success(false); - } - break; case "findAllAsync": if (webView != null) { String find = (String) call.argument("find"); @@ -379,7 +365,7 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { break; case "zoomBy": if (webView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Float zoomFactor = (Float) call.argument("zoomFactor"); + float zoomFactor = (float) call.argument("zoomFactor"); webView.zoomBy(zoomFactor); result.success(true); } else { @@ -410,6 +396,53 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { 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 basename = (String) call.argument("basename"); + boolean autoname = (boolean) call.argument("autoname"); + webView.saveWebArchive(basename, 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; default: result.notImplemented(); } @@ -419,6 +452,9 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { public void dispose() { channel.setMethodCallHandler(null); if (webView != null) { + if (Shared.activityPluginBinding != null) { + Shared.activityPluginBinding.removeActivityResultListener(webView.inAppWebViewChromeClient); + } webView.setWebChromeClient(new WebChromeClient()); webView.setWebViewClient(new WebViewClient() { public void onPageFinished(WebView view, String url) { diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java index 5c3cd1fb..66f5e62a 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java @@ -1,6 +1,7 @@ package com.pichillilorenzo.flutter_inappwebview.InAppWebView; import android.content.Context; +import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -35,6 +36,8 @@ import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.RequiresApi; +import androidx.webkit.WebViewCompat; +import androidx.webkit.WebViewFeature; import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlocker; import com.pichillilorenzo.flutter_inappwebview.ContentBlocker.ContentBlockerAction; @@ -69,6 +72,7 @@ final public class InAppWebView extends InputAwareWebView { public Object id; public InAppWebViewClient inAppWebViewClient; public InAppWebViewChromeClient inAppWebViewChromeClient; + public InAppWebViewRenderProcessClient inAppWebViewRenderProcessClient; public InAppWebViewOptions options; public boolean isLoading = false; public OkHttpClient httpClient; @@ -636,6 +640,11 @@ final public class InAppWebView extends InputAwareWebView { inAppWebViewClient = new InAppWebViewClient((isFromInAppBrowserActivity) ? inAppBrowserActivity : flutterWebView); setWebViewClient(inAppWebViewClient); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE)) { + inAppWebViewRenderProcessClient = new InAppWebViewRenderProcessClient((isFromInAppBrowserActivity) ? inAppBrowserActivity : flutterWebView); + WebViewCompat.setWebViewRenderProcessClient(this, inAppWebViewRenderProcessClient); + } + if (options.useOnDownloadStart) setDownloadListener(new DownloadStartListener()); @@ -745,6 +754,33 @@ final public class InAppWebView extends InputAwareWebView { if (options.regexToCancelSubFramesLoading != null) { regexToCancelSubFramesLoadingCompiled = Pattern.compile(options.regexToCancelSubFramesLoading); } + setScrollBarStyle(options.scrollBarStyle); + if (options.scrollBarDefaultDelayBeforeFade != null) { + setScrollBarDefaultDelayBeforeFade(options.scrollBarDefaultDelayBeforeFade); + } else { + options.scrollBarDefaultDelayBeforeFade = getScrollBarDefaultDelayBeforeFade(); + } + setScrollbarFadingEnabled(options.scrollbarFadingEnabled); + if (options.scrollBarFadeDuration != null) { + setScrollBarFadeDuration(options.scrollBarFadeDuration); + } else { + options.scrollBarFadeDuration = getScrollBarFadeDuration(); + } + setVerticalScrollbarPosition(options.verticalScrollbarPosition); + setVerticalScrollBarEnabled(!options.disableVerticalScroll); + setHorizontalScrollBarEnabled(!options.disableHorizontalScroll); + setOverScrollMode(options.overScrollMode); + if (options.networkAvailable != null) { + setNetworkAvailable(options.networkAvailable); + } + if (options.rendererPriorityPolicy != null && !options.rendererPriorityPolicy.isEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + setRendererPriorityPolicy( + (int) options.rendererPriorityPolicy.get("rendererRequestedPriority"), + (boolean) options.rendererPriorityPolicy.get("waivedWhenNotVisible")); + } else if (options.rendererPriorityPolicy == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + options.rendererPriorityPolicy.put("rendererRequestedPriority", getRendererRequestedPriority()); + options.rendererPriorityPolicy.put("waivedWhenNotVisible", getRendererPriorityWaivedWhenNotVisible()); + } contentBlockerHandler.getRuleList().clear(); for (Map> contentBlocker : options.contentBlockers) { @@ -767,9 +803,6 @@ final public class InAppWebView extends InputAwareWebView { } }); - setVerticalScrollBarEnabled(!options.disableVerticalScroll); - setHorizontalScrollBarEnabled(!options.disableHorizontalScroll); - gestureDetector = new GestureDetector(this.getContext(), new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent ev) { @@ -1300,12 +1333,42 @@ final public class InAppWebView extends InputAwareWebView { } } + if (newOptionsMap.get("scrollBarStyle") != null && !options.scrollBarStyle.equals(newOptions.scrollBarStyle)) + setScrollBarStyle(newOptions.scrollBarStyle); + + if (newOptionsMap.get("scrollBarDefaultDelayBeforeFade") != null && !options.scrollBarDefaultDelayBeforeFade.equals(newOptions.scrollBarDefaultDelayBeforeFade)) + setScrollBarDefaultDelayBeforeFade(newOptions.scrollBarDefaultDelayBeforeFade); + + if (newOptionsMap.get("scrollbarFadingEnabled") != null && !options.scrollbarFadingEnabled.equals(newOptions.scrollbarFadingEnabled)) + setScrollbarFadingEnabled(newOptions.scrollbarFadingEnabled); + + if (newOptionsMap.get("scrollBarFadeDuration") != null && !options.scrollBarFadeDuration.equals(newOptions.scrollBarFadeDuration)) + setScrollBarFadeDuration(newOptions.scrollBarFadeDuration); + + if (newOptionsMap.get("verticalScrollbarPosition") != null && !options.verticalScrollbarPosition.equals(newOptions.verticalScrollbarPosition)) + setVerticalScrollbarPosition(newOptions.verticalScrollbarPosition); + if (newOptionsMap.get("disableVerticalScroll") != null && options.disableVerticalScroll != newOptions.disableVerticalScroll) setVerticalScrollBarEnabled(!newOptions.disableVerticalScroll); if (newOptionsMap.get("disableHorizontalScroll") != null && options.disableHorizontalScroll != newOptions.disableHorizontalScroll) setHorizontalScrollBarEnabled(!newOptions.disableHorizontalScroll); + if (newOptionsMap.get("overScrollMode") != null && !options.overScrollMode.equals(newOptions.overScrollMode)) + setOverScrollMode(newOptions.overScrollMode); + + if (newOptionsMap.get("networkAvailable") != null && options.networkAvailable != newOptions.networkAvailable) + setNetworkAvailable(newOptions.networkAvailable); + + if (newOptionsMap.get("rendererPriorityPolicy") != null && + (options.rendererPriorityPolicy.get("rendererRequestedPriority") != newOptions.rendererPriorityPolicy.get("rendererRequestedPriority") || + options.rendererPriorityPolicy.get("waivedWhenNotVisible") != newOptions.rendererPriorityPolicy.get("waivedWhenNotVisible")) && + Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + setRendererPriorityPolicy( + (int) newOptions.rendererPriorityPolicy.get("rendererRequestedPriority"), + (boolean) newOptions.rendererPriorityPolicy.get("waivedWhenNotVisible")); + } + options = newOptions; } @@ -1412,32 +1475,6 @@ final public class InAppWebView extends InputAwareWebView { channel.invokeMethod("onScrollChanged", obj); } - public void startSafeBrowsing(final MethodChannel.Result result) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { - startSafeBrowsing(getContext(), new ValueCallback() { - @Override - public void onReceiveValue(Boolean value) { - result.success(value); - } - }); - } else { - result.success(false); - } - } - - public void setSafeBrowsingWhitelist(List hosts, final MethodChannel.Result result) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { - setSafeBrowsingWhitelist(hosts, new ValueCallback() { - @Override - public void onReceiveValue(Boolean value) { - result.success(value); - } - }); - } else { - result.success(false); - } - } - class DownloadStartListener implements DownloadListener { @Override public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java index a3d8eb5f..8181d34d 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewChromeClient.java @@ -58,7 +58,7 @@ import io.flutter.plugin.common.PluginRegistry; import static android.app.Activity.RESULT_OK; -public class InAppWebViewChromeClient extends WebChromeClient implements PluginRegistry.ActivityResultListener { +public class InAppWebViewChromeClient extends WebChromeClient implements PluginRegistry.ActivityResultListener, InAppBrowserActivity.ActivityResultListener { protected static final String LOG_TAG = "IABWebChromeClient"; private FlutterWebView flutterWebView; @@ -96,10 +96,13 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR private int mOriginalSystemUiVisibility; public InAppWebViewChromeClient(Object obj) { - if (obj instanceof InAppBrowserActivity) + if (obj instanceof InAppBrowserActivity) { this.inAppBrowserActivity = (InAppBrowserActivity) obj; - else if (obj instanceof FlutterWebView) + this.inAppBrowserActivity.activityResultListeners.add(this); + } + else if (obj instanceof FlutterWebView) { this.flutterWebView = (FlutterWebView) obj; + } this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel; if (Shared.registrar != null) diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewClient.java index e0487490..e792af3c 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewClient.java @@ -6,12 +6,14 @@ import android.net.http.SslCertificate; import android.net.http.SslError; import android.os.Build; import android.os.Bundle; +import android.os.Message; import android.util.Log; import android.view.KeyEvent; import android.webkit.ClientCertRequest; import android.webkit.CookieManager; import android.webkit.CookieSyncManager; import android.webkit.HttpAuthHandler; +import android.webkit.RenderProcessGoneDetail; import android.webkit.SafeBrowsingResponse; import android.webkit.SslErrorHandler; import android.webkit.ValueCallback; @@ -20,15 +22,20 @@ import android.webkit.WebResourceResponse; import android.webkit.WebView; import android.webkit.WebViewClient; +import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; +import androidx.webkit.WebViewFeature; import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.Credential; import com.pichillilorenzo.flutter_inappwebview.CredentialDatabase.CredentialDatabase; import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity; import com.pichillilorenzo.flutter_inappwebview.JavaScriptBridgeInterface; +import com.pichillilorenzo.flutter_inappwebview.Shared; import com.pichillilorenzo.flutter_inappwebview.Util; import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; @@ -47,7 +54,7 @@ import io.flutter.plugin.common.MethodChannel; public class InAppWebViewClient extends WebViewClient { - protected static final String LOG_TAG = "IABWebViewClient"; + protected static final String LOG_TAG = "IAWebViewClient"; private FlutterWebView flutterWebView; private InAppBrowserActivity inAppBrowserActivity; public MethodChannel channel; @@ -358,7 +365,7 @@ public class InAppWebViewClient extends WebViewClient { } } - handler.cancel(); + InAppWebViewClient.super.onReceivedHttpAuthRequest(view, handler, host, realm); } @Override @@ -368,7 +375,7 @@ public class InAppWebViewClient extends WebViewClient { @Override public void notImplemented() { - handler.cancel(); + InAppWebViewClient.super.onReceivedHttpAuthRequest(view, handler, host, realm); } }); } @@ -483,7 +490,7 @@ public class InAppWebViewClient extends WebViewClient { } } - handler.cancel(); + InAppWebViewClient.super.onReceivedSslError(view, handler, error); } @Override @@ -493,7 +500,7 @@ public class InAppWebViewClient extends WebViewClient { @Override public void notImplemented() { - handler.cancel(); + InAppWebViewClient.super.onReceivedSslError(view, handler, error); } }); } @@ -552,7 +559,7 @@ public class InAppWebViewClient extends WebViewClient { } } - request.cancel(); + InAppWebViewClient.super.onReceivedClientCertRequest(view, request); } @Override @@ -562,20 +569,28 @@ public class InAppWebViewClient extends WebViewClient { @Override public void notImplemented() { - request.cancel(); + InAppWebViewClient.super.onReceivedClientCertRequest(view, request); } }); } @Override public void onScaleChanged(WebView view, float oldScale, float newScale) { + super.onScaleChanged(view, oldScale, newScale); final InAppWebView webView = (InAppWebView) view; webView.scale = newScale; + + Map obj = new HashMap<>(); + if (inAppBrowserActivity != null) + obj.put("uuid", inAppBrowserActivity.uuid); + obj.put("oldScale", oldScale); + obj.put("newScale", newScale); + channel.invokeMethod("onScaleChanged", obj); } @RequiresApi(api = Build.VERSION_CODES.O_MR1) @Override - public void onSafeBrowsingHit(final WebView view, WebResourceRequest request, int threatType, final SafeBrowsingResponse callback) { + public void onSafeBrowsingHit(final WebView view, final WebResourceRequest request, final int threatType, final SafeBrowsingResponse callback) { Map obj = new HashMap<>(); if (inAppBrowserActivity != null) obj.put("uuid", inAppBrowserActivity.uuid); @@ -608,7 +623,7 @@ public class InAppWebViewClient extends WebViewClient { } } - callback.showInterstitial(true); + InAppWebViewClient.super.onSafeBrowsingHit(view, request, threatType, callback); } @Override @@ -618,7 +633,7 @@ public class InAppWebViewClient extends WebViewClient { @Override public void notImplemented() { - callback.showInterstitial(true); + InAppWebViewClient.super.onSafeBrowsingHit(view, request, threatType, callback); } }); } @@ -628,6 +643,13 @@ public class InAppWebViewClient extends WebViewClient { final InAppWebView webView = (InAppWebView) view; + if (webView.options.useShouldInterceptRequest) { + WebResourceResponse onShouldInterceptResponse = onShouldInterceptRequest(url); + if (onShouldInterceptResponse != null) { + return onShouldInterceptResponse; + } + } + URI uri; try { uri = new URI(url); @@ -696,10 +718,137 @@ public class InAppWebViewClient extends WebViewClient { @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { + final InAppWebView webView = (InAppWebView) view; + String url = request.getUrl().toString(); + + if (webView.options.useShouldInterceptRequest) { + WebResourceResponse onShouldInterceptResponse = onShouldInterceptRequest(request); + if (onShouldInterceptResponse != null) { + return onShouldInterceptResponse; + } + } + return shouldInterceptRequest(view, url); } + public WebResourceResponse onShouldInterceptRequest(Object request) { + String url = request instanceof String ? (String) request : null; + String method = "GET"; + Map headers = null; + Boolean hasGesture = false; + Boolean isForMainFrame = true; + Boolean isRedirect = false; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && request instanceof WebResourceRequest) { + WebResourceRequest webResourceRequest = (WebResourceRequest) request; + url = webResourceRequest.getUrl().toString(); + headers = webResourceRequest.getRequestHeaders(); + hasGesture = webResourceRequest.hasGesture(); + isForMainFrame = webResourceRequest.isForMainFrame(); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + isRedirect = webResourceRequest.isRedirect(); + } + } + + final Map obj = new HashMap<>(); + if (inAppBrowserActivity != null) + obj.put("uuid", inAppBrowserActivity.uuid); + obj.put("url", url); + obj.put("method", method); + obj.put("headers", headers); + obj.put("isForMainFrame", isForMainFrame); + obj.put("hasGesture", hasGesture); + obj.put("isRedirect", isRedirect); + + Util.WaitFlutterResult flutterResult; + try { + flutterResult = Util.invokeMethodAndWait(channel, "shouldInterceptRequest", obj); + } catch (InterruptedException e) { + e.printStackTrace(); + Log.e(LOG_TAG, e.getMessage()); + return null; + } + + if (flutterResult.error != null) { + Log.e(LOG_TAG, flutterResult.error); + } + else if (flutterResult.result != null) { + Map res = (Map) flutterResult.result; + byte[] data = (byte[]) res.get("data"); + return new WebResourceResponse(res.get("content-type").toString(), res.get("content-encoding").toString(), new ByteArrayInputStream(data)); + } + + return null; + } + + @Override + public void onFormResubmission (final WebView view, final Message dontResend, final Message resend) { + Map obj = new HashMap<>(); + if (inAppBrowserActivity != null) + obj.put("uuid", inAppBrowserActivity.uuid); + obj.put("url", view.getUrl()); + + channel.invokeMethod("onFormResubmission", obj, new MethodChannel.Result() { + + @Override + public void success(@Nullable Object response) { + Map responseMap = (Map) response; + Integer action = (Integer) responseMap.get("action"); + if (action != null) { + switch (action) { + case 1: + resend.sendToTarget(); + return; + case 0: + default: + dontResend.sendToTarget(); + return; + } + } + + InAppWebViewClient.super.onFormResubmission(view, dontResend, resend); + } + + @Override + public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { + Log.d(LOG_TAG, "ERROR: " + errorCode + " " + errorMessage); + } + + @Override + public void notImplemented() { + InAppWebViewClient.super.onFormResubmission(view, dontResend, resend); + } + }); + } + + @Override + public void onPageCommitVisible(WebView view, String url) { + super.onPageCommitVisible(view, url); + Map obj = new HashMap<>(); + if (inAppBrowserActivity != null) + obj.put("uuid", inAppBrowserActivity.uuid); + obj.put("url", url); + channel.invokeMethod("onPageCommitVisible", obj); + } + + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { + Boolean didCrash = detail.didCrash(); + Integer rendererPriorityAtExit = detail.rendererPriorityAtExit(); + + Map obj = new HashMap<>(); + if (inAppBrowserActivity != null) + obj.put("uuid", inAppBrowserActivity.uuid); + obj.put("didCrash", didCrash); + obj.put("rendererPriorityAtExit", rendererPriorityAtExit); + + channel.invokeMethod("onRenderProcessGone", obj); + + return super.onRenderProcessGone(view, detail); + } + @Override public void onUnhandledKeyEvent(WebView view, KeyEvent event) { diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewOptions.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewOptions.java index e7954552..db51846d 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewOptions.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewOptions.java @@ -2,6 +2,7 @@ package com.pichillilorenzo.flutter_inappwebview.InAppWebView; import android.os.Build; import android.util.Log; +import android.view.View; import android.webkit.WebSettings; import com.pichillilorenzo.flutter_inappwebview.ChromeCustomTabs.ChromeCustomTabsOptions; @@ -87,6 +88,16 @@ public class InAppWebViewOptions implements Options { public Boolean supportMultipleWindows = false; public String regexToCancelSubFramesLoading; + public Integer overScrollMode = View.OVER_SCROLL_IF_CONTENT_SCROLLS; + public Boolean networkAvailable = null; + public Integer scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY; + public Integer verticalScrollbarPosition = View.SCROLLBAR_POSITION_DEFAULT; + public Integer scrollBarDefaultDelayBeforeFade = null; + public Boolean scrollbarFadingEnabled = true; + public Integer scrollBarFadeDuration = null; + public Map rendererPriorityPolicy = new HashMap<>(); + public Boolean useShouldInterceptRequest = false; + @Override public InAppWebViewOptions parse(HashMap options) { for (Map.Entry pair : options.entrySet()) { @@ -295,6 +306,33 @@ public class InAppWebViewOptions implements Options { case "regexToCancelSubFramesLoading": regexToCancelSubFramesLoading = (String) value; break; + case "overScrollMode": + overScrollMode = (Integer) value; + break; + case "networkAvailable": + networkAvailable = (Boolean) value; + break; + case "scrollBarStyle": + scrollBarStyle = (Integer) value; + break; + case "verticalScrollbarPosition": + verticalScrollbarPosition = (Integer) value; + break; + case "scrollBarDefaultDelayBeforeFade": + scrollBarDefaultDelayBeforeFade = (Integer) value; + break; + case "scrollbarFadingEnabled": + scrollbarFadingEnabled = (Boolean) value; + break; + case "scrollBarFadeDuration": + scrollBarFadeDuration = (Integer) value; + break; + case "rendererPriorityPolicy": + rendererPriorityPolicy = (Map) value; + break; + case "useShouldInterceptRequest": + useShouldInterceptRequest = (Boolean) value; + break; } } @@ -370,6 +408,15 @@ public class InAppWebViewOptions implements Options { options.put("hardwareAcceleration", hardwareAcceleration); options.put("supportMultipleWindows", supportMultipleWindows); options.put("regexToCancelSubFramesLoading", regexToCancelSubFramesLoading); + options.put("overScrollMode", overScrollMode); + options.put("networkAvailable", networkAvailable); + options.put("scrollBarStyle", scrollBarStyle); + options.put("verticalScrollbarPosition", verticalScrollbarPosition); + options.put("scrollBarDefaultDelayBeforeFade", scrollBarDefaultDelayBeforeFade); + options.put("scrollbarFadingEnabled", scrollbarFadingEnabled); + options.put("scrollBarFadeDuration", scrollBarFadeDuration); + options.put("rendererPriorityPolicy", rendererPriorityPolicy); + options.put("useShouldInterceptRequest", useShouldInterceptRequest); return options; } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewRenderProcessClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewRenderProcessClient.java new file mode 100644 index 00000000..85325638 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebViewRenderProcessClient.java @@ -0,0 +1,100 @@ +package com.pichillilorenzo.flutter_inappwebview.InAppWebView; + +import android.util.Log; +import android.webkit.WebView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.webkit.WebViewFeature; +import androidx.webkit.WebViewRenderProcess; +import androidx.webkit.WebViewRenderProcessClient; + +import com.pichillilorenzo.flutter_inappwebview.InAppBrowser.InAppBrowserActivity; + +import java.util.HashMap; +import java.util.Map; + +import io.flutter.plugin.common.MethodChannel; + +public class InAppWebViewRenderProcessClient extends WebViewRenderProcessClient { + + protected static final String LOG_TAG = "IAWRenderProcessClient"; + private FlutterWebView flutterWebView; + private InAppBrowserActivity inAppBrowserActivity; + public MethodChannel channel; + + public InAppWebViewRenderProcessClient(Object obj) { + super(); + if (obj instanceof InAppBrowserActivity) + this.inAppBrowserActivity = (InAppBrowserActivity) obj; + else if (obj instanceof FlutterWebView) + this.flutterWebView = (FlutterWebView) obj; + this.channel = (this.inAppBrowserActivity != null) ? this.inAppBrowserActivity.channel : this.flutterWebView.channel; + } + + @Override + public void onRenderProcessUnresponsive(@NonNull WebView view, @Nullable final WebViewRenderProcess renderer) { + Map obj = new HashMap<>(); + if (inAppBrowserActivity != null) + obj.put("uuid", inAppBrowserActivity.uuid); + channel.invokeMethod("onRenderProcessUnresponsive", obj, new MethodChannel.Result() { + + @Override + public void success(@Nullable Object response) { + Map responseMap = (Map) response; + Integer action = (Integer) responseMap.get("action"); + if (action != null && renderer != null) { + switch (action) { + case 1: + if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_TERMINATE)) + renderer.terminate(); + break; + } + } + } + + @Override + public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { + Log.d(LOG_TAG, "ERROR: " + errorCode + " " + errorMessage); + } + + @Override + public void notImplemented() { + + } + }); + } + + @Override + public void onRenderProcessResponsive(@NonNull WebView view, @Nullable final WebViewRenderProcess renderer) { + Map obj = new HashMap<>(); + if (inAppBrowserActivity != null) + obj.put("uuid", inAppBrowserActivity.uuid); + channel.invokeMethod("onRenderProcessResponsive", obj, new MethodChannel.Result() { + + @Override + public void success(@Nullable Object response) { + Map responseMap = (Map) response; + Integer action = (Integer) responseMap.get("action"); + if (action != null && renderer != null) { + switch (action) { + case 1: + if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_TERMINATE)) + renderer.terminate(); + break; + } + } + } + + @Override + public void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { + Log.d(LOG_TAG, "ERROR: " + errorCode + " " + errorMessage); + } + + @Override + public void notImplemented() { + + } + }); + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFileProvider.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFileProvider.java new file mode 100644 index 00000000..b94a2cac --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFileProvider.java @@ -0,0 +1,9 @@ +package com.pichillilorenzo.flutter_inappwebview; + +import androidx.core.content.FileProvider; + +public class InAppWebViewFileProvider extends FileProvider { + + // This class intentionally left blank. + +} 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 695f5945..6f0311c9 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java @@ -1,6 +1,17 @@ package com.pichillilorenzo.flutter_inappwebview; +import android.content.pm.PackageInfo; +import android.os.Build; +import android.webkit.ValueCallback; import android.webkit.WebSettings; +import android.webkit.WebView; + +import androidx.webkit.WebViewCompat; +import androidx.webkit.WebViewFeature; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; @@ -17,16 +28,72 @@ public class InAppWebViewStatic implements MethodChannel.MethodCallHandler { } @Override - public void onMethodCall(MethodCall call, MethodChannel.Result result) { + public void onMethodCall(MethodCall call, final MethodChannel.Result result) { switch (call.method) { case "getDefaultUserAgent": result.success(WebSettings.getDefaultUserAgent(Shared.applicationContext)); break; + + + case "clearClientCertPreferences": + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + WebView.clearClientCertPreferences(new Runnable() { + @Override + public void run() { + result.success(true); + } + }); + } else { + result.success(false); + } + break; + case "getSafeBrowsingPrivacyPolicyUrl": + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 && WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL)) { + result.success(WebViewCompat.getSafeBrowsingPrivacyPolicyUrl().toString()); + } else + result.success(null); + break; + case "setSafeBrowsingWhitelist": + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 && WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_WHITELIST)) { + List hosts = (List) call.argument("hosts"); + WebViewCompat.setSafeBrowsingWhitelist(hosts, new ValueCallback() { + @Override + public void onReceiveValue(Boolean value) { + result.success(value); + } + }); + } + else + result.success(false); + break; + + + + case "getCurrentWebViewPackage": + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + result.success( + convertWebViewPackageToMap(WebViewCompat.getCurrentWebViewPackage(Shared.activity))); + } else { + result.success(false); + } + break; default: result.notImplemented(); } } + public Map convertWebViewPackageToMap(PackageInfo webViewPackageInfo) { + if (webViewPackageInfo == null) { + return null; + } + HashMap webViewPackageInfoMap = new HashMap<>(); + + webViewPackageInfoMap.put("versionName", webViewPackageInfo.versionName); + webViewPackageInfoMap.put("packageName", webViewPackageInfo.packageName); + + return webViewPackageInfoMap; + } + public void dispose() { channel.setMethodCallHandler(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 664f2772..fda2cb3c 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/Util.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/Util.java @@ -1,12 +1,16 @@ package com.pichillilorenzo.flutter_inappwebview; import android.content.res.AssetManager; +import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; +import android.os.Parcelable; import android.util.Log; import java.io.IOException; import java.io.InputStream; +import java.io.Serializable; import java.security.Key; import java.security.KeyStore; import java.security.PrivateKey; @@ -115,7 +119,7 @@ public class Util { } } - public static PrivateKeyAndCertificates loadPrivateKeyAndCertificate( String certificatePath, String certificatePassword, String keyStoreType) { + public static PrivateKeyAndCertificates loadPrivateKeyAndCertificate(String certificatePath, String certificatePassword, String keyStoreType) { PrivateKeyAndCertificates privateKeyAndCertificates = null; diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index 342e43ae..60c34f76 100755 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.0+hotfix.6/","dependencies":[]}],"android":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.0+hotfix.6/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"e2e","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"permission_handler","dependencies":[]}],"date_created":"2020-05-23 18:32:59.790460","version":"1.17.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.0+hotfix.6/","dependencies":[]}],"android":[{"name":"e2e","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/e2e-0.2.4+4/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.0.0+hotfix.6/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"e2e","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"permission_handler","dependencies":[]}],"date_created":"2020-05-26 00:10:53.444505","version":"1.17.1"} \ No newline at end of file diff --git a/example/lib/in_app_browser_example.screen.dart b/example/lib/in_app_browser_example.screen.dart index 53f64556..dbcea3ae 100755 --- a/example/lib/in_app_browser_example.screen.dart +++ b/example/lib/in_app_browser_example.screen.dart @@ -101,7 +101,7 @@ class _InAppBrowserExampleScreenState extends State { useOnLoadResource: true, )))); }, - child: Text("Open Webview Browser")), + child: Text("Open In-App Browser")), Container(height: 40), RaisedButton( onPressed: () async { diff --git a/example/lib/in_app_webiew_example.screen.dart b/example/lib/in_app_webiew_example.screen.dart index 1d88b611..190cef65 100755 --- a/example/lib/in_app_webiew_example.screen.dart +++ b/example/lib/in_app_webiew_example.screen.dart @@ -76,13 +76,12 @@ class _InAppWebViewExampleScreenState extends State { BoxDecoration(border: Border.all(color: Colors.blueAccent)), child: InAppWebView( contextMenu: contextMenu, - initialUrl: "https://www.youtube.com/watch?v=oD5RtLhhubg", + initialUrl: "https://github.com/flutter", // initialFile: "assets/index.html", initialHeaders: {}, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( - debuggingEnabled: true, - disableContextMenu: true, + debuggingEnabled: true ), ), onWebViewCreated: (InAppWebViewController controller) { diff --git a/example/lib/main.dart b/example/lib/main.dart index 72cb852c..fedc8d6a 100755 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -12,7 +12,8 @@ import 'package:permission_handler/permission_handler.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - // await Permission.camera.request(); +// await Permission.camera.request(); +// await Permission.storage.request(); // await localhostServer.start(); runApp(MyApp()); } diff --git a/lib/src/in_app_webview_controller.dart b/lib/src/in_app_webview_controller.dart index 3e63f917..eac1da2c 100644 --- a/lib/src/in_app_webview_controller.dart +++ b/lib/src/in_app_webview_controller.dart @@ -1343,56 +1343,12 @@ class AndroidInAppWebViewController { return await _controller._channel.invokeMethod('startSafeBrowsing', args); } - ///Sets the list of hosts (domain names/IP addresses) that are exempt from SafeBrowsing checks. The list is global for all the WebViews. - /// - /// Each rule should take one of these: - ///| Rule | Example | Matches Subdomain | - ///| -- | -- | -- | - ///| HOSTNAME | example.com | Yes | - ///| .HOSTNAME | .example.com | No | - ///| IPV4_LITERAL | 192.168.1.1 | No | - ///| IPV6_LITERAL_WITH_BRACKETS | [10:20:30:40:50:60:70:80] | No | - /// - ///All other rules, including wildcards, are invalid. The correct syntax for hosts is defined by [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3.2.2). - /// - ///[hosts] represents the list of hosts. This value must never be null. - /// - ///**NOTE**: available only on Android 27+. - Future setSafeBrowsingWhitelist({@required List hosts}) async { - assert(hosts != null); - Map args = {}; - args.putIfAbsent('hosts', () => hosts); - return await _controller._channel - .invokeMethod('setSafeBrowsingWhitelist', args); - } - - ///Returns a URL pointing to the privacy policy for Safe Browsing reporting. This value will never be `null`. - /// - ///**NOTE**: available only on Android 27+. - Future getSafeBrowsingPrivacyPolicyUrl() async { - Map args = {}; - return await _controller._channel - .invokeMethod('getSafeBrowsingPrivacyPolicyUrl', args); - } - ///Clears the SSL preferences table stored in response to proceeding with SSL certificate errors. Future clearSslPreferences() async { Map args = {}; await _controller._channel.invokeMethod('clearSslPreferences', args); } - ///Clears the client certificate preferences stored in response to proceeding/cancelling client cert requests. - ///Note that WebView automatically clears these preferences when the system keychain is updated. - ///The preferences are shared by all the WebViews that are created by the embedder application. - /// - ///**NOTE**: On iOS certificate-based credentials are never stored permanently. - /// - ///**NOTE**: available on Android 21+. - Future clearClientCertPreferences() async { - Map args = {}; - await _controller._channel.invokeMethod('clearClientCertPreferences', args); - } - ///Does a best-effort attempt to pause any processing that can be paused safely, such as animations and geolocation. Note that this call does not pause JavaScript. ///To pause JavaScript globally, use [pauseTimers()]. To resume WebView, call [resume()]. Future pause() async { @@ -1413,6 +1369,50 @@ class AndroidInAppWebViewController { Map args = {}; return await _controller._channel.invokeMethod('getOriginalUrl', args); } + + ///Clears the client certificate preferences stored in response to proceeding/cancelling client cert requests. + ///Note that WebView automatically clears these preferences when the system keychain is updated. + ///The preferences are shared by all the WebViews that are created by the embedder application. + /// + ///**NOTE**: On iOS certificate-based credentials are never stored permanently. + /// + ///**NOTE**: available on Android 21+. + static Future clearClientCertPreferences() async { + Map args = {}; + await InAppWebViewController._staticChannel.invokeMethod('clearClientCertPreferences', args); + } + + ///Returns a URL pointing to the privacy policy for Safe Browsing reporting. This value will never be `null`. + /// + ///**NOTE**: available only on Android 27+. + static Future getSafeBrowsingPrivacyPolicyUrl() async { + Map args = {}; + return await InAppWebViewController._staticChannel + .invokeMethod('getSafeBrowsingPrivacyPolicyUrl', args); + } + + ///Sets the list of hosts (domain names/IP addresses) that are exempt from SafeBrowsing checks. The list is global for all the WebViews. + /// + /// Each rule should take one of these: + ///| Rule | Example | Matches Subdomain | + ///| -- | -- | -- | + ///| HOSTNAME | example.com | Yes | + ///| .HOSTNAME | .example.com | No | + ///| IPV4_LITERAL | 192.168.1.1 | No | + ///| IPV6_LITERAL_WITH_BRACKETS | [10:20:30:40:50:60:70:80] | No | + /// + ///All other rules, including wildcards, are invalid. The correct syntax for hosts is defined by [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3.2.2). + /// + ///[hosts] represents the list of hosts. This value must never be null. + /// + ///**NOTE**: available only on Android 27+. + static Future setSafeBrowsingWhitelist({@required List hosts}) async { + assert(hosts != null); + Map args = {}; + args.putIfAbsent('hosts', () => hosts); + return await InAppWebViewController._staticChannel + .invokeMethod('setSafeBrowsingWhitelist', args); + } } ///InAppWebViewControllerIOS class represents the iOS controller that contains only ios-specific methods for the WebView.