美文网首页
WKWebView与JS交互

WKWebView与JS交互

作者: zziazm | 来源:发表于2018-01-03 09:44 被阅读22次

    首先要在使用的地方引入WebKit#import <WebKit/WebKit.h>

    初始化

    WKWebView有一个指定初始化方法:

    /*! @abstract Returns a web view initialized with a specified frame and
     configuration.
     @param frame The frame for the new web view.
     @param configuration The configuration for the new web view.
     @result An initialized web view, or nil if the object could not be
     initialized.
     @discussion This is a designated initializer. You can use
     @link -initWithFrame: @/link to initialize an instance with the default
     configuration. The initializer copies the specified configuration, so
     mutating the configuration after invoking the initializer has no effect
     on the web view.
     */
    
    
    - (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
    

    这个方法里的configuration可以配置很多东西,比如配置js是否支持等等。它有一个属性userContentController,后面讲的OC和JS交互,以及诸如js代码都会用到它。

    JS调用OC的方法

    1.拦截URL
    html的代码:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
            <meta name="apple-mobile-web-app-capable" content="yes">
            <meta name="apple-mobile-web-app-status-bar-style" content="black" />
            <meta name="format-detection" content="telephone=no" />
            <title>分享页</title>
        </head>
        <body>
            <p></p>
            <div>
                <button onclick="showToast();">无参数弹框提示</button>
                <button onclick="showToastWithParameter();">有参数弹框提示</button>
                <button onclick="shareClick();">Click Me!</button>
            </div>
            <p></p>
            <script>
                function showToast() {
                    window.location.href = 'test1://showToast';
                }
            
            function showToastWithParameter() {
                window.location.href = 'test1://showToastWithParameter?parama=666666';
            }
            
            //不使用window.location.href
            function loadURL(url) {
                var iFrame;
                iFrame = document.createElement("iframe");
                iFrame.setAttribute("src", url);
                iFrame.setAttribute("style", "display:none;");
                iFrame.setAttribute("height", "0px");
                iFrame.setAttribute("width", "0px");
                iFrame.setAttribute("frameborder", "0");
                document.body.appendChild(iFrame);
                // 发起请求后这个 iFrame 就没用了,所以把它从 dom 上移除掉
                iFrame.parentNode.removeChild(iFrame);
                iFrame = null;
            }
            function shareClick() {
                loadURL("Test2://shareClick?title=分享的标题&content=分享的内容&url=链接地址&imagePath=图片地址");
            }
            </script>
        </body>
    </html>
    
    

    当用户点击按钮时,会在WKWebview的代理方法:

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
        NSURLRequest *request = [navigationAction request];
        NSString * scheme = request.URL.scheme;
        NSString * host = request.URL.host;
        NSString * query = request.URL.query;
        if ([scheme isEqualToString:@"test1"]) {
            NSString *methodName = host;
            if (query) {
                methodName = [methodName stringByAppendingString:@":"];
            }
            SEL sel = NSSelectorFromString(methodName);
            NSString *parameter = [[query componentsSeparatedByString:@"="] lastObject];
            [self performSelector:sel withObject:parameter];
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
            
        }else if ([scheme isEqualToString:@"test2"]){//JS中的是Test2,在拦截到的url scheme全都被转化为小写。
            NSURL *url = request.URL;
            NSArray *params =[url.query componentsSeparatedByString:@"&"];
            NSMutableDictionary *tempDic = [NSMutableDictionary dictionary];
            for (NSString *paramStr in params) {
                NSArray *dicArray = [paramStr componentsSeparatedByString:@"="];
                if (dicArray.count > 1) {
                    NSString *decodeValue = [dicArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
                    [tempDic setObject:decodeValue forKey:dicArray[0]];
                }
            }
            
            
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"方式一" message:@"这是OC原生的弹出窗" delegate:self cancelButtonTitle:@"收到" otherButtonTitles:nil];
            [alertView show];
            NSLog(@"tempDic:%@",tempDic);
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    

    2.scriptMessageHandler
    这是Apple在WebKit里新增加的方法,位于WKUserContentController类里。

    /*! @abstract Adds a script message handler.
     @param scriptMessageHandler The message handler to add.
     @param name The name of the message handler.
     @discussion Adding a scriptMessageHandler adds a function
     window.webkit.messageHandlers.<name>.postMessage(<messageBody>) for all
     frames.
     */
    - (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
    
    /*! @abstract Removes a script message handler.
     @param name The name of the message handler to remove.
     */
    - (void)removeScriptMessageHandlerForName:(NSString *)name;
    

    第一个方法会在所有的frame里添加一个js的函数window.webkit.messageHandlers.<name>.postMessage(<messageBody>)。比如,我们在OC中添加一个handle:
    [_webView.configuration.userContentController removeScriptMessageHandlerForName:@"shareNothing"];
    当我们在js中调用下面方法时:
    window.webkit.messageHandlers.shareNothing.postMessage(null);//null必须要写
    我们在OC中会收到WKScriptMessageHandler的回调:

    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
        if ([message.name isEqualToString:@"shareNothing"]) {
        }
    }
    

    当然,记得在适当的地方调用removeScriptMessageHandler:

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

    html代码:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
            <meta name="apple-mobile-web-app-capable" content="yes">
            <meta name="apple-mobile-web-app-status-bar-style" content="black" />
            <meta name="format-detection" content="telephone=no" />
            <title>分享页</title>
        </head>
        <body>
            <p></p>
            <div>
                <button onclick="share('分享标题', 'http://cc.cocimg.com/api/uploads/170425/b2d6e7ea5b3172e6c39120b7bfd662fb.jpg', location.href)">分享</button>
                <button onclick="test()">分享不带参数</button>
    
            </div>
            <p></p>
            <script>
                function share (title, imgUrl, link) {
                    //便于WKWebView测试
                    window.webkit.messageHandlers.shareTitle.postMessage({aTitle: title, aImgUrl: imgUrl, aLink: link});
                    //这里需要OC实现
                }
                function test() {
                //便于WKWebView测试
                    window.webkit.messageHandlers.shareNothing.postMessage(null);//null必须要写
                }
            
            </script>
        </body>
    </html>
    

    OC代码:

    - (void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
        [_webView.configuration.userContentController addScriptMessageHandler:self name:@"shareTitle"];
        [_webView.configuration.userContentController addScriptMessageHandler:self name:@"shareNothing"];
    }
    
    - (void)viewWillDisappear:(BOOL)animated{
        [super viewWillDisappear:animated];
        [_webView.configuration.userContentController removeScriptMessageHandlerForName:@"shareTitle"];
        [_webView.configuration.userContentController removeScriptMessageHandlerForName:@"shareNothing"];
    }
    
    #pragma mark -- WKScriptMessageHandler
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
        
        NSString *name = message.name;
        id body = message.body;
        NSLog(@"%@", message.name);
        NSLog(@"%@", message.body);
        
        if ([name isEqualToString:@"shareTitle"]) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"成功" message:@"JS调用OC代码成功!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
            [alert show];
        }
        
        if ([name isEqualToString:@"shareNothing"]) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"成功" message:@"JS调用OC代码成功!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
            [alert show];
        }
    }
    

    3.JS对象:
    html代码:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
            <script>
                function test(paramete){
                    JSObject.share(paramete);
                }
            </script>
        </head>
        <body>
            <button onclick="test('1')" style="width: 80px;height: 35px;">分享</button>
    
            <div id='zsz'></div>
        </body>
    </html>
    
    

    html中用到了JSObject,这里oc里要添加自定义的脚本:

    /**
     * Native为H5提供的Api接口
     *
     * @type {js对象}
     */
    var JSObject = (function() {
    
        var NativeApi = {
            share: function(param) {
                //调用native端
                _nativeShare(param);
            },
        }
        function _nativeShare(param) {
            //js -> oc
            window.webkit.messageHandlers.shareTitle.postMessage(param);
        }
    
        //闭包,把Api对象返回
        return NativeApi;
    })();
    

    OC的代码:

    - (void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
        [self addNativeApiToJS];
    
    }
    - (void)viewWillDisappear:(BOOL)animated{
        [super viewWillDisappear:animated];
        [_webView.configuration.userContentController removeScriptMessageHandlerForName:@"shareTitle"];
    }
    - (void)addNativeApiToJS
    {
        //防止频繁IO操作,造成性能影响
        static NSString *nativejsSource;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            nativejsSource = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"NativeApi" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
        });
        //添加自定义的脚本
        WKUserScript *js = [[WKUserScript alloc] initWithSource:nativejsSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
        [self.webView.configuration.userContentController addUserScript:js];
        //注册回调
        [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"shareTitle"];
    }
    
    #pragma mark -- WKScriptMessageHandler
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
        
        NSString *name = message.name;
        id body = message.body;
        NSLog(@"%@", message.name);
        NSLog(@"%@", message.body);
        
        if ([name isEqualToString:@"shareTitle"]) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"成功" message:@"JS调用OC代码成功!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
            [alert show];
        }
        
    }
    

    相关文章

      网友评论

          本文标题:WKWebView与JS交互

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