近期在開發倉鼠用戶端和笑粗聲來時,都碰到了在不同版本的模拟器或者真機出現浏覽器渲染網頁效果各異的情況,如下圖展示的情況:
在WP7.1模拟器的顯示效果 在WP8.0模拟器的顯示效果 在WP8.1模拟器的顯示效果
自左到右分别為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的浏覽器就正确顯示出結果來了: