工作開發(fā)的app里有一項(xiàng)功能是郵箱驗(yàn)證。主要流程是用戶輸入一個(gè)郵箱地址,例如zlayne1989@163.com,這個(gè)郵箱地址會(huì)被傳回給server,server往這個(gè)郵箱發(fā)送一封郵件,里面包含一個(gè)鏈接。用戶可以使用app自帶的webview打開網(wǎng)頁版郵箱登錄界面。登錄郵箱后,用戶需要點(diǎn)擊郵件里的鏈接,之后webView會(huì)加載公司主站的網(wǎng)頁并提示驗(yàn)證完成。整個(gè)邏輯并不復(fù)雜,但是在這里出了個(gè)小問題,那就是在顯示公司主站的時(shí)候,顯示為亂碼。跟接口那邊確認(rèn),那邊說是已經(jīng)指定了網(wǎng)頁的編碼形式為GBK,按理說不應(yīng)該出現(xiàn)亂碼的情況。后來將驗(yàn)證鏈接用瀏覽器打開依舊是亂碼,查看瀏覽器的設(shè)置,發(fā)現(xiàn)編碼方式指定為自動(dòng)識(shí)別,網(wǎng)頁被識(shí)別為UTF-8,而并沒有將這個(gè)網(wǎng)頁識(shí)別為GBK。后來發(fā)現(xiàn)是代理無服務(wù)器的問題。因?yàn)楣旧贤饩W(wǎng)都要走2.78的服務(wù)器,通過這種方式會(huì)出現(xiàn)亂碼,而使用自己手機(jī)的3G卻是正常的,所以這個(gè)問題就不需要修改了,不影響產(chǎn)品的使用。雖然是代理服務(wù)器的問題,但未找到根源之前,我嘗試著使用UIWebView來解決編碼問題,所以有了這篇博文。
網(wǎng)站設(shè)計(jì)制作過程拒絕使用模板建站;使用PHP+MYSQL原生開發(fā)可交付網(wǎng)站源代碼;符合網(wǎng)站優(yōu)化排名的后臺(tái)管理系統(tǒng);成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)收費(fèi)合理;免費(fèi)進(jìn)行網(wǎng)站備案等企業(yè)網(wǎng)站建設(shè)一條龍服務(wù).我們是一家持續(xù)穩(wěn)定運(yùn)營了10余年的成都創(chuàng)新互聯(lián)公司網(wǎng)站建設(shè)公司。1、UIWebView加載網(wǎng)頁的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;
第一種最簡單,只有一個(gè)NSURLRequest對(duì)象參數(shù)。第二種和第三種都是用來加載“本地”網(wǎng)頁,這里說的“本地”是指需要用[NSString stringWithContentOfURL:url]等類似方式先從網(wǎng)絡(luò)上加載完成網(wǎng)頁數(shù)據(jù),然后通過這倆函數(shù)將網(wǎng)頁用webView顯示出來。顯示的亂碼的情況是直接使用loadRequest加載網(wǎng)頁。于是我嘗試了用loadHTMLString來替換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)目,我采用了最傻瓜的方式來判斷當(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)頁加載放到另一個(gè)線程里,已防止訪問某些”特殊“的郵箱地址(如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來代替,loadData可以指定編碼方式,也可以指定MIMEType,不過這樣一來如果指定的參數(shù)有誤就會(huì)加載不了網(wǎng)頁了。
3、問題
使用上面的方法會(huì)帶來兩個(gè)問題:
(1)因?yàn)槭孪纫褂胹tringWithContentOfURL預(yù)加載網(wǎng)頁,而這個(gè)函數(shù)不會(huì)走UIWebViewDelegate方法:
- (void)webViewDidStartLoad:(UIWebView *)webView - (void)webViewDidFinishLoad:(UIWebView *)webView - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
所以我們無法監(jiān)測(cè)網(wǎng)頁的預(yù)加載情況:何時(shí)開始、何時(shí)結(jié)束、是否成功。例如,如果url為www.google.com,那么在調(diào)用了stringWithContentOfURL之后程序就可能很久都不會(huì)有任何反應(yīng)(墻...),這也是為什么我使用dispatch_async的原因(界面會(huì)卡死)。
(2)若用上面的方法加載了網(wǎng)頁A,而網(wǎng)頁A中其他超鏈接,這些超鏈接又是不完整的,那么在A頁面點(diǎn)擊其他超鏈接則會(huì)出錯(cuò)。例如網(wǎng)頁A中有
測(cè)試超鏈接
如果網(wǎng)頁A是網(wǎng)址為“www.zlayne.com”,webView使用loadRequest加載的網(wǎng)頁A,那么即使頁面上的超鏈接如上所示,用戶也可以跳轉(zhuǎn)到正確頁面。
但是!若webView是通過loadHTMLString加載的網(wǎng)頁A,前面也說過了loadHTMLString是將網(wǎng)頁預(yù)加載下來轉(zhuǎn)換為string,那么這時(shí)候點(diǎn)擊如上的超鏈接就會(huì)出錯(cuò)。因?yàn)閷?shí)際訪問的網(wǎng)址形如:
applewebdata://9cds-dsdf-96sdo-213pnm/common/test.php
解決這個(gè)問題的思路無非就是獲得當(dāng)前頁面的域名,然后跟后邊的拼接起來組成實(shí)際的網(wǎng)址鏈接沒啥技術(shù)含量。
最后,無意中發(fā)現(xiàn)雙擊webView會(huì)使它變小,行為很怪,具體原因不明。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。