UIWebView respond to Javascript calls - iphone

How can I intercept Javascript calls such as window.open as Mobile Safari does? I haven't seen anything listed about this, but it must be possible somehow?
Has anyone done this before?

When the page is finished loaded (webViewDidFinishLoad:), inject a window.open override. Of course it will not work for window.open which are called during page load.
Then use a custom scheme to callback your objective C code.
[EDIT] OK I have tested it. Now it works.
Create a new "view based" project and add a webview in the viewcontroller xib using IB.
#implementation todel2ViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
NSString* page = #"<html><head></head><body><div onclick='javascript:window.open(\"http://www.google.com\");'>this is a test<br/>dfsfsdfsdfsdfdsfs</div></body></html>";
[self.view loadHTMLString:page baseURL:[NSURL URLWithString:#""]];
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString* urlString = [[request URL ] absoluteString ];
NSLog(#"shouldStartLoadWithRequest navigationType=%d", navigationType);
NSLog(#"%#", urlString);
if ([[[request URL] scheme] isEqualToString:#"myappscheme"] == YES)
{
//do something
NSLog(#"it works");
}
return YES;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
//Override Window
NSString*override = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"NewWindow" ofType:#"js"] encoding:4 error:nil];
[self.view stringByEvaluatingJavaScriptFromString:override];
}
#end
The Javascript:
var open_ = window.open;
window.open = function(url, name, properties)
{
var prefix = 'csmobile://';
var address = url;
open_(prefix + address);
return open_(url, name, properties);
};
The log
2011-07-05 14:17:04.383 todel2[31038:207] shouldStartLoadWithRequest navigationType=5
2011-07-05 14:17:04.383 todel2[31038:207] myappscheme:it%20works
2011-07-05 14:17:04.384 todel2[31038:207] it works
2011-07-05 14:17:04.386 todel2[31038:207] shouldStartLoadWithRequest navigationType=5
2011-07-05 14:17:04.386 todel2[31038:207] http://www.google.com/

Related

Xcode 4.3 from a button in a UIWebView open the same url in safari

I am relatively new to Xcode and I have started building an app that uses UIWebView. To make it compliant for App Store submission, Apple prefers you use Safari. To overcome this problem I want to add a button to my UIWebView navigation that, when clicked, will open the same url in Safari. An example of this can be seen in the Twitter app; they have a button that opens the currently viewed UIWebView in a Safari window.
You can use the UIWebViewDelegate's method
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if iWantToOpenThisURLInSafari([request URL]) {
[UIApplication openUrl:[request URL]];
return NO; // tell the webView to not navigate to the URL, I'm handling it
} else {
return YES;
}
}
- (BOOL)iWantToOpenThisURLInSafari:(NSURL* url) [
// you just have to fill in this method.
return NO;
}
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIWebViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intf/UIWebViewDelegate
EDIT: more details as requested by #PaulGraham
// You have a pointer to you webView somewhere
UIWebView *myWebView;
// create a class which implements the UIWebViewDelegate protocol
#interface MyUIWebViewDelegate:NSObject<UIWebViewDelegate>
// in this class' #implementation, implement the shouldStartLoad..method
#implementation
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if iWantToOpenThisURLInSafari([request URL]) {
[UIApplication openUrl:[request URL]];
return NO; // tell the webView to not navigate to the URL, I'm handling it
} else {
return YES;
}
}
// then, set the webView's delegate to an instance of that class
MyUIWebViewDelegate* delegate = [[MyUIWebViewDelegate alloc] init];
webView.delegate = delegate;
// your delegate will now recieve the shouldStartLoad.. messages.

iOS: Webview causes flicking while navigating to another controller

I use webview in my UIVIewController and load the local HTML file in it using following method.
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:filePath]]];
If I put this method in ViewDidLoad, I can see white flicking while navigating to my controller that doesn't look good.
I tried putting this method in ViewWillAppear like below. I am using webViewLoaded flag to make sure that webview has been loaded then only show the current view else it waits but it is going in infinite loop of waiting!
- (void)viewWillAppear:(BOOL)animated {
webViewLoaded = NO;
webView.scalesPageToFit = allowZoom;
webView.dataDetectorTypes = UIDataDetectorTypeNone;
webView.delegate = self;
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:filePath]]];
int count = 0;
while(webViewLoaded == NO)
{
NSLog(#"Waiting...");
[NSThread sleepForTimeInterval:0.1];
if(count++ > 10) break;
}
}
- (void)webViewDidFinishLoad:(UIWebView *)localwebView {
webViewLoaded = YES;
}
I have also tried the same thing in ViewDidLoad but still its going in infinite loop.
Please note that webViewLoaded is "volatile BOOL" but the webview delegate method is not getting called. Not sure what's going on!
Could anyone please help me to fix this. Thanks.
First : You're blocking your main thread and not giving WebView any chance to finish loading. Never block your main thread.
Second : There are two UIWebView delegate methods : webViewDidFinishLoad and webView:didFailLoadWithError: - make sure to listen to both.
If you're trying to wait until WebView completes loading and only show your controller afterwards - use delegation or blocks. Please note that this is not a proper way of doing things - i'm just modifying your example to make it work :
child controller (with WebView) :
-(void)startLoadingWithParent:(id)_parent {
self.parent = _parent;
NSURL * url = [[NSBundle mainBundle] URLForResource:#"resource" withExtension:#"html"];
[webView loadRequest:[NSURLRequest requestWithURL:url]];
}
-(void)webViewDidFinishLoad:(UIWebView *)webView {
[parent showMe:self];
}
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
[parent showError:error];
}
master controller :
-(void)doSomething {
SecondController * ctrl; /// secondController should be created AND has its view loaded at this point
/// ctrl = [SecondController new];
/// ctrl.view;
[ctrl startLoadingWithParent:self];
/// show user that we're doing something - display activity indicator or something
}
-(void)showMe:(UIViewController*)me {
[self.navigationController pushViewControllerAnimated:me];
}
Try using [NSURL fileURLWithPath:filePath]
use Following code for
[self performSelectorInBackground:#selector(webViewLoaded) withObject:nil];
so that it will not affect your UI

Passing a URL from one UIWebView to another UIWebview

When a user clicks a link in the present UIWebView a new view is pushed onto the navigationController's stack that contains a UIWebView. I'd like to pass the URL that was touched to this new UIWebView. How do I go about doing this?
In your UIWebView delegate:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if( navigationType == UIWebViewNavigationTypeLinkClicked ) {
YourWebViewController* vc = [[YourWebViewController alloc] initWithURL:[request URL]];
[self.navigationController pushViewController:vc animated:YES];
[vc release];
return NO;
}
return YES;
}
Then you just need to implement the initializer in your custom viewcontroller:
- (id)initWithURL:(NSURL*)url {
self = [super init];
if( self ) {
myURL = [url retain];
}
return self;
}
Then load it at an appropriate time, like viewDidAppear:
- (void)viewDidAppear:(BOOL)animated {
[webView loadRequest:[NSURLRequest requestWithURL:myURL]];
}

How can I dismissModalViewController when a user hits GO?

I have a view and a button. When the button is pushed, I present a modal view controller that has a uiwebview, and a navigation bar at the top. The hardcoded uiwebview shows a login prompt. Once the user goes in and enters the correct login credentials and hits GO on the keyboard, I not only need it to authenticate me into the server, but also dismiss the modal view controller.
Note the text field I enter data into is part of the website loaded in uiwebview...
When I hit enter now, the web page authenticates, and everything is peachy, but I just need a way to tie in a
[self dismissModalViewControllerAnimated:YES];
command when they hit GO...any thoughts?
Thanks
EDIT
Here is the code that I am implementing in the loginView:
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [[NSURL alloc] initWithString: #"http://website"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
[webView loadRequest: request];
[request release];
[url release];
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[self dismissModalViewControllerAnimated:YES];
return YES;
}
-(IBAction) done{
[self dismissModalViewControllerAnimated:YES];
}
First determine the URL the webpage takes you to on successful login, let's say it's http://website/logedin. Implement UIWebViewDelegate, and detect when a request is made to that address:
- (BOOL)webView:(UIWebView *)wv shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([[request.URL absoluteString] isEqualToString:#"http://website/logedin"]) {
[self dismissModalViewControllerAnimated:YES];
return NO;
}
return YES;
}
you can try with below sample code;
#interface WebViewController : UIViewController {
}
UIWebViewDelegate having few delegate methods, you have to implement it in WebViewController.m (for eg).
-(void) webViewDidStartLoad:(UIWebView *)webView{
}
-(void) webViewDidFinishLoad:(UIWebView *)webView{
-(void) webViewDidFinishLoad:(UIWebView *)webView
}
-(void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
}
Before this, you have to set the delegate for UIWebView from Interface Builder.

Catching modal UIWebView links touches

I have a view controller and I am intercepting the touches on links within the web views it manages.
My main view controller has this method.
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
//I can see this request come in upon a touch
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
NSLog(#"raw: %#", urlString);
//do some stuff (like figure out what capturedFilename is)
ExplainViewController *explanation = [[ExplainViewController alloc] initWithNibName:#"ExplainViewController" bundle:nil file:capturedFilename];
[self.navigationController presentModalViewController:explanation animated:YES];
}
And this loads a modal view properly.
ExplainViewController has a webView itself. When a user touches a link within ExplainViewConroller I'd like to handle that request too (and present another modal view).
ExplainViewController has this but I get no log activity from either method (the following nor the previous):
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
NSLog(#"raw: %#", urlString);
}
I want to know where this link touch request is going and how I can intercept it.
Both mentioned view controllers are using this in their .h
<UIWebViewDelegate>
You mention that both view controllers conform to the UIWebViewDelegate protocol, but is the delegate outlet of the UIWebView in the nib for ExplainViewController.h set to an instance of ExplainViewController. It will not call the method unless the UIWebView delegate property is set.
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
BrowserController *browserController = [[BrowserController alloc] initWithUrl:request.URL.absoluteString];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:browserController];
[self.navigationController presentModalViewController: navController animated:YES];
[browserController release];
[navController release];
return NO;
}
return YES;
}