溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

UIWebView加載網(wǎng)頁(yè)出現(xiàn)亂碼的處理

發(fā)布時(shí)間:2020-07-02 02:56:06 來(lái)源:網(wǎng)絡(luò) 閱讀:2944 作者:zlayne 欄目:開發(fā)技術(shù)

        工作開發(fā)的app里有一項(xiàng)功能是郵箱驗(yàn)證。主要流程是用戶輸入一個(gè)郵箱地址,例如zlayne1989@163.com,這個(gè)郵箱地址會(huì)被傳回給server,server往這個(gè)郵箱發(fā)送一封郵件,里面包含一個(gè)鏈接。用戶可以使用app自帶的webview打開網(wǎng)頁(yè)版郵箱登錄界面。登錄郵箱后,用戶需要點(diǎn)擊郵件里的鏈接,之后webView會(huì)加載公司主站的網(wǎng)頁(yè)并提示驗(yàn)證完成。整個(gè)邏輯并不復(fù)雜,但是在這里出了個(gè)小問(wèn)題,那就是在顯示公司主站的時(shí)候,顯示為亂碼。跟接口那邊確認(rèn),那邊說(shuō)是已經(jīng)指定了網(wǎng)頁(yè)的編碼形式為GBK,按理說(shuō)不應(yīng)該出現(xiàn)亂碼的情況。后來(lái)將驗(yàn)證鏈接用瀏覽器打開依舊是亂碼,查看瀏覽器的設(shè)置,發(fā)現(xiàn)編碼方式指定為自動(dòng)識(shí)別,網(wǎng)頁(yè)被識(shí)別為UTF-8,而并沒有將這個(gè)網(wǎng)頁(yè)識(shí)別為GBK。后來(lái)發(fā)現(xiàn)是代理無(wú)服務(wù)器的問(wèn)題。因?yàn)楣旧贤饩W(wǎng)都要走2.78的服務(wù)器,通過(guò)這種方式會(huì)出現(xiàn)亂碼,而使用自己手機(jī)的3G卻是正常的,所以這個(gè)問(wèn)題就不需要修改了,不影響產(chǎn)品的使用。雖然是代理服務(wù)器的問(wèn)題,但未找到根源之前,我嘗試著使用UIWebView來(lái)解決編碼問(wèn)題,所以有了這篇博文。

1、UIWebView加載網(wǎng)頁(yè)的3種方式:

- (void)loadRequest:(NSURLRequest *)request;
- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL;
- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL;

第一種最簡(jiǎn)單,只有一個(gè)NSURLRequest對(duì)象參數(shù)。第二種和第三種都是用來(lái)加載“本地”網(wǎng)頁(yè),這里說(shuō)的“本地”是指需要用[NSString stringWithContentOfURL:url]等類似方式先從網(wǎng)絡(luò)上加載完成網(wǎng)頁(yè)數(shù)據(jù),然后通過(guò)這倆函數(shù)將網(wǎng)頁(yè)用webView顯示出來(lái)。顯示的亂碼的情況是直接使用loadRequest加載網(wǎng)頁(yè)。于是我嘗試了用loadHTMLString來(lái)替換loadRequest。

2、使用loadHTMLString

在函數(shù)(UIWebViewDelegate)

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType中截獲用戶在郵箱里面點(diǎn)擊的那個(gè)驗(yàn)證鏈接:

NSURL *url=[request URL];
NSString *urlString=[url absoluteString];

由于公司的驗(yàn)證鏈接都是統(tǒng)一格式的(www.51jingying.com/mailtrace.php?.........),因此針對(duì)于這個(gè)項(xiàng)目,我采用了最傻瓜的方式來(lái)判斷當(dāng)前用戶點(diǎn)擊的鏈接是不是郵箱驗(yàn)證鏈接——在urlString里查找"mailtrace.php"。代碼如下:

if(!reloaded && [urlString rangeOfString:@"/mailtrace.php"].length>0){
        reloaded=YES;
        self.webURL=url;
        [self reLoadWebView];
        return NO;
}

因?yàn)樵诤瘮?shù)reLoadWebView中會(huì)使用LoadHTMLString,而這個(gè)函數(shù)也會(huì)調(diào)用上邊的代理方法,因此定義個(gè)一個(gè)標(biāo)志reloaded,保證只加載一次,否則會(huì)出現(xiàn)死循環(huán)。reLoadWebView如下:

- (void)reLoadWebView {
    [self startLoad];
    _errorLabel.text = @"";
    _errorLabel.userInteractionEnabled=NO;
    self.webContainer.userInteractionEnabled=NO;
    
    //GBK編碼(0x0632)
    NSStringEncoding gbkEncoding =CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
    //GB18030(0x0631)
    NSStringEncoding gb18030Encoding =CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGBK_95);
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:self.webURL];
    [(id)self.webContainer.delegate objRetain];
    
    NSStringEncoding *usedEncoding=NULL;
    //將網(wǎng)頁(yè)加載放到另一個(gè)線程里,已防止訪問(wèn)某些”特殊“的郵箱地址(如gmail)導(dǎo)致界面卡住
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //帶 BOM 頭的如 utf-8等這里會(huì)識(shí)別
        NSString *body=[NSString stringWithContentsOfURL:self.webURL usedEncoding:usedEncoding error:nil];
        //識(shí)別不到,按GBK編碼再解碼一次
        if (!body) {
            body = [NSString stringWithContentsOfURL:self.webURL encoding:gbkEncoding error:nil];
        }
        //還是識(shí)別不到,按GB18030編碼再解碼一次.
        if (!body) {
            body = [NSString stringWithContentsOfURL:self.webURL encoding:gb18030Encoding error:nil];
        }
        //顯示
        if (body) {
            [self.webContainer loadHTMLString:body baseURL: nil];
        }else {
            [self.webContainer loadRequest:request];
            
        }
    });
    
}

其中webContainer是UIWebView實(shí)例。其實(shí)以上這些代碼也可以直接用loadData來(lái)代替,loadData可以指定編碼方式,也可以指定MIMEType,不過(guò)這樣一來(lái)如果指定的參數(shù)有誤就會(huì)加載不了網(wǎng)頁(yè)了。

3、問(wèn)題

使用上面的方法會(huì)帶來(lái)兩個(gè)問(wèn)題:

(1)因?yàn)槭孪纫褂胹tringWithContentOfURL預(yù)加載網(wǎng)頁(yè),而這個(gè)函數(shù)不會(huì)走UIWebViewDelegate方法:

- (void)webViewDidStartLoad:(UIWebView *)webView
- (void)webViewDidFinishLoad:(UIWebView *)webView
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error

所以我們無(wú)法監(jiān)測(cè)網(wǎng)頁(yè)的預(yù)加載情況:何時(shí)開始、何時(shí)結(jié)束、是否成功。例如,如果url為www.google.com,那么在調(diào)用了stringWithContentOfURL之后程序就可能很久都不會(huì)有任何反應(yīng)(墻...),這也是為什么我使用dispatch_async的原因(界面會(huì)卡死)。

(2)若用上面的方法加載了網(wǎng)頁(yè)A,而網(wǎng)頁(yè)A中其他超鏈接,這些超鏈接又是不完整的,那么在A頁(yè)面點(diǎn)擊其他超鏈接則會(huì)出錯(cuò)。例如網(wǎng)頁(yè)A中有

<a href="/common/test.php">測(cè)試超鏈接<a/>

如果網(wǎng)頁(yè)A是網(wǎng)址為“www.zlayne.com”,webView使用loadRequest加載的網(wǎng)頁(yè)A,那么即使頁(yè)面上的超鏈接如上所示,用戶也可以跳轉(zhuǎn)到正確頁(yè)面。

        但是!若webView是通過(guò)loadHTMLString加載的網(wǎng)頁(yè)A,前面也說(shuō)過(guò)了loadHTMLString是將網(wǎng)頁(yè)預(yù)加載下來(lái)轉(zhuǎn)換為string,那么這時(shí)候點(diǎn)擊如上的超鏈接就會(huì)出錯(cuò)。因?yàn)閷?shí)際訪問(wèn)的網(wǎng)址形如:

applewebdata://9cds-dsdf-96sdo-213pnm/common/test.php

解決這個(gè)問(wèn)題的思路無(wú)非就是獲得當(dāng)前頁(yè)面的域名,然后跟后邊的拼接起來(lái)組成實(shí)際的網(wǎng)址鏈接沒啥技術(shù)含量。


        最后,無(wú)意中發(fā)現(xiàn)雙擊webView會(huì)使它變小,行為很怪,具體原因不明。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI