這個問題,在網上能看到很多,主要經過調用UIWebView的一個方法stringByEvaluatingJavaScriptFromStringhtml
來實現,與js的交互問題,我想可能用的過程當中會出現很多問題,因此,先開個文章來存放,等過2天用的時候寫個問題,總結下遇到的問題或者經驗什麼的。linux
http://www.cnblogs.com/zhwl/archive/2013/04/19/3030244.htmlweb
這個網址裏的內容不錯,很多使用上面所說的那個方法,並且不僅是單單的用oc調用js,還有用js調用oc!spring
在寫 JavaScript 的時候,可使用一個叫作 window 的對象,像是咱們想要從如今的網頁跳到另一個網頁的時候,就會去修改 window.location.href 的位置;在咱們的 Oective C 程序碼中,若是咱們能夠取得指定的 WebView 的指標,也就能夠拿到這個出如今 JavaScript 中的 window 對象,也就是 [webView windowScriptOect]。函數
這個對象就是 WebView 裏頭的 JS 與咱們的 O C 程序之間的橋樑-window 對象能夠取得網頁裏頭全部的 JS 函數與對象,而若是咱們把一個 O C 對象設定成 windowScriptOect 的 value,JS 也即可以調用 O C 對象的 method。因而,咱們能夠在 O C 程序裏頭要求 WebView 執行一段 JS,也能夠反過來讓 JS 調用一段用 O C 實做的功能。lua
※ 用 Oective C 取得與設定 JavaScript 對象spa
要從 O C 取得網頁中的 JavaScript 對象,也就是對 windowScriptOect 作一些 KVC 調用,像是 valueForKey: 與 valueForKeyPath:。若是咱們在 JS 裏頭,想要知道目前的網頁位置,會這麼寫:.net
varlocation = window.location.href;
用 OC 就能夠這麼調用:調試
NSString*location = [[webView windowScriptOect] valueForKeyPath:@"location.href"];
code
若是咱們要設定 window.location.href,要求開啓另一個網頁,在 JS 裏頭:
window.location.href ='http://spring-studio.net';
O C:
[[webView windowScriptOect] setValue:@"http://spring-studio.net"forKeyPath:@"location.href"];
因爲 O C 與 JS 自己的語言特性不一樣,在兩種語言之間相互傳遞東西之間,就能夠看到二者的差異-
因此,若是咱們想要看一個 JS Array 裏頭有什麼東西,就要先取得這個對象裏頭叫作 length 的 value,而後用 webScriptValueAtIndex: 去看在該 index 位置的內容。假如咱們在 JS 裏頭這樣寫:
varJSArray = {'zonble','dot','net'};
for(vari = 0; i < JSArray.length; i++) {
console.log(JSArray[i]);
}
O C 裏頭就會變成這樣:
WebScriptOect *O = (WebScriptOect *)JSArray;
NSUIntegercount = [[O valueForKey:@"length"] integerValue];
NSMutableArray*a = [NSMutableArrayarray];
for(NSUIntegeri = 0; i < count; i++) {
NSString*item = [O webScriptValueAtIndex:i];
NSLog(@"item:%@", item);
}
※ 用 Oective C 調用 JavaScript function
要用 O C 調用網頁中的 JS function,大概有幾種方法。第一種是直接寫一段跟你在網頁中會撰寫的 JS 如出一轍的程序,叫 windowScriptOect 用 evaluateWebScript: 執行。例如,咱們想要在網頁中產生一個新的 JS function,內容是:
functionx(x) {
returnx + 1;
}
因此在 O C 中能夠這樣寫;
[[webView windowScriptOect] evaluateWebScript:@"function x(x) { return x + 1;}"];
接下來咱們就能夠調用 window.x():
NSNumber*result = [[webView windowScriptOect] evaluateWebScript:@"x(1)"];
NSLog(@"result:%d", [result integerValue]);// Returns 2
因爲在 JS 中,每一個 funciton 其實都是對象,因此咱們還能夠直接取得 window.x 叫這個對象執行本身。在 JS 裏頭若是這樣寫:
window.x.call(window.x, 1);
O C 中即是這樣:
WebScriptOect *x = [[webView windowScriptOect] valueForKey:@"x"];
NSNumber*result = [x callWebScriptMethod:@"call"withArguments:[NSArrayarrayWithOects:x, [NSNumbernumberWithInt:1],nil]];
這種讓某個 WebScriptOect 本身執行本身的寫法,其實比較不會用於從 O C 調用 JS 這一端,而是接下來會提到的,由 JS 調用 O C,由於這樣 JS 就能夠把一個 callback function 送到 O C 程序裏頭。
若是咱們在作網頁,咱們只想要更新網頁中的一個區塊,就會利用 AJAX 的技巧,只對這個區塊須要的資料,對 server 發出 request,而且在 request 完成的時候,要求執行一段 callback function,更新這一個區塊的顯示內容。從 JS 調用 O C也能夠作相似的事情,若是 O C 程序裏頭須要必定時間的運算,或是咱們多是在 O C 裏頭抓取網路資料,咱們即可以把一個 callback function 送到 O C 程序裡,要求 O C 程序在作完工做後,執行這段 callback function。
WebKit 裏頭,全部的 DOM 對象都繼承自 DOMObject,DOMObject 又繼承自 WebScriptObject,因此咱們在取得了某個 DOM 對象以後,也能夠從 Obj C 程序中,要求這個 DOM 對象執行 JS 程序。
假如咱們的網頁中,有一個 id 叫作 「#s」 的文字輸入框(text input),而咱們但願如今鍵盤輸入的焦點放在這個輸入框上,在 JS 裏頭會這樣寫:
document.querySelector('#s').focus();
Obj C:
DOMDocument *document = [[webView mainFrame] DOMDocument];
[[document querySelector:@"#s"] callWebScriptMethod:@"focus"withArguments:nil];
要讓網頁中的 JS 程序能夠調用 Obj C 對象,方法是把某個 Obj C 對象註冊成 JS 中 window 對象的屬性。以後,JS 便也能夠調用這個對象的 method,也能夠取得這個對象的各類 Value,只要是 KVC 能夠取得的 Value,像是 NSString、NSNumber、NSDate、NSArray、NSDictionary、NSValue…等。JS 傳 Array 到 ObjC 時,還須要特別作些處理才能變成 NSArray,從 Obj C 傳一個 NSArray 到 JS 時,會自動變成 JS Array。
首先咱們要注意的是將 Obj C 對象註冊給 window 對象的時機,因爲每次從新載入網頁,window 對象的內容都會有所變更-畢竟每一個網頁都會有不一樣的 JS 程序,因此,咱們須要在適當的時機作這件事情。咱們首先要指定 WebView 的 frame loading delegate(用 setFrameLoadDelegate:),而且實做 webView:didClearWindowObject:forFrame:,WebView 只要更新了 windowScriptObject,就會調用這一段程序。假如咱們如今要讓網頁中的 JS 可使用目前的 controller 對象,會這樣寫:
- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)windowObject forFrame:(WebFrame *)frame
{
[windowObject setValue:selfforKey:@"controller"];
}
如此一來,只要調用 window.controller,就能夠調用咱們的 Obj C 對象。假如咱們的 Obj C Class 裏頭有這些成員變數:
@interfaceMyController :NSObject
{
IBOutletWebView *webView;
IBOUtlet NSWindow*window;
NSString*stringValue;
NSIntegernumberValue;
NSArray*arrayValue;
NSDate*dateValue;
NSDictionary*dictValue;
NSRectframeValue;
}
@end
指定一下 Value:
stringValue =@"string";
numberValue = 24;
arrayValue = [[NSArrayarrayWithObjects:@"text", [NSNumbernumberWithInt:30],nil] retain];
dateValue = [[NSDatedate] retain];
dictValue = [[NSDictionarydictionaryWithObjectsAndKeys:@"value1",@"key1",@"value2",@"key2",@"value3",@"key3",nil] retain];
frameValue = [window frame];
用 JS 讀讀看:
varc = window.controller;
varmain = document.getElementById('main');
varHTML ='';
if(c) {
HTML +='<p>'+ c.stringValue +'<p>';
HTML +='<p>'+ c.numberValue +'<p>';
HTML +='<p>'+ c.arrayValue +'<p>';
HTML +='<p>'+ c.dateValue +'<p>';
HTML +='<p>'+ c.dictValue +'<p>';
HTML +='<p>'+ c.frameValue +'<p>';
main.innerHTML = HTML;
}
結果以下:
string24text,302010-09-09 00:01:04 +0800{ key1 = value1; key2 = value2; key3 = value3; }NSRect: {{275, 72}, {570, 657}}
不過,若是你看完上面的範例,就直接照作,應該不會直接成功出現正確的結果,而是會拿到一堆 undefined,緣由是,Obj C 對象的 Value 預設被保護起來,不會讓 JS 直接存取。要讓 JS 能夠存取 Obj C 對象的 Value,須要實做 +isKeyExcludedFromWebScript: 針對傳入的 Key 一一處理,若是咱們但願 JS 能夠存取這個 key,就回傳 NO:
+ (BOOL)isKeyExcludedFromWebScript:(constchar*)name
{
if(!strcmp(name,"stringValue")) {
returnNO;
}
returnYES;
}
除了能夠讀取 Obj C 對象的 Value 外,也能夠設定 Value,至關於在 Obj C 中使用 setValue:forKey:,若是在上面的 JS 程序中,咱們想要修改 stringValue,直接調用 c.stringValue = ‘new value’ 便可。像前面提到,在這裡傳給 Obj C 的 JS 對象,除了字串與數字外,class 都是 WebScriptObject,空對象是 WebUndefined。
Obj C 的語法沿襲自 SmallTalk,Obj C 的 selector,與 JS 的 function 語法有至關的差別。WebKit 預設的實做是,若是咱們要在 JS 調用 Obj C selector,就是把全部的參數日後面擺,而且把全部的冒號改爲底線,而原來 selector 若是有底線的話,又要另外處理。假使咱們的 controller 對象有個 method,在 Obj C 中寫成這樣:
- (void)setA:(id)a b:(id)b c:(id)c;
在 JS 中就這麼調用:
controller.setA_b_c_('a','b','c');
實在有點醜。因此 WebKit 提供一個方法,可讓咱們把某個 Obj C selector 變成好看一點的 JS function。咱們要實做 webScriptNameForSelector:
+ (NSString*)webScriptNameForSelector:(SEL)selector
{
if(selector ==@selector(setA:b:c:)) {
return@"setABC";
}
returnnil;
}
之後就能夠這麼調用:
controller.setABC('a','b','c');
咱們一樣能夠決定哪些 selector 能夠給 JS 使用,哪些要保護起來,方法是實做 isSelectorExcludedFromWebScript:。而咱們能夠改變某個 Obj C selector 在 JS 中的名稱,咱們也能夠改變某個 value 的 key,方法是實做 webScriptNameForKey:。
有幾件事情須要注意一下:
在上面,咱們用 JS 調用 window.controller.stringValue,與設定裏頭的 value 時,這邊很像咱們使用 Obj C 2.0 的語法,但其實作的是不同的事情。用 JS 調用 controller.stringValue,對應到的 Obj C 語法是 [controller valueForKey:@"stringValue"],而不是調用 Obj C 對象的 property。
若是咱們的 Obj C 對象有個 property 叫作 stringValue,咱們知道,Obj C property 其實會在編譯時,變成 getter/setter method,在 JS 裏頭,咱們便應該要調用 controller.stringValue() 與 controller.setStringValue_()。
後面的一些就不轉貼了,有興趣的去鏈接裏面查看。沒有機器暫時沒法知道調試結果。
—————————————————————————————————————————————————————————————————————————————————
http://blog.sina.com.cn/s/blog_6796844601010nxj.html
http://hi.baidu.com/sadusaga/item/9fabbabb28e826e94fc7fded\
Objective-C與js相互調用及傳參數注意