In a MacOS X application, I create a Window containing a WebView.
The WebView is initialized on a html page that contains an anchor:
Go To Google.
I would like to click on that link from another class.
It seems clear that a simple javascript code would do the trick: document.getElementById("myLink").click();
So, I wrote that small objective-c code that should do it:
NSString *cmd = #"document.getElementById(\"myLink\").click();";
id result = [[attachedWebView windowScriptObject] evaluateWebScript:cmd];
if ([result isMemberOfClass:[WebUndefined class]]) {
NSLog(#"evaluation of <%#> returned WebUndefined", cmd)
But I can't make it work.
If anybody has an idea, that would really help.
I think it is nothing todo with webview, but just your javascript.
Does it work if you try it in Safari's console? I wouldn't expect it to as you can only click() input elements (buttons) reliably cross-browser. A JQuery click() should work tho.
see How do I programmatically click a link with javascript?
So here is the solution I used.
Created a file: WebAgent.js containing the following code:
function myClick(id) {
var fireOnThis = document.getElementById(id);
var evObj = document.createEvent('MouseEvents');
evObj.initEvent( 'click', true, true );
fireOnThis.dispatchEvent(evObj);
}
And the following code in my objective-c class
// load cmd.js
NSString *path = #"/code/testagent/WebAgent/WebAgent/WebAgent.js";
NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[[self attachedWebView ]stringByEvaluatingJavaScriptFromString:jsCode];
//do the click
NSString * anchorId = #"myId";
NSString *call = [NSString stringWithFormat:#"WebAgent_click('%#')",anchorId];
[[self attachedWebView] stringByEvaluatingJavaScriptFromString:call];
NB: I used this solution to have the JS code in a specific file, as I expect to have more JS code in the future.
Thanks for your help.
Related
I've created the below runJavaScriptAlertPanelWithMessage function which displays a javascript alert, however I would like to prevent malicious websites from being able to constantly bring up alerts. I've tried various things but haven't had any luck, so was hoping someone may have an idea on how I can achieve this.
- (void)webView:(WebView *)wv runJavaScriptAlertPanelWithMessage:(NSString *)msg initiatedByFrame:(WebFrame *)frame {
NSString *host = [[NSURL URLWithString:[wv mainFrameURL]] host];
NSString *t = NSLocalizedString(host, #"");
NSString *defaultButton = NSLocalizedString(#"OK", #"");
self.currentJavaScriptAlert = [NSAlert alertWithMessageText:t defaultButton:defaultButton alternateButton:nil otherButton:nil informativeTextWithFormat:msg];
[currentJavaScriptAlert beginSheetModalForWindow:[[frame webView] window] modalDelegate:self didEndSelector:#selector(alertPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
}
Im trying to execute javascript on iPhone by stringByEvaluatingJavaScriptFromString,
i made script
function execute() {
//dosent matter
alert('works');
}
execute();
This script works fine while using in developer console in safari.
But this way :
[self.webView1 stringByEvaluatingJavaScriptFromString:#"javascript: function execute() { alert('works');}execute();"];
Dosent work, i dont see alert, i tried also without "javascript:"
Thats confusing because im using stringByEvaluatingJavaScriptFromString with succes but without using function declaration.
[self.webView1 stringByEvaluatingJavaScriptFromString:#"alert('check');"];
works fine
If anyone is looking for answer, i have noticed that some functions could not work properly without putting them in file.js and then execute by using:
- (void)injectJavascript:(NSString *)resource {
NSString *jsPath = [[NSBundle mainBundle] pathForResource:resource ofType:#"js"];
NSString *js = [NSString stringWithContentsOfFile:jsPath encoding:NSUTF8StringEncoding error:NULL];
[self.webView1 stringByEvaluatingJavaScriptFromString:js];
}
I am writing an app for ios to extract information from a webpage, however, the relevant pieces on the page are built by javascript. So when it is loaded by webview, the javascript is executed and the information displays no problem. If I try to load the page into a string by using the following method, the javascript is loaded, but not actually executed, therefore the string has no useful data in it.
NSData *urlData = [NSData dataWithContentsOfURL:[NSURL URLWithString:fullURL]];
NSString *responseString = [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
Is there another way besides loading the page into webview and exporting it from there? If not, how do you do that?
I'm not sure if there's another way outside of letting the UIWebView execute the JS and render the page, but if you do end up going this route, you could just grab the HTML of the whole page and pass that to the native end like so:
[dummyWebView stringByEvaluatingJavaScriptFromString:#"document.getElementsByTagName('html')[0].outerHTML;"];
Listening to the window.load event might be better to know when the page has finished going through all the JS
Good luck!
You set delegate to webView: self.webView.delegate = self; and implement UIWebViewDelegate:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *html = [webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.outerHTML"];
NSLog(#"html1 = %#", html);
// or use
NSString *html2 = [webView stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
NSLog(#"html2 = %#", html2);
}
<script language="javascript">
alert("Hell! UIWebView!");
</script>
I can see the alert message inside my UIWebView but can I handle this situation?
Update:
I'm loading a web-page into my UIWebView:
- (void)login {
NSString *requestText = [[NSString alloc] initWithFormat: #"%#?user=%#&password=%#", DEFAULT_URL, user.name, user.password]; // YES, I'm using GET request to send password :)
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:requestText]];
[webView loadRequest:request];
}
The target page contain a JS. If user name or password is incorrect this JS show alert.
I have not any access to its sources.
I want to handle it inside my UIWebViewDelegate.
A better solution to this problem is to create a Category for UIWebView for the method
webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:
So that you can handle the alert event in any way that you'd like. I did this because I don't like the default behavior of UIWebView when it puts the filename of the source in the UIAlertView title. The Category looks something like this,
#interface UIWebView (JavaScriptAlert)
- (void)webView:(UIWebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame;
#end
#implementation UIWebView (JavaScriptAlert)
- (void)webView:(UIWebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
UIAlertView* dialogue = [[UIAlertView alloc] initWithTitle:nil message:message delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil];
[dialogue show];
[dialogue autorelease];
}
#end
This seems to do it:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
JSContext *ctx = [webView valueForKeyPath:#"documentView.webView.mainFrame.javaScriptContext"];
ctx[#"window"][#"alert"] = ^(JSValue *message) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"JavaScript Alert" message:[message toString] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
};
}
Note: only tested on iOS 8.
If by "contain a flash" you mean the page you're loading into your web view has an Adobe Flash movie in it, you're out of luck, I'm afraid. Mobile Safari doesn't support Flash, and most likely never will.
In the general case, if you want JavaScript running in a web view to communicate with the native app hosting it, you can load fake URLs (for example: "myapp://alert?The+text+of+the+alert+goes+here."). That will trigger the webView:shouldStartLoadWithRequest:navigationType: delegate method. In that method, inspect the request, and if the URL being loaded is one of these internal communications, trigger the appropriate action in your app, and return NO.
I'm trying to remove a html element within a page I do not own within my ipad app.
Using stringByEvaluatingJavaScriptFromString I can return the element I want:
NSString *source = [webView stringByEvaluatingJavaScriptFromString:#"var parentEl = document.getElementById('header');parentEl.childNodes[5].innerHTML;"];
But when trying to remove it I can not:
[webView stringByEvaluatingJavaScriptFromString:#"var parentEl = document.getElementById('header');parentEl.removeChild(parentEl.childNodes[5]);"];
But if I run this code in safari remotely from the developer tools it works fine, which has me a little stumped!
Perhaps it is because you are missing the object off which you are accessing the childNodes collection:
parentEl = document.getElementById('header');
parentEl.removeChild(parentEl.childNodes[5]);