Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Methods of JavaScript injection using Objective-C

I'm looking for different methods of injecting JavaScript into a WebView (in Cocoa).

I am trying to inject some javascript into the <head> tag of a HTML file that has been loaded into the WebView.

The following method doesn't work for me. It seems to only work with very simple JavaScript with no nested brackets (from what I have tested):

[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"var script = document.createElement('script');"
                                                     "script.type = 'text/javascript';"
                                                     "script.text = \"some simple JavaScript"
                                                     "}\";"
                                                     "document.getElementsByTagName('head')[0].appendChild(script);"]];

Are there any other ways of doing this with more complicated JavaScript / jQuery functions?

The full code I am trying to inject is as follows:

function submitFormForTime(time){
    $(\".t_h\").each(function(i, obj) {
        if ($(this).text() != time) return;
        $(this).parent().find(\"form\").each(function(i, obj){
            obj.submit();
        });
    });
}
like image 546
Conor Taylor Avatar asked Sep 15 '12 08:09

Conor Taylor


1 Answers

You can't use jQuery to add <script> tags. This has been asked many times. See:

  • Can't append <script> element
  • Can I create script tag by jQuery?

You can do it with browser built-in functions, BUT:

Would it work to just assign your function to a variable on your page and then evaluate it? Something like:

-(void)webViewDidFinishLoad:(UIWebView *)webView
{
    // add function to page:
    NSString * js = @"myFunction = function(){ return \"success!\"; }" ;
    [ webView stringByEvaluatingJavaScriptFromString:js ] ;

    // execute newly added function:
    NSString * result = [ webView stringByEvaluatingJavaScriptFromString:@"myFunction();"] ;
    NSLog(@"result=\"%@\"", result) ;
}

update explicit examples:

You should use my above example as a template!

Anyway, there's 2 parts to the process... The Javascript part and the Objective-C part. At the Javascript level, you are doing this:

// assign a function to the variable "someFunction":
var someFunction = function(){...};

// call the function in the variable "someFunction":
someFunction();

You can also do it without assigning the function to a variable, for example, if you don't care about referring to the function in the future. Doing it without a variable and using an anonymous function looks like this:

( function(){...} )() ;

i.e. instead of doing var A = <the function>; A(); you are doing (<the function>)();

Finally, if your anonymous function takes arguments, like yours does, the pattern looks like this:

( function(var0, ..., varN){...} )(arg0, ..., argN);

Using that as a template for your code, your JS ends up like:

( function(time) {
    $(\".t_h\").each(function(i, obj) 
    {
        if ($(this).text() != time)  return;

        $(this).parent().find(\"form\").each(function(i, obj) {
            obj.submit();
        });
    });
})( 123.456 );

So, that's what you want the web view to execute... That's the code we pass to the webview. But you have to build that string in your Obj-C program, with the "complication" of inserting the current time argument (123.456 in the above code).

It looks like this:

NSString * jsTemplate =
    @"( function(time) {"
    @"        $(\".t_h\").each(function(i, obj) {"
    @"            if ($(this).text() != time)  return;"
    @"            $(this).parent().find(\"form\").each(function(i, obj) {"
    @"                obj.submit();"
    @"            });"
    @"        });"
    @"    })( %g );" ;
NSString * js = [ NSString stringWithFormat:jsTemplate, 123.456 ] ;
NSString * result = [ webView stringByEvaluatingJavaScriptFromString:js ] ;

I think I've written enough now :)

like image 87
nielsbot Avatar answered Oct 15 '22 09:10

nielsbot