標籤:
不久之前,項目中用到了UIWebView載入js的功能,之前使用webView都是簡單使用,沒考慮很多與js互動的地方,雖然現在項目完成了,但是回頭看看這方面的知識還是有些茫然,在此記錄一點,然後後續如果有用更多的話再來進行補充。
需求
封裝個view,提供給開發人員使用,暴露兩個方法以供調用:
1、是調用initWithXXX進行初始化位置等等參數配置;
2、調用loadH5PageWithSuccessBlock:failureBlock:讓view中的webView載入H5頁面顯示出來即可。
其主要實現就是webView載入一個URL的過程,給開發人員一個載入失敗和完成的回調。
UIWebView的代理方法
1、首先實現的是UIWebView的shouldStartLoadWithRequest:navigationType:代理方法
註:對於返回的是unicode編碼的字串,用 stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding 進行返回UTF8編碼的字串。
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSLog(@"URL : %@", [request.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]); // click event if ([request.URL.host isEqualToString:@"call_close"]) {// notify click close if (self.gh_clickCloseBlock) { self.gh_clickCloseBlock(webView, request.URL.absoluteString); } [self stopTimer:self.loadStatusCheckTimer]; return NO; } if ([request.URL.host isEqualToString:@"on_click"]) { NSString *URL_String = [request.URL.path substringFromIndex:1]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:URL_String]]; // notify click content if (self.gh_clickBlock) { self.gh_clickBlock(webView, URL_String); } return NO; } return YES;}
如果上述回調中返回YES,那麼webView會進行載入html頁面,執行 webViewDidStartLoad: 回調。
每次在頁面中的點擊都可能會“截獲”該URL,並會再次調用上述回調,那麼通過URL的scheme和host就可以判斷是什麼動作事件,
例如:
如果是host為“call_close”,則可以做一些關閉的操作:移除view,停止定時器等,並添加關閉頁面的block回調給開發人員。
如果是host為“on_click”,則可以添加點擊頁面內容的block回調給開發人員。
2、開始載入的回調
- (void)webViewDidStartLoad:(UIWebView *)webView { NSLog(@"start, %d", webView.loading);}
3、如果載入失敗的話會調用 didFailLoadWithError:
頁面載入逾時等失敗的時機回調給開發人員,但是對於請求中HTTP的狀態代碼error的時候並不能判斷出來,
對於這部分具體可以用NSURLConnection判斷response的statusCode,如果是400以上即可回調失敗,如果是成功響應再允許webView載入這個URL,
我們可以只要response,不需要receiveData,所以在得到response之後將connection cancel掉。
參考相關:http://stackoverflow.com/questions/1061364/how-do-i-get-the-last-http-status-code-from-a-uiwebview
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { NSLog(@"failure : %@", error.description); // page載入失敗的callBack if (self.gh_loadFailBlock) { self.gh_loadFailBlock(webView, error.code); }}
4、page載入完成的回調,啟動定時器進行檢查,不斷擷取js中關於image的載入狀態,以便擷取回調時機。
- (void)webViewDidFinishLoad:(UIWebView *)webView { NSLog(@"finish, %d", webView.loading); [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect=‘none‘;"]; [webView stringByEvaluatingJavaScriptFromString:@"document.body.style.webkitTouchCallout=‘none‘;"]; if(!injectedPageLoadedJS) { injectedPageLoadedJS = YES; [self stopTimer:self.loadStatusCheckTimer]; self.loadStatusCheckTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(checkLoadStatus:) userInfo:nil repeats:YES]; }}
載入html的時候,我們的js會執行對url進行請求的操作,其中會有請求image資源,但是在webView這裡,當html這個page載入完成時就會調用finish回調,如果載入H5頁面的成功回調寫在這裡,可能會出現js還沒有成功請求到圖片資源渲染到頁面上,你已經回調開發人員載入成功。所以期間從finish到image非同步請求完成,中間有段時間需要等待。
解決方式是在頁面載入完成finish之後,通過NSTimer不斷地去擷取js載入image狀態的傳回值,直到擷取成功的傳回值,做出給開發人員的block。
與js簡單互動
和前端協商將js中標示image非同步請求成功的變數定為window.__loadImageStatus__; 這樣js在拿到image請求成功的回調之後,會將此變數賦值為imgLoaded,這個js的值可以通過webView的stringByEvaluatingJavaScriptFromString:方法的傳回值拿到。
何時去取到這個值,需要在webView載入完html頁面時finish回調之後取,可以添加一個定時器,每隔0.5s中通過stringByEvaluatingJavaScriptFromString:拿到傳回值,判斷是否是imgLoaded,如果是,說明此時圖片非同步載入成功,圖片已經展示,在此可以作為給開發人員的成功回調。
- (void)checkLoadStatus:(NSTimer *)timer { NSString *evalString = [_webH5View stringByEvaluatingJavaScriptFromString:@"window.__loadImageStatus__;"]; NSLog(@"+++++js 返回的status值:%@", evalString); if([evalString isEqualToString:@"imgLoaded"]) { //Web page has finished. Shut down the timer. [self stopTimer:timer]; injectedPageLoadedJS = NO; NSLog(@"成功擷取到imgLoaded,js將image load 完成的回調值發給");// 成功回調 if (self.gh_loadAdSuccessBlock) { self.gh_loadAdSuccessBlock(_webH5View, _request.URL.absoluteString); } self.count = 0; } else { if (self.count > 10) { [self stopTimer:timer]; } else { self.count += 1; } }}
註:最好添加一個計數器,當10次(也就是5s)還沒有擷取到js關於image載入成功的傳回值,就可以將timer等相關對象移除,避免長時間等待,影響互動體驗。
iOS中UIWebView的一個需求:獲得js圖片請求完成的回調時機