zoukankan      html  css  js  c++  java
  • Ios开发之 -- js和ios的交互

    ==WebViewJavascriptBridge的介绍==
    #下载:https://github.com/marcuswestin/WebViewJavascriptBridge
    #关于WebViewJavascriptBridge的介绍:http://blog.csdn.net/yanghua_kobe/article/details/8209751
    ==WebViewJavascriptBridge(在与现有的业务代码结合使用中)的小问题==
    *demo部分(  ExampleApp.html界面中第50行):
     
           bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) {


           因为底层回传是两个參数responseCallback(message.error, message.responseData) ,因此reponse相应的是message.error,此demo中得到的是undefinded;
     
      
    *源代码实现部分(webview载入回调事件webViewDidFinishLoad):
       
    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        if (webView != _webView) { return; }


        if (![[_webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) {
            NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"];
            NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
            [_webView stringByEvaluatingJavaScriptFromString:js];
        }
        
        if (self.startupMessageQueue) {
            for (id queuedMessage in self.startupMessageQueue) {
                [self _dispatchMessage:queuedMessage];
            }
            self.startupMessageQueue = nil;
        }
        
        if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
            [self.webViewDelegate webViewDidFinishLoad:webView];
        }
    }


    WebViewJavascriptBridge的使用流程中要将webview的delegate首先设置为自身,这是必须条件,
    假设现有的业务代码中须要使用webview的回调事件。则须要在初始化WebViewJavascriptBridge时制定业务代码自身为兴许的delegate。
    在设定兴许delegate之后,会出现故障。


    以上代码会造成webViewDidFinishLoad被调用两次:业务代码中设置webview的回调事件,而以上代码中引入.js.txt资源,资源里有对dom的直接改动。也会触发webViewDidFinishLoad回调函数。
    由此造成业务代码中的webViewDidFinishLoad会被运行两次,形成错误或者不必要的多次调用。


    处理:在js.txt资源引入之前不运行兴许的代码处理。即阻止第一次的viewdidload的兴许调用,改动后例如以下:


    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        
        if (webView != _webView) { return; }
        if (![[_webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == 'object'"] isEqualToString:@"true"]) {
            NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"];
            NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
            [_webView stringByEvaluatingJavaScriptFromString:js];
        }
        //2012-12-3 对于源代码的变动,在js.txt载入之前,对于业务兴许调用,不处理;
        else{
            if (self.startupMessageQueue) {
                for (id queuedMessage in self.startupMessageQueue) {
                    [self _dispatchMessage:queuedMessage];
                }
                self.startupMessageQueue = nil;
            }
            if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
                [self.webViewDelegate webViewDidFinishLoad:webView];
            }
        }
    }
     
    *源代码部分(初始化函数):nil不能作为NSdictionary的value;

    错误:
    - (void)callHandler:(NSString *)handlerName {
        [self callHandler:handlerName data:nil responseCallback:nil];
    }
    正确:
    - (void)callHandler:(NSString *)handlerName {
        [self callHandler:handlerName data:[NSNull null] responseCallback:nil];
    }



    ==WebViewJavascriptBridge的使用==
    ===js和ios交互的直接代码实现===
    *jos对于js的调用:

    [self.paperQuestionsShowWebview stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"setQuestionContent('%@')",qTitle]];

    *js对于ios的调用:

    在html js代码中改变当前window的href;


        window.location.href="selfEvaluate/"+value;


    以上事件触发webview的shouldStartLoadWithRequest的回调事件;


    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
       
        NSString *relativePath = request.mainDocumentURL.relativePath;
        if ([relativePath hasSuffix:@".html"]) {
            return YES;
        }
        else{
            NSRange doingRange = [relativePath rangeOfString:@"/doing/"];
            if (doingRange.length>0) {
                //获取用户选择的选项
                NSString *userNewChoice = [relativePath substringFromIndex:doingRange.location+doingRange.length];
                //更新选项内容到server端
                //推断当前选项跟已经提交到server端的时候一致,假设不一致。则提交到server端
                if (![userNewChoice isEqualToString:self.currentQuestionAnswer]) {
                    [self.delegate updateQuestionUserChoiceWithPid:self.paperId questionSequence:self.currentQuestionSequence choice:userNewChoice
     remainTime:self.reimainTime sender:self];
                    //NSLog(@"update");
                }
            }
            else{
                .....
            }
            return NO;
        }
    }



    ===js和ios交互的(WebViewJavascriptBridge)代码实现===
    *ios端的实现:
     
      引入头文件:
      #import "WebViewJavascriptBridge.h";
     
     
      指定WebViewJavascriptBridge 属性:
       @property (strong, nonatomic) WebViewJavascriptBridge *javascriptBridge;
     
     
      初始化 WebViewJavascriptBridge;
        _javascriptBridge = [WebViewJavascriptBridge bridgeForWebView:_paperQuestionsShowWebview webViewDelegate:self handler:nil];
     

      注冊函数。
        [_javascriptBridge registerHandler:@"setSubjectiveQuestionScore" handler:^(id data, WVJBResponse *response){
                //获取用户选择的选项
                 NSInteger userScoreChoice = [(NSString *)data integerValue];
                //更新选项内容到server端
                //推断当前选项跟已经提交到server端的时候一致,假设不一致,则提交到server端
                
                //假设选择新的分数,则同步到server端
                if (userScoreChoice!=self.currentQuestionScore) {
                    [self.delegate updateQuestionUserChooseScoreWithPid:self.paperId questionSequence:self.currentQuestionSequence score:userScoreChoice sender:self];
                }
            }];
     
     
      调用js代码。
       [_javascriptBridge callHandler:@"setRightAnswer" data:qAnswer ];
     
     
    *js的实现:
     
      必要的事件注冊和初始化:
       document.addEventListener('WebViewJavascriptBridgeReady', onBridgeReady, false);
       function onBridgeReady(event) {
                    var bridge = event.bridge;
                    //调用初始化函数。取消队列,使消息可以得到直接处理;
                    bridge.init(function(message) {
                                alert(message);
                                });
       }
     
     
      注冊函数:
       function onBridgeReady(event) {
                 ......
                     bridge.registerHandler('setQuestionContent',function(content){


                                   var e_content = document.getElementByIdx_x('qcontent');
                                  e_content.innerHTML= content;
                                           
                    });
       }
     
     
      实现js对ios的调用:
          newChoiceElement.onclick = function(){
                   bridge.callHandler('choose',this.value);
           }
     


    ===js和ios交互的(WebViewJavascriptBridge)代码实现中须要注意的问题===
    #ios端必须保障框架中ios的实现作为webview的delegate。而业务代码作为兴许的delegate处理在初始化中增加;不然消息得不到传递(会增加一个队列,可是不会触发消息传递);
    #js端必须实现init函数,不然消息得不到传递(会增加一个队列。可是不会触发消息传递)。
    #关于參数(ios端):单个的对象能够直接传递(int等基础类型须要转换成相应的对象);多值传递须要组成NSDictionary进行传递;
    #关于參数(js端):单个对象直接传递;多值组成json格式字符串{'aa':'ss','sdd':'rrr'};
    #js语法以及编辑器对于错误的指示不明显,造成一些字符或标点错误。以及语法不完毕的错误非常难被发现,是消耗时间比較长的地方,须要通过寻找更加完好的js编辑器解决;


    ===代码引入WebViewJavascriptBridge实现ios和js交互的优点===
    #协议:自己实现,在通讯的部分须要自己构建传递协议,多人实现造成构建的传递协议不同,比較easy混乱,採用统一的底层框架,能够降低这个问题;
    #传递对象的字符转义:框架对这块又处理,不用自己再对一些字符进行转移;
    #框架封装了js和ios的多次交互,在实现比較复杂的交互时比較实用,这块假设开发者自己实现。则代码质量难控制,并且有一定的工作量;

    document:属性

    document.title //设置文档标题等价于HTML的
    document.bgColor //设置页面背景色
    document.fgColor //设置前景色(文本颜色)
    document.linkColor //未点击过的链接颜色
    document.alinkColor //激活链接(焦点在此链接上)的颜色
    document.vlinkColor //已点击过的链接颜色
    document.URL //设置URL属性从而在同一窗体打开还有一网页
    document.fileCreatedDate //文件建立日期,仅仅读属性
    document.fileModifiedDate //文件改动日期,仅仅读属性
    document.fileSize //文件大小,仅仅读属性
    document.cookie //设置和读出cookie
    document.charset //设置字符集 中文简体:gb2312
    document:方法
    document.write() //动态向页面写入内容
    document_createElement_x_x_x(Tag) //创建一个html标签对象
    document.getElementByIdx_xx_x_x(ID) //获得指定ID值的对象
    document.getElementsByName(Name) //获得指定Name值的对象
    document.body.a(oTag)
    body:子对象
    document.body //指定文档主体的開始和结束等价于


    document.body.bgColor //设置或获取对象后面的背景颜色
    document.body.link //未点击过的链接颜色
    document.body.alink //激活链接(焦点在此链接上)的颜色
    document.body.vlink //已点击过的链接颜色
    document.body.text //文本色
    document.body.innerText //设置…之间的文本
    document.body.innerHTML //设置…之间的HTML代码
    document.body.topMargin //页面上边距
    document.body.leftMargin //页面左边距
    document.body.rightMargin //页面右边距
    document.body.bottomMargin //页面下边距
    document.body.background //背景图片
    document.body.a(oTag) //动态生成一个HTML对象

    location:子对象
    document.location.hash // #号后的部分
    document.location.host // 域名+port号
    document.location.hostname // 域名
    document.location.href // 完整URL
    document.location.pathname // 文件夹部分
    document.location.port // 端口号
    document.location.protocol // 网络协议(http:)
    document.location.search // ?号后的部分
    经常使用对象事件:
    documeny.location.reload() //刷新网页
    document.location.reload(URL) //打开新的网页
    document.location.assign(URL) //打开新的网页
    document.location.replace(URL) //打开新的网页
    selection-选区子对象
    document.selection

  • 相关阅读:
    Ionic Tabs使用
    Angular 4 延缓加载组件
    JSP include 指令
    JSP 执行流程
    Tomcat 配置
    Spring boot 项目创建(Spring Boot 1.5.7 + Spring Data JPA + MySql)
    Java Web Service 学习笔记
    Tomcat 去除项目名称
    Angular 4 路由守卫
    Angular 4 辅助路由
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/7150949.html
Copyright © 2011-2022 走看看