美文网首页
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