Trigger objective C method from javascript using JavaScriptCore in iOS 7 in ViewControllers
Asked Answered
C

1

9

I am loading a url in the webview which has below HTML and javascript function call. Now I am looking into when user touches submit button in webview it should call any method in viewController. Webview should load url(webview delegate) is one approach but is there any new way to get know when javascript function is called by webview should inform viewcontroller or trigger any method in view controller.

I am not looking for this solution this we need to

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

    NSLog(@"passed data from web view : %@",[[request URL] query]);

    if([[[request URL] query] isEqualToString:@"clickedOnLineNo"])
    {
//Do your action here

    }

We have to navigate to a fake URL from your javascript method like,

window.location = "someLink://yourApp/form_Submitted:param1:param2:param3";  

on a button click or your required action.

But is there any new possibility from JavaScriptCore to achieve the same.

Chauchaucer answered 7/2, 2014 at 11:6 Comment(6)
here is the sample HTML page which I am loading <!DOCTYPE html> <html> <head> <script type="text/javascript"> <!-- document.write("<h1></h1>"); function submitButton( ) { //This function should be called in Objective C class when user touches the button on webview } //--> </script> </head> <body> <h1>My Mobile App</h1> <p>Please enter the Details</p> <form name="feedback" method="post" action="mailto:[email protected]"> <!-- Form elements will go in here --> </form> <form name="inputform"> <input type="button" onClick="submitButton()" value="submit"> </form> </body> </html>Chauchaucer
you can create a phonegap application, that app you can call at the place of webview. will perform the same excatly you wantLowis
Thanks Rahul but is there no possibility from JavaScriptCore frame work which Apple recently introduced in iOS 7.Chauchaucer
possible duplicate of Calling an Objective-C function from JavaScript hosted on some web pageCommunicant
Thanks Dark but that link has same approach of calling a fake url in web viewChauchaucer
So, what's wrong with this approach? It looks like this is the only approach. See also How to call Objective-C from Javascript? and similar questions (unless I miss something, the search will turn up plenty of similar questions to yours, all with the same answers).Communicant
S
22

The Objective-C interface in the JavascriptCore framework introduced with iOS 7 permits calling Objective-C methods from Javascript. For a great intro to these features, check out the 2013 WWDC introduction "Integrating JavaScript into Native Apps" session on Apple's developer network: https://developer.apple.com/videos/wwdc/2013/?id=615

It does have a brief section towards the end on WebView (MacOs only not iOS)

The sample code below shows how to implement what you want for iOS.

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0,40,320,320)];
    webView.delegate = self;
    [self.view addSubview:webView];
     NSString *pageSource = @"<!DOCTYPE html> <html> <head> </head> <body> <h1>My Mobile App</h1> <p>Please enter the Details</p> <form name=\"feedback\" method=\"post\" action=\"mailto:[email protected]\"> <!-- Form elements will go in here --> </form> <form name=\"inputform\"> <input type=\"button\" onClick=\"submitButton('My Test Parameter')\" value=\"submit\"> </form> </body> </html>";
    [webView loadHTMLString:pageSource baseURL:nil];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    JSContext *context =  [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; // Undocumented access
    context[@"submitButton"] = ^(NSString *param1) {
        [self yourObjectiveCMethod:param1];
    };
}

- (void)yourObjectiveCMethod:(NSString *)param1 {
    NSLog(@"User clicked submit. param1=%@", param1);
}

Things to note:

  • Accessing the JSContext of a UIWebView is undocumented. Two techniques are known (see Access the JavaScriptCore engine of a UIWebView). The first technique is used here.
  • You don't need to define the javascript function "submitButton" inside the page, you will define the function from Objective-C using the webView's JSContext
  • A page load in a webview causes its JSContext to get replaced, hence you should implement a delegate for the UIWebView and define your Objective-C callback in your implementation of the selector for -webViewDidFinishLoad:
  • I've assumed you will want to pass parameters to this callback, so I've shown a sample parameter. Although this is not covered in the video tutorial mentioned above (or the PDF equivalent), looking at JSValue.h shows that JavascriptCore offers built-in conversion between the following Objective-C and Javascript types:

.

  Objective-C type  |   JavaScript type
--------------------+---------------------
        nil         |     undefined
       NSNull       |        null
      NSString      |       string
      NSNumber      |   number, boolean
    NSDictionary    |   Object object
      NSArray       |    Array object
       NSDate       |     Date object
      NSBlock *     |   Function object *
         id **      |   Wrapper object **
       Class ***    | Constructor object ***

* Instances of NSBlock with supported arguments types will be presented to
JavaScript as a callable Function object. For more information on supported
argument types see JSExport.h. If a JavaScript Function originating from an
Objective-C block is converted back to an Objective-C object the block will
be returned. All other JavaScript functions will be converted in the same
manner as a JavaScript object of type Object.

** For Objective-C instances that do not derive from the set of types listed
above, a wrapper object to provide a retaining handle to the Objective-C
instance from JavaScript. For more information on these wrapper objects, see
JSExport.h. When a JavaScript wrapper object is converted back to Objective-C
the Objective-C instance being retained by the wrapper is returned.

*** For Objective-C Class objects a constructor object containing exported
class methods will be returned. See JSExport.h for more information on
constructor objects.
Snack answered 8/2, 2014 at 16:13 Comment(2)
JS context works similar somehow like [webView stringByEvaluatingJavaScriptFromString:@"document.getElementById('lastname').value;"]; but it offers more than that. Thanks Mike for the explanation.Chauchaucer
@TMacGyver - Apple has not formally documented the Objective-C extensions they added to the JavaScriptCore framework when iOS7 was released, so your mileage may vary for either of the 2 known techniques. I haven't submitted an app using either technique, however there have been reports on SO of successful submissions using the first technique (as used in the example above). See mprudhom's answer to #18921036Snack

© 2022 - 2024 — McMap. All rights reserved.