Android. WebView and loadData

Viewed 150775

It's possible to use following method for content's setting of a web-view loadData(String data, String mimeType, String encoding)

How to handle the problem with unknown encoding of html data?!

Is there a list of encodings?!

I know from my college that in my case html comes from DB and is encoded with latin-1. I try to set encoding parameter to latin-1, to ISO-8859-1 / iso-8859-1, but still have problem with displaying of special signs like ä, ö, ü.

I'll be very thankful for any advice.

9 Answers

As I understand it, loadData() simply generates a data: URL with the data provide it.

Read the javadocs for loadData():

If the value of the encoding parameter is 'base64', then the data must be encoded as base64. Otherwise, the data must use ASCII encoding for octets inside the range of safe URL characters and use the standard %xx hex encoding of URLs for octets outside that range. For example, '#', '%', '\', '?' should be replaced by %23, %25, %27, %3f respectively.

The 'data' scheme URL formed by this method uses the default US-ASCII charset. If you need need to set a different charset, you should form a 'data' scheme URL which explicitly specifies a charset parameter in the mediatype portion of the URL and call loadUrl(String) instead. Note that the charset obtained from the mediatype portion of a data URL always overrides that specified in the HTML or XML document itself.

Therefore, you should either use US-ASCII and escape any special characters yourself, or just encode everything using Base64. The following should work, assuming you use UTF-8 (I haven't tested this with latin1):

String data = ...;  // the html data
String base64 = android.util.Base64.encodeToString(data.getBytes("UTF-8"), android.util.Base64.DEFAULT);
webView.loadData(base64, "text/html; charset=utf-8", "base64");

The safest way to load htmlContent in a Web view is to:

  1. use base64 encoding (official recommendation)
  2. specify UFT-8 for html content type, i.e., "text/html; charset=utf-8" instead of "text/html" (personal advice)

"Base64 encoding" is an official recommendation that has been written again (already present in Javadoc) in the latest 01/2019 bug in Chrominium (present in WebView M72 (72.0.3626.76)):

https://bugs.chromium.org/p/chromium/issues/detail?id=929083

Official statement from Chromium team:

"Recommended fix:
Our team recommends you encode data with Base64. We've provided examples for how to do so:

This fix is backwards compatible (it works on earlier WebView versions), and should also be future-proof (you won't hit future compatibility problems with respect to content encoding)."

Code sample:

webView.loadData(
    Base64.encodeToString(
        htmlContent.getBytes(StandardCharsets.UTF_8),
        Base64.DEFAULT), // encode in Base64 encoded 
    "text/html; charset=utf-8", // utf-8 html content (personal recommendation)
    "base64"); // always use Base64 encoded data: NEVER PUT "utf-8" here (using base64 or not): This is wrong! 

the answers above doesn't work in my case. You need to specify utf-8 in meta tag

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    </head>
    <body>
        <!-- you content goes here -->
    </body>
</html>

this is fast and working // data = any html or math string

public void putInWebview(String data, WebView wv) {
        String htmlstring = "<head><meta name='viewport' content='width=device-width, shrink-to-fit=YES' user-scalable='no'><script type=\"text/x-mathjax-config\">MathJax.Hub.Config({tex2jax: {inlineMath: [['\\(','\\)']],processEscapes: true},\"HTML-CSS\": { linebreaks: { automatic: true, width: \"container\" } } } )</script><script id=\"MathJax-script\" async src=\"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js\" ></script></head>" +
                "<body style=\"font-size:100%; font-family: Arial \"  > " + data + "</body></html>";
        String qstnencodedHtml = Base64.encodeToString(htmlstring.getBytes(), Base64.NO_PADDING);
        if (Build.VERSION.SDK_INT >= 19) {
            wv.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        }
        else {
            wv.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
        wv.getSettings().setJavaScriptEnabled(true);
        wv.loadData(qstnencodedHtml, "text/html", "base64");

    }
Related