解决web view白屏问题

2018-03-20  本文已影响401人  huicuihui
问题描述:

点击文章列表进入文章详情,会有几秒显示空白页面,之后才是加载请求数据。加载请求数据显示加载动画,这段时间是可以接受的。主要矛盾是解决加载动画显示之前的白屏问题。

解决方法:

把页面文件保存到本地, 加载的时候,加载本地的,因为文章详情里面html文件代码都一样,框架都是那样的。只要后台那边不改代码,一般情况下都不变,所以把那个文件存到本地,以后都读本地读文件即可。不用去请求服务器,不再受服务器响应速度影响。

代码如下:

在加载webView的时候改为下面方法:
- (void)loadHtml {
    NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
   NSString *path = [cachesPath stringByAppendingString:[NSString stringWithFormat:@"/Caches/%lu.html",[@"huancunwenzhang" hash]]];
   NSString *htmlString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

//有缓存
    if (!(htmlString == nil || [htmlString isEqualToString:@""])) {
        [_wkWebview loadHTMLString:htmlString baseURL:[NSURL URLWithString:self.urlString]];
    }
//没缓存
 else {
        NSURL *url = [NSURL URLWithString:self.urlString];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [_wkWebview loadRequest:request];
//没有缓存需要缓存
        [self writeToCache];
    }
}

注还有优化的地方:
可以把上面htmlString读取到内存中,常驻内存中,app运行时使用同一个。减少一点读取文件的时间。

将html文件保存到本地:
- (void)writeToCache {
//@"https://app.ningmengyun.com/news/newsDetail.html" 是html文件路径,后面不需要加某篇文章id等参数。
    NSString *htmlResponseStr = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"https://app.ningmengyun.com/news/newsDetail.html"] encoding:NSUTF8StringEncoding error:nil];

    //创建文件管理器
    NSFileManager *fileManager = [NSFileManager defaultManager];
    //获取document路径
    NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    [fileManager createDirectoryAtPath:[cachesPath stringByAppendingString:@"/Caches"] withIntermediateDirectories:YES attributes:nil error:nil];
    //写入路径
    NSString *path = [cachesPath stringByAppendingString:[NSString stringWithFormat:@"/Caches/%lu.html",[@"huancunwenzhang" hash]]];
    [htmlResponseStr writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
}

设置html文件过期时间

在请求数据的时候,header中有一个过期时间。

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;

在上面方法中打印navigationResponse可以看到header。

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
    NSString *cacheControl = [(NSHTTPURLResponse*)navigationResponse.response allHeaderFields][@"Cache-Control"]; // max-age, must-revalidate, no-cache
    NSArray *cacheControlEntities = [cacheControl componentsSeparatedByString:@","];

    for(NSString *substring in cacheControlEntities) {
        
        if([substring rangeOfString:@"max-age"].location != NSNotFound) {
            
            // do some processing to calculate expiresOn
            NSString *maxAge = nil;
            NSArray *array = [substring componentsSeparatedByString:@"="];
            if([array count] > 1)
                maxAge = array[1];
            
           NSDate * expiresOnDate = [[NSDate date] dateByAddingTimeInterval:[maxAge intValue]];
        }
    }
    decisionHandler(WKNavigationResponsePolicyAllow);
}

问题:
当后台那边对html文件进行了修改之后,app内html文件还没到过期时间,那么就会出请求不到数据等等问题。
解决方法:
可以只请求该url地址的header头, 请求的数据也不多,响应相应的比其他的请求快些。
对应的代码如下:

/**
 请求header,获取头部的信息。
 */
- (void)requestWebViewHeader:(void (^)(BOOL isLoadCache))block {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager HEAD:self.urlString parameters:nil success:^(NSURLSessionDataTask * _Nonnull task) {
        NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
        if ([[userDefaults objectForKey:kHtml_lastModified] isEqual:[(NSHTTPURLResponse*)task.response allHeaderFields][@"Last-Modified"]]) {
            block(YES);
        } else {
            block(NO);
            [[NSUserDefaults standardUserDefaults] setObject:[(NSHTTPURLResponse*)task.response allHeaderFields][@"Last-Modified"] forKey:kHtml_lastModified];
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"%@",error);
        block(YES);
    }];
}
控制台输出:
(lldb) po task.response
<NSHTTPURLResponse: 0x60400082f480> { URL: http://apptest.ningmengyun.com/news/newsDetail.html?ArticleID=1159&withNavigationBar=true } { Status Code: 200, Headers {
    "Accept-Ranges" =     (
        bytes
    );
    "Content-Encoding" =     (
        gzip
    );
    "Content-Length" =     (
        1353
    );
    "Content-Type" =     (
        "text/html"
    );
    Date =     (
        "Mon, 23 Apr 2018 04:06:18 GMT"
    );
    Etag =     (
        "\"809d9cf9cbd7d31:0\""
    );
    "Last-Modified" =     (
        "Thu, 19 Apr 2018 10:48:39 GMT"
    );
    Server =     (
        "Microsoft-IIS/7.5"
    );
    Vary =     (
        "Accept-Encoding"
    );
    "X-Powered-By" =     (
        "ASP.NET"
    );
} }

(lldb) po lastModified
Thu, 19 Apr 2018 10:48:39 GMT

(lldb) 

关于url的问题:

点击每条文章,传入的url为https://app.ningmengyun.com/news/newsDetail.html?ArticleID=1034,其中的ArticleID为每条文章的id,但是缓存html和请求header头的时候不需要整个url,只需要前面的地址即可。参数都不需要。即:https://app.ningmengyun.com/news/newsDetail.html

请求头的参考:
https://blog.csdn.net/u013583789/article/details/52129316

上一篇 下一篇

猜你喜欢

热点阅读