Saulius Antanavicius
Saulius Antanavicius

Reputation: 1381

Stop WebView from going to any urls

I've made a simple app for mac, however when it laods in content(via JS) it redirects due to adds or something, is there any way to prevent WebView to going to any other URL than the one defined in the code?

Currently trying to stop it with (UPDATED)

webberAppDelegate.h

#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
@interface webberAppDelegate : NSObject <NSApplicationDelegate> {
    WebView *webview;
}

@property (assign)IBOutlet WebView *webview;

@end

webberAppDelegate.m

#import "webberAppDelegate.h"

@implementation webberAppDelegate

//@synthesize window;
//@synthesize webber;
@synthesize webview;

- (void)applicationDidFinishLaunching:(NSNotification *)Notification 
{
    NSURL*url=[NSURL URLWithString:@"http://simplyshows.com/dev/forums/"];
    NSURLRequest*request=[NSURLRequest requestWithURL:url];
    [[webview mainFrame] loadRequest:request];
    webview.resourceLoadDelegate = self;

}

-(NSURLRequest*) webView:(WebView*)webview resource:(id)sender willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectresponse fromDataSource:(WebDataSource*)dataSource {
    NSLog(@"willSendRequest delegate method called");
}

@end

Upvotes: 1

Views: 4124

Answers (4)

ACBM
ACBM

Reputation: 667

Although jstevenco's answer explains how you can know if a webview is trying to go to another url, it doesn't answer how you can prevent the webview from going to such url.

If you want to prevent WebView to going to any other URL you must implement the WebPolicyDelegate Protocol. It's important to note that this is an informal protocol so you cannot write @interface MyDelegate : NSObject <WebPolicyDelegate>.

Instead in your webberAppDelegate.h import Webkit:

#import <WebKit/WebPolicyDelegate.h>

and in webberAppDelegate.m implement the method webView:decidePolicyForNavigationAction:request:frame:decisionListener:, this method "is invoked every time a server redirect is encountered unless blocked by an earlier policy decision". (WebPolicyDelegate Protocol Documentation)

In this method you need to tell the decisionListener that it must ignore any redirection. This is the implementation:

 - (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation
         request:(NSURLRequest *)request
           frame:(WebFrame *)frame
decisionListener:(id <WebPolicyDecisionListener>)listener { 

        [listener ignore];

     }

However, beware with this implementation because you will ignore ANY redirect, and I don't think that's what you want (it would be a static webpage); more likely, what you want it's to prevent redirections that leave your domain so probably what you really want is:

 - (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation
         request:(NSURLRequest *)request
           frame:(WebFrame *)frame
decisionListener:(id <WebPolicyDecisionListener>)listener { 


    if (![[[request URL] absoluteString] hasPrefix:@"yourdomain.com"]) {

        [listener ignore];
    }

  }

Upvotes: 0

Jimmy Koerting
Jimmy Koerting

Reputation: 1241

As far as I can say, these two delegate methods can catch URLs for other frames/content. You should try around and test them on your pages. Read the Help for these methods to see how to e.g. prevent the client redirect.

// WebView delegate methods

// Used to indicate that we've started loading (so that we can update our progress indicator
// and status text field)
- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame
{
    if( frame == [myWebView mainFrame] )
        NSLog(@"EntryController: Started loading mainFrame");
    else
        NSLog(@"EntryController: Started loading Frame : %@", [[frame.dataSource request] URL]); 
}


- (void)webView:(WebView *)sender willPerformClientRedirectToURL:(NSURL *)URL
          delay:(NSTimeInterval)seconds fireDate:(NSDate *)date
          forFrame:(WebFrame *)frame
{
    NSLog(@"EntryController: willPerformClientRedirectToURL: %@",URL);    
}

greetings Jimmy

Upvotes: 0

jstevenco
jstevenco

Reputation: 2953

See here for details on connection:willSendRequest:redirectResponse:

UPDATED: sorry, I breezed right over the fact that this is a Mac app not an iPhone app. Limited experience with the former; however, I believe that the same concepts apply, just instantiated differently.

Looking at the documentation, it looks like you want webView:resource:willSendRequest:redirectResponse:fromDataSource (see here for details). You'll also need to set webberAppDelegate's resourceLoadDelegate to self.

UPDATED: okay, here's a bit more detail on the process. You need to understand a bit about how protocols and delegates work in Objective-C. Read that material in support of what follows.

Protocols function like interfaces in Java or C#, or abstract functions in C++. They are basically a form of contract. They are mandatory by default but can be marked explicitly as @optional, meaning the compiler won't choke if one is omitted. If you look at the documentation for WebResourceLoadDelegate, you'll see that all the methods are optional. We want just one here, the webView:resource:willSendRequest:redirectResponse:fromDataSource method.

The other part of this is the concept of the delegate. Delegates function as callbacks. This involves both an object that will carry out the callback logic and an implementation of the logic (i.e., the implementation of the method from the protocol above). This can be implemented in a number of ways, but Cocoa has a more-or-less standardized way of doing it. You need to provide the implementation of the method, and you need to identify which object is going to carry out the logic. Note that WebView has a bunch of different delegate protocols. Adopting all or part of one of them is called conforming to the protocol. This is stated in code as (I am providing a skeleton of your class here):

@interface webberAppDelegate : NSObject<WebResourceLoadDelegate> {
    WebView* webview;
}
@end

here I'm assuming you derive from NSObject; substitute whatever your base class is. This lets the compiler know to expect that you'll provide implementations of the mandatory methods as well as whichever optional methods you require. It will complain if you do not implement the mandatory methods.

The more critical piece is to establish that the Webview ivar has a delegate that is going to provide implementations for one or all of methods declared by WebResourceLoadDelegate. You have a property for this ivar -- webview. Somewhere (e.g., in the viewDidLoad -- that's where I'd do it in iOS) you need to declare:

webview.resourceLoadDelegate = self;

assuming you want the callback handled by webberAppDelegate. Then in webberAppDelegate's implementation you need to provide the definition for the method webView:resource:willSendRequest:redirectResponse:fromDataSource:

-(NSURLRequest*) webView:(WebView*)webview resource:(id)sender willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectresponse fromDataSource:(WebDataSource*)dataSource {
    NSLog(@"willSendRequest delegate method called");
}

If you implement this much, you should see the log statement echoed in the console when you run your application. It's in that method that you need to handle the redirect. As I said before, I'm not well versed in the implementation of this protocol. According to this thread, it may actually be the WebPolicyDelegate protocol that you want. The principles involved will be the same.

Upvotes: 2

Srikar Appalaraju
Srikar Appalaraju

Reputation: 73588

Yes you can do this. Implement

– webView:shouldStartLoadWithRequest:navigationType:

This delegate . This method gets called whenever your webview is about to make a request. So now when someone clicks a button on your webpage, you will get a call to this method. After you catch this call, you can choose to do whatever you want with it. Like redirect the link through your own servers, or log a request to your server about user activity etc.

Example - here you are trying to intercept any links clicked on your webpage & pass it through myMethodAction first.

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{ 
    if(navigationType == UIWebViewNavigationTypeLinkClicked)
    {
         if(overrideLinksSwitch.on == TRUE)
         {
             [self myMethodAction];
             [myWebView stopLoading];
             return YES;
         }
        else
        {
            return YES;
        }
    }
    return YES;
}

Hope this helps...

Upvotes: -1

Related Questions