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]);
Related
I'm trying to migrate from using a UIWebview to a WKWebview, and I need to invoke various Javascript functions that live in the webview.
In the UIWebview I have no trouble doing this, but the WKWebview throws an WKErrorDomain Error 4 for any and all calls. I thought it might be a race condition where I was calling functions that didn't exist in the DOM yet, but I added a debug statement to make those same calls once the page loaded and they're not working. I even did a 'document.body.innerHTML' which returned nil when there's clearly content being displayed in the webview.
The twist is that when inspecting the web code via Safari Web Inspector, everything works well and all calls work.
Why and how could this be? I do initialize the WKWebView with a WKWebViewConfiguration so that it'll share cookies across different webviews, so there might be something there, but I'm stumped.
This is how i initialize the WKWebView
WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc] init];
config.processPool = [[WKProcessPool alloc] init];
WKUserContentController* userContentController = WKUserContentController.new;
WKUserScript * cookieScript = [[WKUserScript alloc] initWithSource: #"document.cookie = 'cookie1=value1; domain=blah; path=/;';" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[userContentController addUserScript:cookieScript];
config.userContentController = userContentController;
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0,0,50,50) configuration:config];
Here's a debugging statement where I log the document's innerHTML into the console log, which prints (nil) instead of the HTML.
NSLog(#"%#", [self.webView evaluateJavaScript:#"document.body.innerHTML" completionHandler:nil]);
WKWebView executes JS async unlike UIWebView; You cannot print like how you are doing..
Try this
[self.webView evaluateJavaScript:#"document.body.innerHTML" completionHandler:^(id result, NSError *error) {
NSLog(#"Error is %#",error);
NSLog(#"JS result %#" ,result);
}];
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);
}
I'm using UIWebView in a project. Sometimes it doesn't call the webViewDidFinishLoad method. Because the web page have some javascripts. The method
- (BOOL) webView: (UIWebView *) webView shouldStartLoadWithRequest: (NSURLRequest *) request navigationType: (UIWebViewNavigationType) navigationType
is getting call but webViewDidFinishLoad doesn't. I want to catch that method. Because I'm start an animation when the webview start loading. Then I want to stop this animation when it finished. It's not working with websites having javascript content. Any one have an idea please?
Thanks
webViewDidFinishLoad method gets called when the UIWebView has finished loading the url, in your case since you are calling a javascript, it doesn't load your content, it just calls a javascript function in your already loaded webview. But YES you can catch the javascript actions in the same method you stated as below
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSString *url = [[request URL] absoluteString];
if(navigationType == UIWebViewNavigationTypeLinkClicked){
if([url rangeOfString:#"SOMETHING"].length > 0 ){
//if your action returns something appended in your url like the anchors work
//DO YOUR STUFFS
}
}
return TRUE;
}
apparently, the webview in ios checks specifically for "iframe" tags in the html's dom and in case it finds, it creates events based on that tag as well. therefore, a simple however a patchy solution would be adding the following code in the part of the dom that is changing (for example, in the actual template of each section):
<iframe></iframe>
did the trick for me..
I'm hoping to be able to use PhoneGap for my app. I will have to build a custom protocol/plugin so that I can call Native methods from the Javascript. I know you can call a success function in the Javascript when the native code returns.
What I need to be able to do is call a javascript function from the native code. Basically the app will connect to an OSX companion app over local network and when the OSX app send data to the iOS app it is processed in an Objective C method, I need to be able to send the result into the PhoneGap/javascript and do something with it in the WebView.
Is this possible? I have only been able to find information about calling native from javascript not the other way around.
Thanks,
Thomas
Using the code from Answer below here:
MyPhoneGapPlugin.m
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(#"Connected To %#:%i.", host, port);
NSString* jsString = [NSString stringWithFormat:#"alert(connected to: %#);", host];
[theWebView stringByEvaluatingJavaScriptFromString:jsString];
[self readWithTag:2];
}
Giving me the error 'Unknown receiver 'theWebView' did you mean 'UIWebView'?
UPDATE: Found the answer: using the phonegap helper I can write something like this...
[super writeJavascript:#"alert('connected');"];
You can easily call JavaScript from native code with a UIWebView:
[webView stringByEvaluatingJavaScriptFromString:#"myJSFunction()"];
To use the result of a function somewhere as an arg to a JS function:
NSString *stringData = getStringData(); // however you get it
[webView stringByEvaluatingJavaScriptFromString:
[NSString stringWithFormat:#"myJSFunction(%#)", stringData]];
Found the PhoneGap helper to accomplish this... Write javascript to the webView using:
[super writeJavascript:#"alert('it works');"];
You should try this,
[webView stringByEvaluatingJavaScriptFromString:#"sendSelectedDate()"];
Will this work for you?
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/DisplayWebContent/Tasks/JavaScriptFromObjC.html
Taken from this page:
You can also call JavaScript functions with arguments. Assume that you have written a JavaScript function which looks like this:
function addImage(image, width, height) { ... }
Its purpose is to add an image to a web page. It is called with three arguments: image, the URL of the image; width, the screen width of the image; and height, the screen height of the image. You can call this method one of two ways from Objective-C. The first creates the array of arguments prior to using the WebScriptObject bridge:
id win = [webView windowScriptObject];
NSArray *args = [NSArray arrayWithObjects:
#"sample_graphic.jpg",
[NSNumber numberWithInt:320],
[NSNumber numberWithInt:240],
nil];
[win callWebScriptMethod:#"addImage"
withArguments:args];
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.