WKWebView讲解与使用

随着IOS开发的应用,对于网页嵌入也愈来愈多了,在IOS 8以前咱们使用UIWebView展现详情页,自从IOS 8以后就出现了WKWebView,相比UIWebView,WKWebView优化了较多的体验。下面将讲述WKWebView的知识点以及运用,大概须要花费10-20分钟时间,但愿对你们有所帮助!!!java

 

1、WKWebView优势

WKWebView采用跨进程方案,Nitro JS解析器,高达60fps的刷新率,理论上性能和Safari比肩,并且对H5也实现了高度支持。web

1.WKWebView的内存开销比UIWebView小不少json

2.内置手势服务器

3.支持了更多的HTML5特性weex

4.有Safari相同的JavaScript引擎app

5.提供经常使用的属性,如加载网页进度的estimatedProgress属性dom

 

下面来对比UIWebView和WKWebView的流程区别(左边是UIWebView,右边是WKWebView)ide

WKWebView的流程粒度更加细致,不但在不但在请求的时候会询问WKWebView是否请求数据,还会在返回数据以后询问WKWebView是否加载数据。函数

#请求数据的时候询问
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
#返回数据的时候询问
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;

 

在流程中,WKWebView返回的错误粒度也比UIWebView细:post

#请求数据时发生的error
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
#请求以后加载H5发生的error
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;

2、WKWebView基本使用

2.1 基本使用

2.1.1 使用WKWebView引用头文件

- (void)setupWebview{
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.selectionGranularity = WKSelectionGranularityDynamic;
    config.allowsInlineMediaPlayback = YES;
    WKPreferences *preferences = [WKPreferences new];
    //是否支持JavaScript
    preferences.javaScriptEnabled = YES;
    //不经过用户交互,是否能够打开窗口
    preferences.javaScriptCanOpenWindowsAutomatically = YES;
    config.preferences = preferences;
    WKWebView *webview = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight - 64) configuration:config];
    [self.view addSubview:webview];
     
    /* 加载服务器url的方法*/
    NSString *url = @"https://www.baidu.com";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    [webview loadRequest:request];
     
    webview.navigationDelegate = self;
    webview.UIDelegate = self;
}

WKWebViewConfiguration和WKPreferences中不少属性对WebView初始化进行设置。

2.1.2 下面遵循协议和实现的协议方法:

#pragma mark - 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 decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    //容许跳转
    decisionHandler(WKNavigationActionPolicyAllow);
    //不容许跳转
    //decisionHandler(WKNavigationActionPolicyCancel);
}
/* 在收到响应后,决定是否跳转 */
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
     
    NSLog(@"%@",navigationResponse.response.URL.absoluteString);
    //容许跳转
    decisionHandler(WKNavigationResponsePolicyAllow);
    //不容许跳转
    //decisionHandler(WKNavigationResponsePolicyCancel);
}

 

3、WKWebView开发细节

3.1 url 中文处理

有时候咱们加载的url中出现了中文,须要咱们手动转码,可是同时又要保证URL中的特殊字符保持不变,那么咱们可使用下面的方法(方法)

- (NSURL *)url{
#pragma clang diagnostic push
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
    return [NSURL URLWithString:(NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", NULL,kCFStringEncodingUTF8))];
#pragma clang diagnostic pop
}

 

3.2 获取h5中的标题以及添加进度条

获取h5中的标题和添加进度条放在一块儿展现看起来更明朗一点,在初始化webView,添加两个观察者分别用来监听webView的estimateProgress和title属性

webview.navigationDelegate = self;
webview.UIDelegate = self;
     
[webview addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
[webview addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];

添加建立进度条,并添加进度条图层属性:

@property (nonatomic,weak) CALayer *progressLayer;

-(void)setupProgress{
    UIView *progress = [[UIView alloc]init];
    progress.frame = CGRectMake(0, 0, KScreenWidth, 3);
    progress.backgroundColor = [UIColor  clearColor];
    [self.view addSubview:progress];
     
    CALayer *layer = [CALayer layer];
    layer.frame = CGRectMake(0, 0, 0, 3);
    layer.backgroundColor = [UIColor greenColor].CGColor;
    [progress.layer addSublayer:layer];
    self.progressLayer = layer;
}

实现观察者的回调方法:

#pragma mark - KVO回馈
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<nskeyvaluechangekey,id> *)change context:(void *)context{
    if ([keyPath isEqualToString:@"estimatedProgress"]) {
        self.progressLayer.opacity = 1;
        if ([change[@"new"] floatValue] <[change[@"old"] floatValue]) {
            return;
        }
        self.progressLayer.frame = CGRectMake(0, 0, KScreenWidth*[change[@"new"] floatValue], 3);
        if ([change[@"new"]floatValue] == 1.0) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                self.progressLayer.opacity = 0;
                self.progressLayer.frame = CGRectMake(0, 0, 0, 3);
            });
        }
    }else if ([keyPath isEqualToString:@"title"]){
        self.title = change[@"new"];
    }
}</nskeyvaluechangekey,id>

 

3.3 添加userAgent信息

有时候h5的欧版须要咱们为WebView的请求添加userAgent,用来识别操做系统等一下信息,可是若是每次用到webView都要添加一次的话会比较麻烦,下面是一种解决问题的办法

在Appdelegate中添加一个WKWebView的属性,启动app时直接为该属性添加userAgent:

- (void)setUserAgent {
    _webView = [[WKWebView alloc] initWithFrame:CGRectZero];
    [_webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) {
        if (error) { return; }
        NSString *userAgent = result;
        if (![userAgent containsString:@"/mobile-iOS"]) {
            userAgent = [userAgent stringByAppendingString:@"/mobile-iOS"];
            NSDictionary *dict = @{@"UserAgent": userAgent};
            [TKUserDefaults registerDefaults:dict];
        }
    }];
}

这样一来,在app建立webView时存在了咱们添加的userAgent的信息。

 

3.4 JS调用OC

js会经过如下方法调用原生方法

window.webkit.messageHandlers.<#对象名#>.postMessage(<#参数#>)

在原生中咱们只要实现WKScriptMessageHandler的代理方法就能够了,值得注意的是参数name须要与上述代码中对象名一致。

// 添加scriptMessageHandler
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;

最后在

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

在这个方法中获取作下判断,响应对应的方法便可:

// 初始化WKWebView,在实例化WKWebViewConfiguration对象的时候咱们同时添加scriptMessageHandler
 //进行配置控制器
        WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
        //实例化对象
        configuration.userContentController = [WKUserContentController new];
        //调用JS方法
        [configuration.userContentController addScriptMessageHandler:self name:@"btnClick"];

#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if ([message.name isEqualToString:@"btnClick"]) {
        NSDictionary *jsData = message.body;
        NSLog(@"%@", message.name, jsData);
        //读取js function的字符串
        NSString *jsFunctionString = jsData[@"result"];
        //拼接调用该方法的js字符串(convertDictionaryToJson:方法将NSDictionary转成JSON格式的字符串)
        NSString *jsonString = [NSDictionary convertDictionaryToJson:@{@"test":@"123", @"data":@"666"}];
        NSString *jsCallBack = [NSString stringWithFormat:@"(%@)(%@);", jsFunctionString, jsonString];
        //执行回调
        [self.weWebView evaluateJavaScript:jsCallBack completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            if (error) {
                NSLog(@"err is %@", error.domain);
            }
        }];
    }
}

以上须要注意的是,因为message的body只能是NSNumber,NSString,NSDate,NSArray,NSDictionary,NSNull这几种类型,咱们没法将js函数直接原生,在须要进行回调的环境下,咱们将js回调函数转为String后再传给原生,再由原生获取后进行回调操做,实际上这是已经进行了动态js注入。

 

3.5 OC调用JS

动态注入js方法就比较简单了,咱们只要实现相应的方法就能够。

- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;

下面有一段示例代码

// 此处是设置须要调用的js方法以及将对应的参数传入,须要以字符串的形式
NSString *jsFounction = [NSString stringWithFormat:@"getAppConfig('%@')", APP_CHANNEL_ID];
// 调用API方法
    [self.weexWebView evaluateJavaScript:jsFounction completionHandler:^(id object, NSError * _Nullable error) {
        NSLog(@"obj:%@---error:%@", object, error);
    }];

 

以上就是WKWebView的基本使用,但愿你们对WKWebView的理解有所提升,谢谢!!!

相关文章
相关标签/搜索