简体   繁体   中英

How to stop EditText showing javascript after Android HtmlCompat.fromHtml() creates a Spanned

I have an EditText in my view. I am using HtmlCompat.fromHtml() to show the contents of an email in this EditText so it can be viewed and edited. If the html contains any JavaScript then it is being rendered in the resulting Spanned.

If I have the following (example) code:

String htmlString = "<html>\n" +
    "\n" +
    "<head>\n" +
    "    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n" +
    "    <script type=\"text/javascript\">\n" +
    "        alert(\"This should not appear in the EditText\");\n" +
    "    </script>\n" +
    "</head>\n" +
    "\n" +
    "<body style=\"margin: 0;padding: 0;box-sizing: border-box;-webkit-font-smoothing: antialiased;-webkit-text-size-adjust: none;width: 100% !important;height: 100% !important;line-height: 1.6;margin-top: 0 !important;margin-left: 0 !important;margin-right: 0 !important\" class=\"\">\n" +
    "    <div dir=\"auto\">Technician booked for tomorrow morning\n" +
    "        <br>\n" +
    "        <br>\n" +
    "    </div>\n" +
    "    <div dir=\"auto\">\n" +
    "        <a href=\"http://www.bluemail.me/r?b=15726\"></a>\n" +
    "    </div>\n" +
    "</body>\n" +
    "\n" +
    "</html>";

emailTextView.setText(HtmlCompat.fromHtml(htmlString, HtmlCompat.FROM_HTML_MODE_COMPACT));

then the EditText shows the contents of <script type=\\"text/javascript\\">alert(\\"This should not appear in the EditText\\");</script> I would have expected it to be removed/hidden. But I get:

显示问题的屏幕截图

Is there any way to stop this or is there some other way to have html from an email rendered in an EditText for editing? I know that Gmail can do it on Android, but I can't see how it was done?

<script>whatever</script> is being stripped leaving the "whatever" in place. This is the default behavior of HtmlCompat.fromHtml() for tags it does not recognize. You will need to strip the problem tags and the associated text from the string before calling HtmlCompat.fromHtml(). You could do this with a straight string match or with a regular expression.

For Java:

String newString =  mHtmlString.replaceAll("(?is)<script.*?</script>","")

For Kotlin:

val newString = mHtmlString.replace(Regex("(?is)<script.*?</script>"), "")

A second way is to use the tag handler that you can specify in the call to fromHtml(String, int, ImageGetter, TagHandler) .

override fun handleTag(
    opening: Boolean,
    tag: String,
    output: Editable,
    xmlReader: XMLReader?
) {
    class DeleteSpan

    if (!tag.equals("script", true)) {
        return
    }
    if (opening) {
        output.setSpan(DeleteSpan(), output.length, output.length, Spannable.SPAN_MARK_POINT)
    } else {
        val spans = output.getSpans(0, output.length, DeleteSpan::class.java)
        val lastSpan = spans[spans.size - 1]
        output.apply {
            delete(getSpanStart(lastSpan), getSpanEnd(lastSpan))
            removeSpan(lastSpan)
        }
    }
}

This second method simply deletes the contents of the script tag from the output.

In case anyone is interested, the java version of @Cheticamp's answer that I came up with was:

Html.ImageGetter imageGetter = new PicassoImageGetter(textView);
textView.setText(HtmlCompat.fromHtml(htmlString, HtmlCompat.FROM_HTML_MODE_COMPACT, imageGetter, new Html.TagHandler() {

    @Override
    public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
        if (!tag.equals("script")) {
            return;
        }
        if (opening) {
            output.setSpan(new DeleteScriptTagContent(), output.length(), output.length(), Spannable.SPAN_MARK_POINT);
        } else {
            Object[] spans = output.getSpans(0, output.length(), DeleteScriptTagContent.class);
            if (spans.length == 0) {
                return;
            }
            Object lastSpan = spans[spans.length - 1];
            int startIndex = output.getSpanStart(lastSpan);
            int endIndex = output.getSpanEnd(lastSpan);
            if (startIndex == -1 || endIndex == -1) {
                return;
            }
            output.delete(startIndex, endIndex);
        }
    }

    class DeleteScriptTagContent {
    }
}));
textView.setMovementMethod(LinkMovementMethod.getInstance());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM