天天看點

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的後續調用,修改後如下:

    //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];

正确:

    [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;

        nsrange doingrange = [relativepath rangeofstring:@"/doing/"];

        if (doingrange.length>0) {

            //擷取使用者選擇的選項

            nsstring *usernewchoice = [relativepath substringfromindex:doingrange.location+doingrange.length];

            //更新選項内容到伺服器端

            //判斷目前選項跟已經送出到伺服器端的時候一緻,如果不一緻,則送出到伺服器端

            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];

            //如果選擇新的分數,則同步到伺服器端

            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);

                            });

   }

  注冊函數:

             ......

                 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互動的好處===

#協定:自己實作,在通訊的部分需要自己建構傳遞協定,多人實作造成建構的傳遞協定不同,比較容易混亂,采用統一的底層架構,可以減少這個問題;

#傳遞對象的字元轉義:架構對這塊又處理,不用自己再對一些字元進行轉移;

#架構封裝了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 // 域名+端口号

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

上一篇: js

繼續閱讀