【轉】iOS 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創建

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

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代理事件

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

// 頁面開始加載時調用
- (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];
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM