- WKWebView需要iOS9或更高版本
優(yōu)點(diǎn)
1.多進(jìn)程,在app的主進(jìn)程之外執(zhí)行
2.使用更快的Nitro JavaScript引擎
3.異步執(zhí)行處理JavaScript
4.消除某些觸摸延遲
5.支持服務(wù)端的身份校驗(yàn)
6.支持對錯(cuò)誤的自簽名安全證書和證書進(jìn)行身份驗(yàn)證
問題
1.需要iOS9或更高版本(WKWebView在iOS8引入,但是很多功能,支持比較全面在iOS9以后的版本)
2.不支持通過AJAX請求本地存儲(chǔ)的文件
3.不支持"Accept Cookies"的設(shè)置
4.不支持"Advanced Cache Settings"(高級緩存設(shè)置)
5.App退出會(huì)清除HTML5的本地存儲(chǔ)的數(shù)據(jù)
6.不支持記錄WebKit的請求
7.不能進(jìn)行截屏操作
具體翻譯文參考:WKWebView相比于UIWebView瀏覽器之間內(nèi)核引擎的區(qū)別
原文 WKWebView: Differences from UIWebView browsing engine
一、WKWebView的基本初始化
- 需要引入 #import <WebKit/WebKit.h>
- (WKWebView *)wkWebview
{
if (!_wkWebview) {
// 0.網(wǎng)頁配置對象
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
// 1.原生與JS交互管理
WKUserContentController *userContentController = [[WKUserContentController alloc] init];
/// 解決循環(huán)引用
// 0.在viewdisAppear方法中
// [self.wkWebview.configuration.userContentController removeScriptMessageHandlerForName:@"ScanAction"];
// [userContentController addScriptMessageHandler:self name:@"ScanAction"];
// 1.繼承系統(tǒng)的NSProxy
// [userContentController addScriptMessageHandler:(id<WKScriptMessageHandler>)[XPZ_Proxy proxyWithTarget:self] name:@"ScanAction"];
// 2.自定義NSProxy
// [userContentController addScriptMessageHandler:(id<WKScriptMessageHandler>)[XPZ_CustomProxy proxyWithTarget:self] name:@"ScanAction"];
// 3.自定義WKScriptMessageHandler
XPZ_WKWeakScriptMessageHandler *scriptMessageHandle = [[XPZ_WKWeakScriptMessageHandler alloc] initWithScriptMessageHandlerWith:self];
[userContentController addScriptMessageHandler:scriptMessageHandle name:@"ScanAction"];
// 添加
config.userContentController = userContentController;
// 3.WKWebview設(shè)置
WKPreferences *prefer = [[WKPreferences alloc] init];
//設(shè)置是否支持javaScript 默認(rèn)是支持的
prefer.javaScriptEnabled = true;
// /最小字體大小
prefer.minimumFontSize = 40.0;
// // 在iOS上默認(rèn)為NO,表示是否允許不經(jīng)過用戶交互由javaScript自動(dòng)打開窗口
prefer.javaScriptCanOpenWindowsAutomatically = true;
// 添加
config.preferences = prefer;
// 是使用h5的視頻播放器在線播放, 還是使用原生播放器全屏播放
config.allowsInlineMediaPlayback = YES;
//設(shè)置視頻是否需要用戶手動(dòng)播放 設(shè)置為NO則會(huì)允許自動(dòng)播放
config.mediaTypesRequiringUserActionForPlayback = YES;
//設(shè)置是否允許畫中畫技術(shù) 在特定設(shè)備上有效
config.allowsPictureInPictureMediaPlayback = YES;
//設(shè)置請求的User-Agent信息中應(yīng)用程序名稱 iOS9后可用
config.applicationNameForUserAgent = @"ChinaDailyForiPad";
_wkWebview = [[WKWebView alloc] initWithFrame:self.view.frame configuration:config];
_wkWebview.UIDelegate = self;
_wkWebview.navigationDelegate = self;
// 是否允許手勢左滑返回上一級, 類似導(dǎo)航控制的左滑返回
_wkWebview.allowsBackForwardNavigationGestures = YES;
//可返回的頁面列表, 存儲(chǔ)已打開過的網(wǎng)頁
WKBackForwardList * backForwardList = [_wkWebview backForwardList];
//頁面后退
[_wkWebview goBack];
//頁面前進(jìn)
[_wkWebview goForward];
//刷新當(dāng)前頁面
[_wkWebview reload];
[self.view addSubview:_wkWebview];
}
return _wkWebview;
}
- 主要說下WKUserContentController:這個(gè)類主要用來做native與JavaScript的交互管理,依靠
WKScriptMessageHandler協(xié)議 - 主要用到以下方法
// 添加腳本信息
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
// 移除腳本信息
- (void)removeScriptMessageHandlerForName:(NSString *)name;
// 例:
[userContentController addScriptMessageHandler:scriptMessageHandle name:@"ScanAction"];
- JS中代碼
function scanClick() {
window.webkit.messageHandlers.ScanAction.postMessage(null);
}
- 對應(yīng)的協(xié)議方法,專門用來處理監(jiān)聽JavaScript方法從而調(diào)用原生OC方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
// message.body -- Allowed types are NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull.
// NSDictionary *bodyParam = (NSDictionary*)message.body;
// NSString *func = [bodyParam objectForKey:@"function"];
//
// NSLog(@"MessageHandler Name:%@", message.name);
// NSLog(@"MessageHandler Body:%@", message.body);
// NSLog(@"MessageHandler Function:%@",func);
if ([message.name isEqualToString:@"ScanAction"]) {
NSLog(@"掃一掃");
}
// 將結(jié)果返回給js
NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"廣東省深圳市南山區(qū)學(xué)府路XXXX號"];
[self.wkWebview evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@----%@",result, error);
}];
}
- ??在使用
addScriptMessageHandler:方法時(shí)會(huì)造成內(nèi)存泄漏
[configuration.userContentController addScriptMessageHandler:self name:name]
這里
userContentController持有了self,然后userContentController又被configuration持有,最終被wkwebview持有,然后wkwebview是self的一個(gè)成員變量,所以self也持有self,所以就造成了循環(huán)引用,導(dǎo)致界面不會(huì)被釋放
- 解決辦法, 以下提供了4種方案
- 使用
removeScriptMessageHandlerForName:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.wkWebview.configuration.userContentController removeScriptMessageHandlerForName:@"ScanAction"];
}
- 創(chuàng)建繼承系統(tǒng)的NSProxy的類
[userContentController addScriptMessageHandler:(id<WKScriptMessageHandler>)[XPZ_Proxy proxyWithTarget:self] name:@"ScanAction"];
// NSProxy類中的代碼
// XPZ_Proxy.h 中代碼
@interface XPZ_Proxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@property (weak, nonatomic) id target;
@end
// XPZ_Proxy.m 中代碼
@implementation XPZ_Proxy
+ (instancetype)proxyWithTarget:(id)target
{
// NSProxy對象不需要調(diào)用init,因?yàn)樗緛砭蜎]有init方法
XPZ_Proxy *proxy = [XPZ_Proxy alloc];
proxy.target = target;
return proxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
[invocation invokeWithTarget:self.target];
}
@end
- 創(chuàng)建自定義的NSProxy類
// XPZ_CustomProxy.h 中代碼
@interface XPZ_CustomProxy : NSObject
@property (nonatomic, weak) id target;
+ (instancetype)proxyWithTarget:(id)target;
@end
// XPZ_CustomProxy.m 中代碼
@implementation XPZ_CustomProxy
+ (instancetype)proxyWithTarget:(id)target
{
XPZ_CustomProxy *proxy = [[XPZ_CustomProxy alloc] init];
proxy.target = target;
return proxy;
}
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return self.target;
}
@end
- 自定義WKScriptMessageHandler
//XPZ_WKWeakScriptMessageHandler.h 中代碼
@interface XPZ_WKWeakScriptMessageHandler : NSObject <WKScriptMessageHandler>
- (instancetype)initWithScriptMessageHandlerWith:(id<WKScriptMessageHandler>)scriptMessageHandler;
@property (nonatomic, weak, readonly) id<WKScriptMessageHandler> scriptMessageHandler;
@end
// XPZ_WKWeakScriptMessageHandler.m 中代碼
- (instancetype)initWithScriptMessageHandlerWith:(id<WKScriptMessageHandler>)scriptMessageHandler
{
self = [super init];
if (self) {
_scriptMessageHandler = scriptMessageHandler;
}
return self;
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
[self userContentController:userContentController didReceiveScriptMessage:message];
}
@end
二、WKWebView的代理方法
1.WKUIDelegate
#pragma mark WKUIDelegate
// 警告
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction * action = [UIAlertAction actionWithTitle:@"確認(rèn)" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}];
[alert addAction:action];
[self presentViewController:alert animated:YES completion:nil];
}
// 確認(rèn)框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
// DLOG(@"msg = %@ frmae = %@",message,frame);
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}])];
[alertController addAction:([UIAlertAction actionWithTitle:@"確認(rèn)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
// 輸入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.text = defaultText;
}];
[alertController addAction:([UIAlertAction actionWithTitle:@"完成" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(alertController.textFields[0].text?:@"");
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
// 創(chuàng)建一個(gè)新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
return [[WKWebView alloc]init];
}
2.WKNavigationDelegate
#pragma mark - WKNavigationDelegate
/*
WKNavigationDelegate主要處理一些跳轉(zhuǎn)、加載處理操作,WKUIDelegate主要處理JS腳本,確認(rèn)框,警告框等
*/
// 頁面開始加載時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
}
// 頁面加載失敗時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
[self.progressView setProgress:0.0f animated:NO];
}
// 當(dāng)內(nèi)容開始返回時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
}
// 頁面加載完成之后調(diào)用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
// 設(shè)置字體
// NSString *fontFamilyStr = @"document.getElementsByTagName('body')[0].style.fontFamily='Arial';";
// [webView evaluateJavaScript:fontFamilyStr completionHandler:nil];
// //設(shè)置顏色
// [ webView evaluateJavaScript:@"document.getElementsByTagName('body')[0].style.webkitTextFillColor= '#9098b8'" completionHandler:nil];
// //修改字體大小
// [ webView evaluateJavaScript:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '200%'"completionHandler:nil];
}
//提交發(fā)生錯(cuò)誤時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
[self.progressView setProgress:0.0f animated:NO];
}
// 接收到服務(wù)器跳轉(zhuǎn)請求即服務(wù)重定向時(shí)之后調(diào)用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
}
// 在發(fā)送請求之前,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSString *href = navigationAction.request.URL.absoluteString;
if ([href hasPrefix:@"http"]||[href hasPrefix:@"https"]) {
}
if ([href hasPrefix:@"config:"]) {
// parse and get json, then ...
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
3.WKScriptMessageHandler
#pragma mark WKScriptMessageHandler
// 用來處理監(jiān)聽JavaScript方法從而調(diào)用原生OC方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
// message.body -- Allowed types are NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull.
// NSDictionary *bodyParam = (NSDictionary*)message.body;
// NSString *func = [bodyParam objectForKey:@"function"];
//
// NSLog(@"MessageHandler Name:%@", message.name);
// NSLog(@"MessageHandler Body:%@", message.body);
// NSLog(@"MessageHandler Function:%@",func);
if ([message.name isEqualToString:@"ScanAction"]) {
NSLog(@"掃一掃");
}
// 將結(jié)果返回給js
NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"廣東省深圳市南山區(qū)學(xué)府路XXXX號"];
[self.wkWebview evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@----%@",result, error);
}];
}
三、JS與OC的交互
1.JavaScriptCore
- UIWebView
// 創(chuàng)建JSContext
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.context = context;
// 調(diào)用系統(tǒng)相機(jī)
context[@"iOSCamera"] = ^(){
dispatch_async(dispatch_get_main_queue(), ^{
});
return @"調(diào)用相機(jī)";
};
// callWithArguments:
JSValue *labelAction = self.context[@"picCallback"];
[labelAction callWithArguments:@[@"參數(shù)"]];
在從UIWebView過度到WkWebView,我們還向之前使用UIWebView那樣,在頁面加載完成后,獲取JSContext上下文
會(huì)發(fā)現(xiàn)在self.jsContext = [_wkWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];這里崩了,原因就是WKWebView不支持JavaScriptCore的方式, 但提供messagehandler的方式為JavaScript與OC通信;
到這里我們會(huì)想如何拿到WKWebView JsContext上下文,可是很遺憾我們無法獲取上下文,因?yàn)椴季趾蚃avaScript是在另一個(gè)進(jìn)程上處理的。
2.MessageHandler
這個(gè)方法上面提到過,主要是依靠WKScriptMessageHandler協(xié)議類和WKUserContentController兩個(gè)類:WKUserContentController對象負(fù)責(zé)注冊JS方法,設(shè)置處理接收J(rèn)S方法的代理,代理遵守WKScriptMessageHandler,實(shí)現(xiàn)捕捉到JS消息的回調(diào)方法。
- 上面是JS調(diào)用OC,補(bǔ)充一下OC調(diào)用JS方法
// 將結(jié)果返回給js
NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"廣東省深圳市南山區(qū)學(xué)府路XXXX號"];
[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"%@----%@",result, error);
}];
- JS中代碼
function setLocation(location) {
asyncAlert(location);
document.getElementById("returnValue").value = location;
}
3.WebViewJavascriptBridge
通過CocoaPods集成
WebViewJavascriptBridge
在工程的Podfile里面添加以下代碼:
pod 'WebViewJavascriptBridge'
- 引入頭文件
#import <WKWebViewJavascriptBridge.h>
- 初始化 WKWebViewJavascriptBridge
_webViewBridge = [WKWebViewJavascriptBridge bridgeForWebView:_wkWebview];
[_webViewBridge setWebViewDelegate:self];
- 注冊并調(diào)用js方法
// js調(diào)用原生
[_webViewBridge registerHandler:@"scanClick" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"data : %@",data);
responseCallback(@"12345678");
}];
// 原生調(diào)用js方法
// // 如果不需要參數(shù),不需要回調(diào),使用這個(gè)
// [_webViewBridge callHandler:@"testJSFunction"];
// // 如果需要參數(shù),不需要回調(diào),使用這個(gè)
// [_webViewBridge callHandler:@"testJSFunction" data:@"一個(gè)字符串"];
// 如果既需要參數(shù),又需要回調(diào),使用這個(gè)
[_webViewBridge callHandler:@"testJSFunction" data:@"一個(gè)字符串" responseCallback:^(id responseData) {
NSLog(@"調(diào)用完JS后的回調(diào):%@",responseData);
}];
- 復(fù)制并粘貼到您的 JS 中:setupWebViewJavascriptBridge
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'https://__bridge_loaded__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}
- 最后調(diào)用
setupWebViewJavascriptBridge
WebViewJavascriptBridge.callHandler('scanClick', {'foo': 'bar'}, function(response) {
alert('掃描結(jié)果:' + response);
document.getElementById("returnValue").value = response;
})
setupWebViewJavascriptBridge(function(bridge) {
bridge.registerHandler('testJSFunction', function(data, responseCallback) {
alert('JS方法被調(diào)用:'+data);
responseCallback('js執(zhí)行過了');
})
})
4.攔截URL
#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSURL *URL = navigationAction.request.URL;
NSString *scheme = [URL scheme];
if ([scheme isEqualToString:@""]) {
// 在這里解析URL
// 需要調(diào)用js方法 還可以通過以下這種方法插入js例:
// 將結(jié)果返回給js
// NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"廣東省深圳市南山區(qū)學(xué)府路XXXX號"];
// [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
// NSLog(@"%@----%@",result, error);
// }];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
四.加載進(jìn)度條和title的監(jiān)聽
注意:
iOS9之前,被觀察這對觀察者之間是unsafe_unretain引用,觀察者釋放之后會(huì)造成野指針
而iOS9 之后是weak引用關(guān)系,對象釋放之后,指針也釋放,不會(huì)崩潰
通知NSNotification在注冊者被回收時(shí)需要手動(dòng)移除,是一直以來的使用準(zhǔn)則。原因是在MRC時(shí)代,通知中心持有的是注冊者的unsafe_unretained指針,在注冊者被回收時(shí)若不對通知進(jìn)行手動(dòng)移除,則指針指向被回收的內(nèi)存區(qū)域,成為野指針。這時(shí)再發(fā)送通知,便會(huì)造成crash。而在iOS 9以后,通知中心持有的是注冊者的weak指針,這時(shí)即使不對通知進(jìn)行手動(dòng)移除,指針也會(huì)在注冊者被回收后自動(dòng)置空。我們知道,向空指針發(fā)送消息是不會(huì)有問題的。
?? 但是有一個(gè)例外。如果用- (id <NSObject>)addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));這個(gè)API來注冊通知,可以直接傳入block類型參數(shù)。使用這個(gè)API會(huì)導(dǎo)致注冊者被系統(tǒng)retain,因此仍然需要像以前一樣手動(dòng)移除通知,同時(shí)這個(gè)block類型參數(shù)也需注意避免循環(huán)引用。
-
所以不再需要寫移除觀察者方法
[self.wkWebview removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress))]; [self.wkWebview removeObserver:self forKeyPath:NSStringFromSelector(@selector(title))]; 添加監(jiān)測網(wǎng)頁加載進(jìn)度的觀察者
[self.wkWebview addObserver:self
forKeyPath:@"estimatedProgress"
options:0
context:nil];
//添加監(jiān)測網(wǎng)頁標(biāo)題title的觀察者
[self.wkWebview addObserver:self
forKeyPath:@"title"
options:NSKeyValueObservingOptionNew
context:nil];
#pragma mark kvo 監(jiān)聽進(jìn)度 必須實(shí)現(xiàn)此方法
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
context:(void *)context{
if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))]
&& object == _wkWebview) {
NSLog(@"網(wǎng)頁加載進(jìn)度 = %f",_wkWebview.estimatedProgress);
self.progressView.progress = _wkWebview.estimatedProgress;
if (_wkWebview.estimatedProgress >= 1.0f) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.progressView.progress = 0;
});
}
}else if([keyPath isEqualToString:@"title"]
&& object == _wkWebview){
self.navigationItem.title = _wkWebview.title;
}else{
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
}