zoukankan      html  css  js  c++  java
  • 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;

     

     

  • 相关阅读:
    Andrew Ng机器学习公开课笔记–Principal Components Analysis (PCA)
    Python For Data Analysis -- Pandas
    Python For Data Analysis -- NumPy
    Python For Data Analysis -- IPython
    Andrew Ng机器学习公开课笔记 – Factor Analysis
    Andrew Ng机器学习公开课笔记 -- Mixtures of Gaussians and the EM algorithm
    Andrew Ng机器学习公开课笔记 -- Online Learning
    Machine Learning in Action -- Support Vector Machines
    HDU-1090-A+B for Input-Output Practice (II)(骗訪问量的)
    五种内部类形式将线程隐藏于类中
  • 原文地址:https://www.cnblogs.com/xsyl/p/5757451.html
Copyright © 2011-2022 走看看