Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call Objective-C from Javascript?

I have a WebView, and I want to call a view in Objective-C from JavaScript. Does someone know how I can do this?


I have this code in my ViewController:

- (BOOL)webView:(UIWebView *)webView2 
 shouldStartLoadWithRequest:(NSURLRequest *)request 
 navigationType:(UIWebViewNavigationType)navigationType {

 NSString *requestString = [[request URL] absoluteString];
 NSArray *components = [requestString componentsSeparatedByString:@":"];

 if ([components count] > 1 && 
  [(NSString *)[components objectAtIndex:0] isEqualToString:@"myapp"]) {
  if([(NSString *)[components objectAtIndex:1] isEqualToString:@"myfunction"]) 
  {

   NSLog([components objectAtIndex:2]); [[Airship shared] displayStoreFront]; //<- This is the code to open the Store
   NSLog([components objectAtIndex:3]); // param2
   // Call your method in Objective-C method using the above...
  }
  return NO;
 }

 return YES; // Return YES to make sure regular navigation works as expected.
}

And in Javascript:

function store(event)
{
    document.location = "myapp:" + "myfunction:" + param1 + ":" + param2;
}

But nothing happens.

like image 670
Obliviux Avatar asked Nov 02 '09 17:11

Obliviux


4 Answers

The standard workaround for UIWebView is to set a UIWebViewDelegate, and implement the method webView:shouldStartLoadWithRequest:navigationType:. In your JavaScript code, navigate to some fake URL that encodes the information you want to pass to your app, like, say:

window.location = "fake://myApp/something_happened:param1:param2:param3";

In your delegate method, look for these fake URLs, extract the information you need, take whatever action is appropriate, and return NO to cancel the navigation. It's probably best if you defer any lengthy processing using some flavor of performSelector.

like image 198
Sixten Otto Avatar answered Oct 31 '22 18:10

Sixten Otto


The window.location method of calling objective c from JS isn't recommended. One example of problems: if you make two immediate consecutive calls one is ignored (since you can't change location too quickly) - try it yourself..

I recommend the following alternative approach:

function execute(url) 
{
  var iframe = document.createElement("IFRAME");
  iframe.setAttribute("src", url);
  document.documentElement.appendChild(iframe);
  iframe.parentNode.removeChild(iframe);
  iframe = null;
}

You call the execute function repeatedly and since each call executes in its own iframe, they should not be ignored when called quickly.

Credits to this guy.

like image 23
talkol Avatar answered Oct 31 '22 20:10

talkol


Obliviux,

Your code seems to be perfect.

The reason for the problem is that you must have missed to map the delegate.

Either

  1. Connect the delegate of the webView to the file owner in the .xib file

or

  1. Use webView.delegate = self;

in your viewDidLoad.

Thanks

like image 4
sm abbas Avatar answered Oct 31 '22 18:10

sm abbas


Like people said here, you have to use the method webView:shouldStartLoadWithRequest:navigationType: from the UIWebviewDelegate.

This api http://code.google.com/p/jsbridge-to-cocoa/ does it for you. It is very lightweight. You can pass images, strings and arrays from javascript to objective-C.

like image 3
John Avatar answered Oct 31 '22 19:10

John