From 0c576ef84a1c7f79b228f205cc687ab1b945bda1 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Wed, 12 Sep 2018 11:34:13 -0700 Subject: [PATCH] Expose AllowFileAccess property in WebView Summary: This diff adds a new property in ReactWebView to be able to configure allowFileAccess Reviewed By: achen1 Differential Revision: D9789466 fbshipit-source-id: 39d042ac6ef69e44f006a4c4b0c2dd900f84dbc9 --- .../Components/WebView/WebView.android.js | 7 ++ RNTester/js/WebViewExample.js | 1 + .../views/webview/ReactWebViewManager.java | 97 +++++++++---------- 3 files changed, 56 insertions(+), 49 deletions(-) diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js index 4b37052400a..4661ce89612 100644 --- a/Libraries/Components/WebView/WebView.android.js +++ b/Libraries/Components/WebView/WebView.android.js @@ -150,6 +150,12 @@ class WebView extends React.Component { */ scalesPageToFit: PropTypes.bool, + /** + * Sets whether the webview allow access to file system. + * @platform android + */ + allowFileAccess: PropTypes.bool, + /** * Sets the user-agent for this WebView. The user-agent can also be set in native using * WebViewConfig. This prop will overwrite that config. @@ -317,6 +323,7 @@ class WebView extends React.Component { style={webViewStyles} source={resolveAssetSource(source)} scalesPageToFit={this.props.scalesPageToFit} + allowFileAccess={this.props.allowFileAccess} injectedJavaScript={this.props.injectedJavaScript} userAgent={this.props.userAgent} javaScriptEnabled={this.props.javaScriptEnabled} diff --git a/RNTester/js/WebViewExample.js b/RNTester/js/WebViewExample.js index e4c4fdf1b21..025d0348c68 100644 --- a/RNTester/js/WebViewExample.js +++ b/RNTester/js/WebViewExample.js @@ -436,6 +436,7 @@ exports.examples = [ backgroundColor: BGWASH, height: 100, }} + allowFileAccess={true} originWhitelist={FILE_SYSTEM_ORIGIN_WHITE_LIST} source={require('./helloworld.html')} scalesPageToFit={true} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java index 1f5d0032dcd..cbeaa014da4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java @@ -8,21 +8,8 @@ package com.facebook.react.views.webview; import android.annotation.TargetApi; -import android.content.Context; -import com.facebook.react.uimanager.UIManagerModule; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Pattern; -import javax.annotation.Nullable; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - import android.content.ActivityNotFoundException; +import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Picture; @@ -53,6 +40,7 @@ import com.facebook.react.common.build.ReactBuildConfig; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.SimpleViewManager; import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.events.ContentSizeChangeEvent; import com.facebook.react.uimanager.events.Event; @@ -62,10 +50,14 @@ 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 java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.regex.Pattern; import javax.annotation.Nullable; import org.json.JSONException; import org.json.JSONObject; @@ -140,10 +132,10 @@ public class ReactWebViewManager extends SimpleViewManager { mLastLoadFailed = false; dispatchEvent( - webView, - new TopLoadingStartEvent( - webView.getId(), - createWebViewEvent(webView, url))); + webView, + new TopLoadingStartEvent( + webView.getId(), + createWebViewEvent(webView, url))); } @Override @@ -153,7 +145,7 @@ public class ReactWebViewManager extends SimpleViewManager { // url blacklisting if (mUrlPrefixesForDefaultIntent != null && mUrlPrefixesForDefaultIntent.size() > 0) { ArrayList urlPrefixesForDefaultIntent = - mUrlPrefixesForDefaultIntent.toArrayList(); + mUrlPrefixesForDefaultIntent.toArrayList(); for (Object urlPrefix : urlPrefixesForDefaultIntent) { if (url.startsWith((String) urlPrefix)) { launchIntent(view.getContext(), url); @@ -196,10 +188,10 @@ public class ReactWebViewManager extends SimpleViewManager { @Override public void onReceivedError( - WebView webView, - int errorCode, - String description, - String failingUrl) { + WebView webView, + int errorCode, + String description, + String failingUrl) { super.onReceivedError(webView, errorCode, description, failingUrl); mLastLoadFailed = true; @@ -212,16 +204,16 @@ public class ReactWebViewManager extends SimpleViewManager { eventData.putString("description", description); dispatchEvent( - webView, - new TopLoadingErrorEvent(webView.getId(), eventData)); + webView, + new TopLoadingErrorEvent(webView.getId(), eventData)); } protected void emitFinishEvent(WebView webView, String url) { dispatchEvent( - webView, - new TopLoadingFinishEvent( - webView.getId(), - createWebViewEvent(webView, url))); + webView, + new TopLoadingFinishEvent( + webView.getId(), + createWebViewEvent(webView, url))); } protected WritableMap createWebViewEvent(WebView webView, String url) { @@ -342,8 +334,8 @@ public class ReactWebViewManager extends SimpleViewManager { public void callInjectedJavaScript() { if (getSettings().getJavaScriptEnabled() && - injectedJS != null && - !TextUtils.isEmpty(injectedJS)) { + injectedJS != null && + !TextUtils.isEmpty(injectedJS)) { evaluateJavascriptWithFallback("(function() {\n" + injectedJS + ";\n})();"); } } @@ -366,9 +358,9 @@ public class ReactWebViewManager extends SimpleViewManager { evaluateJavascriptWithFallback("(" + "window.originalPostMessage = window.postMessage," + "window.postMessage = function(data) {" + - BRIDGE_NAME + ".postMessage(String(data));" + + BRIDGE_NAME + ".postMessage(String(data));" + "}" + - ")"); + ")"); } } @@ -438,8 +430,8 @@ public class ReactWebViewManager extends SimpleViewManager { // Fixes broken full-screen modals/galleries due to body height being 0. webView.setLayoutParams( - new LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT)); + new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT)); setGeolocationEnabled(webView, false); if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { @@ -511,7 +503,7 @@ public class ReactWebViewManager extends SimpleViewManager { String html = source.getString("html"); if (source.hasKey("baseUrl")) { view.loadDataWithBaseURL( - source.getString("baseUrl"), html, HTML_MIME_TYPE, HTML_ENCODING, null); + source.getString("baseUrl"), html, HTML_MIME_TYPE, HTML_ENCODING, null); } else { view.loadData(html, HTML_MIME_TYPE, HTML_ENCODING); } @@ -588,14 +580,21 @@ public class ReactWebViewManager extends SimpleViewManager { @ReactProp(name = "urlPrefixesForDefaultIntent") public void setUrlPrefixesForDefaultIntent( - WebView view, - @Nullable ReadableArray urlPrefixesForDefaultIntent) { + WebView view, + @Nullable ReadableArray urlPrefixesForDefaultIntent) { ReactWebViewClient client = ((ReactWebView) view).getReactWebViewClient(); if (client != null && urlPrefixesForDefaultIntent != null) { client.setUrlPrefixesForDefaultIntent(urlPrefixesForDefaultIntent); } } + @ReactProp(name = "allowFileAccess") + public void setAllowFileAccess( + WebView view, + @Nullable Boolean allowFileAccess) { + view.getSettings().setAllowFileAccess(allowFileAccess != null && allowFileAccess); + } + @ReactProp(name = "geolocationEnabled") public void setGeolocationEnabled( WebView view, @@ -626,13 +625,13 @@ public class ReactWebViewManager extends SimpleViewManager { @Override public @Nullable Map getCommandsMap() { return MapBuilder.of( - "goBack", COMMAND_GO_BACK, - "goForward", COMMAND_GO_FORWARD, - "reload", COMMAND_RELOAD, - "stopLoading", COMMAND_STOP_LOADING, - "postMessage", COMMAND_POST_MESSAGE, - "injectJavaScript", COMMAND_INJECT_JAVASCRIPT - ); + "goBack", COMMAND_GO_BACK, + "goForward", COMMAND_GO_FORWARD, + "reload", COMMAND_RELOAD, + "stopLoading", COMMAND_STOP_LOADING, + "postMessage", COMMAND_POST_MESSAGE, + "injectJavaScript", COMMAND_INJECT_JAVASCRIPT + ); } @Override @@ -659,13 +658,13 @@ public class ReactWebViewManager extends SimpleViewManager { "var event;" + "var data = " + eventInitDict.toString() + ";" + "try {" + - "event = new MessageEvent('message', data);" + + "event = new MessageEvent('message', data);" + "} catch (e) {" + - "event = document.createEvent('MessageEvent');" + - "event.initMessageEvent('message', true, true, data.data, data.origin, data.lastEventId, data.source);" + + "event = document.createEvent('MessageEvent');" + + "event.initMessageEvent('message', true, true, data.data, data.origin, data.lastEventId, data.source);" + "}" + "document.dispatchEvent(event);" + - "})();"); + "})();"); } catch (JSONException e) { throw new RuntimeException(e); }