iOS WKWebView 如何使用

apple官方文档https://developer.apple.com/documentation/webkit

WKWebView 是苹果在iOS 8中引入的新组件,目的是提供一个现代的支持最新Webkit功能的网页浏览控件,摆脱过去 UIWebView的老、旧、笨,特别是内存占用量巨大的问题。它使用与Safari中一样的Nitro JavaScript引擎,大大提高了页面js执行速度。

相比于UIWebView的优势: 

在性能、稳定性、占用内存方面有很大提升; 

允许JavaScript的Nitro库加载并使用(UIWebView中限制) 

增加加载进度属性:estimatedProgress,不用在自己写假进度条了 支持了更多的HTML的属性

具体分析WKWebView的优劣势

内存占用是UIWebView的1/4~1/3

页面加载速度有提升,有的文章说它的加载速度比UIWebView提升了一倍左右。

更为细致地拆分了 UIWebViewDelegate 中的方法

自带进度条。不需要像UIWebView一样自己做假进度条(通过NJKWebViewProgress和双层代理技术实现),技术复杂度和代码量,根贴近实际加载进度优化好的多。

允许JavaScript的Nitro库加载并使用(UIWebView中限制)

可以和js直接互调函数,不像UIWebView需要第三方库WebViewJavascriptBridge来协助处理和js的交互。

不支持页面缓存,需要自己注入cookie,而UIWebView是自动注入cookie。

无法发送POST参数问题

基本参数解释:

WKWebView:网页的渲染与展示,通过WKWebViewConfiguration可以进行自定义配置。

WKWebViewConfiguration:这个类专门用来配置WKWebView。

WKPreference:这个类用来进行相关webView设置。

WKProcessPool:这个类用来配置进程池,与网页视图的资源共享有关。

WKUserContentController:这个类主要用来做native与JavaScript的交互管理。

WKUserScript:用于进行JavaScript注入。

WKScriptMessageHandler:这个类专门用来处理JavaScript调用native的方法。

WKNavigationDelegate:网页跳转间的导航管理协议,这个协议可以监听网页的活动。

WKNavigationAction:网页某个活动的示例化对象。

WKUIDelegate:用于交互处理JavaScript中的一些弹出框。

WKBackForwardList:堆栈管理的网页列表。

WKBackForwardListItem:每个网页节点对象。

1.加载网页

WKWebViewConfiguration *webConfiguration = [WKWebViewConfiguration new];

   WKWebView *webView=[[WKWebView alloc]initWithFrame:CGRectZero configuration:webConfiguration];

    [self.view addSubview:self.webView];

    [webView mas_makeConstraints:^(MASConstraintMaker *make) {

        make.top.offset(self.zxNavigationbarHeight);

        make.left.right.offset(0);

        make.bottom.offset(0);

    }];

    NSURL *url = [NSURL URLWithString:self.strUrl];

    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];

    [webView loadRequest:request];

2.进度条和标题

    _progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, self.zxNavigationbarHeight,                                                     self.view.frame.size.width, 2)];

    _progressView.tintColor = [UIColor blueColor];

    _progressView.trackTintColor = [UIColor clearColor];

    [self.view addSubview:_progressView];

//添加监测网页加载进度的观察者

    [self.webView addObserver:self

                   forKeyPath:NSStringFromSelector(@selector(estimatedProgress))

                      options:0

                      context:nil];

    [self.webView addObserver:self

                   forKeyPath:@"title"

                      options:NSKeyValueObservingOptionNew

                      context:nil];

//kvo 监听进度和标题 必须实现此方法

-(void)observeValueForKeyPath:(NSString *)keyPath

                     ofObject:(id)object

                       change:(NSDictionary<NSKeyValueChangeKey,id> *)change

                      context:(void *)context{


    if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))]

        && object == _webView) {


        DDLog(@"网页加载进度 = %f",_webView.estimatedProgress);

        self.progressView.progress = _webView.estimatedProgress;

        if (_webView.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 == _webView){

        self.navigationItem.title = _webView.title;

    }else{

        [super observeValueForKeyPath:keyPath

                             ofObject:object

                               change:change

                              context:context];

    }

}

- (void)dealloc{

    //移除观察者

    [_webView removeObserver:self

                  forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];

    [_webView removeObserver:self

                  forKeyPath:NSStringFromSelector(@selector(title))];

}

3.刷新、上一页、下一页

- (void)goBackAction:(id)sender{

    if ([self.webView canGoBack]) {

        [self.webView goBack];

    }

}

- (void)refreshAction:(id)sender{

    [self.webView reload];

}

-(void)goNextAction:(id)sender{

    if ([self.webView canGoForward]) {

        [self.webView goForward];

    }

}

4.OC调用JS

//OC调用JS

- (void)ocToJs{

    //changeColor()是JS方法名,completionHandler是异步回调block

    NSString *jsString = [NSString stringWithFormat:@"changeColor('%@')", @"Js颜色参数"];

    [_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) {

        DDLog(@"改变HTML的背景色");

    }];


    //改变字体大小 调用原生JS方法

    NSString *jsFont = [NSString stringWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'", arc4random()%99 + 100];

    [_webView evaluateJavaScript:jsFont completionHandler:nil];


    NSString * path =  [[NSBundle mainBundle] pathForResource:@"girl" ofType:@"png"];

    NSString *jsPicture = [NSString stringWithFormat:@"changePicture('%@','%@')", @"pictureId",path];

    [_webView evaluateJavaScript:jsPicture completionHandler:^(id _Nullable data, NSError * _Nullable error) {

        DDLog(@"切换本地头像");

    }];


}

//OC调用JS改变背景色

    function changeColor(parameter)

    {

        document.body.style.backgroundColor = randomColor();

    }

5.JS调用OC

//方式一.WKNavigationDelegate通过即将跳转的url拦截

// 根据WebView对于即将跳转的HTTP请求头信息和相关信息来决定是否跳转

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {


    NSString * urlStr = navigationAction.request.URL.absoluteString;

    NSLog(@"发送跳转请求:%@",urlStr);

    //自己定义的协议头

    NSString *htmlHeadString = @"github://";

    if([urlStr hasPrefix:htmlHeadString]){

        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"通过截取URL调用OC" message:@"你想前往我的Github主页?" preferredStyle:UIAlertControllerStyleAlert];

        [alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {


        }])];

        [alertController addAction:([UIAlertAction actionWithTitle:@"打开" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

            NSURL * url = [NSURL URLWithString:[urlStr stringByReplacingOccurrencesOfString:@"github://callName_?" withString:@""]];

            [[UIApplication sharedApplication] openURL:url];


        }])];

        [self presentViewController:alertController animated:YES completion:nil];


        decisionHandler(WKNavigationActionPolicyCancel);


    }else{

        decisionHandler(WKNavigationActionPolicyAllow);

    }

}

//方式二.WKScriptMessageHandler注册相应交互事件

//自定义的WKScriptMessageHandler 是为了解决内存不释放的问题

        WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self];

        //这个类主要用来做native与JavaScript的交互管理

        WKUserContentController * wkUController = [[WKUserContentController alloc] init];

        //注册一个name为jsToOcNoPrams的js方法 设置处理接收JS方法的对象

        [wkUController addScriptMessageHandler:weakScriptMessageDelegate  name:@"jsToOcNoPrams"];

        [wkUController addScriptMessageHandler:weakScriptMessageDelegate  name:@"jsToOcWithPrams"];


        config.userContentController = wkUController;

- (void)dealloc{

    //移除注册的js方法

    [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsToOcNoPrams"];

    [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsToOcWithPrams"];

}

//被自定义的WKScriptMessageHandler在回调方法里通过代理回调回来,绕了一圈就是为了解决内存不释放的问题

//通过接收JS传出消息的name进行捕捉的回调方法

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

    DDLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);

    //用message.body获得JS传出的参数体

    NSDictionary * parameter = message.body;

    //JS调用OC

    if([message.name isEqualToString:@"jsToOcNoPrams"]){

        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js调用到了oc" message:@"不带参数" preferredStyle:UIAlertControllerStyleAlert];

        [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

        }])];

        [self presentViewController:alertController animated:YES completion:nil];


    }else if([message.name isEqualToString:@"jsToOcWithPrams"]){

        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js调用到了oc" message:parameter[@"params"] preferredStyle:UIAlertControllerStyleAlert];

        [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

        }])];

        [self presentViewController:alertController animated:YES completion:nil];

    }

}

function jsToOcFunction1()

    {

       window.webkit.messageHandlers.jsToOcNoPrams.postMessage({});

    }


    function jsToOcFunction2()

    {

        window.webkit.messageHandlers.jsToOcWithPrams.postMessage({"params":"我是参数"});

    }

//方式三.WKUIDelegate捕获系统交互

/**

*  web界面中有弹出警告框时调用

*

*  @param webView          实现该代理的webview

*  @param message          警告框中的内容

*  @param completionHandler 警告框消失调用

*/

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"HTML的弹出框" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];

    [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

        completionHandler();

    }])];

    [self presentViewController:alertController animated:YES completion:nil];

}

// 确认框

//JavaScript调用confirm方法后回调的方法 confirm是js中的确定框,需要在block中把用户选择的情况传递进去

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];

    [alertController addAction:([UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

        completionHandler(NO);

    }])];

    [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

        completionHandler(YES);

    }])];

    [self presentViewController:alertController animated:YES completion:nil];

}

// 输入框

//JavaScript调用prompt方法后回调的方法 prompt是js中的输入框 需要在block中把用户输入的信息传入

- (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:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

        completionHandler(alertController.textFields[0].text?:@"");

    }])];

    [self presentViewController:alertController animated:YES completion:nil];

}

// 页面是弹出窗口 _blank 处理

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {

    if (!navigationAction.targetFrame.isMainFrame) {

        [webView loadRequest:navigationAction.request];

    }

    return nil;

}

function showAlert()

    {

        alert("被OC截获到了");

    }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容