Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opening WebView links in Safari

Tags:

cocoa

I am developing an application in Cocoa, and I would like to know if there is a way/how to make any link clicked in my webview to launch in Safari (or the default browser). Thanks in advance!

like image 286
Michael Avatar asked Dec 25 '10 15:12

Michael


2 Answers

I just ran into this problem myself, and solved it this way:

My main controller object was set as the policyDelegate for the WebView.

Then implement this method:

- (void)webView:(WebView *)webView 
    decidePolicyForNavigationAction:(NSDictionary *)actionInformation
    request:(NSURLRequest *)request frame:(WebFrame *)frame 
    decisionListener:(id < WebPolicyDecisionListener >)listener
{
    NSString *host = [[request URL] host];
    if (host) {
        [[NSWorkspace sharedWorkspace] openURL:[request URL]];
    } else {
        [listener use];
    }
}

I needed to have the check for the host there, because otherwise when I load the initial content of the WebView (just a static html page in my project), it was being launched in Safari. Now, just links with actual hosts (external links) get sent to Safari, which is the behavior I wanted. I think I could also have not set the policyDelegate until after the initial page was loaded.

like image 106
Laura Avatar answered Oct 25 '22 18:10

Laura


I came across the same problem and the solution I have found is not too intuitive.

As a previous answer indicated, you have to use the WebPolicyDelegate protocol, defined in <WebKit/WebPolicyDelegate.h>. It is an informal protocol, so you cannot write @interface MyDelegate : NSObject <WebPolicyDelegate>.

#import <WebKit/WebPolicyDelegate.h> (or the whole WebKit.h) and implement the webView:decidePolicyForNavigationAction:request:frame:decisionListener: method as follows:

- (void)webView:(WebView *)webView 
decidePolicyForNavigationAction:(NSDictionary *)actionInformation
        request:(NSURLRequest *)request 
          frame:(WebFrame *)frame 
decisionListener:(id <WebPolicyDecisionListener>)listener
{
  if ([actionInformation objectForKey:WebActionElementKey]) {
    [listener ignore];
    [[NSWorkspace sharedWorkspace] openURL:[request URL]];
  }
  else {
    [listener use];
  }
}

Then set your class as PolicyDelegate for the WebView.

Logic dictates you should use a different key from the actionInformation dictionary, namely WebActionNavigationTypeKey, whose value should be an enum that can include WebNavigationTypeLinkClicked. Unfortunately, the values I have seen look random and far beyond the correct range (6 decimal digits integers while the enum goes from 0 to 5).

But, there is something else to check, the WebActionElementKey, that returns the HTML entity that originates the navigation action. When loading data in the frame from code, its value is nil whereas when user clicks a link, its value is the (parsed) <a> entity. Checking it for non-nil value does the trick.

like image 42
Raúl Pedroche Avatar answered Oct 25 '22 18:10

Raúl Pedroche