Capture (and prevent) alert() modal in UIWebView [duplicate] - javascript

<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.

Related

pass alert from UIWebView to iOS app

I have create an app, which works fine. The only thing i need is to pass the alerts from uiwebview to my iOS app.
i have this alert on my uiwebview
<div id="alerts" class="alerts">
<p class="alert-red">ok. come back again tomorrow, not now.</p>
i want this alert to transfer into my app and make it into an uialertview
UIAlertView *errr = [[UIAlertView alloc]initWithTitle:#"nil" message:#"ok. come back again tomorrow, not now." delegate:self cancelButtonTitle:#"Ok, Got it" otherButtonTitles:nil, nil];
[errr show];
any idea how to achieve this result? do i need NSNotification to listen when this alert show up on uiwebview?
I tried something like this
NSString *theTitle=[webView stringByEvaluatingJavaScriptFromString:#"var targetDiv = document.getElementById('alerts').getElementsByClassName('alert-red')[0];"];
NSLog(#"%#",theTitle);
So I can try to retrieve that message from "alert-red" but doesn't work.
I'm new to javascript and html
This is the typical workaround used to solve this problem:
in your webpage when you want to show this alert, run this javascript code:
window.location = 'custom_action';
then in objc implement shouldStartLoadWithRequest on your controller (and set yourWebView.delegate = yourController)
-(BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
// detect when the webview switches to this custom url
if([[[request URL] absoluteString] isEqualToString: #"custom_action"]) {
UIAlertView *errr = [[UIAlertView alloc]initWithTitle:#"nil" message:#"ok. come back again tomorrow, not now." delegate:self cancelButtonTitle:#"Ok, Got it" otherButtonTitles:nil, nil];
[errr show];
// this prevents the webview from actually trying to load the custom url
return NO;
}
// allow the url to load if its not your custom url
return YES;
}

WKWebview's javascript call returns nil

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

stringByEvaluatingJavaScriptFromString returns empty string but in safari returns a full string

I'm calling stringByEvaluatingJavaScriptFromString with a js function call ([self.webview stringByEvaluatingJavaScriptFromString:#"someMethod()"].
On the iphone it is returning an empty string but when I debug in safari using "Develop -> myphone -> index.html" the same call returns a correct result as expected.
I should also point out that the JS file with the method sits locally on the device as with the whole "website"
How can i check this ?
First, you need to be sure that the webView has loaded properly, so do any code after it has notified you that it's done with the UIWebViewDelegate method. Then, you have to make sure that you are at the right URL for that JS method to work (you could be redirected to a mobile site (look for .m in the URL)). If you are, there's probably no helping it, so you will have to test any JS you'll use on the iPhone on the mobile website, by opening the same URL in your computer and looking around. Run this test:
#import "MyWebViewController.h"
#interface MyWebViewController() <UIWebViewDelegate>
// If you have a storyboard
#property (nonatomic, weak) IBOutlet UIWebView *webView;
// If you don't have a storyboard
// #property (nonatomic, strong) UIWebView *webView;
#end
#implementation MyWebViewController
- (void)viewDidLoad
{
// If you don't have a storyboard
// self.webView = [[UIWebView alloc] initWithFrame:self.view.frame];
// [self.view addSubview:self.webView];
self.webView.delegate = self;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSLog(#"The URL of the site we are on is: %#", webView.request.URL.absoluteString);
NSLog(#"Now, I'll evaluate the JS: %#", [webView stringByEvaluatingJavaScriptFromString:#"someMethod()"]);
}
#end

I would like to export the contents of ios web view as html

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

(iOS) Run bookmarklets in UIWebView?

I am trying to add Readability (a third party app) compatibility with my web browser, and I tracked down a bookmarklet to save a page to Readability:
javascript:(%28function%28%29%7Bwindow.baseUrl%3D%27http%3A//www.readability.com%27%3Bwindow.readabilityToken%3D%27bbRmvVb9nTNRWSVEGb9yrcFP4USUHnTjk2EVWXjn%27%3Bvar%20s%3Ddocument.createElement%28%27script%27%29%3Bs.setAttribute%28%27type%27%2C%27text/javascript%27%29%3Bs.setAttribute%28%27charset%27%2C%27UTF-8%27%29%3Bs.setAttribute%28%27src%27%2CbaseUrl%2B%27/bookmarklet/read.js%27%29%3Bdocument.documentElement.appendChild%28s%29%3B%7D%29%28%29)
however, I can't seem to get it to work. It works in desktop Safari and mobile/iPhone Safari. But both of the methods below do nothing:
[webview stringByEvaluatingJavaScriptFromString: readability];
[webview loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString: readability]]];
(readability is a string with the value above)
Is there another method to run javascript bookmarklets that I am unaware of or am I doing something wrong? Help is much appreciated.
Greg
You got this error is because the javascript url is encoded, you should decode the javascript string, (may be you use NSURL to pass the string, so it was encoded by NSURL)
then use the webview stringByEvaluatingJavaScriptFromString, this solution work well
-(void)loadUrl:(NSURL*)url
{
if ([[url scheme] isEqualToString:#"javascript"])
{
NSRange range = [[url absoluteString] rangeOfString:#"javascript:"];
NSString *javaScriptString = [[[url absoluteString] substringFromIndex:range.location + range.length] URLDecodedString];
[self stringByEvaluatingJavaScriptFromString:javaScriptString];
}
else
{
[self loadRequest:[NSURLRequest requestWithURL:url]];
}
}
You probably need to use their API. What you are trying to do is likely prevented for security reasons, and you need to put your own API key in the request.

Categories

Resources