標籤:des cPage style class blog code
原文 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強大的隔離儲存區 (Isolated Storage)優勢就在這裡體現出來了,記得隔離儲存區 (Isolated Storage)所儲存的檔案怎麼訪問嗎,沒錯就是通過一個隔離儲存區 (Isolated Storage)Uri!那麼我們就把網頁的常值內容暫時儲存在隔離儲存區 (Isolated Storage)裡,獲得一個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的瀏覽器就正確顯示出結果來了: