详解iOS webview加载时序和缓存问题总结

iOS webView的加载时序

UIWebView加载顺序:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {

  NSLog(@"开始请求webview:%@",request.URL.relativeString);
  return YES;

}
 - (void)webViewDidStartLoad:(UIWebView *)webView {
    NSLog(@"开始加载webview");
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
   NSLog(@"结束加载webview");
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(nonnull NSError *)error {
    NSLog(@"webView加载失败");
 }

加载的结果:

2017-04-27 08:53:00.535 H5页面调试[1273:150877] 开始请求webview:http://xxxx/index1.html
2017-04-27 08:53:00.537 H5页面调试[1273:150877] 开始加载webview

-----------------显示开始加载html CSS js 和图片资源等(JS引擎单线程顺序执行)---------------

2017-04-27 08:53:01.069 H5页面调试[1273:150877] 结束加载webview

 WKWebView加载时序:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
  NSLog(@"webview开始请求");
  decisionHandler(WKNavigationActionPolicyAllow);
}
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
  NSLog(@"webView开始加载");
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
  NSLog(@"webview开始收到响应");
  decisionHandler(WKNavigationResponsePolicyAllow);
}

-----------------显示开始加载html CSS js 和图片资源等(JS引擎单线程顺序执行)---------------

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
  NSLog(@"1");
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
  NSLog(@"webview结束加载内容");
}
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error{
  NSLog(@"webview加载失败");
}
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
  NSLog(@"开始重定向的函数");
}
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
  NSLog(@"2");
  completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
}

iOS webView加载html5缓存

1.加载html5的过程

每次加载一个HTML5页面,都会有较多的请求。除了HTML主URL自身的请求外,HTML外部引用的JS、CSS、字体文件、图片都是一个独立的HTTP请求,每一个请求都串行的(可能有连接复用)。

2.设置清除html5页面缓存

html5端设置meta标签:

代码如下:

<meta http-equiv="Pragma" content="no-cache" /><meta http-equiv="Cache-Control" content="no-cache" /><meta http-equiv="Expires" content="0" />

ios:设置加载的网络请求不采用本地缓存和远程缓存

PS:设置上面的只是紧紧可以保证html文件每次从服务器中获取,不从缓存文件中拿,而对于外联CSS JS图片等文件仍旧是从缓存中获取的;

3.设置css JS文件不从缓存中读取

通过添加版本号的和随机数的方法,保证每次加载JS CSS连接都是最新的,通常的做法是添加一个版本号,在每次更新了JS CSS时给版本号+1;保证没有更新时采用缓存文件

有更新可以从服务中获取;

解决方法

1、随机数法

方法一:

document.write( " <script src='test.js?rnd= " + Math.random() + " '></s " + " cript> " )

方法二:

var js = document.createElement( " script " )

js.src = " test.js " + Math.random()

document.body.appendChild(js)

这样采用随机数的话, js文件将永远得不到缓存,每次都必须重新从服务器加载,即使没有任何更改。

大家如果经常上国外网站的话,可以看到他们通常采用这样的方式来解决:

<script src="test.js?ver=113"></script>

其中 ver=113 的 113就是版本号

这样真正做到了应该缓存的时候缓存静态文件,当版本有更新的时候从获取最新的版本,并更新缓存。

对于图像 <img src="test.jps?ver=版本号"> 来有效利用和更新缓存.

4.iOS清除缓存文件

- (void)removeWebCache{
  if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
    NSSet *websiteDataTypes= [NSSet setWithArray:@[
                            WKWebsiteDataTypeDiskCache,
                            //WKWebsiteDataTypeOfflineWebApplication
                            WKWebsiteDataTypeMemoryCache,
                            //WKWebsiteDataTypeLocal
                            WKWebsiteDataTypeCookies,
                            //WKWebsiteDataTypeSessionStorage,
                            //WKWebsiteDataTypeIndexedDBDatabases,
                            //WKWebsiteDataTypeWebSQLDatabases
                            ]];

    // All kinds of data
    //NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes];
    NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{

    }];
    [[NSURLCache sharedURLCache] removeAllCachedResponses];

  } else {
    //先删除cookie
    NSHTTPCookie *cookie;
    NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (cookie in [storage cookies])
    {
      [storage deleteCookie:cookie];
    }

    NSString *libraryDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *bundleId = [[[NSBundle mainBundle] infoDictionary]
                objectForKey:@"CFBundleIdentifier"];
    NSString *webkitFolderInLib = [NSString stringWithFormat:@"%@/WebKit",libraryDir];
    NSString *webKitFolderInCaches = [NSString
                     stringWithFormat:@"%@/Caches/%@/WebKit",libraryDir,bundleId];
    NSString *webKitFolderInCachesfs = [NSString
                      stringWithFormat:@"%@/Caches/%@/fsCachedData",libraryDir,bundleId];
    NSError *error;
    /* iOS8.0 WebView Cache的存放路径 */
    [[NSFileManager defaultManager] removeItemAtPath:webKitFolderInCaches error:&error];
    [[NSFileManager defaultManager] removeItemAtPath:webkitFolderInLib error:nil];
    /* iOS7.0 WebView Cache的存放路径 */
    [[NSFileManager defaultManager] removeItemAtPath:webKitFolderInCachesfs error:&error];
    NSString *cookiesFolderPath = [libraryDir stringByAppendingString:@"/Cookies"];
    [[NSFileManager defaultManager] removeItemAtPath:cookiesFolderPath error:&error];
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
  }
}

关于保存在沙盒中的缓存文件如下图:

5.针对UIWebView出现的内存泄漏方法(网上)

  - (void)webViewDidFinishLoad:(UIWebView *)webView
  {
    //防止内存泄漏
    [[NSUserDefaults standardUserDefaults] setInteger:0 forKey:@"WebKitCacheModelPreferenceKey"];
    //本地webkit硬盘图片的缓存;
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDiskImageCacheEnabled"];//自己添加的,原文没有提到。
    //静止webkit离线缓存
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitOfflineWebApplicationCacheEnabled"];//自己添加的,,原文没有提到。
    [[NSUserDefaults standardUserDefaults] synchronize];
  }

  - (void)dealloc
  {
    [webView loadHTMLString:@"" baseURL:nil];
    [webView stopLoading];
    [webView removeFromSuperview];
    webView = nil;
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
    [[NSURLCache sharedURLCache] setDiskCapacity:0];
    [[NSURLCache sharedURLCache] setMemoryCapacity:0];
    NSLog(@"释放了webview");
  }

  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
     int cacheSizeMemory = 4*1024*1024; // 4MB int      

     cacheSizeDisk = 32*1024*1024; // 32MB
     NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
     [NSURLCache setSharedURLCache:sharedCache];
  }
  - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
     [[NSURLCache sharedURLCache] removeAllCachedResponses];
  }

PS:经测试好像没什么卵用,先放在这里反正写了也没什么坏处

确定

1.如果没有CDN缓存影响;每次杀死APP后重新进入,第一次加载webview,都会加载全部的数据资源(外联js,外联css,图片等)退出去后,如果在没有更新js,css内容时,默认只会加载html内容,PS:html中的内容 在每次加载webView中都会从服务器中更新一下;

2.如果js css后面都添加了版本号,那么在每次更新版本号时,或者说资源链接变化时,webView一定会重新加载新的内容;如下图

<script type="text/javascript" src="index1.js?v=1.0.0"></script>

疑问?

1.经测试发现,JS CSS没有加版本号,更新JS CSS的内容有时候也会及时从服务器中更新获取,大多数时候又不会更新;不知道是不是跟web服务器的缓存策略有关,还是文件超期了?还是CDN缓存有关?

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Swift使用WKWebView在iOS应用中调用Web的方法详解

    自从iOS8开始,Apple引入了WKWebView欲代替UIWebView.相比而言,WKWebView消耗内从更少,功能也更加强大.让我们来看看WKWebView怎么使用吧! 0.初始化 (1)首先需要引入WebKit库 复制代码 代码如下: #import <WebKit/WebKit.h> (2)初始化方法分为以下两种 复制代码 代码如下: // 默认初始化 - (instancetype)initWithFrame:(CGRect)frame; // 根据对webview的相关配置,

  • iOS 对当前webView进行截屏的方法

    UIWebView和WKWebView的截屏有所区别: UIWebView: func getImage(context: ServiceExecuteContext) -> UIImage { //创建一个基于位图的图形上下文并指定大小 UIGraphicsBeginImageContextWithOptions(context.fromViewController.webView.bounds.size, true, 0) //renderInContext呈现接受者及其子范围到指定的上下文

  • IOS中UIWebView加载Loading的实现方法

    第一种方法:使用UIView and UIActivityIndicatorView 复制代码 代码如下: //创建UIWebView WebView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 44, 320, 400)]; [WebView setUserInteractionEnabled:NO]; [WebView setBackgroundColor:[UIColor clearColor]]; [WebView setDelega

  • ios开发加载webview显示进度条实例

    很多APP加载webView页面的时候都有进度条显示,今天我们这里主要使用相对轻量级的WKWebView加载网页,至于WKWebView 和UIWebView的区别与联系这里就不多讲了,自己百度哈哈... WKWebView加载网页进度跳显示主要效果如下: 这里主要是使用KVO监听WKWebView的"estimatedProgress"属性,通过监听该属性的变化才是进度条的长度. 1.定义便利构造函数.以及属性和控件 var url: String? var progresslaye

  • 详解iOS webview加载时序和缓存问题总结

    iOS webView的加载时序 UIWebView加载顺序: - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSLog(@"开始请求webview:%@",request.URL.relativeString); return YES; } -

  • 详解Android Webview加载网页时发送HTTP头信息

    详解Android Webview加载网页时发送HTTP头信息 当你点击一个超链接进行跳转时,WebView会自动将当前地址作为Referer(引荐)发给服务器,因此很多服务器端程序通过是否包含referer来控制盗链,所以有些时候,直接输入一个网络地址,可能有问题,那么怎么解决盗链控制问题呢,其实在webview加载时加入一个referer就可以了,如何添加呢? 从Android 2.2 (也就是API 8)开始,WebView新增加了一个接口方法,就是为了便于我们加载网页时又想发送其他的HT

  • 详解Android WebView加载html片段

    这里我先简单描述一下需求:服务器返回的是html页面的一部分带有标签的内容. 解决的思路是:将服务器返回的内容片段拼凑成一个完整的页面. 下面直接上核心代码: 这里是WebView一些配置 WebSettings settings = webView.getSettings(); settings.setJavaScriptEnabled(true); settings.setDomStorageEnabled(true); settings.setUseWideViewPort(true);

  • 详解JS异步加载的三种方式

    一:同步加载 我们平时使用的最多的一种方式. <script src="http://yourdomain.com/script.js"></script> <script src="http://yourdomain.com/script.js"></script> 同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止后续的解析,只有当当前加载完成,才能进行下一步操作.所以默认同步执行才是安全的.但这样如果js中有输

  • 详解Spring ApplicationContext加载过程

    1.找准入口,使用ClassPathXmlApplicationContext的构造方法加载配置文件,用于加载classPath下的配置文件 //第一行,执行完成之后就完成了spring配置文件的加载,刷新spring上下文 ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext( "classpath:spring-mvc.xml"); //获取实例Bean Person person=con

  • 详解Android布局加载流程源码

    一.首先看布局层次 看这么几张图 我们会发现DecorView里面包裹的内容可能会随着不同的情况而变化,但是在Decor之前的层次关系都是固定的.即Activity包裹PhoneWindow,PhoneWindow包裹DecorView.接下来我们首先看一下三者分别是如何创建的. 二.Activity是如何创建的 首先看到入口类ActivityThread的performLaunchActivity方法: private Activity performLaunchActivity(Activi

  • 详解Qt如何加载libxl库

    使用工具 1.Qt 5.12.3集成开发环境 2.libxl-3.9.4.3(官方下载地址:https://www.libxl.com/download.html) 提示:以下是本篇文章正文内容,下面案例可供参考 一.如何导入libxl库 由于官方给出的教程是MinGW32导入动态库我这边也照着导入libxl的32位动态库,使用MinGW64开发环境同理,如果qt使用的是mvsc环境的朋友可以不用参考此教程 1.pro文件导入静态链接库 1.把lib32.dll文件路径放入到pro文件中: LI

  • Spring详解四种加载配置项的方法

    目录 1.spring加载yml文件 2.spring 加载 properties 文件 3.spring加载系统磁盘(properties)文件 4.spring加载xml文件 5.Java基于InputStream读取properties配置文件 本文默认 spring 版本是 spring5 1 spring 加载 yml 文件 2 spring 加载 properties 文件 3 spring 加载 系统磁盘 文件 4 spring 加载 xml 文件 5 Java 基于 InputS

  • 详解Vue3如何加载动态菜单

    目录 1. 整体思路 2. 实现细节 2.1 加载细节 2.2 getInfo 2.3 generateRoutes 1. 整体思路 首先我们来梳理下整体上的实现思路,首先一点:整体思路和 vhr 一模一样. 考虑到有的小伙伴可能已经忘记 vhr 中前端动态菜单的实现思路了,因此本文再和大家分析一下. 为了确保在所有的 .vue 文件中都能访问到到菜单数据,所以选择将菜单数据存入 vuex 中,vuex 是 vue 中一个存储数据的公共地方,所有的 .vue 文件都可以从 vuex 中读取到数据

  • 详解Vue-Cli 异步加载数据的一些注意点

    刚开始学vue的时候没有使用脚手架,现在用脚手架写法有点不同,今天遇到的问题是使用豆瓣api异步加载数据的时候,会一直在命令行上报错,基本上错误都是xxx 未定义. 例子 <template> <div v-if="moviesData"> <!-- 正在上映的电影-北京 --> <h1>{{ moviesData.title }}</h1> </div> </template> <script&

随机推荐