-
Notifications
You must be signed in to change notification settings - Fork 25k
Add prop + event for blacklisting URL-schemes in WebView #10654
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
876024b
98ba789
c71a009
0eeb21a
d1b87ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -310,6 +310,16 @@ class WebView extends React.Component { | |
| */ | ||
| scalesPageToFit: PropTypes.bool, | ||
|
|
||
| /** | ||
| * Function that is invoked when a defined URL-scheme has been rejected. | ||
| */ | ||
| onUrlSchemeRejected: PropTypes.func, | ||
|
|
||
| /** | ||
| * An array defining rejected URL-schemes. | ||
| */ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment doesn't add any info to the name Can you please explain what "rejected" means? |
||
| rejectedUrlSchemes: PropTypes.array, | ||
|
|
||
| /** | ||
| * Function that allows custom handling of any web view requests. Return | ||
| * `true` from the function to continue loading the request and `false` | ||
|
|
@@ -400,6 +410,7 @@ class WebView extends React.Component { | |
| key="webViewKey" | ||
| style={webViewStyles} | ||
| source={resolveAssetSource(source)} | ||
| rejectedUrlSchemes={this.props.rejectedUrlSchemes} | ||
| injectedJavaScript={this.props.injectedJavaScript} | ||
| bounces={this.props.bounces} | ||
| scrollEnabled={this.props.scrollEnabled} | ||
|
|
@@ -409,6 +420,7 @@ class WebView extends React.Component { | |
| onLoadingStart={this._onLoadingStart} | ||
| onLoadingFinish={this._onLoadingFinish} | ||
| onLoadingError={this._onLoadingError} | ||
| onUrlSchemeRejected={this._onUrlSchemeRejected} | ||
| messagingEnabled={messagingEnabled} | ||
| onMessage={this._onMessage} | ||
| onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} | ||
|
|
@@ -539,13 +551,19 @@ class WebView extends React.Component { | |
| var {onMessage} = this.props; | ||
| onMessage && onMessage(event); | ||
| } | ||
|
|
||
| _onUrlSchemeRejected = (event: Event) => { | ||
| var onUrlSchemeRejected = this.props.onUrlSchemeRejected; | ||
| onUrlSchemeRejected && onUrlSchemeRejected(event); | ||
| }; | ||
| } | ||
|
|
||
| var RCTWebView = requireNativeComponent('RCTWebView', WebView, { | ||
| nativeOnly: { | ||
| onLoadingStart: true, | ||
| onLoadingError: true, | ||
| onLoadingFinish: true, | ||
| onUrlSchemeRejected: true, | ||
| onMessage: true, | ||
| messagingEnabled: PropTypes.bool, | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ | |
| import javax.annotation.Nullable; | ||
|
|
||
| import java.io.UnsupportedEncodingException; | ||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.Locale; | ||
| import java.util.Map; | ||
|
|
@@ -53,6 +54,7 @@ | |
| import com.facebook.react.views.webview.events.TopLoadingFinishEvent; | ||
| import com.facebook.react.views.webview.events.TopLoadingStartEvent; | ||
| import com.facebook.react.views.webview.events.TopMessageEvent; | ||
| import com.facebook.react.views.webview.events.UrlSchemeRejectedEvent; | ||
|
|
||
| import org.json.JSONObject; | ||
| import org.json.JSONException; | ||
|
|
@@ -69,6 +71,7 @@ | |
| * - topLoadingFinish | ||
| * - topLoadingStart | ||
| * - topLoadingError | ||
| * - urlSchemeRejected | ||
| * | ||
| * Each event will carry the following properties: | ||
| * - target - view's react tag | ||
|
|
@@ -132,6 +135,11 @@ public void onPageStarted(WebView webView, String url, Bitmap favicon) { | |
|
|
||
| @Override | ||
| public boolean shouldOverrideUrlLoading(WebView view, String url) { | ||
| if (((ReactWebView)view).isUrlSchemeRejected(url)) { | ||
| dispatchUrlSchemeRejectedEvent(view, url); | ||
| return true; | ||
| } | ||
|
|
||
| if (url.startsWith("http://") || url.startsWith("https://") || | ||
| url.startsWith("file://")) { | ||
| return false; | ||
|
|
@@ -205,6 +213,8 @@ private WritableMap createWebViewEvent(WebView webView, String url) { | |
| private static class ReactWebView extends WebView implements LifecycleEventListener { | ||
| private @Nullable String injectedJS; | ||
| private boolean messagingEnabled = false; | ||
| private @Nullable ArrayList<String> rejectedUrlSchemes; | ||
|
|
||
|
|
||
| private class ReactWebViewBridge { | ||
| ReactWebView mContext; | ||
|
|
@@ -271,6 +281,19 @@ public void callInjectedJavaScript() { | |
| } | ||
| } | ||
|
|
||
| public void setRejectedUrlSchemes(@Nullable ArrayList<String> rejectedUrlSchemes) { | ||
| this.rejectedUrlSchemes = rejectedUrlSchemes; | ||
| } | ||
|
|
||
| public ArrayList<String> getRejectedUrlSchemes() { | ||
| return rejectedUrlSchemes; | ||
| } | ||
|
|
||
| public Boolean isUrlSchemeRejected(String url) { | ||
| String scheme = getUrlScheme(url); | ||
| return scheme != null && rejectedUrlSchemes != null && rejectedUrlSchemes.contains(scheme); | ||
| } | ||
|
|
||
| public void linkBridge() { | ||
| if (messagingEnabled) { | ||
| if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { | ||
|
|
@@ -404,6 +427,10 @@ public void setSource(WebView view, @Nullable ReadableMap source) { | |
| if (previousUrl != null && previousUrl.equals(url)) { | ||
| return; | ||
| } | ||
| if (((ReactWebView)view).isUrlSchemeRejected(url)) { | ||
| dispatchUrlSchemeRejectedEvent(view, url); | ||
| return; | ||
| } | ||
| if (source.hasKey("method")) { | ||
| String method = source.getString("method"); | ||
| if (method.equals(HTTP_METHOD_POST)) { | ||
|
|
@@ -445,6 +472,35 @@ public void setSource(WebView view, @Nullable ReadableMap source) { | |
| view.loadUrl(BLANK_URL); | ||
| } | ||
|
|
||
| @ReactProp(name = "rejectedUrlSchemes") | ||
| public void setRejectedUrlSchemes(WebView view, @Nullable ReadableArray rejectedUrlSchemesArray) { | ||
| if (rejectedUrlSchemesArray != null) { | ||
| ArrayList<String> rejectedUrlSchemes = new ArrayList<String>(); | ||
|
|
||
| for (int i = 0; i < rejectedUrlSchemesArray.size(); i++) { | ||
| rejectedUrlSchemes.add(rejectedUrlSchemesArray.getString(i)); | ||
| } | ||
|
|
||
| ((ReactWebView) view).setRejectedUrlSchemes(rejectedUrlSchemes); | ||
| } else { | ||
| ((ReactWebView) view).setRejectedUrlSchemes(null); | ||
| } | ||
| } | ||
|
|
||
| private static void dispatchUrlSchemeRejectedEvent(WebView view, String url) { | ||
| final WritableMap params = Arguments.createMap(); | ||
| params.putString("scheme", getUrlScheme(url)); | ||
| params.putString("url", url); | ||
| dispatchEvent(view, new UrlSchemeRejectedEvent(view.getId(), params)); | ||
| } | ||
|
|
||
| private static String getUrlScheme(String url) { | ||
| if (url.contains("://")) | ||
| return url.split("://")[0]; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm pretty sure there's a method for this in the SDK. |
||
|
|
||
| return null; | ||
| } | ||
|
|
||
| @ReactProp(name = "onContentSizeChange") | ||
| public void setOnContentSizeChange(WebView view, boolean sendContentSizeChangeEvents) { | ||
| if (sendContentSizeChangeEvents) { | ||
|
|
@@ -527,4 +583,9 @@ private static void dispatchEvent(WebView webView, Event event) { | |
| reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher(); | ||
| eventDispatcher.dispatchEvent(event); | ||
| } | ||
|
|
||
| @Override | ||
| public @Nullable Map getExportedCustomDirectEventTypeConstants() { | ||
| return MapBuilder.of(UrlSchemeRejectedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onUrlSchemeRejected")); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| /** | ||
| * Copyright (c) 2015-present, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under the BSD-style license found in the | ||
| * LICENSE file in the root directory of this source tree. An additional grant | ||
| * of patent rights can be found in the PATENTS file in the same directory. | ||
| */ | ||
|
|
||
| package com.facebook.react.views.webview.events; | ||
|
|
||
| import com.facebook.react.bridge.WritableMap; | ||
| import com.facebook.react.uimanager.events.Event; | ||
| import com.facebook.react.uimanager.events.RCTEventEmitter; | ||
|
|
||
| /** | ||
| * Event emitted when url scheme has been blocked from loading | ||
| */ | ||
| public class UrlSchemeRejectedEvent extends Event<UrlSchemeRejectedEvent> { | ||
|
|
||
| public static final String EVENT_NAME = "urlSchemeRejected"; | ||
| private WritableMap mEventData; | ||
|
|
||
| public UrlSchemeRejectedEvent(int viewId, WritableMap eventData) { | ||
| super(viewId); | ||
| mEventData = eventData; | ||
| } | ||
|
|
||
| @Override | ||
| public String getEventName() { | ||
| return EVENT_NAME; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean canCoalesce() { | ||
| return false; | ||
| } | ||
|
|
||
| @Override | ||
| public short getCoalescingKey() { | ||
| // All events for a given view can be coalesced. | ||
| return 0; | ||
| } | ||
|
|
||
| @Override | ||
| public void dispatch(RCTEventEmitter rctEventEmitter) { | ||
| rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment doesn't add any info to the name
onUrlSchemeRejectedbelow.Can you please explain what "rejected" means?