UIWebView liên kết mở trong Safari


304

Tôi có một UIWebView rất đơn giản với nội dung từ gói ứng dụng của mình. Tôi muốn bất kỳ liên kết nào trong chế độ xem web sẽ mở trong Safari thay vì trong chế độ xem web. Điều này có thể không?


Câu trả lời được chấp nhận dưới đây sẽ không hoạt động trong mọi trường hợp.
IanS

Tôi đã thêm một câu trả lời tốt hơn. Vui lòng đánh dấu câu trả lời của tôi là câu được chấp nhận.
IanS

Câu trả lời:


657

Thêm phần này vào đại biểu UIWebView:

(được chỉnh sửa để kiểm tra loại điều hướng. Bạn cũng có thể chuyển qua file://các yêu cầu có liên kết tương đối)

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

    return YES;
}

Phiên bản Swift:

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

Phiên bản 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
}

Phiên bản Swift 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
}

Cập nhật

Như openURLđã bị phản đối trong iOS 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;
}

rút ra, bạn có phiền cập nhật câu trả lời của bạn với tham chiếu đến câu trả lời và ý kiến ​​dưới đây.
Toby Allen

Làm cách nào để quay lại ứng dụng sau khi người dùng đóng trình duyệt?
Johnny Everson

3
@ Jhonny Everson: Bạn không kiểm soát được những gì xảy ra sau khi bất kỳ ứng dụng bên ngoài nào (bao gồm cả Safari) bị đóng. Nếu bạn muốn quay lại ứng dụng của mình khi người dùng duyệt xong, đừng mở Safari, chỉ cần sử dụng UIWwbView và nút "Xong".
geon

1
Làm việc như một cơ duyên với tệp HTML cục bộ.
hoại tử

1
Tôi nghĩ, trong Swift, a switchthích hợp hơn cho các loại enum
SDJMcHattie 17/2/2016

44

Nếu có ai thắc mắc, giải pháp của Drawnonward sẽ giống như thế này trong Swift :

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

bất kỳ ý tưởng nào để làm điều này CHỈ với các URL có https: // http: // hoặc mailto:? sử dụng nhanh chóng? Câu hỏi ở đây cần một câu trả lời nhanh chóng! stackoverflow.com/questions/2532453/
Mạnh

@JedGrant phiên bản nhanh chóng ngay bây giờ trên stackoverflow.com/questions/2532453/ cấp
Carl Sharman

2
đảm bảo sử dụngUIWebViewDelegate
Jay Mayu

28

Một nhận xét nhanh cho câu trả lời của người dùng 306253: hãy cẩn thận với điều này, khi bạn cố gắng tự tải một cái gì đó trong UIWebView (tức là ngay cả từ mã), phương pháp này sẽ ngăn nó xảy ra.

Những gì bạn có thể làm để ngăn chặn điều này (cảm ơn Wade) là:

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

return YES;

Bạn cũng có thể muốn xử lý UIWebViewNavigationTypeFormSubmittedUIWebViewNavigationTypeFormResubmittedcác loại.


8
+1 Tôi có cùng một vấn đề. Giải pháp là kiểm tra UIWebViewNavlationTypeLinkClicky là loại yêu cầu, THÌ mở URL và trả về KHÔNG, nếu không thì trả về CÓ.
Wade Mueller

Wade bạn nên đăng bình luận của bạn như là một câu trả lời
Toby Allen

16

Các câu trả lời khác có một vấn đề: họ dựa vào hành động bạn làm chứ không dựa vào chính liên kết để quyết định tải nó trong Safari hay trong webview.

Bây giờ đôi khi đây là chính xác những gì bạn muốn, điều đó là tốt; nhưng một số lần khác, đặc biệt nếu bạn có các liên kết neo trong trang của mình, bạn thực sự muốn chỉ mở các liên kết bên ngoài trong Safari chứ không phải các liên kết nội bộ. Trong trường hợp đó bạn nên kiểm tra URL.hosttài sản của yêu cầu của bạn.

Tôi sử dụng đoạn mã đó để kiểm tra xem tôi có tên máy chủ trong URL đang được phân tích cú pháp hay nếu nó được nhúng 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; 
    }
}

Tất nhiên bạn có thể điều chỉnh biểu thức chính quy để phù hợp với nhu cầu của bạn.


Lưu ý: biểu thức chính quy được lấy từ stackoverflow.com/questions/106179/iêu
KPM

1
Có cho điểm về việc lọc các yêu cầu đến, không cho phân tích tên máy chủ. Cách tiếp cận tốt hơn sẽ là lọc dựa trên sơ đồ URL. Trên iOS 8.4 (trình giả lập), tôi đã sử dụng "applewebdata" làm sơ đồ cho các liên kết neo, nhưng điều đó có thể thay đổi theo phiên bản đích.
MandisaW

Ý tưởng tốt MandisaW. Để cho phép các liên kết neo, tôi kiểm tra lược đồ "tập tin"if (request.URL?.scheme != "file")
David Douglas

7

Trong Swift, bạn có thể sử dụng mã sau:

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
    }

}

Đảm bảo bạn kiểm tra giá trị URL và loại điều hướng.


1

Đây là Xamarin iOS tương đương với câu trả lời của drawonward.

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

Câu trả lời được chấp nhận không hoạt động.

Nếu trang của bạn tải URL thông qua Javascript, thì navigationTypesẽ như vậy UIWebViewNavigationTypeOther. Thật không may, cũng bao gồm tải trang nền như phân tích.

Để phát hiện điều hướng trang, bạn cần so sánh [request URL]với [request mainDocumentURL].

Giải pháp này sẽ hoạt động trong mọi trường hợp:

- (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
Bạn có thể đăng một phiên bản Swift 4 này không?
Amjad

1

Từ chối ứng dụng Lưu ý:

Cuối cùng UIWbViewlà chết và Apple sẽ không chấp nhận nó nữa.

Apple bắt đầu gửi email đến tất cả chủ sở hữu Ứng dụng vẫn đang sử dụng UIWebView:

Sử dụng API không dùng nữa - Apple sẽ ngừng chấp nhận việc gửi các ứng dụng sử dụng UIWebViewAPI.

Apple rất coi trọng Quyền riêng tư của Người dùng và rõ ràng là họ sẽ không cho phép xem web không an toàn .

Vì vậy, hãy xóa UIWebView khỏi ứng dụng của bạn càng sớm càng tốt. không sử dụng thử sử dụng UIWebViewtrong ứng dụng mới được tạo và tôi thích sử dụng WKWebViewnếu có thể

ITMS-90809: Sử dụng API không dùng nữa - Apple sẽ ngừng chấp nhận việc gửi các ứng dụng sử dụng API UIWebView. Xem https://developer.apple.com/documentation/uikit/uiwebview để biết thêm thông tin.

Thí dụ:

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

Trong trường hợp của tôi, tôi muốn đảm bảo rằng tất cả mọi thứ trong chế độ xem web sẽ mở Safari ngoại trừ tải ban đầu và vì vậy tôi sử dụng ...

- (BOOL)webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
     if(inType != UIWebViewNavigationTypeOther) {
        [[UIApplication sharedApplication] openURL:[inRequest URL]];
        return NO;
     }
     return YES;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.