Fork me on GitHub

WKWebView基本使用

为何使用WKWebView

App开发过程中不可避免的会用到加载网页,从iOS2开始,我们一直使用的是UIWebView加载,这个网页加载器加载速度慢、占用内存多、优化困难,如果加载网页过多,还可能因为过度占用内存而被系统kill掉。

iOS8以后,Apple推出了WebKit,提供了替换UIWebView的组件WKWebView,毫无疑问WKWebView将逐步取代笨重的UIWebView

WKWebView新特性

  • 在性能、稳定性、功能方面有很大提升,网页加载速度快、内存占用少
  • 支持更多的HTML5特性
  • 与Safari相同的JavaScript引擎
  • 官方宣称的高达60fps的滚动刷新率以及内置手势
  • 增加加载进度属性:estimatedProgress
  • 将UIWebViewDelegate与UIWebView重构成了14类与3个协议(查看苹果官方文档);

WKWebView使用说明

初始化方法分两种(记得导入#import <WebKit/WebKit.h>

1
2
3
4
5
// 默认初始化
- (instancetype)initWithFrame:(CGRect)frame;

// 根据对webview的相关配置,进行初始化
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;

加载网页与HTML代码的方式与UIWebView相同

1
2
3
4
5
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];

[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];

[self.view addSubview:webView];

网页导航刷新相关属性及方法

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
// 是否可以后退
@property (nonatomic, readonly) BOOL canGoBack;
// 是否可以向前
@property (nonatomic, readonly) BOOL canGoForward;
// 是否正在加载
@property (nonatomic, readonly) BOOL loading;
// 加载进度,取值(0~1)
@property (nonatomic, readonly) double estimatedProgress;
// 是否允许左右划手势导航,默认不允许
@property (nonatomic) BOOL allowsBackForwardNavigationGestures;
// WKBackForwardList类型,访问历史列表,可以通过前进后退按钮访问,或者通过goToBackForwardListItem函数跳到指定页面
@property (nonatomic, readonly, strong) WKBackForwardList *backForwardList;

// 刷新
- (WKNavigation *)reload;
// 停止加载
- (void)stopLoading;
// 后退函数
- (WKNavigation *)goBack;
// 前进函数
- (WKNavigation *)goForward;
// 会比较网络数据是否有变化,没有变化则使用缓存,否则从新请求。
- (WKNavigation *)reloadFromOrigin;
// 跳转到某个指定历史页面
- (WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;

WKWebView代理方法

1.WKNavigationDelegate

该代理提供的方法,可以用来追踪加载过程(页面开始加载、加载完成、加载失败)、决定是否执行跳转。

用来追踪加载过程(页面开始加载、加载完成、加载失败)的方法:

1
2
3
4
5
6
7
8
9
10
11
// 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;

// 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;

// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;

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

页面跳转的代理方法:

1
2
3
4
5
6
7
8
// 接收到服务器跳转请求之后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;

// 在收到响应后,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;

// 在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

2.WKUIDelegate

UI界面相关,原生控件支持,三种提示框:输入、确认、警告。首先将web提示框拦截然后再做处理。

1
2
3
4
5
6
7
8
9
10
11
// 创建一个新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;

// 输入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler;

// 确认框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;

// 警告框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;

3.WKScriptMessageHandler

这个协议中包含一个必须实现的方法,这个方法是提高App与web端交互的关键,它可以直接将接收到的JS脚本转为OC或Swift对象。提供从网页中接收消息的回调方法。

1
2
// 从web界面中接收到一个脚本时调用
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

小技巧

  • 自适应屏幕宽度
1
2
3
4
5
6
7
8
9
10
11
12
13
NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";

WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];

WKUserContentController *wkUController = [[WKUserContentController alloc] init];

[wkUController addUserScript:wkUScript];

WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];

wkWebConfig.userContentController = wkUController;

_web1 = [[WKWebView alloc] initWithFrame:CGRectNull configuration:wkWebConfig];
  • 获取页面高度
1
2
3
4
5
6
#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
[webView evaluateJavaScript:@"document.body.offsetHeight" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
_webHeight = [result doubleValue];
}];
}
  • 图片自适应设备宽度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
NSString *js = @"function imgAutoFit() { \
var imgs = document.getElementsByTagName('img'); \
for (var i = 0; i < imgs.length; ++i) {\
var img = imgs[i]; \
img.style.maxWidth = %f; \
} \
}";

js = [NSString stringWithFormat:js, [UIScreen mainScreen].bounds.size.width - 20];

WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];

WKUserContentController *wkUController = [[WKUserContentController alloc] init];

[wkUController addUserScript:wkUScript];

WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
wkWebConfig.userContentController = wkUController;

_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 64, qScreenWidth, qScreenHeight - 64) configuration:wkWebConfig];

参考内容:

使用WKWebView替换UIWebView

UIWebView、WKWebView使用详解及性能分析

WKWebView的使用和各种坑的解决方法(OC+Swift)

-------------本文结束感谢您的阅读-------------

本文作者:乔羽 / FightingJoey

发布时间:2017年04月27日 - 15:53

最后更新:2018年11月15日 - 11:47

原始链接:https://fightingjoey.github.io/2017/04/27/开发/WKWebView基本使用/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

坚持原创技术分享,您的支持将鼓励我继续创作!