android: allow whitelisting urls to bypass default webview loading
Summary: This is a workaround for missing PDF url support in Android WebView, which is a general known issue: when tapping a PDF url within WebView, instead of doing nothing, we just let android default intent handle it (e.g. it will open Chrome to load it). This is basically to trick `shouldOverrideUrlLoading()` to return true for the specific url. The drawback is that product code needs to provide the whitelist. The proper fix would be to use PdfRenderer in that method, but it seems like it's only for API >= 21... Differential Revision: D5619383 fbshipit-source-id: f86b930f970dab9a5f57999df69ce94b9508edc9
This commit is contained in:
parent
1cc7ae2ae1
commit
40a2885847
|
@ -195,6 +195,15 @@ class WebView extends React.Component {
|
|||
* @platform android
|
||||
*/
|
||||
saveFormDataDisabled: PropTypes.bool,
|
||||
|
||||
/**
|
||||
* Used on Android only, controls whether the given list of URL prefixes should
|
||||
* make {@link com.facebook.react.views.webview.ReactWebViewClient} to launch a
|
||||
* default activity intent for those URL instead of loading it within the webview.
|
||||
* Use this to list URLs that WebView cannot handle, e.g. a PDF url.
|
||||
* @platform android
|
||||
*/
|
||||
urlPrefixesForDefaultIntent: PropTypes.arrayOf(PropTypes.string),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -276,6 +285,7 @@ class WebView extends React.Component {
|
|||
allowUniversalAccessFromFileURLs={this.props.allowUniversalAccessFromFileURLs}
|
||||
mixedContentMode={this.props.mixedContentMode}
|
||||
saveFormDataDisabled={this.props.saveFormDataDisabled}
|
||||
urlPrefixesForDefaultIntent={this.props.urlPrefixesForDefaultIntent}
|
||||
/>;
|
||||
|
||||
return (
|
||||
|
|
|
@ -12,6 +12,7 @@ package com.facebook.react.views.webview;
|
|||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
@ -110,6 +111,7 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
|
|||
protected static class ReactWebViewClient extends WebViewClient {
|
||||
|
||||
protected boolean mLastLoadFailed = false;
|
||||
protected @Nullable ReadableArray mUrlPrefixesForDefaultIntent;
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView webView, String url) {
|
||||
|
@ -137,8 +139,21 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
|
|||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
if (url.startsWith("http://") || url.startsWith("https://") ||
|
||||
url.startsWith("file://") || url.equals("about:blank")) {
|
||||
boolean useDefaultIntent = false;
|
||||
if (mUrlPrefixesForDefaultIntent != null && mUrlPrefixesForDefaultIntent.size() > 0) {
|
||||
ArrayList<Object> urlPrefixesForDefaultIntent =
|
||||
mUrlPrefixesForDefaultIntent.toArrayList();
|
||||
for (Object urlPrefix : urlPrefixesForDefaultIntent) {
|
||||
if (url.startsWith((String) urlPrefix)) {
|
||||
useDefaultIntent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!useDefaultIntent &&
|
||||
(url.startsWith("http://") || url.startsWith("https://") ||
|
||||
url.startsWith("file://") || url.equals("about:blank"))) {
|
||||
return false;
|
||||
} else {
|
||||
try {
|
||||
|
@ -205,6 +220,10 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
|
|||
event.putBoolean("canGoForward", webView.canGoForward());
|
||||
return event;
|
||||
}
|
||||
|
||||
public void setUrlPrefixesForDefaultIntent(ReadableArray specialUrls) {
|
||||
mUrlPrefixesForDefaultIntent = specialUrls;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,6 +233,7 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
|
|||
protected static class ReactWebView extends WebView implements LifecycleEventListener {
|
||||
protected @Nullable String injectedJS;
|
||||
protected boolean messagingEnabled = false;
|
||||
protected @Nullable ReactWebViewClient mReactWebViewClient;
|
||||
|
||||
protected class ReactWebViewBridge {
|
||||
ReactWebView mContext;
|
||||
|
@ -254,6 +274,16 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
|
|||
cleanupCallbacksAndDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWebViewClient(WebViewClient client) {
|
||||
super.setWebViewClient(client);
|
||||
mReactWebViewClient = (ReactWebViewClient)client;
|
||||
}
|
||||
|
||||
public @Nullable ReactWebViewClient getReactWebViewClient() {
|
||||
return mReactWebViewClient;
|
||||
}
|
||||
|
||||
public void setInjectedJavaScript(@Nullable String js) {
|
||||
injectedJS = js;
|
||||
}
|
||||
|
@ -413,7 +443,7 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
|
|||
public void setAllowUniversalAccessFromFileURLs(WebView view, boolean allow) {
|
||||
view.getSettings().setAllowUniversalAccessFromFileURLs(allow);
|
||||
}
|
||||
|
||||
|
||||
@ReactProp(name = "saveFormDataDisabled")
|
||||
public void setSaveFormDataDisabled(WebView view, boolean disable) {
|
||||
view.getSettings().setSaveFormData(!disable);
|
||||
|
@ -507,7 +537,17 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
|
|||
view.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
|
||||
} else if ("compatibility".equals(mixedContentMode)) {
|
||||
view.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "urlPrefixesForDefaultIntent")
|
||||
public void setUrlPrefixesForDefaultIntent(
|
||||
WebView view,
|
||||
@Nullable ReadableArray urlPrefixesForDefaultIntent) {
|
||||
ReactWebViewClient client = ((ReactWebView) view).getReactWebViewClient();
|
||||
if (client != null && urlPrefixesForDefaultIntent != null) {
|
||||
client.setUrlPrefixesForDefaultIntent(urlPrefixesForDefaultIntent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue