Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass a JavaScript callback function to Cocoa/Obj-C?

I'm trying to pass a function reference from JavaScript in a WebView, so my Objective-C code can call then back into that function when the asynchronous Obj-C method completes. I see how to pass in simple types -- strings, numbers, etc. -- but can't seem to figure out how to pass something a function reference, like

window.myRootObject.myObjCSelector("some-string", function(data) { 
  console.log(data); 
});

I've Googled around, but continue to come up short, and haven't found a reference to this in the docs (yet). Working in Cocoa, but would love to be able to do the same sort of thing on iOS.

Thanks in advance for any help!

Edit: The function argument should be anonymous -- hopefully this clarifies. :)

like image 447
Christian Nunciato Avatar asked Dec 07 '22 15:12

Christian Nunciato


1 Answers

Finally figured this out. There might be a better way (and if so, please chime in!) but the following seems to work. In my Obj-C (NSObject-derived) class -- into which I pass a reference to a WebView -- I define the following script-accessible method:

#import <WebKit/WebKit.h>
#import <JavaScriptCore/JavaScriptCore.h>

- (void) search:(NSString *)prefix withCallback:(WebScriptObject *)callback;

... which is intended to take two arguments: a string to search with, and an anonymous function callback to handle the result. It's implemented thusly:

- (void) search:(NSString *)prefix withCallback:(WebScriptObject *)callback
{
  // Functions get passed in as WebScriptObjects, which give you access to the function as a JSObject
  JSObjectRef ref = [callback JSObject];

  // Through WebView, you can get to the JS globalContext
  JSContextRef ctx = [[view mainFrame] globalContext];

  // In my case, I have a JSON string I want to pass back into the page as a JavaScript object
  JSValueRef obj = JSValueMakeFromJSONString(ctx, JSStringCreateWithCFString((__bridge CFStringRef)responseString)); 

  // And here's where I call the callback and pass in the JS object
  JSObjectCallAsFunction(ctx, ref, NULL, 1, &obj, NULL);
}

This actually works asynchronously as well, through Objective-C blocks, but the gist is above. Hope it helps someone else!

like image 119
Christian Nunciato Avatar answered Mar 07 '23 11:03

Christian Nunciato