iOS WKWebView基本使用总结

转自: http://yoursite.com/2018/06/11/WKWebView/

UIWebView废弃,迁移WKWebView

WWDC 2018中 ,在安全方面,Session上来就宣布了一件重量级的大事,UIWebView正式被官方宣布废弃,建议开发者迁移适配到WKWebView。

在XCode9中UIWebView还是 NS_CLASS_AVAILABLE_IOS(2_0),而我们从最新的Xcode10再看UIWebView就已经是这个样子了

UIKIT_EXTERN API_DEPRECATED("No longer supported; please adopt WKWebView.", ios(2.0, 12.0)) API_PROHIBITED(tvos, macos) @interface UIWebView : UIView <NSCoding, UIScrollViewDelegate>

WKWebView从诞生之初相比UIWebView有太多的优势,无论是内存泄露还是网页性能,并且WKWebView可以同时支持macOS与iOS。由于WKWebView的独特设计,网页运行在独立的进程,如果网页遇到Crash,不会影响App的正常运行。

但是WKWebView不支持JSContext,不支持NSURLProtocol,Cookie管理蛋疼等问题确实给让不少开发者不想丢弃UIWebView,但最后通牒来了还是准备着手替换吧。

下面的一些方法均是看了许多大神的博客后总结到一起的,自己并未一一验证,后续发现错误会去纠正。

WKWebView的特点

  • 性能高,稳定性好,占用的内存比较小,
  • 支持JS交互
  • 支持HTML5 新特性
  • 可以添加进度条(然并卵,不好用,还是习惯第三方的)。
  • 支持内建手势,
  • 据说高达60fps的刷新频率(不卡)

初始化WKWebView

一、先导入头文件 #import <WebKit/WebKit.h>

二、WKWebView创建

WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
   config.selectionGranularity = WKSelectionGranularityDynamic;
   config.allowsInlineMediaPlayback = YES;
   WKPreferences *preferences = [WKPreferences new];
   //是否支持JavaScript
   preferences.javaScriptEnabled = YES;
   //不通过用户交互,是否可以打开窗口
   preferences.javaScriptCanOpenWindowsAutomatically = YES;
   config.preferences = preferences;
   self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:config];
   [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.baidu.com/"]]];
   self.webView.navigationDelegate = self;
   self.webView.UIDelegate = self;
   //开了支持滑动返回
   self.webView.allowsBackForwardNavigationGestures = YES;
   [self.view addSubview:self.webView];
   
   [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
   [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];

 

  • WKWebViewConfiguration 用于配置WKWebView的一些属性
  • WKPreferences 用于配置WKWebView视图的一些属性
  • 加上<WKNavigationDelegate, WKUIDelegate>两个代理

三、WKNavigationDelegate代理事件

// 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
    NSLog(@"页面开始加载时调用");
}
// 当内容开始返回时调用 内容开始到达主帧时被调用(即将完成)
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
    NSLog(@"当内容开始返回时调用");
}
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {//这里修改导航栏的标题,动态改变
    self.title = webView.title;
    NSLog(@"页面加载完成之后调用");   
}

// 在收到响应后,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
    
//    NSLog(@"webView==%@",webView);
//    NSLog(@"navigationResponse==%@",navigationResponse);
    
    WKNavigationResponsePolicy actionPolicy = WKNavigationResponsePolicyAllow;
    //这句是必须加上的,不然会异常
    decisionHandler(actionPolicy);
    
}
// 在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    
    self.title = webView.title;
    
    WKNavigationActionPolicy actionPolicy = WKNavigationActionPolicyAllow;
    
    if (navigationAction.navigationType == WKNavigationTypeBackForward) {//判断是返回类型
        
        //同时设置返回按钮和关闭按钮为导航栏左边的按钮 这里可以监听左滑返回事件,仿微信添加关闭按钮。
//        self.navigationItem.leftBarButtonItems = @[self.backBtn, self.closeBtn];
        
        //可以在这里找到指定的历史页面做跳转
        //        if (webView.backForwardList.backList.count>0) {                                  //得到栈里面的list
        //            DLog(@"%@",webView.backForwardList.backList);
        //            DLog(@"%@",webView.backForwardList.currentItem);
        //            WKBackForwardListItem * item = webView.backForwardList.currentItem;          //得到现在加载的list
        //            for (WKBackForwardListItem * backItem in webView.backForwardList.backList) { //循环遍历,得到你想退出到
        //                //添加判断条件
        //                [webView goToBackForwardListItem:[webView.backForwardList.backList firstObject]];
        //            }
        //        }
    }
    
    NSLog(@"webView.backForwardList.backList.count==%lu",(unsigned long)webView.backForwardList.backList.count);
    
    if (webView.backForwardList.backList.count > 0) {
        self.navigationItem.leftBarButtonItems = @[self.backBtn, self.closeBtn];
    }else {
        self.navigationItem.leftBarButtonItems = nil;
    }
    
    //这句是必须加上的,不然会异常
    decisionHandler(actionPolicy);
}

//MARK: 以下为不常用的

// 接收到服务器跳转请求之后再执行
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"接收到服务器跳转请求之后再执行");
}

// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"页面加载失败时调用");
}

//在提交的主帧中发生错误时调用
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
    NSLog(@"在提交的主帧中发生错误时调用");
}

//当webView需要响应身份验证时调用(如需验证服务器证书)
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable   credential))completionHandler {
//    NSLog(@"当webView需要响应身份验证时调用(如需验证服务器证书)");
//    completionHandler(nil,nil);
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        
        NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
        
        completionHandler(NSURLSessionAuthChallengeUseCredential,card);
        
    }
}

//当webView的web内容进程被终止时调用。(iOS 9.0之后)
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0)) {
    NSLog(@"当webView的web内容进程被终止时调用。(iOS 9.0之后)");
}

四、WKUIDelegate代理事件,主要实现与js的交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//显示一个JS的Alert(与JS交互) 在JS端调用alert函数时,会触发此代理方法
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {

    NSLog(@"弹窗alert====message==%@==frame==%@",message,frame);

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *a2 = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }];
    [alert addAction:a2];

    [self presentViewController:alert animated:YES completion:nil];
    
//    completionHandler();

}

//弹出一个输入框(与JS交互的)JS端调用prompt函数时,会触发此方法
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
    
    NSLog(@"弹窗输入框==prompt==%@==defaultText==%@==frame==%@",prompt,defaultText,frame);
    
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:prompt message:defaultText preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *a1 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        //这里必须执行不然页面会加载不出来
        completionHandler(@"");
    }];
    UIAlertAction *a2 = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        NSLog(@"%@",[alert.textFields firstObject].text);
        completionHandler([alert.textFields firstObject].text);
    }];
    [alert addAction:a1];
    [alert addAction:a2];
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        NSLog(@"textField.text==%@",textField.text);
    }];
    [self presentViewController:alert animated:YES completion:nil];
    
}

//显示一个确认框(JS的) JS端调用confirm函数时,会触发此方法
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    
    NSLog(@"弹窗确认框==message==%@==frame==%@",message,frame);
    
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }];
    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }];
    [alertController addAction:cancelAction];
    [alertController addAction:okAction];
    [self presentViewController:alertController animated:YES completion:nil];
    
}

五、JS调用OC方法

  • 在JS中调用方法为:

window.webkit.messageHandlers.方法名.postMessage(参数);

  • 在OC中:
1
2
3
4
5
6
   //设置addScriptMessageHandler与name.并且设置<WKScriptMessageHandler>协议与协议方法
   [[_webView configuration].userContentController addScriptMessageHandler:self name:@"takePicturesByNative"];

//在dealloc方法中需要释放掉
   [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"takePicturesByNative"];
  • 在WKScriptMessageHandler中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    if ([message.name isEqualToString:@"takePicturesByNative"]) {
        [self takePicturesByNativeWithBody:message.body];
    }
}
- (void)takePicturesByNativeWithBody:(NSString *)body {
    NSLog(@"调用了takePicturesByNative方法");
    
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:body preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *a1 = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

    }];
    [alert addAction:a1];
    
    [self presentViewController:alert animated:YES completion:nil];
    
}

在使用上述方法中发现,addScriptMessageHandler:self中发生了循环引用,造成webview不会被释放掉,故经测试有以下两种解决方案:

1.新建个WeakScriptMessageDelegate类

1
2
3
4
5
6
7
8
9
10
11
#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface WeakScriptMessageDelegate : NSObject <WKScriptMessageHandler>

@property (nonatomic, assign) id<WKScriptMessageHandler> scriptDelegate;

+ (instancetype)scriptWithDelegate:(id<WKScriptMessageHandler>)delegate;

@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@implementation WeakScriptMessageDelegate

- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate {
    self = [super init];
    if (self) {
        _scriptDelegate = scriptDelegate;
    }
    return self;
}

+ (instancetype)scriptWithDelegate:(id<WKScriptMessageHandler>)delegate {
    return [[WeakScriptMessageDelegate alloc]initWithDelegate:delegate];
}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}

@end
设置addScriptMessageHandler方法更换为:
1
2
[[_webView configuration].userContentController addScriptMessageHandler:[WeakScriptMessageDelegate scriptWithDelegate:self] name:@"takePicturesByNative"];

2.不在初始化时添加ScriptMessageHandler, 而是和Notificenter/KVC一个思路

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    [_webView.configuration.userContentController addScriptMessageHandler:self name:@"takePicturesByNative"];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    [_webView.configuration.userContentController removeScriptMessageHandlerForName:@"takePicturesByNative"];

}

六、OC调用JS方法

1
2
3
4
5
6
7
8
9
10
    //设置JS
//    NSString *inputValueJS = @"document.getElementsByName('input')[0].attributes['value'].value";
//    NSString *inputValueJS = @"shareCallback()";
    NSString *inputValueJS = @"js代码";

    //执行JS
    [webView evaluateJavaScript:inputValueJS completionHandler:^(id _Nullable response, NSError * _Nullable error) {
        NSLog(@"value: %@ error: %@", response, error);
    }];

七、给webview添加请求头

1
2
3
4
5
6
NSString *urlString = @"https://www.baidu.com/";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request addValue:@"123" forHTTPHeaderField:@"token"];
[self.webView loadRequest:request];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    
    WKNavigationActionPolicy actionPolicy = WKNavigationActionPolicyAllow;

    //同步HTTPHeaderFields里的参数
    
    NSMutableURLRequest *mutableRequest = [navigationAction.request mutableCopy];
    NSDictionary *requestHeaders = navigationAction.request.allHTTPHeaderFields;
    //我们项目使用的token同步的,cookie的话类似
    if (requestHeaders[@"token"]) {
        decisionHandler(actionPolicy);//允许跳转
    }else {
        //这里添加请求头,把需要的都添加进来
        [mutableRequest setValue:@"123" forHTTPHeaderField:@"token"];
        
        [webView loadRequest:mutableRequest];
        decisionHandler(actionPolicy);//允许跳转
    }
    
}

注:在UIWeb里边是直接用的request 但是在这里需要写上navigationAction.出来的request

八、WKWebView加载不受信任的https

解决方法:在plist文件中设置Allow Arbitrary Loads in Web Content 置为 YES,并实现wkwebView下面的代理方法,就可解决

1
2
3
4
5
6
7
8
9
10
11
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{  
      
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {  
          
        NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];  
          
        completionHandler(NSURLSessionAuthChallengeUseCredential,card);  
          
    }  
}

九、监听WKWebView的进度条和标题

1
2
3
4
5
6
7
[self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
[self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];

//需要注意的是销毁的时候一定要移除监控
[self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
[self.webView removeObserver:self forKeyPath:@"title"];
1
2
3
4
5
6
7
8
9
10
11
12
13
@property (nonatomic, weak) CALayer *progressLayer;

    UIView *progress = [[UIView alloc]init];
    progress.frame = CGRectMake(0, 0, KScreenWidth, 3);
    progress.backgroundColor = [UIColor  clearColor];
    [self.view addSubview:progress];
    
    CALayer *layer = [CALayer layer];
    layer.frame = CGRectMake(0, 0, 0, 3);
    layer.backgroundColor = [UIColor greenColor].CGColor;
    [progress.layer addSublayer:layer];
    self.progressLayer = layer;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma mark - KVO回馈

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
    if ([keyPath isEqualToString:@"estimatedProgress"]) {
        self.progressLayer.opacity = 1;
        if ([change[@"new"] floatValue] <[change[@"old"] floatValue]) {
            return;
        }
        self.progressLayer.frame = CGRectMake(0, 0, KScreenWidth*[change[@"new"] floatValue], 3);
        if ([change[@"new"]floatValue] == 1.0) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                self.progressLayer.opacity = 0;
                self.progressLayer.frame = CGRectMake(0, 0, 0, 3);
            });
        }
    }else if ([keyPath isEqualToString:@"title"]){
        self.title = change[@"new"];
    }
    
}

十、解决cookie问题

以前UIWebView会自动去NSHTTPCookieStorage中读取cookie,但是WKWebView并不会去读取,因此导致cookie丢失以及一系列问题,解决方式就是在request中手动帮其添加上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
self.webView.UIDelegate = self;
self.webView.navigationDelegate = self;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.test.com"]];
[request addValue:[self readCurrentCookieWithDomain:@"http://www.test.com/"] forHTTPHeaderField:@"Cookie"];
[self.webView loadRequest:request];

- (NSString *)readCurrentCookieWithDomain:(NSString *)domainStr{
    NSHTTPCookieStorage*cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    NSMutableString * cookieString = [[NSMutableString alloc]init];
    for (NSHTTPCookie*cookie in [cookieJar cookies]) {
        [cookieString appendFormat:@"%@=%@;",cookie.name,cookie.value];
    }

//删除最后一个“;”
    [cookieString deleteCharactersInRange:NSMakeRange(cookieString.length - 1, 1)];
    return cookieString;
}

但是这只能解决第一次进入的cookie问题,如果页面内跳转(a标签等)还是取不到cookie,因此还要再加代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- (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];

}

十一、加载页面后自动关闭的问题

问题描述,我加载一web页面后,进行各种操作,比说我充值,什么的,然后想要在充值提出成功后自顶关闭这个web页面回到上一层或者返回到某一个界面,就用下面的方法,一般判断URL 包含的字符串都是后台给定的,在这里只需要判断就好了!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//**WKNavigationDelegate**里面的代理方法(上面有)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    //获取请求的url路径.
    NSString *requestString = navigationResponse.response.URL.absoluteString;
    WKLog(@"requestString:%@",requestString);
    // 遇到要做出改变的字符串
    NSString *subStr = @"www.baidu.com";
    if ([requestString rangeOfString:subStr].location != NSNotFound) {
        WKLog(@"这个字符串中有subStr");
        //回调的URL中如果含有百度,就直接返回,也就是关闭了webView界面
        [self.navigationController  popViewControllerAnimated:YES];
    }
    
    decisionHandler(WKNavigationResponsePolicyAllow);

}

十二、清除缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//清除本地缓存
- (void)clearCache {
    /* 取得Library文件夹的位置*/
    NSString *libraryDir = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask, YES)[0];
    /* 取得bundle id,用作文件拼接用*/ NSString *bundleId = [[[NSBundle mainBundle] infoDictionary]objectForKey:@"CFBundleIdentifier"];
    /* * 拼接缓存地址,具体目录为App/Library/Caches/你的APPBundleID/fsCachedData */
    NSString *webKitFolderInCachesfs = [NSString stringWithFormat:@"%@/Caches/%@/fsCachedData",libraryDir,bundleId];
    NSError *error;
    /* 取得目录下所有的文件,取得文件数组*/
    NSFileManager *fileManager = [NSFileManager defaultManager];
    //NSArray *fileList = [[NSArray alloc] init];
    //fileList便是包含有该文件夹下所有文件的文件名及文件夹名的数组
    NSArray *fileList = [fileManager contentsOfDirectoryAtPath:webKitFolderInCachesfs error:&error];
    /* 遍历文件组成的数组*/
    for(NSString * fileName in fileList)
    {
        /* 定位每个文件的位置*/
        NSString * path = [[NSBundle bundleWithPath:webKitFolderInCachesfs] pathForResource:fileName ofType:@""];
        /* 将文件转换为NSData类型的数据*/
        NSData * fileData = [NSData dataWithContentsOfFile:path];
        /* 如果FileData的长度大于2,说明FileData不为空*/
        if(fileData.length >2)
        {
            /* 创建两个用于显示文件类型的变量*/
            int char1 =0;
            int char2 =0;
            [fileData getBytes:&char1 range:NSMakeRange(0,1)];
            [fileData getBytes:&char2 range:NSMakeRange(1,1)];
            /* 拼接两个变量*/ NSString *numStr = [NSString stringWithFormat:@"%i%i",char1,char2];
            /* 如果该文件前四个字符是6033,说明是Html文件,删除掉本地的缓存*/
            if([numStr isEqualToString:@"6033"])
            {
                [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@",webKitFolderInCachesfs,fileName]error:&error]; continue;
                
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
- (void)cleanCacheAndCookie {
    //清除cookies
    NSHTTPCookie *cookie;
    NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (cookie in [storage cookies])
    {
        [storage deleteCookie:cookie];
    }
    
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
    NSURLCache * cache = [NSURLCache sharedURLCache];
    [cache removeAllCachedResponses];
    [cache setDiskCapacity:0];
    [cache setMemoryCapacity:0];
    
    if (@available(iOS 9.0, *)) {
        
        WKWebsiteDataStore *dateStore = [WKWebsiteDataStore defaultDataStore];
        [dateStore fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes]
                         completionHandler:^(NSArray<WKWebsiteDataRecord *> * __nonnull records)
         {
             for (WKWebsiteDataRecord *record  in records)
             {
                 
                 [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:record.dataTypes
                                                           forDataRecords:@[record]
                                                        completionHandler:^
                  {
                      NSLog(@"Cookies for %@ deleted successfully",record.displayName);
                  }];
             }
         }];

    }
    
}
1
2
3
4
5
6
7
8
9
- (void)dealloc {
    
    [_webView stopLoading];
    [_webView setNavigationDelegate:nil];
    [self clearCache];
    [self cleanCacheAndCookie];
    
}

附:demo中使用的返回上一页和关闭浏览器的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#pragma mark - Actions

- (void)backNative {
    //判断是否有上一层H5页面
    if ([self.webView canGoBack]) {
        //如果有则返回
        [self.webView goBack];
        //同时设置返回按钮和关闭按钮为导航栏左边的按钮
//        self.navigationItem.leftBarButtonItems = @[self.backBtn, self.closeBtn];
    }else {
        [self closeNative];
    }
}

- (void)closeNative {
    
    if (self.webView.backForwardList.backList.count>0) {                                  //得到栈里面的list
        NSLog(@"backList==%@",self.webView.backForwardList.backList);
        NSLog(@"currentItem==%@",self.webView.backForwardList.currentItem);
        
        [self.webView goToBackForwardListItem:[self.webView.backForwardList.backList firstObject]];

//        WKBackForwardListItem * item = self.webView.backForwardList.currentItem;          //得到现在加载的list
//        for (WKBackForwardListItem * backItem in self.webView.backForwardList.backList) { //循环遍历,得到你想退出到
//            //添加判断条件
//            [self.webView goToBackForwardListItem:[self.webView.backForwardList.backList firstObject]];
//        }
    }
    
    [self.navigationController popViewControllerAnimated:YES];
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值