UI基础 - WKWebView
前言
1 - 从 iOS 8 开始就引入了新的浏览器控件 WKWebView,用于取代 UIWebView!优点如下
① 内存开销更小
② 内置手势
③ 支持更多 H5 特性
④ 有 Safari 相同的 JavaScript 引擎
⑤ 提供更多属性。比如加载进度、标题、准确的得到页面数等等
⑥ 提供了更精细的加载流程回调
⑦ WKWebView 的流程粒度更加细致,不但在请求的时候会询问 WKWebView 是否请求数据,还会在返回数据之后询问 WKWebView 是否加载数据
2 - UIWebView 和 WKWebView
WKWebView
1 - 如何使用 WKWebView
1 #import "ViewController.h" 2 #import <WebKit/WebKit.h> // 需要引入头文件 3 @interface ViewController ()<WKNavigationDelegate,WKUIDelegate> 4 5 @property(nonatomic,strong)WKWebView *webView; 6 @property(nonatomic,strong)UIProgressView *progressView; 7 8 @end 9 10 @implementation ViewController 11 12 - (void)viewDidLoad { 13 [super viewDidLoad]; 14 self.view.backgroundColor = [UIColor blackColor]; 15 16 // 获取已打开页面数量 17 // UIWebView 提供了 pagecount,但是没有卵用! WKWebView 中的 backList 记录了可回退的页面信息 18 // 已打开页面数量 = backList.count + 当前页 19 int pageCount = self.webView.backForwardList.backList.count + 1; 20 21 // 进度条 22 self.progressView.hidden = NO; 23 [self progressBarLoading]; 24 25 // 加载本地PDF文件 26 NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Demo22P" ofType:@"pdf"]; 27 NSURL *url = [NSURL fileURLWithPath:filePath]; 28 NSURLRequest *request = [NSURLRequest requestWithURL:url]; 29 [self.webView loadRequest:request]; 30 } 31 #pragma mark - H5页面 标题更换 32 -(void)renewTitle{ 33 // 导航栏标题经常要根据当前 H5页面 标题更换 34 // 以前都是在页面加载完成后,使用 window.document.title 来获取 35 // 现在 WKWebView 提供了相关字段,我们只需要监听这个字段即可 36 [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL]; 37 } 38 39 #pragma mark - 动态加载进度条 40 -(void)progressBarLoading{ 41 // 早期的 UIWKWebView 无法获取加载进度,只能知晓开始加载和结束加载 42 // 因此以前的做法是做一个假的进度条,等到结束的时候再突然设置成 100% 43 44 // WKWebView 提供了 estimatedProgress来监听加载进度,提供了 loading 来获取加载状态 45 // 我们可以拖个 UIProgressView 来显示进度(也很多人用 layer 实现,还可以做渐变的效果,视觉上更优) 46 [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL]; 47 [self.webView addObserver:self forKeyPath:@"loading" options:NSKeyValueObservingOptionNew context:NULL]; 48 } 49 #pragma mark - 监听方法 50 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { 51 52 //---------------------- H5页面 标题更换 53 if ([keyPath isEqualToString:@"title"]) { 54 NSString *title = (NSString *)change[NSKeyValueChangeNewKey]; 55 self.title = title; 56 } 57 58 //---------------------- 动态加载进度条 59 if ([keyPath isEqualToString:@"estimatedProgress"]) { 60 CGFloat estimatedProgress = [change[NSKeyValueChangeNewKey] floatValue]; 61 NSLog(@"页面加载进度:%f", estimatedProgress); 62 [self.progressView setProgress:estimatedProgress]; 63 }else if ([keyPath isEqualToString:@"loading"]) { 64 BOOL loading = [change[NSKeyValueChangeNewKey] boolValue]; 65 NSLog(@"%@", loading ? @"开始加载" : @"停止加载"); 66 //self.progressView.hidden = !loading; // 是否隐藏进度条 67 } 68 } 69 70 #pragma mark - 懒加载 71 - (WKWebView *)webView{ 72 if (_webView == nil) { 73 74 // 初始化配置定制 75 WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; 76 // 用户拷贝网页内容的时候的粒度 77 configuration.selectionGranularity = WKSelectionGranularityDynamic; 78 // 允许在网页内部播放视频 79 configuration.allowsInlineMediaPlayback = YES; 80 81 WKPreferences *preferences = [WKPreferences new]; 82 // 是否支持 JavaScript 83 preferences.javaScriptEnabled = YES; 84 // 不通过用户交互,是否可以打开窗口 85 preferences.javaScriptCanOpenWindowsAutomatically = YES; 86 configuration.preferences = preferences; 87 88 // WKWebView 89 _webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, [UIApplication sharedApplication].statusBarFrame.size.height+10+10+20, self.view.frame.size.width, self.view.frame.size.height - [UIApplication sharedApplication].statusBarFrame.size.height-40-20) configuration:configuration]; 90 [self.view addSubview:_webView]; 91 // 有两种代理:UIDelegate负责界面弹窗;navigationDelegate负责加载、跳转等 92 _webView.UIDelegate = self; 93 _webView.navigationDelegate = self; 94 } 95 return _webView; 96 } 97 98 // 进度条 99 -(UIProgressView *)progressView{ 100 if(_progressView == nil){ 101 _progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(50, [UIApplication sharedApplication].statusBarFrame.size.height+10, self.view.frame.size.width-50*2, 20)]; 102 //进度条类型 103 [_progressView setProgressViewStyle:UIProgressViewStyleDefault]; 104 [self.view addSubview:_progressView]; 105 } 106 return _progressView; 107 } 108 109 #pragma mark - <WKNavigationDelegate> 110 /* 页面开始加载 */ 111 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{ 112 } 113 /* 开始返回内容 */ 114 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{ 115 116 } 117 /* 页面加载完成 */ 118 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{ 119 120 } 121 /* 页面加载失败 */ 122 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{ 123 124 } 125 /* 在发送请求之前,决定是否跳转 */ 126 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ 127 // 允许跳转 128 decisionHandler(WKNavigationActionPolicyAllow); 129 // 不允许跳转 130 //decisionHandler(WKNavigationActionPolicyCancel); 131 } 132 /* 在收到响应后,决定是否跳转 */ 133 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{ 134 135 NSLog(@"decidePolicyForNavigationResponse = %@",navigationResponse.response.URL.absoluteString); 136 // 允许跳转 137 decisionHandler(WKNavigationResponsePolicyAllow); 138 // 不允许跳转 139 //decisionHandler(WKNavigationResponsePolicyCancel); 140 } 141 142 #pragma mark - <WKUIDelegate> 143 // 处理 alert 弹窗事件 144 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{ 145 146 // 弹窗 147 [self alert:@"温馨提示" message:message?:@"" buttonTitles:@[@"确认"] handler:^(int index, NSString *title) { 148 completionHandler(); 149 }]; 150 } 151 152 // 处理 Confirm 弹窗事件 153 - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{ 154 155 [self alert:@"温馨提示" message:message?:@"" buttonTitles:@[@"取消", @"确认"] handler:^(int index, NSString *title) { 156 completionHandler(index != 0); 157 }]; 158 } 159 160 /// 处理 TextInput 弹窗事件 161 - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler { 162 163 UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:prompt preferredStyle:UIAlertControllerStyleAlert]; 164 [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 165 textField.text = defaultText; 166 }]; 167 [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 168 completionHandler(nil); 169 }]]; 170 [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 171 NSString *text = [alert.textFields firstObject].text; 172 NSLog(@"字符串:%@", text); 173 completionHandler(text); 174 }]]; 175 [self presentViewController:alert animated:YES completion:nil]; 176 } 177 178 #pragma mark - 自定义弹窗 179 - (void)alert:(NSString *)title message:(NSString *)message { 180 [self alert:title message:message buttonTitles:@[@"确定"] handler:nil]; 181 } 182 183 - (void)alert:(NSString *)title message:(NSString *)message buttonTitles:(NSArray *)buttonTitles handler:(void(^)(int, NSString *))handler { 184 185 UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; 186 187 for (int i = 0; i < buttonTitles.count; i++) { 188 [alert addAction:[UIAlertAction actionWithTitle:buttonTitles[i] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 189 if (handler) { 190 handler(i, action.title); 191 } 192 }]]; 193 } 194 [self presentViewController:alert animated:YES completion:nil]; 195 } 196 197 @end
运行效果:PDF文件加载完成