Android中的WebView和loadData

111

可以使用以下方法设置 web-view 的内容: loadData(String data, String mimeType, String encoding)

如何处理 html 数据的未知编码问题?!

是否有编码列表?!

我从我的大学了解到,在我的情况下,html 来自数据库并使用 Latin-1 编码。 我尝试将编码参数设置为 latin-1、ISO-8859-1 / iso-8859-1,但仍然无法正确显示特殊符号,如 ä、ö、ü。

非常感谢任何建议。

9个回答

211
myWebView.loadData(myHtmlString, "text/html; charset=UTF-8", null);

这个方案完美运行,尤其是在 Android 4.0 上,它显然忽略了 HTML 中内部的字符编码。

已在2.3和4.0.3上测试。

事实上,我不知道除了“base64”之外,最后一个参数还能取什么值。一些谷歌的例子中将其设置为 null。


3
如果您的字符集超出了US-ASCII字符集,那么这种方法就无法“完美”地运作。 - Andrey Novikov
1
刚在一个4.2.2的设备上尝试了一下,效果非常好,但在一个2.3.6的设备上却只显示相同的垃圾字符。:S - Frank
这对我来说也适用于4.1.2(它也忽略HTML内部的字符集),并且使用Latin1编码!想象一下。 - Luis A. Florit
3
@Frank 我也一样,在HTC One 2.3.7上测试(可能所有的姜饼版本)得到了相同的垃圾结果,我不得不使用Andrey Novikov的解决方案,即WebView.loadDataWithBaseURL() - ForceMagic
1
根据谷歌的建议,需要使用base64。在此处阅读更多信息 https://dev59.com/YG865IYBdhLWcg3wKLJP#54614344 并查看谷歌的相关视频!(链接在我的回答中;-)) - Pascal
显示剩余2条评论

149

WebView.loadData()根本无法正常工作。我所做的是:

String header = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";
myWebView.loadData(header+myHtmlString, "text/html", "UTF-8");
我认为在你的情况下,你应该在标题和WebView.loadData()中将UTF-8替换为latin1或ISO-8859-1。

为了给出一个完整的答案,这里是官方编码列表:http://www.iana.org/assignments/character-sets

我更新了我的答案以包容更多:

要使用非latin1编码的WebView.loadData(),您必须对HTML内容进行编码。之前的示例在Android 4+上没有正常工作,因此我已将其修改为如下所示:

WebSettings settings = myWebView.getSettings();
settings.setDefaultTextEncodingName("utf-8");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
    String base64 = Base64.encodeToString(htmlString.getBytes(), Base64.DEFAULT);
    myWebView.loadData(base64, "text/html; charset=utf-8", "base64");
} else {
    String header = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";
    myWebView.loadData(header + htmlString, "text/html; charset=UTF-8", null);

}

但是后来我改用了 WebView.loadDataWithBaseURL(),代码变得非常简洁,并且不再依赖于Android版本:

WebSettings settings = myWebView.getSettings();
settings.setDefaultTextEncodingName("utf-8");
myWebView.loadDataWithBaseURL(null, htmlString, "text/html", "utf-8", null);

由于某种原因,这些函数的实现完全不同。


1
你好,安德烈。我尝试了你的解决方案。不幸的是,它对我没有起作用 :( - Tima
你尝试过我描述的UTF-8了吗?现在当我想到你的问题时,我意识到在Java中所有字符串都是UTF-8编码的,所以我的示例应该可以完好地工作。 - Andrey Novikov
是的,我认为问题就在那里。尝试将此字符串输出到 Toast 或 Dialog 进行测试,看看你得到了什么。 - Andrey Novikov
5
在4.0版本及以上,编码应该在mime类型中设置为"text/html; charset=utf-8",否则它将无法被识别。 - marwinXXII
2
最后一个片段(使用loadDataWithBaseURL方法的那个)在4.2.2和2.3.6设备上都非常好用 :D - Frank
显示剩余4条评论

41
据我所了解,loadData()只是使用提供的数据生成一个 data: URL。
请参阅loadData()Javadocs
如果encoding参数的值为“base64”,则数据必须以base64编码。否则,数据必须使用ASCII编码用于安全URL字符范围内的八位字节,并使用标准的%xx十六进制URL编码用于范围外的八位字节。例如,“#”、“%”、“\\”、“?”应分别替换为%23、%25、%27、%3f。
此方法形成的“data”方案URL使用默认的US-ASCII字符集。如果您需要设置不同的字符集,则应该形成一个显式指定URL的mediatype部分中的charset参数的“data”方案URL,并调用loadUrl(String)。请注意,从数据URL的mediatype部分获得的字符集始终覆盖HTML或XML文档本身指定的字符集。
因此,您应该使用US-ASCII并自己转义任何特殊字符,或者只需使用Base64编码所有内容。假设您使用UTF-8(我未在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");

这让我想起在四处漫游之前先检查文档! - Pradeep
谢谢回答!我正在将不同的内置上下文HTML帮助加载到Webview中,但有时只能工作一些时间。这个修复解决了这个问题。 - eric

21

我有这个问题,但是:

String content = "<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" /></head><body>";
content += mydata + "</body></html>";
WebView1.loadData(content, "text/html", "UTF-8");

不适用于所有设备。并且我合并了一些方法:

String content = 
       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"+
       "<html><head>"+
       "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />"+
       "</head><body>";

content += myContent + "</body></html>";

WebView WebView1 = (WebView) findViewById(R.id.webView1);
WebView1.loadData(content, "text/html; charset=utf-8", "UTF-8");

它有效。


这不是Google推荐的做法。请查看我的回答并观看视频讲解;-)https://dev59.com/YG865IYBdhLWcg3wKLJP#54614344 - Pascal
我在使用loadData时遇到了类似的问题,后来我发现将HTML内容简单保存到文件中,然后使用webview.loadURL("file:///$filesDir/myfile.html")就可以解决问题。 - dkoukoul

13
在Web视图中加载htmlContent的最安全的方法是:
  1. 使用base64编码(官方建议)
  2. 指定UTF-8作为html内容类型,即使用"text/html; charset=utf-8"而不是"text/html"(个人建议)
"Base64编码"是一个官方推荐,已经在最新的01/2019版本的Chrominium中再次写入(已经在Javadoc中存在),该版本存在于WebView M72(72.0.3626.76)中。

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

CHROMIUM团队的官方声明:

"推荐修复方案:
我们的团队建议您使用Base64对数据进行编码。我们提供了如何进行编码的示例:

这个修复方案向后兼容(适用于早期的WebView版本),并且也应对未来兼容性问题(您不会遇到与内容编码相关的未来兼容性问题)。

示例:

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!
);  

12

使用以下代码:

String customHtml = text;
           wb.loadDataWithBaseURL(null,customHtml,"text/html", "UTF-8", null);

1
15篇帖子后,这是唯一一个对我有效的。 - Guy Cothal
尽管看起来很疯狂,但这是我在使用AndroidX时唯一有效的解决方法。 - CodeMylife

5
 String strWebData="html...." //**Your html string**

 WebView webDetail=(WebView) findViewById(R.id.webView1);

 WebSettings websetting = webDetail.getSettings();

 websetting.setDefaultTextEncodingName("utf-8");

 webDetail.loadData(strWebData, "text/html; charset=utf-8", null);

1

以上的答案在我的情况下不起作用。你需要在 meta 标签中指定 utf-8

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

0

这是快速且有效的 // 数据 = 任何HTML或数学字符串

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");

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接