Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I inject a user script on iOS?

I'm working on Fahrii, which is, essentially, a userscript enabled mobile browser. At the moment, I'm having trouble invoking the scripts on a web page that's loaded into a UIWebView. I'd like to keep this public APIs if possible. If not, a proof of concept would at least be nice, so I can get a better understanding of how this works. I'm trying to do it in the webViewDidFinishLoad: method.

I've tried injecting by reading out the webView's content (using JavaScript) and then loading it back with loadHTML:baseURL:, but that causes infinite recursion. (A completed load causes a script to be injected, which is in turn causing a completed "load".)

Next, I've tried something like this:

    [self.browser stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.body.innerHTML = %@", originalHTMLWithScriptsInjected]];

The script seems to be injected, but not run.

The only way I got this to work was to use the ASIHTTPRequest library to make the actual requests, but then I ended up having trouble with login forms, besides for which, I have to make each request twice in that case.

I might be doing something that's either impossible, or I'm just doing it the wrong away. So, how can I invoke a user script on an existing UIWebView with content loaded from the web?

Edit:

Here's some more code, including the changes proposed by @rich:

 //
 //  Run the remaining scripts
 //

NSMutableString *scriptTextToInject = [[NSMutableString alloc]init];

//
//  Add each script into the page
//

for (Userscript *script in scriptsToExecute) {

    //
    //  Read the userscript
    //

    NSString *scriptToLoad = [NSString stringWithContentsOfURL:[NSURL URLWithString:script.pathToScript] encoding:NSUTF8StringEncoding error:&error];

    NSLog(@"Script to load: %@", scriptToLoad);

    [scriptTextToInject appendFormat:@"%@\n\n",scriptToLoad];
}

NSString *documentHeadBefore = [self.browser stringByEvaluatingJavaScriptFromString:@"document.getElementsByTagName('head')[0].innerHTML"];

//
//  Inject the scripts
//

NSString *scriptWrappedInATag = [NSString stringWithFormat:@"window.onload() = function(){var script = document.createElement('script');\n"
                                 "script.charset = 'UTF-8'"
                                 "script.setAttribute(\"type\",\"text/javascript\");\n"
                                 "text = \"function u(){\n"
                                 "%@"
                                 "}\";\n"
                                 "document.getElementsByTagName('head')[0].appendChild(script);}", scriptTextToInject];
NSLog(@"Scripts wrapped in a tag: %@", scriptWrappedInATag);

NSString *runResults = [self.browser stringByEvaluatingJavaScriptFromString:@"u();"];

NSString *documentHeadAfter = [self.browser stringByEvaluatingJavaScriptFromString:@"document.getElementsByTagName('head')[0].innerHTML"];

NSLog(@"Before: %@ \n\n\n\n After: %@", documentHeadBefore, documentHeadAfter);
like image 349
Moshe Avatar asked Aug 05 '11 21:08

Moshe


People also ask

Do iphones allow scripting?

Allow scripts to run from a shortcut On your iOS or iPadOS device, go to Settings > Shortcuts > Advanced. Turn on Allow Running Scripts. WARNING: Running shortcuts with scripts could cause data loss.

How do I run a script in Safari?

In the shortcut editor, click at the top of the action list, begin typing “Run JavaScript…” in the search field, then double-click the Run JavaScript on Active Safari Tab action to add it to the shortcut editor. Write your script in the text field in the Run JavaScript on Active Safari Tab action.


1 Answers

An example of doing just this is below. I had the same problem until I realized that the js needed to be injected into the page. To properly inject the js you need to write it into the head of the dom as shown below.

- (void)webViewDidFinishLoad:(UIWebView *)webView {
 [webView stringByEvaluatingJavaScriptFromString:@"var script = document.createElement('script');"  
 "script.type = 'text/javascript';"  
 "script.text = \"function myFunction() { "  
 "window.scrollTo(100,100)"
 "}\";"  
 "document.getElementsByTagName('head')[0].appendChild(script);"];  

 [webView stringByEvaluatingJavaScriptFromString:@"myFunction();"];
}    
like image 152
rich Avatar answered Sep 22 '22 14:09

rich