原文 Windows Phone 7.5/8.0/8.1 WebBrowser 渲染异常的原因及解决方法
近期在开发仓鼠客户端和笑粗声来时,都碰到了在不同版本的模拟器或者真机出现浏览器渲染网页效果各异的情况,如下图展示的情况:
自左到右分别为WP7、WP8.0和WP8.1模拟器的效果,可以看到左图网页渲染出来了,但是中文乱码了;中图网页压根就没渲染出来;右图非常坚挺完美。本文就来讨论如何一一解决这些问题。
首先说明一下我的实验环境和场景,这是一个WP7 Silverlight App,使用一个WebBrowser控件来显示一个网页,而网页不是用通常的Navigate方法进行跳转的,而是先把网页源码下载下来再使用NavigateToString方法显示出来。
以下是这个网页的全部源码
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>仓鼠游戏中心</title> <style type="text/css"> *{ margin:0px; padding:0px;} body{ font-size:12px; font-family:"微软雅黑";} .box{ width:320px; height:auto; margin:auto;} .box:after{content:"";clear:both;display:block;height:0;overflow:hidden;} .banner{ width:320px; min-height:123px;} .ContentApp{ width:320px; height:auto; margin:10px auto;} .ContentApp:after{content:"";clear:both;display:block;height:0;overflow:hidden;} .TitleBg{ width:122px; height:39px; background:url(http://oxl-cdn.com/img/cangshuyx/ad/Video_FullScreen/TitleBg.png) no-repeat; font-size:12px; text-align:center; color:#FFF;} .MoutCont{ width:300px; min-height:30px; border:#fbb500 dashed 2px; margin:1px auto; border-radius:5px;} .MoutCont:after{content:"";clear:both;display:block;height:0;overflow:hidden;} .MoutCont ul li{ float:left; list-style:none;} .MoutCont ul li h3,span{ float:left; padding:5px 3px;} .MoutCont ul li h3{ color:#ff0000; padding-left:15px;} .MoutCont p{ text-indent:2em; line-height:22px; padding:5px; padding-left:10px;} .MoutCont b{color:#ff0000;} </style> </head> <body> <div class="box"> <div class="banner"><img src="http://oxl-cdn.com/img/cangshuyx/logo/shangcheng/20140620/txcqbg_20140620.png" width="320" height="113"></div> <div class="ContentApp"> <div class="TitleBg">礼包内容</div> <div class="MoutCont"> <p>150钻石+50000金币+改变武器*10</p> </div> </div> <div class="ContentApp"> <div class="TitleBg">领取方式</div> <div class="MoutCont"> <p>在家园界面中——点击右上角活动奖励——选择礼包兑换界面——输入激活码——点击兑换礼包按钮</p> </div> </div> <div class="ContentApp"> <div class="TitleBg">游戏特点</div> <div class="MoutCont" > <p>每种礼包每一个玩家可以重复兑换,但每一枚激活码只能兑换一次,领取激活码后,请尽快使用</p> </div> </div> <p style="text-align:center; margin-top:30px;">本礼包最终解释权归仓鼠游戏中心所有</p> </div> </body> </html>
细心的读者会从这个网页的内容可以注意到两点,第一,这个网页是UTF8编码的,第二,这个网页的内容包含中文。
从上面三种情况来看,一个是中文乱码问题,一个是网页没有渲染成功只是显示了HTML标签。根据上述情况,可以得出:
1)因为解析编码的问题出现中文乱码,这种情况只会出现在WP7浏览器中(实际上第二幅图中的乱码不是这种引起)
2)因为WP8浏览器的自身缺陷,导致NavigateToString的时候渲染失败了,只加载了网页的源码出来(因为相当于纯文本显示,所以出现了图中的中文乱码)
3)WP8.1浏览器完全没有这些问题出现
接下来我们逐一解决这些问题。
1)对于WP7浏览器
这是WP7浏览器设计缺陷导致的,只要在UTF-8编码下,包含非通用英文字符就会出现乱码问题,包括中文、日文、阿拉伯文、韩文、俄语等。我们知道ASCII码是用7位二进制数定义的,最大编码只定义到127,共128个通用字符,并不包含其他外文字符。由于128-255是扩展的编码,本来并不作为显示使用,而我们的浏览器却强硬地要求这些字符当作显示字符,显然就渲染不出来了,因而出现乱码,那么解决的方法就是将大于127的字符转化成扩展ASCII码。
虽然标准 ASCII 码是 7 位编码,但由于计算机基本处理单位为字节( 1byte = 8bit ),所以一般仍以一个字节来存放一个 ASCII 字符。每一个字节中多余出来的一位(最高位)在计算机内部通常保持为 0 (在数据传输时可用作奇偶校验位)。由于标准 ASCII 字符集字符数目有限,在实际应用中往往无法满足要求。为此,国际标准化组织又制定了ISO2022 标准,它规定了在保持与 ISO646 兼容的前提下将 ASCII 字符集扩充为 8 位代码的统一方法。 ISO 陆续制定了一批适用于不同地区的扩充 ASCII 字符集,每种扩充 ASCII 字符集分别可以扩充 128 个字符,这些扩充字符的编码均为高位为1的8位代码(即十进制数 128~255 ),称为扩展 ASCII 码。扩展的 ASCII 字符满足了对更多字符的需求。扩展的 ASCII 包含 ASCII 中已有的 128 个字符,又增加了 128 个字符,总共是 256 个。
我们看一下扩展ASCII码表
以及ASCII对照表
有了这些背景知识,我们就明白了ASCII码都以&#+对应的十进制码组成的,因此我们在程序中,就要对大于127号的字符进行转换,在您的程序中添加下面一个方法进行处理
public static string ConvertExtendedAscii(string html) { string retVal = ""; if (string.IsNullOrEmpty(html)) { return retVal; } char[] s = html.ToCharArray(); foreach (char c in s) { if (Convert.ToInt32(c) > 127) retVal += "&#" + Convert.ToInt32(c) + ";"else retVal += c; } return retVal; }
加上这段处理之后再使用NavigateToString,可以看到WP7浏览器已经可以正常显示出网页来了:
同样的问题为什么在WP8以及WP8.1就不会出现呢?因为WP8和WP8.1在一开始就已经使用了扩展ASCII码,所以渲染的时候不会有乱码问题了。
2)对于WP8.0浏览器
笔者在实验中惊奇地发现,原来这个网页的源码里包含了两个meta标签,而我只要去除其中任意一个,网页的内容就正常显示了,但实际的生产需求并不能保证只包含一个meta标签。经过和WP7以及WP8.1浏览器在同样的情形下的对比,笔者发现,这个问题确实只会出现在WP8.0的浏览器的NavigateToString方法上,如果我直接Nagivate一个网页URI是没有任何问题的。所以这应该是WP8.0的WebBrowser在NavigateToString解析时出现的BUG...系统问题坑爹。
下面说一下解决方法,对于WP8.0,不要使用NavigateToString了,还是使用Navigate方法,但是这个网页内容是文本啊,怎么跳转到一个uri啊?
WP强大的独立存储优势就在这里体现出来了,记得独立存储所保存的文件怎么访问吗,没错就是通过一个独立存储Uri!那么我们就把网页的文本内容暂时存储在独立存储里,获得一个uri,让WebBrowser跳转到这个Uri就可以了。代码如下:
using (System.IO.IsolatedStorage.IsolatedStorageFile file = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()) { if (!file.DirectoryExists("temp")) { file.CreateDirectory("temp"); } using (System.IO.IsolatedStorage.IsolatedStorageFileStream fs = new System.IO.IsolatedStorage.IsolatedStorageFileStream("temp\\review.html", System.IO.FileMode.Create, file)) { byte[] bytes = System.Text.Encoding.UTF8.GetBytes(gift.ContentText); fs.Write(bytes, 0, bytes.Length); } } _WebBrowser.Navigate(new Uri("temp\\review.html", UriKind.Relative));
如此一来,在WP8的浏览器就正确显示出结果来了:
Windows Phone 7.5/8.0/8.1 WebBrowser 渲染异常的原因及解决方法,布布扣,bubuko.com