Safari에서 UIWebView 열린 링크


304

내 응용 프로그램 번들의 내용이 포함 된 매우 간단한 UIWebView가 있습니다. 웹보기의 링크가 웹보기 대신 Safari에서 열리기를 원합니다. 이게 가능해?


아래에 허용 된 답변이 모든 경우에 적용되는 것은 아닙니다.
IanS

더 나은 답변을 추가했습니다. 내 답변을 수락 된 것으로 표시하십시오.
IanS

답변:


657

이것을 UIWebView 델리게이트에 추가하십시오 :

(탐색 유형을 확인하도록 편집되었습니다. file://상대 링크 인 요청을 통과 할 수도 있습니다)

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

    return YES;
}

스위프트 버전 :

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

스위프트 3 버전 :

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

스위프트 4 버전 :

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebView.NavigationType) -> Bool {
    guard let url = request.url, navigationType == .linkClicked else { return true }
    UIApplication.shared.open(url, options: [:], completionHandler: nil)
    return false
}

최신 정보

openURLiOS 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;
}

아래 답변과 의견을 참조하여 답변을 업데이트 하시겠습니까?
Toby Allen

사용자가 브라우저를 닫으면 응용 프로그램으로 돌아가는 방법은 무엇입니까?
Johnny Everson

3
@ Jhonny Everson : 외부 앱 (Safari 포함)을 닫은 후 발생하는 작업을 제어 할 수 없습니다. 사용자가 브라우징을 마쳤을 때 앱으로 돌아가려면 Safari를 열지 말고 UIWwbView와 "완료"버튼을 사용하십시오.
geon

1
로컬 HTML 파일의 매력처럼 작동했습니다.
necixy

1
Swift에서는 switch열거 형 유형에 a 가 바람직 하다고 생각 합니다.
SDJMcHattie

44

궁금한 점이 있다면 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
}

https : // http : // 또는 mailto :가있는 URL로만이 작업을 수행하는 방법에 대한 아이디어가 있습니까? 신속한 사용? 여기서 질문은 빠른 답변이 필요합니다! stackoverflow.com/questions/2532453/…
Jed Grant


2
사용하십시오UIWebViewDelegate
제이 마유에게

28

user306253의 답변에 대한 한 가지 간단한 설명 : UIWebView에 직접 (예 : 코드에서) 무언가를로드하려고하면이 방법으로 인해 발생하지 않도록주의하십시오.

이것을 방지하기 위해 할 수있는 일은 (Wade 덕분에) 다음과 같습니다.

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

return YES;

UIWebViewNavigationTypeFormSubmittedUIWebViewNavigationTypeFormResubmitted유형 을 처리 할 수도 있습니다.


8
+1 나는 같은 문제가 있었다. 해결책은 요청 유형으로 UIWebViewNavigationTypeLinkClicked를 확인한 다음 URL을 열고 NO를 반환하고 그렇지 않으면 YES를 반환합니다.
웨이드 뮬러

답변으로 댓글을 올리셔야합니다
Toby Allen

16

다른 답변에는 한 가지 문제가 있습니다. 링크에 의존하지 않고 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; 
    }
}

물론 필요에 맞게 정규식을 조정할 수 있습니다.



1
예, 들어오는 요청을 필터링 할 때, 호스트 이름 구문 분석은 아닙니다. 더 좋은 방법은 URL 체계를 기준으로 필터링하는 것입니다. iOS 8.4 (시뮬레이터)에서 앵커 링크의 구성표로 "applewebdata"가 사용되었지만 대상 버전에 따라 다를 수 있습니다.
MandisaW

좋은 생각 MandisaW. 앵커 링크를 허용하기 위해 "파일"체계를 확인합니다if (request.URL?.scheme != "file")
David Douglas

7

Swift에서는 다음 코드를 사용할 수 있습니다.

extension YourViewController: UIWebViewDelegate {
    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebView.NavigationType) -> Bool {
        if let url = request.url, navigationType == UIWebView.NavigationType.linkClicked {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
            return false
        }
        return true
    }

}

URL 값과 navigationType을 확인하십시오.


1

다음은 drawnonward의 답변과 동일한 Xamarin 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을로드하는 경우 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;
    }
}

1
Swift 4 버전을 게시 할 수 있습니까?
Amjad

1

앱 거부 참고 :

마침내 UIWbView애플은 죽었고 애플은 더 이상 받아들이지 않을 것이다.

Apple은 여전히 ​​사용중인 모든 앱 소유자에게 이메일을 보내기 시작했습니다 UIWebView.

더 이상 사용되지 않는 API 사용-Apple은 API를 사용하는 앱의 제출을 ​​허용하지 않습니다 UIWebView.

Apple은 사용자 개인 정보를 매우 중요하게 생각하며 안전하지 않은 웹뷰를 허용하지 않습니다 .

따라서 가능한 빨리 앱에서 UIWebView를 제거하십시오. UIWebView새로 만든 앱에서 사용하지 말고 WKWebView가능한 경우 사용 하는 것이 좋습니다

ITMS-90809 : 더 이상 사용되지 않는 API 사용-Apple은 UIWebView API를 사용하는 앱의 제출을 ​​허용하지 않습니다. 자세한 내용은 https://developer.apple.com/documentation/uikit/uiwebview 를 참조하십시오.

예:

import UIKit
import WebKit

class WebInfoController: UIViewController,WKNavigationDelegate {

    var webView : WKWebView = {
        var webview = WKWebView()
        return webview
    }()

    var _fileName : String!

    override func viewDidLoad() {
        self.view.addSubview(webView)
        webView.fillSuperview()
        let url = Bundle.main.url(forResource: _fileName, withExtension: "html")!
        webView.loadFileURL(url, allowingReadAccessTo: url)
        let request = URLRequest(url: url)
        webView.load(request)
    }


    func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {
        print(error.localizedDescription)
    }
    func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        print("Strat to load")
    }
    func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
        print("finish to load")
    }
}

0

필자의 경우 웹로드의 모든 것이 초기로드를 제외하고 Safari를 열도록하고 싶습니다.

- (BOOL)webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
     if(inType != UIWebViewNavigationTypeOther) {
        [[UIApplication sharedApplication] openURL:[inRequest URL]];
        return NO;
     }
     return YES;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.