WebView和JS交互

作者: MadeLife | 来源:发表于2016-12-07 15:02 被阅读0次

    前言

    在开发IOS应用的过程中,难免的会遇到和WebView打交道的场景,通常为了实现产品经理的功能需求还要去和WebView里面的JS进行交互。作为一个刚IOS开发的新人来说,第一次肯定会遇到各种问题和各种坑。在这里我把我的问题和解决方法罗列出来,希望对其他的大胸弟们有所帮助。

    概述

    IOS提供给我们的WebView控件类型总共有3中,UIWebViewWkWebViewSFSafariView。这三种类型的控件有这不同的使用限制和要求,在实际项目中,我们需要根据项目的实际要求选择其中的一个就可以了。接下来,我会介绍一下这三种类型的区别。

    UIWebView

    UIWebView作为IOS应用提供给开发者最早的一个控件,最初还是一个很不错的控件,但是基于今天的现状而言,却显得有些鸡肋了。加载速度慢,内存开销大对于产品和开发者来说都是很大的问题,特别是在第一次加载网页时,经常会出现加载10秒以上的情况。

    UIWebView加载过程

    UIWebView加载网页主要会用到一下四个方法

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    

    当WebView收到一个打开链接请求时,会触发此方法,向我们询问是否要加载这个链接请求,返回YES就表示允许加载这个链接请求,否则不加载链接请求。

    - (void) webViewDidStartLoad:(UIWebView *)webView
    

    当上一步允许加载链接请求后,WebView会触发此方法,告知我们要开始加载了,这时我们可以加一个loading的效果提示用户。

    - (void) webViewDidFinishLoad:(UIWebView *)webView
    

    当整个网页加载完成之后会触发此方法,如果上一步加上loading效果的话,在这个就要去掉了

    - (void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
    

    当加载过程中出错,比如无网络、404什么的,会执行这个方法。这里我们要把loading去掉,如果为了友好的话,可以展示一个加载失败的界面。

    UIWebView和JS交互

    UIWebView和JS交互主要依托于一个JSExport的协议,具体来说就是在加载网页的过程中,我们去拿到网页运行JS的环境,然后JS执行某些方法时我们就可以捕获到,然后执行自己的逻辑。

    注意:和JS的交互过程中需要分两种情况,一种是捕获JS中无参数或一种参数的方法,另一种是捕获JS中大于等于2个参数的方法。因为OC中的方法名是由传统意义上的方法名+外部参数名构成的,所以当我们捕获第二种情况的JS方法时需要注意和OC方法名的对应关系。下面的示例中会有介绍。

    OK,接下来给大家放出一段示例代码,示例中会讲解到UIWebView和加载一个网页的流程,以及网页的JS如何和原生的代码交互。

    ViewController.h

    //
    //  ViewController.h
    //  webviewDemo
    //
    //  Created by 孙天文 on 16/11/15.
    //  Copyright © 2016年 孙天文. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    #import <JavaScriptCore/JavaScriptCore.h>
    
    //定义一个和JS交互的协议,用来处理JS中的方法,这个协议中列出了4个方法,分别是无参数、一个参数、两个参数以及三个参数的方法
    @protocol demoJsResponseProtocol <JSExport>
    
    - (void) sayHello;
    
    - (void) setTitle:(NSString *)title;
    
    //下面是大于等于两个参数的情况,要注意这个格式和JS中的格式对比
    - (void) setTitle:(NSString *)title Left:(NSString *)leftTitle;
    
    - (void) setTitle:(NSString *)title Left:(NSString *)leftTitle Right:(NSString *)rightTitle;
    
    @end
    
    @interface ViewController : UIViewController<demoJsResponseProtocol>
    
    @end
    

    ViewController.m

    //
    //  ViewController.m
    //  webviewDemo
    //
    //  Created by 孙天文 on 16/11/15.
    //  Copyright © 2016年 孙天文. All rights reserved.
    //
    
    #import "ViewController.h"
    
    @interface ViewController ()<UIWebViewDelegate,JSExport>
        
    @property (strong,nonatomic) UIWebView *webView;
     
     //JS运行环境   
    @property (strong,nonatomic) JSContext *jsContext;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
        self.webView.delegate = self;
        
        //加载本地html文件
        NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"html"];
        NSString *htmlString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
        NSString *basePath = [[NSBundle mainBundle] bundlePath];
        NSURL *baseURL = [NSURL fileURLWithPath:basePath];
        
        [self.webView loadHTMLString:htmlString baseURL:baseURL];
        
        [self.view addSubview:self.webView];
    }
        
    //网页加载前调用的方法
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
        
        return YES;
    }
        
    //开始加载
    - (void) webViewDidStartLoad:(UIWebView *)webView{
        NSLog(@"start laod");
    }
        
    //加载完成
    - (void) webViewDidFinishLoad:(UIWebView *)webView{
        self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        self.jsContext[@"demoapi"] = self;
        NSLog(@"laod finish");
    }
    
    //加载出错
    - (void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
        NSLog(@"load error %@",error);
    }
        
    //执行JS方法
    - (void) doJavaScriptFunction:(NSString *)jsfunction{
        [self.jsContext evaluateScript:jsfunction];
        
    }
    
    - (void) sayHello{
        [self showAlertDesc:@"hello world"];
    }
        
    - (void) setTitle:(NSString *)title{
        [self showAlertDesc:@"setTitle"];
    }
        
    //下面是大于等于两个参数的情况,要注意这个格式和JS中的格式对比    
    - (void) setTitle:(NSString *)title Left:(NSString *)leftTitle{
        [self showAlertDesc:@"setTitleLeft"];
    }
        
    - (void) setTitle:(NSString *)title Left:(NSString *)leftTitle Right:(NSString *)rightTitle{
        [self showAlertDesc:@"setTitleLeftRight"];
    }
        
    - (void) showAlertDesc:(NSString *)desc{
        UIAlertController *alertController  = [UIAlertController alertControllerWithTitle:@"" message:desc preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
        [alertController addAction:okAction];
        [self presentViewController:alertController animated:YES completion:nil];
    }
        
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    

    test.html

    <!DOCTYPE html>
    <html>
        <head>
            <style>
                .button{
                    background-color: #d9edf7!important;
                    display:block;
                    margin-top:40px;
                    height:30px;
                }
            </style>
        </head>
        <body>
            <a href = "#" class = "button" onclick = "sayHello()">Say Hello</a>
            <a href = "#" class = "button" onclick = "setTitle()">Set Title</a>
            <a href = "#" class = "button" onclick = "setTitle2()">Set Title Left</a>
            <a href = "#" class = "button" onclick = "setTitle3()">Set Title Left Right</a>
        </body>
        
        <script type="text/javascript">
            function sayHello(){
                demoapi.sayHello();
            }
        
            function setTitle(){
                demoapi.setTitle("Title1");
            }
        
            //下面是大于等于两个参数的情况,要注意这个格式和JS中的格式对比
            function setTitle2(){
                demoapi.setTitleLeft("Title2","LeftTitle2");
            }
        
            function setTitle3(){
                demoapi.setTitleLeftRight("Title3","LeftTitle3","RightTitle3");
            }
        </script>
    </html>
    

    WKWebView

    WKWebView作为苹果官方推荐的Web控件,在UIWebView的基础上进行重构,加载速度和内存开销上都有很大的提升,当我们需要集成该控件时,需要去注意改控件提供和方法和UIWebView的不同。需要注意一点,这个控件要求系统版本最低是IOS8,如果你的项目需要覆盖IOS8一下的用户的话,还是乖乖的去用UIWebView吧。

    详细情况后续补充

    SFSafariView

    SFSafariView给人直观的印象是把Safari内嵌到了APP当中,目前笔者还没有接触过,这里就不在叙述更多的信息了,如果后面结果的话,会再写一篇博客进行详细说明。

    相关文章

      网友评论

        本文标题:WebView和JS交互

        本文链接:https://www.haomeiwen.com/subject/uggdmttx.html