WKWebView基本使用

519 阅读4分钟

为何使用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>

// 默认初始化
- (instancetype)initWithFrame:(CGRect)frame;

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

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

WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];

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

[self.view addSubview:webView];

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

// 是否可以后退
@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

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

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

// 页面开始加载时调用
- (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;

页面跳转的代理方法:

// 接收到服务器跳转请求之后调用
- (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提示框拦截然后再做处理。

// 创建一个新的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对象。提供从网页中接收消息的回调方法。

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

小技巧

  • 自适应屏幕宽度
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];
  • 获取页面高度
#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];
    }];
}
  • 图片自适应设备宽度
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];
  • 加载本地网页
NSURL * url = [[NSBundle mainBundle] URLForResource:@"fuwutiaokuan.html" withExtension:nil];
[self.wkWebView loadRequest:[NSURLRequest requestWithURL:url]];

参考内容:

使用WKWebView替换UIWebView

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

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