Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 426|回复: 0

iOS8 无缝切换WKWebView,借鉴IMYWebview,解决进度条,cookie,本地页面等问题

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-4-19 10:08:28 | 显示全部楼层 |阅读模式

    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;

     

     

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-16 08:11 , Processed in 0.102756 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表