==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