美文网首页
iOS开发-JS与原生OC互相调用之问题总结一

iOS开发-JS与原生OC互相调用之问题总结一

作者: iOS_ZZ | 来源:发表于2018-10-09 10:49 被阅读0次

    近期由于工作和个人的闲置没有及时的更新博客,为此对各位同学表示抱歉,今天我们就聊聊那些在iOS中JS与原生OC互相调用,那么废话不多说直接上代码~

    • JS中的一些细节
    • stringByEvaluatingJavaScriptFromString方法注意
    • UIWebView拦截URL总结
    • OC调用JS方法(注意点)

    JS中的一些细节

    • JS中自定义的URL,在被拦截到的时候url scheme会全部转成小写!
    • html中需要设置编码,否则中文参数可能会出现编码问题!
    • JS打开一个iFrame的方式替代直接用document.location的方式,以避免多次请求,被替换覆盖的问题!

    stringByEvaluatingJavaScriptFromString方法注意

    • stringByEvaluatingJavaScriptFromString是一个同步的方法,使用它执行JS方法时,如果JS方法比较耗的时候,会造成界面卡顿!尤其是js弹出alert的时候。alert也会阻塞界面,等待用户响应,而stringByEvaluatingJavaScriptFromString又会等待js执行完毕返回。这就造成了死锁。官方推荐使用WKWebView的evaluateJavaScript:completionHandler:代替这个方法。
    • 其实我们也有另外一种方式,自定义一个延迟执行alert的方法来防止阻塞,然后我们调用自定义的alert方法。同理,耗时较长的js方法也可以放到setTimeout中。
    `function asyncAlert(content)``{    `
    
    `     setTimeout(function(){         `
    
    `          alert(content);         `
    
    `     },1);`
    
    `}`
    

    UIWebView拦截URL总结

    • 为什么自定义一个loadURL方法,而不直接使用window.location.href?
      答:因为如果当前网页正使用window.location.href加载网页的同时,调用window.location.href去调用OC原生方法,会导致加载网页的操作被取消掉。同样的,如果连续使用window.location.href执行两次OC原生调用,也有可能导致第一次的操作被取消掉。所以我们使用自定义的loadURL,来避免这个问题。
    • loadURL的实现可以参考关于UIWebView和PhoneGap一文。
    • 为什么loadURL中的链接,要规范使用统一的scheme?
      答:便于在OC中做拦截处理,减少在JS中调用一些OC没有实现的方法时,造成的webView跳转现象。因为我们在OC中拦截URL时,根据scheme
      (即actionType)来区分是调用原生的方法还是正常的网页跳转。然后根据host(即//后的部分getLocation)来区分执行什么操作。
    • 为什么自定义一个asyncAlert方法?
      答:因为有的JS调用是需要OC返回结果到JS的。stringByEvaluatingJavaScriptFromString是一个同步方法,会等待js 方法执行完成,而弹出的alert也会阻塞界面等待用户响应,所以他们可能会造成死锁。导致alert 卡死界面。如果回调的JS 是一个耗时的操作,那么建议将耗时的操作也放入setTimeoutfunction 中。
    • UIWebView是如何拦截URL的?
      答:UIWebView有一个代理方法,可以拦截到每一个链接的Request。return YES,webView 就会加载这个链接;return NO,webView就不会加载这个链接。我们就在这个拦截的代理方法中处理自己的URL。
    • 代码示例
    #pragma mark - UIWebViewDelegate
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:
    (UIWebViewNavigationType)navigationType {
    
    NSURL *URL = request.URL;
    NSString *scheme = [URL scheme]; 
    
    if ([scheme isEqualToString:@"haleyaction"]) {
    
            [self handleCustomAction:URL];
    
            returnNO;
    
        }
    
     returnYES;
    
    }
    
    • 这里通过scheme,来拦截掉自定义的URL就非常容易了,如果不同的方法使用不同的scheme,那么判断起来就非常的麻烦。那么直接代码示例:
    #pragma mark - 拦截URL调OC原生的方法
    - (void)handleCustomAction:(NSURL *)URL {
    
        NSString *host = [URL host];
    
        if ([host isEqualToString:@"scan"]) {
    
        } elseif ([host isEqualToString:@"share"]) {
    
            [self share:URL];
    
        } elseif ([host isEqualToString:@"getLocation"]) {
    
            [self getLocation];
    
        } elseif ([host isEqualToString:@"pay"]) {
    
            [self payAction:URL];
    
        } elseif ([host isEqualToString:@"shake"]) {
    
            [self shakeAction];
    
        } elseif ([host isEqualToString:@"back"]) {
    
            [self goBack];
    
        }
    
    }
    
    • 如何将结果回调到JS中
    - (void)getLocation {
     // 获取位置信息
    
     // 将结果返回给js
    
     NSString *jsStr = [NSStringstringWithFormat:@"setLocation('%@')",@"广东省深圳市宝安区西乡街道XXXX号"];
    
        [self.webView stringByEvaluatingJavaScriptFromString:jsStr];
    }
    
    • 当然有时候我们在JS中调用OC方法的时候,也需要传参数到OC中,怎么传呢?就像一个get请求一样,把参数拼接在后面就行:
    function share() {
        loadURL("haleyAction://shareClick?title=测试标题&content=测试内容&url=http://www.baidu.com");
    }
    
    • 那么如何获取到这些参数呢?所有的参数都在URL的query中,先通过&将字符串拆分,在通过=把参数拆分成key和value示例代码:
    - (void)share:(NSURL *)URL
    {
        NSArray *params =[URL.query componentsSeparatedByString:@"&"];
    
        NSMutableDictionary *tempDic = [NSMutableDictionary dictionary];
    
        for (NSString *paramStrin params) {
    
            NSArray *dicArray = [paramStr componentsSeparatedByString:@"="];
    
            if (dicArray.count >1) {   
                NSString *decodeValue = [dicArray[1]
    stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
                [tempDic setObject:decodeValue forKey:dicArray[0]];
            }
        }
        NSString *title = [tempDic objectForKey:@"title"];
    
        NSString *content = [tempDic objectForKey:@"content"];
    
        NSString *url = [tempDic objectForKey:@"url"];
    
     // 在这里执行分享的操作
    
     // 将分享结果返回给js
    
        NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url];
    
        [self.webView stringByEvaluatingJavaScriptFromString:jsStr];
    }
    

    OC调用JS方法(注意点)

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

    相关文章

      网友评论

          本文标题:iOS开发-JS与原生OC互相调用之问题总结一

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