2010-05-24 4 views
285

У меня очень простой UIWebView с контентом из моего приложения. Я хотел бы, чтобы любые ссылки в веб-представлении открывались в Safari, а не в веб-представлении. Это возможно?UIWebView open links in Safari

+0

Принятая ответ ниже не будет работать во всех случаях. – IanS

+0

Я добавил лучший ответ. Пожалуйста, отметьте мой ответ как принятый. – IanS

ответ

625

Добавьте к этому UIWebView делегата:

(отредактированный для проверки навигации типа можно также пройти через file:// запросов, которые были бы относительные ссылки.)

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { 
    if (navigationType == UIWebViewNavigationTypeLinkClicked) { 
     [[UIApplication sharedApplication] openURL:[request URL]]; 
     return NO; 
    } 

    return YES; 
} 

Swift Версия:

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { 
     if navigationType == UIWebViewNavigationType.LinkClicked { 
      UIApplication.sharedApplication().openURL(request.URL!) 
      return false 
     } 
     return true 
    } 

Swift 3 версия:

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool { 
    if navigationType == UIWebViewNavigationType.linkClicked { 
     UIApplication.shared.openURL(request.url!) 
     return false 
    } 
    return true 
} 

Update

Как openURL устарел в ИО 10:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { 
     if (navigationType == UIWebViewNavigationTypeLinkClicked) { 
      UIApplication *application = [UIApplication sharedApplication]; 
      [application openURL:[request URL] options:@{} completionHandler:nil]; 
      return NO; 
     } 

     return YES; 
} 
+0

обратный, не могли бы вы обновить свой ответ со ссылкой на ответ и комментарии ниже. –

+0

Как вернуться к приложению после закрытия браузера? –

+3

@ Jhonny Everson: У вас нет контроля над тем, что произойдет после закрытия любого внешнего приложения (включая Safari). Если вы хотите вернуться в свое приложение, когда пользователь закончил просмотр, не открывайте Safari, просто используйте UIWwbView и кнопку «Готово». – geon

28

Один быстрый комментарий к ответу user306253 в: осторожность с этим, при попытке загрузить что-то в UIWebView самостоятельно (т.е. даже из кода), этот метод предотвратит его.

Что вы можете сделать, чтобы предотвратить это (спасибо Wade) является:

if (inType == UIWebViewNavigationTypeLinkClicked) { 
    [[UIApplication sharedApplication] openURL:[inRequest URL]]; 
    return NO; 
} 

return YES; 

Вы также можете обрабатывать UIWebViewNavigationTypeFormSubmitted и UIWebViewNavigationTypeFormResubmitted типов.

+8

+1 У меня была такая же проблема. Решение заключалось в том, чтобы проверить, что UIWebViewNavigationTypeLinkClicked как тип запроса, ТОГДА откройте URL-адрес и верните НЕТ, иначе верните ДА. –

+0

Wade вы должны выслать свой комментарий в качестве ответа –

15

Другие ответы имеют одну проблему: они полагаются на действие, которое вы делаете, а не на ссылку, чтобы решить, загружать ли ее в Safari или в веб-режиме.

Теперь иногда это именно то, что вы хотите, что хорошо; но иногда, особенно если у вас есть привязывающие ссылки на вашей странице, вы действительно хотите открыть только внешние ссылки в Safari, а не внутренние. В этом случае вы должны проверить свойство URL.host по вашему запросу.

я использую этот кусок кода, чтобы проверить, есть ли у меня имя хоста в URL, который будучи проанализирован, или если он встроен HTML:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { 
    static NSString *regexp = @"^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9-]*[a-zA-Z0-9])[.])+([A-Za-z]|[A-Za-z][A-Za-z0-9-]*[A-Za-z0-9])$"; 
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regexp]; 

    if ([predicate evaluateWithObject:request.URL.host]) { 
     [[UIApplication sharedApplication] openURL:request.URL]; 
     return NO; 
    } else { 
     return YES; 
    } 
} 

Конечно, Вы можете адаптировать регулярное выражение, чтобы соответствовать вашим необходимо.

+0

Примечание: регулярное выражение получено из http://stackoverflow.com/questions/106179/regular-expression-to-match-hostname-or-ip-address – KPM

+1

Да к пункт о фильтрации входящих запросов, нет для синтаксического анализа имени хоста. Лучшим подходом будет фильтрация на основе схемы URL. На iOS 8.4 (симулятор) я получил «applewebdata», используемый в качестве схемы для привязанных ссылок, но это может варьироваться в зависимости от целевой версии. – MandisaW

+0

Хорошая идея MandisaW. Чтобы разрешить привязные ссылки, я проверяю схему «файл» 'if (request.URL? .scheme! =" File ")' –

43

Если кто-то удивляется, решение Drawnonward был бы выглядеть в Swift:

func webView(webView: UIWebView!, shouldStartLoadWithRequest request: NSURLRequest!, navigationType: UIWebViewNavigationType) -> Bool { 
    if navigationType == UIWebViewNavigationType.LinkClicked { 
     UIApplication.sharedApplication().openURL(request.URL) 
     return false 
    } 
    return true 
} 
+0

любую идею, как это сделать ТОЛЬКО с URL-адресами, которые имеют https: // http: // или mailto :? используя быстрый? Вопрос здесь требует быстрого ответа! http://stackoverflow.com/questions/2532453/force-a-webview-link-to-launch-safari –

+0

@JedGrant быстрая версия сейчас на http://stackoverflow.com/questions/2532453/force-a-webview- link-to-launch-safari/30648750 # 30648750 – Carl

+4

изменить запрос.URL! для Swift 1.2+ –

0

В моем случае я хочу, чтобы убедиться, что абсолютно все в веб откроется окно Safari, кроме начальной загрузки и поэтому я использовать ...

- (BOOL)webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType { 
    if(inType != UIWebViewNavigationTypeOther) { 
     [[UIApplication sharedApplication] openURL:[inRequest URL]]; 
     return NO; 
    } 
    return YES; 
} 
7

В Swift вы можете использовать следующий код:

extension YourViewController : UIWebViewDelegate { 
    func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { 
     if let url = request.URL where navigationType == UIWebViewNavigationType.LinkClicked { 
      UIApplication.sharedApplication().openURL(url) 
      return false 
     } 
     return true 
    } 
} 

Убедитесь, что вы указали значение URL и тип navigationType.

1

Вот эквивалент XAMAIN iOS от обратного вызова.

class WebviewDelegate : UIWebViewDelegate { 
    public override bool ShouldStartLoad (UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navigationType) { 
     if (navigationType == UIWebViewNavigationType.LinkClicked) { 
      UIApplication.SharedApplication.OpenUrl (request.Url); 
      return false; 
     } 
     return true; 
    } 
} 
1

Принятый ответ не работает.

Если ваша страница загружает URL-адреса через Javascript, то navigationType будет UIWebViewNavigationTypeOther. К сожалению, к ним также относятся фоновые загрузки страниц, такие как аналитика.

Чтобы обнаружить навигацию по страницам, вам необходимо сравнить [request URL] с [request mainDocumentURL].

Это решение будет работать во всех случаях:

- (BOOL)webView:(UIWebView *)view shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)type 
{ 
    if ([[request URL] isEqual:[request mainDocumentURL]]) 
    { 
     [[UIApplication sharedApplication] openURL:[request URL]]; 
     return NO; 
    } 
    else 
    {  
     return YES; 
    } 
} 
+0

Можете ли вы опубликовать версию Swift 4? – Amjad