forked from flutter/plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[webview_flutter]Allow specifying a navigation delegate(Android and D…
…art). (flutter#1236) This allows the app to prevent specific navigations(e.g prevent navigating to specific URLs). flutter/flutter#25329 iOS implementation in flutter#1323
- Loading branch information
Showing
9 changed files
with
373 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 124 additions & 0 deletions
124
...flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// Copyright 2019 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
package io.flutter.plugins.webviewflutter; | ||
|
||
import android.annotation.TargetApi; | ||
import android.os.Build; | ||
import android.util.Log; | ||
import android.webkit.WebResourceRequest; | ||
import android.webkit.WebView; | ||
import androidx.webkit.WebViewClientCompat; | ||
import io.flutter.plugin.common.MethodChannel; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
// We need to use WebViewClientCompat to get | ||
// shouldOverrideUrlLoading(WebView view, WebResourceRequest request) | ||
// invoked by the webview on older Android devices, without it pages that use iframes will | ||
// be broken when a navigationDelegate is set on Android version earlier than N. | ||
class FlutterWebViewClient extends WebViewClientCompat { | ||
private static final String TAG = "FlutterWebViewClient"; | ||
private final MethodChannel methodChannel; | ||
private boolean hasNavigationDelegate; | ||
|
||
FlutterWebViewClient(MethodChannel methodChannel) { | ||
this.methodChannel = methodChannel; | ||
} | ||
|
||
void setHasNavigationDelegate(boolean hasNavigationDelegate) { | ||
this.hasNavigationDelegate = hasNavigationDelegate; | ||
} | ||
|
||
@TargetApi(Build.VERSION_CODES.LOLLIPOP) | ||
@Override | ||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { | ||
if (!hasNavigationDelegate) { | ||
return false; | ||
} | ||
notifyOnNavigationRequest( | ||
request.getUrl().toString(), request.getRequestHeaders(), view, request.isForMainFrame()); | ||
// We must make a synchronous decision here whether to allow the navigation or not, | ||
// if the Dart code has set a navigation delegate we want that delegate to decide whether | ||
// to navigate or not, and as we cannot get a response from the Dart delegate synchronously we | ||
// return true here to block the navigation, if the Dart delegate decides to allow the | ||
// navigation the plugin will later make an addition loadUrl call for this url. | ||
// | ||
// Since we cannot call loadUrl for a subframe, we currently only allow the delegate to stop | ||
// navigations that target the main frame, if the request is not for the main frame | ||
// we just return false to allow the navigation. | ||
// | ||
// For more details see: https://github.com/flutter/flutter/issues/25329#issuecomment-464863209 | ||
return request.isForMainFrame(); | ||
} | ||
|
||
@Override | ||
public boolean shouldOverrideUrlLoading(WebView view, String url) { | ||
if (!hasNavigationDelegate) { | ||
return false; | ||
} | ||
// This version of shouldOverrideUrlLoading is only invoked by the webview on devices with | ||
// webview versions earlier than 67(it is also invoked when hasNavigationDelegate is false). | ||
// On these devices we cannot tell whether the navigation is targeted to the main frame or not. | ||
// We proceed assuming that the navigation is targeted to the main frame. If the page had any | ||
// frames they will be loaded in the main frame instead. | ||
Log.w( | ||
TAG, | ||
"Using a navigationDelegate with an old webview implementation, pages with frames or iframes will not work"); | ||
notifyOnNavigationRequest(url, null, view, true); | ||
return true; | ||
} | ||
|
||
private void notifyOnNavigationRequest( | ||
String url, Map<String, String> headers, WebView webview, boolean isMainFrame) { | ||
HashMap<String, Object> args = new HashMap<>(); | ||
args.put("url", url); | ||
args.put("isForMainFrame", isMainFrame); | ||
if (isMainFrame) { | ||
methodChannel.invokeMethod( | ||
"navigationRequest", args, new OnNavigationRequestResult(url, headers, webview)); | ||
} else { | ||
methodChannel.invokeMethod("navigationRequest", args); | ||
} | ||
} | ||
|
||
private static class OnNavigationRequestResult implements MethodChannel.Result { | ||
private final String url; | ||
private final Map<String, String> headers; | ||
private final WebView webView; | ||
|
||
private OnNavigationRequestResult(String url, Map<String, String> headers, WebView webView) { | ||
this.url = url; | ||
this.headers = headers; | ||
this.webView = webView; | ||
} | ||
|
||
@Override | ||
public void success(Object shouldLoad) { | ||
Boolean typedShouldLoad = (Boolean) shouldLoad; | ||
if (typedShouldLoad) { | ||
loadUrl(); | ||
} | ||
} | ||
|
||
@Override | ||
public void error(String errorCode, String s1, Object o) { | ||
throw new IllegalStateException("navigationRequest calls must succeed"); | ||
} | ||
|
||
@Override | ||
public void notImplemented() { | ||
throw new IllegalStateException( | ||
"navigationRequest must be implemented by the webview method channel"); | ||
} | ||
|
||
private void loadUrl() { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { | ||
webView.loadUrl(url, headers); | ||
} else { | ||
webView.loadUrl(url); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
org.gradle.jvmargs=-Xmx1536M | ||
android.useAndroidX=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.