如何在 iOS 上注入用户脚本?
Posted
技术标签:
【中文标题】如何在 iOS 上注入用户脚本?【英文标题】:How can I inject a user script on iOS? 【发布时间】:2011-10-21 05:44:11 【问题描述】:我正在开发Fahrii,它本质上是一个支持用户脚本的移动浏览器。目前,我无法在加载到 UIWebView 的网页上调用脚本。如果可能的话,我想保留这个公共 API。如果没有,至少概念证明会很好,所以我可以更好地理解它是如何工作的。我正在尝试在webViewDidFinishLoad:
方法中做到这一点。
我尝试通过读取 webView 的内容(使用 javascript)进行注入,然后使用 loadhtml:baseURL:
将其加载回来,但这会导致无限递归。 (完成的加载会导致脚本被注入,这反过来又会导致完成的“加载”。)
接下来,我尝试了这样的事情:
[self.browser stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.body.innerHTML = %@", originalHTMLWithScriptsInjected]];
脚本似乎被注入,但没有运行。
我让它工作的唯一方法是使用 ASIHTTPRequest 库来发出实际的请求,但后来我在登录表单上遇到了麻烦,除此之外,在这种情况下我必须发出两次请求。
我可能正在做一些不可能的事情,或者我只是做错了。 那么,如何在现有的 UIWebView 上调用用户脚本并使用从 Web 加载的内容?
编辑:
这里还有一些代码,包括@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);
【问题讨论】:
-stringByEvaluatingJavaScriptFromString: 是在 webview 上调用 javascript 的正确方法,但看起来你不能这样设置 document.body.innerHTML。我猜苹果希望你用 -loadHTMLString:baseURL: 方法来做到这一点。但是请描述您想要做什么,或者向我们展示您想要运行的 javascript 代码。 这个想法是将用户脚本注入页面。我成功的唯一方法是使用单独的请求并将响应手动加载到 WebView 中。 当心不要将该编辑视为“更多代码”以外的任何内容(即“包括@rich 提出的更改”可能会产生误导) 1) 为什么将它包含在window.onload
中?我认为这暗示了一个时间问题(没有一个)2)无论如何,这不是你将某些东西分配给window.onload
的方式(额外的括号)3)放置在scriptWrappedInATag
中的代码永远不会被调用/传递给@987654329 @.*直接跳到下面富人的回答*
【参考方案1】:
下面是一个这样做的例子。在意识到需要将js注入页面之前,我遇到了同样的问题。要正确注入 js,您需要将其写入 dom 的头部,如下所示。
- (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();"];
【讨论】:
这是否规避了 Apple 对 UIWebView 施加的 10 秒执行时间限制? 我已经在几个应用程序中使用过它,它在页面加载之前执行,所以按照 Apple 标准去是很好的 有趣,谢谢!我会检查一下,然后告诉你进展如何。 您确定将 webView 委托设置为 self 吗?在这种情况下,这是一个常见的事故 是的,代码正在运行,但它不工作。该脚本似乎没有正确注入。【参考方案2】:您应该直接将字符串传递给 stringByEvaluatingJavaScriptFromString: 方法,如下所示:
NSString *result = [webView stringByEvaluatingJavaScriptFromString:@"Script To Be Run"];
【讨论】:
以上是关于如何在 iOS 上注入用户脚本?的主要内容,如果未能解决你的问题,请参考以下文章