iOS8 無縫切換WKWebView,借鑒IMYWebview,解決進度條,cookie,本地頁面等問題


webkit使用WKWebView來代替IOS的UIWebView和OSX的WebView,並且使用Nitro JavaScript引擎,這意味着所有第三方瀏覽器運行JavaScript將會跟safari一樣快。


第一、WKWebView增加的屬性和方法
類比UIWebView,跟UIWebView的API對比,
增加的屬性
1、estimatedProgress 加載進度條,在IOS8之前我們是通過一個假的進度條來實現
2、backForwardList 表示historyList
3、WKWebViewConfiguration *configuration; 初始化webview的配置
增加的方法
1、- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration 
初始化
3、(WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item; 
跳到歷史的某個頁面
第二、相同的屬性和方法
goBack、goForward、canGoBack、canGoForward、stopLoading、loadRequest、scrollView
第三、被刪去的屬性和方法:
1、- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
在跟js交互時,我們使用這個API,目前WKWebView完檔沒有給出實現類似功能的API
2、無法設置緩存
在UIWebView,使用NSURLCache緩存,通過setSharedURLCache可以設置成我們自己的緩存,但WKWebView不支持NSURLCache
第四、delegate方法的不同
UIWebView支持的代理是UIWebViewDelegate,WKWebView支持的代理是WKNavigationDelegate和WKUIDelegate
WKNavigationDelegate主要實現了涉及到導航跳轉方面的回調方法
WKUIDelegate主要實現了涉及到界面顯示的回調方法:如WKWebView的改變和js相關內容
具體來說WKNavigationDelegate除了有開始加載、加載成功、加載失敗的API外,還具有額外的三個代理方法:
1、- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
這個代理是服務器redirect時調用
2、- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
這個代理方法表示當客戶端收到服務器的響應頭,根據response相關信息,可以決定這次跳轉是否可以繼續進行。
3.- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler

根據webView、navigationAction相關信息決定這次跳轉是否可以繼續進行,這些信息包含HTTP發送請求,如頭部包含User-Agent,Accept

 

 

個人補充:

無縫切換網頁:  https://github.com/li6185377/IMYWebView/tree/master/IMYWebView

切換是遇到的坑:進度條的問題/cookie/ios8.0加載本地網頁的處理!

/**

 *  將文件copytmp目錄(wk打開本地網頁的解決方法 8.0wkwebview8.0系統,不支持加載本地html頁面,所以需要用以下方法修復!!

 *

 *  @param fileURL fileURL

 *

 *  @return

 */

- (NSURL *)fileURLForBuggyWKWebView8:(NSURL *)fileURL {

    

    NSError *error = nil;

    if (!fileURL.fileURL || ![fileURL checkResourceIsReachableAndReturnError:&error]) {

        return nil;

    }

    // Create "/temp/www" directory

    NSFileManager *fileManager= [NSFileManager defaultManager];

    NSURL *temDirURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:@"www"];

    [fileManager createDirectoryAtURL:temDirURL withIntermediateDirectories:YES attributes:nil error:&error];

    

    // 取到本地html后的錨點

    NSString *lastPathComponent = [[fileURL.absoluteString componentsSeparatedByString:@"/"] lastObject];

    

    NSURL *dstURL = [NSURL URLWithString:[temDirURL.absoluteString stringByAppendingString:lastPathComponent]];

    // Now copy given file to the temp directory

    [fileManager removeItemAtURL:dstURL error:&error];

    [fileManager copyItemAtURL:fileURL toURL:dstURL error:&error];

    // Files in "/temp/www" load flawlesly :)

    return dstURL;

}

 

/**

 *  打開本地網頁

 *

 *  @param url

 */

- (void)loadLocalPath:(NSString *)path {

    

    if(path){

        

        if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {

            

            // iOS9. One year later things are OK.

            NSURL *fileURL = [NSURL URLWithString:[NSString stringWithFormat:@"file://%@",path]];

            [self loadRequest:[NSURLRequest requestWithURL:fileURL]];

            

        } else if ([[UIDevice currentDevice].systemVersion floatValue] < 8.0) {

            // iOS8.0 以下的 走普通UIWebview

            NSURL *fileURL = [NSURL URLWithString:[NSString stringWithFormat:@"file://%@",path]];

            NSURLRequest *request = [NSURLRequest requestWithURL:fileURL];

            [self loadRequest:request];

            

        } else {

            // iOS8. Things can be workaround-ed

            //   Brave people can do just this

            //   fileURL = try! pathForBuggyWKWebView8(fileURL)

            //   webView.loadRequest(NSURLRequest(URL: fileURL))

            NSURL *fileURL = [self fileURLForBuggyWKWebView8:[NSURL URLWithString:[NSString stringWithFormat:@"file://%@",path]]];

            NSURLRequest *request = [NSURLRequest requestWithURL:fileURL];

            [self loadRequest:request];

        }

    }

}

cookie的添加:

wkwebview 和http不共享cookie,所以在請求的時候拿不到cookie!
 
 
所以在loadRequset的時候需要給請求設置cookie
{
        NSMutableURLRequest *requestNew = [NSMutableURLRequest requestWithURL:request.URL];
        [requestNew addValue:[YZTWebView readCurrentCookie:request.URL] forHTTPHeaderField:@"Cookie"];
        return [(WKWebView *)self.realWebView loadRequest:requestNew];
}
 
但是還存在一個問題,cookie只會設置一次,假如網頁間的跳轉用到了ajax,這樣cookie就會失效,需要需要在wk的didFinishNavigation方法中手動編寫js代碼去設置cookie!
還需要注意的問題就是js寫的cookie需要設定path。path不同的話cookie也設置不了!
/**
 *  wkwebview 加載完成
 */
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    
    //取出cookie
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    //js函數
    NSString *JSFuncString =
    @"function setCookie(name,value,expires)\
    {\
    var oDate=new Date();\
    oDate.setDate(oDate.getDate()+expires);\
    document.cookie=name+'='+value+';expires='+oDate+';path=/'\
    }\
    function getCookie(name)\
    {\
    var arr = document.cookie.match(new RegExp('(^| )'+name+'=([^;]*)(;|$)'));\
    if(arr != null) return unescape(arr[2]); return null;\
    }\
    function delCookie(name)\
    {\
    var exp = new Date();\
    exp.setTime(exp.getTime() - 1);\
    var cval=getCookie(name);\
    if(cval!=null) document.cookie= name + '='+cval+';expires='+exp.toGMTString();\
    }";
    
    //拼湊js字符串
    NSMutableString *JSCookieString = JSFuncString.mutableCopy;
    for (NSHTTPCookie *cookie in cookieStorage.cookies) {
        NSString *excuteJSString = [NSString stringWithFormat:@"setCookie('%@', '%@', 1);", cookie.name, cookie.value];
        [JSCookieString appendString:excuteJSString];
    }
    //執行js
    [webView evaluateJavaScript:JSCookieString completionHandler:nil];
    
    [self callback_webViewDidFinishLoad];
}
 
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
    NSArray *cookies =[NSHTTPCookiecookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
   
    for (NSHTTPCookie *cookie in cookies) {
        [[NSHTTPCookieStoragesharedHTTPCookieStorage] setCookie:cookie];
    }
   
    decisionHandler(WKNavigationResponsePolicyAllow);
}
 
進度條問題:
WKWeb和UIWeb使用進度條的時候用estimatedProgress ,這個屬性是Wk獨有的,但是UIWeb的時候也給這個值去賦值,這樣就可以一起使用這個屬性,在控制器中去用kvo檢測這個值!
 
WK中檢測進度條的方法:
/**
 *  kvo 觀察進度/標題 wkwebview 進度條需要添加觀察者
 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
   
    if([keyPath isEqualToString:@"estimatedProgress"]) {
       
        self.estimatedProgress = [change[NSKeyValueChangeNewKey] doubleValue];
    } elseif([keyPath isEqualToString:@"title"]) {
       
        self.title = change[NSKeyValueChangeNewKey];
    }
 
UIWe
/**
 *  進度代理方法
 *
 *  @param webViewProgress webViewProgress
 *  @param progress        progress
 */
- (void)webViewProgress:(NJKWebViewProgress *)webViewProgress updateProgress:(float)progress {
   
    // 先進行判斷,如果變化小於傳遞過來的值則賦值,因為有可能出現小於的情況
    if (self.estimatedProgress <= progress) {
        // 讓UIWebview的進度條也用此賦值
        self.estimatedProgress = progress;
    }
 
 
然后在外部的控制器去kvo檢測。
坑:
在控制器的did finish中:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    NSLog(@"webview開始完成");
    [selfupdateNaviLeftButtton];
    [self.webViewresetWebView];

    // 只有UIWebview 加載本地html的時候會出現網頁加載完成,但是進度條不足1.0的情況,所以在完成方法中特別手動設置一下!
    // 判斷是否是加載本地網頁,本地網頁沒有http
    BOOL hasHttp = [[self.webView.URLabsoluteString] hasPrefix:@"http"];
    if (IOS_VERSION < 8.0 && !hasHttp) {
        self.webView.estimatedProgress = 1.0f;
    }
   
    _isFinish = YES;
}
 

 #warning  默認設置就是NO。在ios8系統中會導致手勢問題,程序崩潰

self.allowsBackForwardNavigationGestures =YES;

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM