views:

639

answers:

2

I have an application using a WebKit WebView and I'd like to map URL's that are loaded in this WebView with a custom URL protocol to a different HTTP URL. For example, say I am loading:

custom://path/to/resource

I would like to internally actually load:

http://something-else.com/path/to/resource

In other words, the custom protocol serves almost as a shorthand. I can't however use -webView:resource:willSendRequest:redirectResponse:fromDataSource:, because I want WebKit to actually believe this is the URL in question, not to simply redirect from one to the other.

So far I've been attempting to use a custom NSURLProtocol subclass. However, this is proving trickier than I first thought because, at least to my understanding, I will have to do the actual loading myself in the NSURLProtocol subclass' startLoading method. I'd like a way to just hand off the work to the existing HTTP protocol loader, but I can't find an easy way to do this.

Does anyone have a recommendation for this, or perhaps an alternative way to solve this issue?

Thanks!

+1  A: 

I use the policy delegate. It has some disadvantages, but it's simple and sufficient for my needs. I do something like this:

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

{
    if ([request.URL.scheme isEqualToString:@"custom"]) {

        // do something interesting
        // like force the webview to load another URL

        [listener ignore];
        return;
    }

    [listener use];
}

For my use, I also need to stop the propagation of the JS events. So I usually place the URL in an onclick event handler that calls window.event.stopPropagation(); after setting the location.href.

It's not very fancy, but it's a very flexible and very simple way to communication a JS event to cocoa.

isaiah
Does this have the effect of making the webview think its at the custom protocol URL though? If I simply load a new URL from that if-block, I feel I'll be in the same position as before: effectively creating a redirect. But perhaps I am misunderstanding the fashion in which I am supposed to load a new URL from there.
Francisco Ryan Tolmasky I
"Does this have the effect of making the webview think its at the custom protocol URL though?" No, definitely not. If your goal is to set the href.location to one thing and load another, then this solution won't get you there. Sorry. In this case, when the custom scheme is detected, the even it killed -- so the location.href never changes. "effectively creating a redirect" It's not the same as a redirect. In a redirect the first URL is loaded, handled, etc. Then the next URL is loaded. Using the policy delegate and calling [listener ignore] completely kills the first URL load.
isaiah
A: 

You can implement the WebResourceLoadDelegate method:

- (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource

This should allow you to change the request for one with the HTTP URL.

Alternatively, implementing an NSURLProtocol subclass isn't very hard for this because your protocol can internally fire up another NSURLConnection using the correct HTTP URL and map its delegate methods to the protocol client's.

Mike Abdullah