Objective-c与JS交互
2013-12-27 17:24
253 查看
Let’s change the subject: this time no more talks about memory but always on UIWebView component. When we use this component for something else than just displaying webpages, like building UI with HTML, Javascript, … We often want to call Javascript functions
from objective C and the opposite.
The first move is easily done with the following piece of code:
But calling objective-c from a Javascript function is not easy as Iphone SDK doesn’t offer any native way to do this! So we have to use any king of hack to do this …
The most known, used and buggy practice is to register a UIWebViewDelegate on
your web view and « catch-and-immediatly-cancel » a location change done in javascript.
(a very extremely plenty much advised practice!)
There is weird but apprehensible bugs with this practice:
a lot of javascript/html stuff get broken when we cancel a location change:
All setInterval and setTimeout immediatly stop on location change
Every innerHTML won’t work after a canceled location change!
You may get other really weird bugs, really hard to diagnose …
Sample application highlighting these bugs
Key files of this example:
MyWebview.m: Objective-c part, that inherit from UIWebView. Set the UIWebViewDelegate
and catch requests in shouldStartLoadWithRequest selector.
NativeBridge.js: Tiny javascript library in order to change the location
and offer a way to send arguments and receive a response.
webview-script.js: Test case script, that highlight these bugs.
In webview-script.js: InnerHTML stop working whereas textContent continues to …
But we can’t charge Apple on this bug. I mean we try to load another location in the document we are working on! The webview component may start doing stuff before the delegate call, which cancel the load …
We have to find alternative way to communicate with the native code!
The only thing we have to change is in Javascript code. Instead of changing the document location, we create an IFrame and set its location to a value that trigger the shouldStartLoadWithRequest method.
And voilà!
Here is another sample application, with exactly the same structures and test file.
But this time you are going to see innerHTML and setTimeout working! Again, this demo contains a library (NativeBridge.js) that allow to send arguments to native code and get back a result in javascript asynchronously, with a callback function.
Best practice example!
Finally I provide the communication library under LGPL licence so it can ease your work on iphone platform! As I know that it’s really not easy ;-)
MyWebView.m: ObjectiveC part,
NativeBridge.js: Javascript side.
The code is full of comment, so you may easily use and tweak it!
Github repo
Posted by Alexandre
Poirot Oct 6th, 2010 iphone-sdk
from objective C and the opposite.
Call Javascript function from Objective-C:
The first move is easily done with the following piece of code:// In your Javascript files: function myJavascriptFunction () { // Do whatever your want! } // ----------------------------------- // And in your Objective-C code: // Call Javascript function from Objective-C: [webview stringByEvaluatingJavaScriptFromString:@"myJavascriptFunction()"];
Call Objective-C function from Javascript:
But calling objective-c from a Javascript function is not easy as Iphone SDK doesn’t offer any native way to do this! So we have to use any king of hack to do this …The most known, used and buggy practice is to register a UIWebViewDelegate on
your web view and « catch-and-immediatly-cancel » a location change done in javascript.
(a very extremely plenty much advised practice!)
// In Objective-C - someFunctionOnInit { webView = [[UIWebView alloc] init]; // Register the UIWebViewDelegate in order to shouldStartLoadWithRequest to be called (next function) webView.delegate = self; } // This function is called on all location change : - (BOOL)webView:(UIWebView *)webView2 shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { // Intercept custom location change, URL begins with "js-call:" if ([[[request URL] absoluteString] hasPrefix:@"js-call:"]) { // Extract the selector name from the URL NSArray *components = [requestString componentsSeparatedByString:@":"]; NSString *function = [components objectAtIndex:1]; // Call the given selector [self performSelector:NSSelectorFromString(functionName)]; // Cancel the location change return NO; } // Accept this location change return YES; } - (void)myObjectiveCFunction { // Do whatever you want! } // ----------------------------------- // Now in your javascript simply do this to call your objective-c function: // /!\ But for those who just read title and code, take care, this is a buggy practice /!\\n window.location = "js-call:myObjectiveCFunction";
What’s wrong with UIWebViewDelegate, shouldStartLoadWithRequest and location change ?
There is weird but apprehensible bugs with this practice:a lot of javascript/html stuff get broken when we cancel a location change:
All setInterval and setTimeout immediatly stop on location change
Every innerHTML won’t work after a canceled location change!
You may get other really weird bugs, really hard to diagnose …
Sample application highlighting these bugs
Key files of this example:
MyWebview.m: Objective-c part, that inherit from UIWebView. Set the UIWebViewDelegate
and catch requests in shouldStartLoadWithRequest selector.
NativeBridge.js: Tiny javascript library in order to change the location
and offer a way to send arguments and receive a response.
webview-script.js: Test case script, that highlight these bugs.
In webview-script.js: InnerHTML stop working whereas textContent continues to …
document.getElementById("count").innerHTML = i; document.getElementById("count2").textContent = i;
But we can’t charge Apple on this bug. I mean we try to load another location in the document we are working on! The webview component may start doing stuff before the delegate call, which cancel the load …
We have to find alternative way to communicate with the native code!
Better way to call Objective-C
The only thing we have to change is in Javascript code. Instead of changing the document location, we create an IFrame and set its location to a value that trigger the shouldStartLoadWithRequest method.And voilà!
var iframe = document.createElement("IFRAME"); iframe.setAttribute("src", "js-frame:myObjectiveCFunction"; document.documentElement.appendChild(iframe); iframe.parentNode.removeChild(iframe); iframe = null;
Here is another sample application, with exactly the same structures and test file.
But this time you are going to see innerHTML and setTimeout working! Again, this demo contains a library (NativeBridge.js) that allow to send arguments to native code and get back a result in javascript asynchronously, with a callback function.
Best practice example!
Free Objective-C<->Javascript library
Finally I provide the communication library under LGPL licence so it can ease your work on iphone platform! As I know that it’s really not easy ;-)MyWebView.m: ObjectiveC part,
NativeBridge.js: Javascript side.
The code is full of comment, so you may easily use and tweak it!
Github repo
Posted by Alexandre
Poirot Oct 6th, 2010 iphone-sdk
相关文章推荐
- iOS中js与objective-c的交互
- iOS中js与objective-c的交互
- Objective-C和JS交互
- ios中objective-c与js的交互
- Objective-c与js交互
- iOS中js与objective-c的交互(转)
- iOS中js与objective-c的简单交互
- iOS js与objective-c的交互(转)
- Objective-C UIWebview JS 交互
- iOS js与objective-c的交互(转)
- Objective-c与js交互专题
- ios中objective-c与js的交互
- js(javascript)与OC(Objective-C)交互
- 在 Mac Webview 中 Objective-c 与 JS 交互
- iOS中js与objective-c的交互
- js(javascript)与ios(Objective-C)相互通信交互
- JS与Objective-C交互(网页与原生交互---使用JavaScriptCore)
- UIWebView 与 JS 交互(1):Objective-C 调用 Javascript
- iOS JS 交互之利用系统JSContext实现 JS调用OC方法以及Objective-C调用JavaScript方法
- UIWebView 与 JS 交互(1):Objective-C 调用 Javascript