Reputation: 1381
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)
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
@interface webberAppDelegate : NSObject <NSApplicationDelegate> {
WebView *webview;
}
@property (assign)IBOutlet WebView *webview;
@end
#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
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
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
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
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