简体   繁体   中英

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();
        });
    });
}

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

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(){...} )() ;

ie instead of doing var A = <the function>; A(); 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 :)

I would get all the HTML from web view, then I'd inject the code and reload the page. It's still not a proper method of injection, but it may work.

NSString *htmlDataString = [webView stringByEvaluatingJavaScriptFromString: @"document.documentElement.outerHTML"];
// use nsstring methds to find the place for injecting
// inject avascript code
[webView loadHTMLString:htmlDataString baseURL:nil];

Of course you may have base URL from your request, if so replace that nil.

I didn't tried this, but if the problem is with the brackets and the complexity of the code, you can try calling a JS file stored in the bundle. Maybe it solves that. For example:

NSData *fileData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@”submitFormForTime” ofType:@”js”]];

NSString *jsString = [[NSMutableString alloc] initWithData:fileData encoding:NSUTF8StringEncoding];

[webView stringByEvaluatingJavaScriptFromString:jsString];

Maybe setting the encoding type helps to parse all the brackets in a right way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM