Skip to content

Commit

Permalink
Properly escape JavaScript code on Android (#20366)
Browse files Browse the repository at this point in the history
Summary:
These changes will fix executing javascript with any special characters, by making use of the `evaluateJavascript` function on Android 4.4+, and by properly escaping the URI on Android <4.4.

Fixes #19611Fixes #20365Fixes #9749Closes #19655Closes #12321

This PR supersedes #19655 by patching the same problem in all the places, and fixing it for Android <4.4 as well.
Pull Request resolved: #20366

Differential Revision: D9242968

Pulled By: hramos

fbshipit-source-id: f2e1abc786ba333dbd8aaa8922e716fd99ec26e0
  • Loading branch information
LinusU authored and facebook-github-bot committed Aug 9, 2018
1 parent 8ee9002 commit e6b305b
Showing 1 changed file with 21 additions and 4 deletions.
Expand Up @@ -16,6 +16,7 @@
import javax.annotation.Nullable;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
Expand Down Expand Up @@ -325,11 +326,25 @@ public void setMessagingEnabled(boolean enabled) {
}
}

protected void evaluateJavascriptWithFallback(String script) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
evaluateJavascript(script, null);
return;
}

try {
loadUrl("javascript:" + URLEncoder.encode(script, "UTF-8"));
} catch (UnsupportedEncodingException e) {
// UTF-8 should always be supported
throw new RuntimeException(e);
}
}

public void callInjectedJavaScript() {
if (getSettings().getJavaScriptEnabled() &&
injectedJS != null &&
!TextUtils.isEmpty(injectedJS)) {
loadUrl("javascript:(function() {\n" + injectedJS + ";\n})();");
evaluateJavascriptWithFallback("(function() {\n" + injectedJS + ";\n})();");
}
}

Expand All @@ -348,7 +363,7 @@ public void onReceiveValue(String value) {
});
}

loadUrl("javascript:(" +
evaluateJavascriptWithFallback("(" +
"window.originalPostMessage = window.postMessage," +
"window.postMessage = function(data) {" +
BRIDGE_NAME + ".postMessage(String(data));" +
Expand Down Expand Up @@ -637,9 +652,10 @@ public void receiveCommand(WebView root, int commandId, @Nullable ReadableArray
break;
case COMMAND_POST_MESSAGE:
try {
ReactWebView reactWebView = (ReactWebView) root;
JSONObject eventInitDict = new JSONObject();
eventInitDict.put("data", args.getString(0));
root.loadUrl("javascript:(function () {" +
reactWebView.evaluateJavascriptWithFallback("(function () {" +
"var event;" +
"var data = " + eventInitDict.toString() + ";" +
"try {" +
Expand All @@ -655,7 +671,8 @@ public void receiveCommand(WebView root, int commandId, @Nullable ReadableArray
}
break;
case COMMAND_INJECT_JAVASCRIPT:
root.loadUrl("javascript:" + args.getString(0));
ReactWebView reactWebView = (ReactWebView) root;
reactWebView.evaluateJavascriptWithFallback(args.getString(0));
break;
}
}
Expand Down

1 comment on commit e6b305b

@fungilation
Copy link

@fungilation fungilation commented on e6b305b Aug 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did some testing on remaining breakage with injected JS inside Android's webview. I see one, with Mark.js.

Inside html of WebView.source:

<head>
<script src="js/mark.min.js" charset="UTF-8"></script>
</head>

With mark.min.js being https://github.com/julmot/mark.js/blob/8.11.1/dist/mark.min.js.

And then subsequently, in injected JS:

if (typeof Mark === 'undefined') {
      alert('No Mark.js');   // with or without Chrome, Mark.js fails to load on Android
    }
    else {
      alert('Mark.js loaded');
}

I'm on RN 0.57.0-rc.0, and 'No Mark.js' is still alerted from within Android's webview. Have always worked on iOS.

This is a great PR though, thanks @LinusU! It has fixed comment issues on Android webview. Should I write this in a new issue, or this isn't enough details for repro? I'm also using https://github.com/alinz/react-native-webview-bridge which extends RN's webview, if it makes any difference.

Please sign in to comment.