1
|
varlocation = window.location.href; |
1
|
NSString*location = [[webView windowScriptObject] valueForKeyPath:@"location.href"];
1
|
window.location.href ='http://spring-studio.net';
1
|
|
[[webView windowScriptObject] setValue:@"http://spring-studio.net"forKeyPath:@"location.href"];
1
2
3
4
|
varJSArray = {'zonble','dot','net'}; for(vari = 0; i < JSArray.length; i++) { console.log(JSArray[i]); } |
1
2
3
4
5
6
7
8
|
WebScriptObject *obj = (WebScriptObject *)JSArray; NSUIntegercount = [[obj valueForKey:@"length"] integerValue]; NSMutableArray*a = [NSMutableArrayarray]; for(NSUIntegeri = 0; i < count; i++) { NSString*item = [obj webScriptValueAtIndex:i]; NSLog(@"item:%@", item); } |
1
2
3
|
functionx(x) { returnx + 1; } |
1
|
[[webView windowScriptObject] evaluateWebScript:@"function x(x) { return x + 1;}"];
1
2
|
NSNumber*result = [[webView windowScriptObject] evaluateWebScript:@"x(1)"]; NSLog(@"result:%d", [result integerValue]);// Returns 2 |
1
|
window.x.call(window.x, 1);
1
2
|
WebScriptObject *x = [[webView windowScriptObject] valueForKey:@"x"]; NSNumber*result = [x callWebScriptMethod:@"call"withArguments:[NSArrayarrayWithObjects:x, [NSNumbernumberWithInt:1],nil]]; |
1
|
|
document.querySelector('#s').focus();
1
2
|
|
DOMDocument *document = [[webView mainFrame] DOMDocument]; [[document querySelector:@"#s"] callWebScriptMethod:@"focus"withArguments:nil];
1
2
3
4
|
- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)windowObject forFrame:(WebFrame *)frame { [windowObject setValue:selfforKey:@"controller"]; } |
01
02
03
04
05
06
07
08
09
10
11
12
13
|
@interfaceMyController :NSObject { IBOutletWebView *webView; IBOUtlet NSWindow*window; NSString*stringValue; NSIntegernumberValue; NSArray*arrayValue; NSDate*dateValue; NSDictionary*dictValue; NSRectframeValue; } @end |
1
2
3
4
5
6
|
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]; |
01
02
03
04
05
06
07
08
09
10
11
12
|
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}}
1
2
3
4
5
6
7
|
+ (BOOL)isKeyExcludedFromWebScript:(constchar*)name { if(!strcmp(name,"stringValue")) { returnNO; } returnYES; } |
1
|
- (void)setA:(id)a b:(id)b c:(id)c;
controller.setA_b_c_('a','b','c');
1
|
|
1
2
3
4
5
6
7
|
+ (NSString*)webScriptNameForSelector:(SEL)selector { if(selector ==@selector(setA:b:c:)) { return@"setABC"; } returnnil; } |
1
|
|
controller.setABC('a','b','c');
用 JavaScript 调用 Objective C 2.0 的 property
在上面,我们用 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_()。
Javascript 中,Function 即对象的特性
JS 的 function 是对象,当一个 Obj C 对象的 method 出现在 JS 中时,这个 method 在 JS 中,也可以或多或少当做对象处理。我们在上面产生了 setABC,也可以试试看把它倒出来瞧瞧:
console.log(controller.setABC);
我们可以从结果看到:
这个 function 是 native code。因为是 native code,所以我们无法对这个 function 调用 call 或是 apply。
另外,在把我们的 Obj C 对象注册成 window.controller 后,我们会许也会想要让 controller 变成一个 function 来执行,像是调用 window.controller();或是,我们就只想要产生一个可以让 JS 调用的 function,而不是整个对象都放进 JS 里头。我们只要在 Obj C 对象中,实作 invokeDefaultMethodWithArguments:,就可以回传在调用 window.controller() 时想要的结果。
现在我们可以综合练习一下。前面提到,由于我们可以把 JS 对象以 WebScriptObject 这个 class 传入 Obj C 程序,Obj C 程序中也可以要求执行 WebScriptObject 的各项 function。我们假如想把 A 与 B 两个数字丢进 Obj C 程序里头做个加法,加完之后出现在网页上,于是我们写了一个 Obj C method:
JS 里头就可以这样调用:
※ 其他平台上 WebKit 的实作
除了 Mac OS X,WebKit 这几年也慢慢移植到其他的作业系统与 framework 中,也或多或少都有 Native API 要求 WebView 执行 Js,以及从 JS 调用 Native API 的机制。
跟 Mac OS X 比较起来,iPhone 上 UIWebView 的公开 API 实在少上许多。想要让 UIWebView 执行一段 JS,可以透过调用 stringByEvaluatingJavaScriptFromString:,只会回传字串结果,所以能够做到的事情也就变得有限,通常大概就拿来取得像 window.title 这些资讯。在 iPhone 上我们没办法将某个 Obj C 对象变成 JS 对象,所以,在网页中触发了某些事件,想要通知 Obj C 这一端,往往会选择使用像「zonble://」这类 Customized URL scheme。
ChromeOS 完全以 WebKit �u作使用者介面,不过我们没办法在 ChomeOS 上写我们在这边所讨论的桌面或行动应用程序,所以不在我们讨论之列。(顺道岔题,ChromeOS 是设计来给 Netbook 使用的作业系统,可是像 Toshiba 都已经用 Android,做出比 Netbook 更小的 Smartbook,而且应用程序更多,ChromeOS 的产品做出来的话,实在很像 Google 拿出两套东西,自己跟自己对打)。
Android 的 WebView 对象提供一个叫做 addJavascriptInterface() 的 method,可以将某个 Java 对象注册成 JS 的 window 对象的某个属性,就可以让 JS 调用 Java 对象。不过,在调用 Java 对象时,只能够传递简单的文字、数字,�}杂的 JS 对象就没办法了。而在 Android 上想要 WebView 执行一段 JS,在文件中没看到相关资料,网路上面找到的说法是,可以透过 loadUrl(),把某段 JS 用 bookmarklet 的形式传进去。
在 QtWebKit 里头,可以对 QWebFrame 调用 addToJavaScriptWindowObject,把某个 QObject 暴露在 JS 环境中,我不清楚 JS 可以传递哪些东西到 QObject 里头就是了。在 QtWebKit 中也可以取得网页里头的 DOM 对象(QWebElement
、QWebElementCollection),我们可以对 QWebFrame 还有这些 DOM 对象调用 evaluateJavaScript,执行 Javascript。
GTK 方面,因为是 C API,所以在应用程序与 JS 之间,就不是透过操作包装好的对象,而是调用 WebKit 里头 JavaScript Engine 的 C API。
※ JavaScriptCore Framework
我们在 Mac OS X 上面,也可以透过 C API,要求 WebView 执行 Javascript。首先要 import 。如果我们想要简单改一下 window.location.href:
如果我们想要让 WebView 里头的 JS,可以调用我们的 C Function:
那麽,只要 JS 调用 window.myFunc(),就可以取得们放在 myFunc 这个 C function 中回传的结果:
|