首页 > 代码库 > wkwebview 代理介绍

wkwebview 代理介绍

iOS 8引入了一个新的框架——WebKit,之后变得好起来了。在WebKit框架中,有WKWebView可以替换UIKit的UIWebView和AppKit的WebView,而且提供了在两个平台可以一致使用的接口。WebKit框架使得开发者可以在原生App中使用Nitro来提高网页的性能和表现,Nitro就是Safari的JavaScript引擎。

WebKit 介绍

下面举个??

代码中有详细的注释

////  ViewController.m//  WKWebView01////  Created by njdby on 16/7/8.//  Copyright © 2016年 njdby. All rights reserved.//#import "ViewController.h"#import <WebKit/WebKit.h>@interface ViewController ()<WKUIDelegate, WKNavigationDelegate,WKScriptMessageHandler>@property (nonatomic, strong) WKWebView *webView;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];    // 设置偏好设置    config.preferences = [[WKPreferences alloc] init];    // 默认为0    config.preferences.minimumFontSize = 10;    // 默认认为YES    config.preferences.javaScriptEnabled = YES;    // 在iOS上默认为NO,表示不能自动通过窗口打开    config.preferences.javaScriptCanOpenWindowsAutomatically = NO;    // web内容处理池,由于没有属性可以设置,也没有方法可以调用,不用手动创建    config.processPool = [[WKProcessPool alloc] init];    // 通过JS与webview内容交互    config.userContentController = [[WKUserContentController alloc] init];    // 注入JS对象名称AppModel,当JS通过AppModel来调用时,    // 我们可以在WKScriptMessageHandler代理中接收到    [config.userContentController addScriptMessageHandler:self name:@"AppModel"];    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds                                      configuration:config];    [self.view addSubview:self.webView];    // 导航代理    self.webView.navigationDelegate = self;    // 与webview UI交互代理    self.webView.UIDelegate = self;//    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.baidu.com"]]];    NSURL *path = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"html"];    [self.webView loadRequest:[NSURLRequest requestWithURL:path]];    // 添加KVO监听    [self.webView addObserver:self                   forKeyPath:@"loading"                      options:NSKeyValueObservingOptionNew                      context:nil];    [self.webView addObserver:self                   forKeyPath:@"title"                      options:NSKeyValueObservingOptionNew                      context:nil];    [self.webView addObserver:self                   forKeyPath:@"estimatedProgress"                      options:NSKeyValueObservingOptionNew                      context:nil];}#pragma mark - WKUIDelegate#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_9_0- (void)webViewDidClose:(WKWebView *)webView {    NSLog(@"%s", __FUNCTION__);}#endif// 创建一个新的WebView(标签带有 target=‘_blank‘ 时,导致WKWebView无法加载点击后的网页的问题。)- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {    // 接口的作用是打开新窗口委托    WKFrameInfo *frameInfo = navigationAction.targetFrame;    if (![frameInfo isMainFrame]) {        [webView loadRequest:navigationAction.request];    }    return nil;}// 在JS端调用alert函数时,会触发此代理方法。// JS端调用alert时所传的数据可以通过message拿到// 在原生得到结果后,需要回调JS,是通过completionHandler回调- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {    NSLog(@"%s", __FUNCTION__);    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert" message:@"JS调用alert" preferredStyle:UIAlertControllerStyleAlert];    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {        completionHandler();    }]];    [self presentViewController:alert animated:YES completion:NULL];    NSLog(@"%@", message);}// JS端调用confirm函数时,会触发此方法// 通过message可以拿到JS端所传的数据// 在iOS端显示原生alert得到YES/NO后// 通过completionHandler回调给JS端- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {    NSLog(@"%s", __FUNCTION__);    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"confirm" message:@"JS调用confirm" preferredStyle:UIAlertControllerStyleAlert];    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {        completionHandler(YES);    }]];    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {        completionHandler(NO);    }]];    [self presentViewController:alert animated:YES completion:NULL];    NSLog(@"%@", message);}// JS端调用prompt函数时,会触发此方法// 要求输入一段文本// 在原生输入得到文本内容后,通过completionHandler回调给JS- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {    NSLog(@"%s", __FUNCTION__);    NSLog(@"%@", prompt);    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS调用输入框" preferredStyle:UIAlertControllerStyleAlert];    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {        textField.textColor = [UIColor redColor];    }];    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {        completionHandler([[alert.textFields lastObject] text]);    }]];    [self presentViewController:alert animated:YES completion:NULL];}#pragma mark - WKNavigationDelegate#pragma mark - WKNavigationDelegate/** *  在发送请求之前,决定是否跳转 * *  @param webView          实现该代理的 *  @param navigationAction 当前navigation *  @param decisionHandler  是否调转block */- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {    NSString *hostname = navigationAction.request.URL.host.lowercaseString;    if (navigationAction.navigationType == WKNavigationTypeLinkActivated        && ![hostname containsString:@".baidu.com"]) {        // 对于跨域,需要手动跳转        [[UIApplication sharedApplication] openURL:navigationAction.request.URL];        // 不允许web内跳转        decisionHandler(WKNavigationActionPolicyCancel);    } else {       self.progressView.alpha = 1.0;        decisionHandler(WKNavigationActionPolicyAllow);    }    NSLog(@"%s", __FUNCTION__);}/** *  在收到响应后,决定是否跳转 * *  @param webView            实现该代理的webview *  @param navigationResponse 当前navigation *  @param decisionHandler    是否跳转block */- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {    //    NSLog(@"%@",navigationResponse.response);    // 如果响应的地址是百度,则允许跳转    //    if ([navigationResponse.response.URL.host.lowercaseString isEqual:@"www.baidu.com"]) {    //    //        // 允许跳转    //        decisionHandler(WKNavigationResponsePolicyAllow);    //        return;    //    }    //    // 不允许跳转    //    decisionHandler(WKNavigationResponsePolicyCancel);    decisionHandler(WKNavigationResponsePolicyAllow);}/** *  页面开始加载时调用 * *  @param webView    实现该代理的webview *  @param navigation 当前navigation */- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation {    NSLog(@"%s", __FUNCTION__);}/** *  接收到服务器跳转请求之后调用 * *  @param webView      实现该代理的webview *  @param navigation   当前navigation */- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation {    NSLog(@"%s", __FUNCTION__);}/** *  加载失败时调用 * *  @param webView    实现该代理的webview *  @param navigation 当前navigation *  @param error      错误 */- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {    NSLog(@"%s", __FUNCTION__);}/** *  当内容开始返回时调用 * *  @param webView    实现该代理的webview *  @param navigation 当前navigation */- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation {    NSLog(@"%s", __FUNCTION__);}/** *  页面加载完成之后调用 * *  @param webView    实现该代理的webview *  @param navigation 当前navigation */- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {    NSLog(@"%s", __FUNCTION__);}// 导航失败时会回调- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {}// 对于HTTPS的都会触发此代理,如果不要求验证,传默认就行// 如果需要证书验证,与使用AFN进行HTTPS证书验证是一样的- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler {    NSLog(@"%s", __FUNCTION__);    completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);}// 9.0才能使用,web内容处理中断时会触发- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {    NSLog(@"%s", __FUNCTION__);}// 从web界面中接收到一个脚本时调用#pragma mark - WKScriptMessageHandler- (void)userContentController:(WKUserContentController *)userContentController      didReceiveScriptMessage:(WKScriptMessage *)message {    if ([message.name isEqualToString:@"AppModel"]) {        // 打印所传过来的参数,只支持NSNumber, NSString, NSDate, NSArray,        // NSDictionary, and NSNull类型        NSLog(@"======>%@", message.body);    }}#pragma mark - KVO- (void)observeValueForKeyPath:(NSString *)keyPath                      ofObject:(id)object                        change:(NSDictionary<NSString *,id> *)change                       context:(void *)context {    if ([keyPath isEqualToString:@"loading"]) {        NSLog(@"loading");    } else if ([keyPath isEqualToString:@"title"]) {        self.title = self.webView.title;    } else if ([keyPath isEqualToString:@"estimatedProgress"]) {        NSLog(@"progress: %f", self.webView.estimatedProgress);        self.progressView.progress = self.webView.estimatedProgress;    }    // 加载完成    if (!self.webView.loading) {        // 手动调用JS代码        // 每次页面完成都弹出来,大家可以在测试时再打开        NSString *js = @"callJsAlert()";        [self.webView evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) {            NSLog(@"response: %@ error: %@", response, error);            NSLog(@"call js alert by native");        }];        NSString *jsData = http://www.mamicode.com/@"calltoValue(‘参数‘)";        [self.webView evaluateJavaScript:jsData completionHandler:^(id _Nullable response, NSError * _Nullable error) {            NSLog(@"response: %@ error: %@", response, error);            NSLog(@"------->call js alert by native");        }];        [UIView animateWithDuration:0.5 animations:^{          self.progressView.alpha = 0;        }];    }}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}@end
<!DOCTYPE html><html>    <head>        <title>iOS and Js</title>        <style type="text/css">            * {                font-size: 40px;            }        </style>    </head>    <body>        <div style="margin-top: 100px">            <h1>Test how to use objective-c call js</h1><br/>            <div><input type="button" value=http://www.mamicode.com/"call js alert" onclick="callJsAlert()"></div>            <br/>            <div><input type="button" value=http://www.mamicode.com/"Call js confirm" onclick="callJsConfirm()"></div><br/>        </div>        <br/>        <div>            <div><input type="button" value=http://www.mamicode.com/"Call Js prompt " onclick="callJsInput()"></div><br/>            <div>Click me here: <a href=http://www.mamicode.com/"http://www.baidu.com">Jump to Baidu</a></div>        </div>        <br/>        <div id="SwiftDiv">            <span id="jsParamFuncSpan" style="color: red; font-size: 50px;"></span>        </div>        <script type="text/javascript">            function callJsAlert() {                alert(‘Objective-C call js to show alert‘);                window.webkit.messageHandlers.AppModel.postMessage({body: ‘call js alert in js‘});            }        function callJsConfirm() {            if (confirm(‘confirm‘, ‘Objective-C call js to show confirm‘)) {                document.getElementById(‘jsParamFuncSpan‘).innerHTML                = ‘true‘;            } else {                document.getElementById(‘jsParamFuncSpan‘).innerHTML                = ‘false‘;            }            // AppModel是我们所注入的对象            window.webkit.messageHandlers.AppModel.postMessage({body: ‘call js confirm in js‘});        }        function calltoValue(data){            window.webkit.messageHandlers.AppModel.postMessage({body:data})        }        function callJsInput() {            var response = prompt(‘Hello‘, ‘Please input your name:‘);            document.getElementById(‘jsParamFuncSpan‘).innerHTML = response;            // AppModel是我们所注入的对象            window.webkit.messageHandlers.AppModel.postMessage({body: response});        }        </script>    </body></html>



文/Ylang(简书作者)
原文链接:http://www.jianshu.com/p/b9728204e5f9
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

wkwebview 代理介绍