iOS WKWebKit

WKWebView 使用时需要

1
#import <WebKit/WebKit>

它的使用更加的方便,功能更加的齐全,所以逐步的取代了 UIWebView。

加载方法

加载网页

同 UIWebView 的方法相同

1
2
3
NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
NSURLRequest *request =[NSURLRequest requestWithURL:url];
[self.webview loadRequest:request];

加载本地文件

加载本地文件的时候不再采用

1
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;

这个方法,而是采用了新的方法:

1
2
NSURL *url = [NSURL fileURLWithPath:@"/Users/ios/Desktop/图片/xxx.jpg"];
[webView loadFileURL:url allowingReadAccessToURL:url];

使用

1
-(nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessUR;

这个方法加载本地文件,不会调用发送网络请求的代理。

一些用于网络加载的方法

1
2
3
- (WKNavigation *)loadRequest:(NSURLRequest *)request;
- (WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
- (WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL;

同网页刷新有关的函数

1
2
3
4
5
6
7
8
@property (nonatomic, readonly) BOOL canGoBack;
@property (nonatomic, readonly) BOOL canGoForward;
- (WKNavigation *)goBack;
- (WKNavigation *)goForward;
- (WKNavigation *)reload;
- (WKNavigation *)reloadFromOrigin; // 增加的函数
- (WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item; // 增加的函数
- (void)stopLoading;
  1. reloadFromOrigin 会比较网络数据是否有变化,没有变化则使用缓存,否则从新请求。
  2. goToBackForwardListItem:比向前向后更强大,可以跳转到某个指定历史页面

常用的属性

  1. allowsBackForwardNavigationGestures:BOO L类型,是否允许左右划手势导航,默认不允许
  2. estimatedProgress:加载进度,取值范围 0~1
  3. title:页面 title
  4. scrollView.scrollEnabled:是否允许上下滚动,默认允许
  5. backForwardList:WKBackForwardList 类型,访问历史列表,可以通过前进后退按钮访问,或者通过 goToBackForwardListItem 函数跳到指定页面

代理协议

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
#pragma mark - WKNavigationDelegate 代理方法

/**
* 每当加载一个请求之前会调用该方法,通过该方法决定是否允许或取消请求的发送
*
* @param navigationAction 导航动作对象
* @param decisionHandler 请求处理的决定
*/

- (void)webView:(WKWebView*)webView decidePolicyForNavigationAction:(WKNavigationAction*)navigationAction decisionHandler:(void(^)(WKNavigationActionPolicy))decisionHandler{
NSLog(@"每当加载一个请求之前会调用该方法,通过该方法决定是否允许或取消请求的发送");
// 获得协议头(可以自定义协议头,根据协议头判断是否要执行跳转)
NSString *scheme = navigationAction.request.URL.scheme;
if ([scheme isEqualToString:@"itheima"]) {
// decisionHandler 对请求处理回调
//WKNavigationActionPolicyCancel:取消请求
//WKNavigationActionPolicyAllow:允许请求
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}

/**
* 当开始发送请求时调用
*/
- (void)webView:(WKWebView*)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
NSLog(@"当开始发送请求时调用");
}
/**
* 当请求过程中出现错误时调用
*/
- (void)webView:(WKWebView*)webView didFailNavigation:(WKNavigation*)navigation withError:(NSError *)error {
NSLog(@"当请求过程中出现错误时调用");
}

/**
* 当开始发送请求时出错调用
*/
- (void)webView:(WKWebView*)webView didFailProvisionalNavigation:(WKNavigation*)navigation withError:(NSError *)error {
NSLog(@"当开始发送请求时出错调用");
}

/**
* 每当接收到服务器返回的数据时调用,通过该方法可以决定是否允许或取消导航
*/
- (void)webView:(WKWebView*)webView decidePolicyForNavigationResponse:(WKNavigationResponse*)navigationResponse decisionHandler:(void(^)(WKNavigationResponsePolicy))decisionHandler{
NSLog(@"每当接收到服务器返回的数据时调用,通过该方法可以决定是否允许或取消导航");
//decisionHandler 对响应的处理
//WKNavigationActionPolicyCancel:取消响应
//WKNavigationActionPolicyAllow:允许响应
decisionHandler(WKNavigationResponsePolicyAllow);
}

/**
* 当收到服务器返回的受保护空间(证书)时调用
* @param challenge 安全质询-->包含受保护空间和证书
* @param completionHandler 完成回调-->告诉服务器如何处置证书
*/
- (void)webView:(WKWebView*)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullablecredential))completionHandler {
NSLog(@"当收到服务器返回的受保护空间(证书)时调用");
// 创建凭据对象
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
// 告诉服务器信任证书
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
}

/**
* 当网页加载完毕时调用:该方法使用最频繁
*/
- (void)webView:(WKWebView*)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
NSLog(@"当网页加载完毕时调用:该方法使用最频繁");
[webView evaluateJavaScript:@"document.title" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@",result);
}];
}

WKWebKit 与 JS 交互

OC 调用 JS

1
2
3
[webView evaluateJavaScript:@"document.title" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@",result);
}];

运行时加载 JS 代码

1
2
3
4
5
6
7
8
9
10
11
12
NSString *js = @"window.alert('欢迎体验WkWebView!');";
//初始化WKUserScript对象
//WKUserScriptInjectionTimeAtDocumentStart 为网页加载完成时注入
WKUserScript *script = [[WKUserScript alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
//根据生成的WKUserScript对象,初始化WKWebViewConfiguration
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
[config.userContentController addUserScript:script];
WKWebView * webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.baidu.com"]]];
webView.UIDelegate = self;
webView.navigationDelegate = self;
[self.view addSubview:webView];
1
2
3
4
5
6
7
8
//在JS端调用alert函数时,会触发此代理方法。
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;

//JS端调用confirm函数时,会触发此代理方法。
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;

//JS端调用prompt函数时,会触发此代理方法。
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler;

上面的3个方法需要在方法需要调用

1
completionHandler();

JS 调用 OC

在 UIWebView 中 JS 调用 OC 可以采用拦截网络请求的方式,当然在 WKWebView 中也可以采用这种方式。但是 WKWebView 提供了一种新特性,叫做 MessageHandler,用它可以很方便的实现 JS 对 OC 的调用。使用方式如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
[config.userContentController addScriptMessageHandler:self name:@"jsMethod"];
self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];

NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:nil];
NSURL *fileURL = [NSURL fileURLWithPath:urlStr];
[self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL];

self.webView.navigationDelegate = self;
self.webView.UIDelegate = self;
[self.view addSubview:self.webView];

/**
*注意addScriptMessageHandler 容易引起循环引用,所以要在适当的地方调用 - (void)removeScriptMessageHandlerForName:(NSString *)name;方法进行移除
*/

实现 WKScriptMessageHandler 的协议方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
// message.body -- Allowed types are NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull.
NSLog(@"body:%@",message.body);
if ([message.name isEqualToString:@"jsMethod"]) {
[self js_Method:message.body];
}
}

- (void)js_Method:(NSDictionary *)params{
if (params && [params isKindOfClass:[NSDictionary class]]) {
NSLog(@"%@",params);
}
}

实现这种调用的 JS 代码为

1
window.webkit.messageHandlers.jsMethod.postMessage({longitude:1.00,latitude:20});