美文网首页
iOS与JavaScript交互一: 拦截URL

iOS与JavaScript交互一: 拦截URL

作者: Carson_Zhu | 来源:发表于2018-02-14 20:30 被阅读37次

    本地HTML

    简单的两个按钮演示OC传数据到JavaScriptOC获取JavaScript数据。

    <!DOCTYPE html>
    <html lang="zh-cn">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
        <script>
            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 asyncAlert(content) {
                setTimeout(function(){
                    alert(content);
                },1);
            }
            
            function showAlert() {
                loadURL("test://showAlert");
            }
            
            function alertWithMessage(content) {
                asyncAlert(content);
                document.getElementById("returnValue").value = content;
            }
            
            function setColor() {
                loadURL("test://setColor?r=10&g=170&b=250&a=0.5");
            }
            
        </script>
    </head>
    <body>
    
        <input type="button" value="OC调用JS方法" onclick="showAlert()">
        <input type="button" value="JS传数据到OC" onclick="setColor()">
    
    </body>
    </html>
    

    UIWebView拦截URL

    加载WebView
    - (void)loadWebView {
        self.webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
        self.webView.delegate = self; // 设置代理
        
        NSURL *indexURL = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html"];
        NSURLRequest *request = [NSURLRequest requestWithURL:indexURL];
        [self.webView loadRequest:request]; // 加载html
        [self.view addSubview:self.webView];
    }
    
    拦截URL

    WebView拦截URL是在shouldStartLoadWithRequest:代理方法中拦截每一个链接的Requestreturn YES就会加载这个链接,return NO就不会加载这个连接。

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
        NSString *scheme = request.URL.scheme;
        if ([scheme isEqualToString:@"test"]) {
            [self handleURL:request.URL];
            return NO;
        }
        return YES;
    }
    

    这里通过scheme,来拦截掉自定义的URL就非常容易了,如果不同的方法使用不同的scheme,那么判断起来就非常的麻烦。

    - (void)handleURL:(NSURL *)URL {
        if ([URL.host isEqualToString:@"showAlert"]) {
            // 将结果返回给JS
            NSString *jsStr = [NSString stringWithFormat:@"alertWithMessage('%@')",@"OC调用JS的方法"];
            [self.webView stringByEvaluatingJavaScriptFromString:jsStr];
        }
        else if ([URL.host isEqualToString:@"setColor"]) {
            // 解析传过来的字符串,拿到属于颜色的部分
            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]];
                }
            }
            CGFloat r = [[tempDic objectForKey:@"r"] floatValue];
            CGFloat g = [[tempDic objectForKey:@"g"] floatValue];
            CGFloat b = [[tempDic objectForKey:@"b"] floatValue];
            CGFloat a = [[tempDic objectForKey:@"a"] floatValue];
            // 设置导航颜色方便观察
            self.navigationController.navigationBar.backgroundColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a];
        }
    }
    
    UIWebView调用JS方法
    // UIWebView调用JS方法
    - (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
    

    如果回调执行的JS方法带参数,而参数不是字符串时,不要加单引号,否则可能导致调用JS方法失败。

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:userProfile options:NSJSONWritingPrettyPrinted error:nil];
    NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSString *jsStr = [NSString stringWithFormat:@"loginResult('%@',%@)",type, jsonStr];
    [self.webView stringByEvaluatingJavaScriptFromString:jsStr];
    

    HMTLJS环境中插入全局变量、JS方法等。

    [webView stringByEvaluatingJavaScriptFromString:@"var arr = [3, 4, 'abc'];"];
    
    效果:

    WKWebView拦截URL

    WKWebViewUIWebView拦截URL的处理方式基本一样。除了代理方法和WKWebView的使用不太一样。

    加载WKWebView
    - (void)loadWKWebView {
        WKWebViewConfiguration *config = [WKWebViewConfiguration new];
        WKPreferences *preferences = [WKPreferences new];
        preferences.minimumFontSize = 30;
        config.preferences = preferences;
        self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
        self.webView.UIDelegate = self;
        self.webView.navigationDelegate = self;
        
        NSURL *URL = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html"];
        NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
        [self.webView loadRequest:request];
        [self.view addSubview:self.webView];
    }
    
    拦截URL

    使用WKNavigationDelegate中的代理方法,拦截自定义的URL来实现JS调用OC方法。注意调用decisionHandler这个block,否则会导致App崩溃。

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
        NSString *scheme = navigationAction.request.URL.scheme;
        if ([scheme isEqualToString:@"test"]) {
            [self handleURL:navigationAction.request.URL];
            decisionHandler(WKNavigationActionPolicyCancel); //不允许跳转
            return;
        }
        decisionHandler(WKNavigationActionPolicyAllow); // 允许跳转
    }
    
    - (void)handleURL:(NSURL *)URL {
        if ([URL.host isEqualToString:@"showAlert"]) {
            NSString *jsStr = [NSString stringWithFormat:@"alertWithMessage('%@')",@"OC调用JS的方法"];
            [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
                NSLog(@"%@----%@",result, error);
            }];
        }
        
        else if ([URL.host isEqualToString:@"setColor"]) {
            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]];
                }
            }
            CGFloat r = [[tempDic objectForKey:@"r"] floatValue];
            CGFloat g = [[tempDic objectForKey:@"g"] floatValue];
            CGFloat b = [[tempDic objectForKey:@"b"] floatValue];
            CGFloat a = [[tempDic objectForKey:@"a"] floatValue];
            
            self.navigationController.navigationBar.backgroundColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a];
        }
    }
    
    WKWebView调用JS方法

    JS执行成功还是失败会在completionHandler中返回。所以使用这个API就可以避免执行耗时的JS,或者alert导致界面卡住的问题。

    - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
    
    WKWebView中使用弹窗

    如果在WKWebView中使用alertconfirm等弹窗,就得实现WKUIDelegate中相应的代理方法。

    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
        UIAlertController *alertCrontroller = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
        [alertCrontroller addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            completionHandler();
        }]];
        [self presentViewController:alertCrontroller animated:YES completion:nil];
    }
    

    其中completionHandler这个block一定得调用,至于在哪里调用,倒是无所谓,我们也可以写在方法实现的第一行,或者最后一行。

    效果:

    相关文章

      网友评论

          本文标题:iOS与JavaScript交互一: 拦截URL

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