UIWebView membuka tautan di Safari

304

Saya memiliki UIWebView yang sangat sederhana dengan konten dari bundel aplikasi saya. Saya ingin tautan apa pun dalam tampilan web dibuka di Safari alih-alih dalam tampilan web. Apakah ini mungkin?

David Beck
sumber
Jawaban yang diterima di bawah tidak akan berfungsi dalam semua kasus.
IanS
Saya telah menambahkan jawaban yang lebih baik. Harap tandai jawaban saya sebagai yang diterima.
IanS

Jawaban:

657

Tambahkan ini ke delegasi UIWebView:

(diedit untuk memeriksa jenis navigasi. Anda juga dapat melewati file://permintaan yang merupakan tautan relatif)

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

    return YES;
}

Versi Swift:

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

Versi 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
}

Versi 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
}

Memperbarui

Seperti yang openURLtelah ditinggalkan di 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;
}
ditarik ke depan
sumber
ditarik ke depan, maukah Anda memperbarui jawaban Anda dengan mengacu pada jawaban dan komentar di bawah ini.
Toby Allen
Bagaimana cara kembali ke aplikasi begitu pengguna menutup browser?
Johnny Everson
3
@ Jhonny Everson: Anda tidak memiliki kendali atas apa yang terjadi setelah aplikasi eksternal apa pun (termasuk Safari) ditutup. Jika Anda ingin kembali ke aplikasi saat pengguna selesai menjelajah, jangan buka Safari, cukup gunakan UIWwbView dan tombol "Selesai".
geon
1
Bekerja seperti pesona dengan file HTML lokal.
necixy
1
Saya pikir, di Swift, a switchlebih disukai untuk tipe enum
SDJMcHattie
44

Jika ada yang bertanya-tanya, solusi Drawnonward akan terlihat seperti ini di Swift :

func webView(webView: UIWebView!, shouldStartLoadWithRequest request: NSURLRequest!, navigationType: UIWebViewNavigationType) -> Bool {
    if navigationType == UIWebViewNavigationType.LinkClicked {
        UIApplication.sharedApplication().openURL(request.URL)
        return false
    }
    return true
}
DiegoFrings
sumber
ada ide bagaimana melakukan ini HANYA dengan URL yang memiliki https: // http: // atau mailto :? menggunakan swift? Pertanyaan di sini membutuhkan jawaban cepat! stackoverflow.com/questions/2532453/…
Jed Grant
@JedGrant versi cepat sekarang di stackoverflow.com/questions/2532453/...
Carl Sharman
2
pastikan untuk menggunakanUIWebViewDelegate
Jay Mayu
28

Satu komentar cepat untuk jawaban user306253: hati-hati dengan ini, ketika Anda mencoba memuat sesuatu di UIWebView sendiri (yaitu, bahkan dari kode), metode ini akan mencegahnya terjadi.

Yang dapat Anda lakukan untuk mencegah hal ini (terima kasih Wade) adalah:

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

return YES;

Anda mungkin juga ingin menangani UIWebViewNavigationTypeFormSubmitteddan UIWebViewNavigationTypeFormResubmittedjenisnya.

MonsieurDart
sumber
8
+1 Saya mengalami masalah yang sama. Solusi adalah memeriksa UIWebViewNavigationTypeLinkClicked sebagai jenis permintaan, MAKA buka URL dan kembali TIDAK, jika tidak kembalikan YA.
Wade Mueller
Wade Anda harus memposting komentar Anda sebagai jawaban
Toby Allen
16

Jawaban lain memiliki satu masalah: mereka bergantung pada tindakan yang Anda lakukan dan bukan pada tautan itu sendiri untuk memutuskan apakah akan memuatnya di Safari atau di tampilan web.

Sekarang kadang-kadang inilah yang Anda inginkan, yang baik-baik saja; tetapi di lain waktu, terutama jika Anda memiliki tautan jangkar di halaman Anda, Anda benar-benar ingin membuka hanya tautan eksternal di Safari, dan bukan yang internal. Dalam hal ini Anda harus memeriksa URL.hostproperti permintaan Anda.

Saya menggunakan potongan kode itu untuk memeriksa apakah saya memiliki nama host di URL yang sedang diuraikan, atau apakah html yang disematkan:

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

Tentu saja Anda dapat menyesuaikan ekspresi reguler agar sesuai dengan kebutuhan Anda.

KPM
sumber
Catatan: ekspresi reguler berasal dari stackoverflow.com/questions/106179/…
KPM
1
Ya to the point tentang memfilter permintaan masuk, tidak ke penguraian hostname. Pendekatan yang lebih baik adalah menyaring berdasarkan skema URL. Di iOS 8.4 (simulator), saya menggunakan "applewebdata" yang digunakan sebagai skema untuk tautan jangkar, tetapi itu mungkin berbeda dengan versi target.
MandisaW
Ide bagus MandisaW. Untuk mengizinkan tautan jangkar, saya memeriksa skema "file"if (request.URL?.scheme != "file")
David Douglas
7

Di Swift Anda dapat menggunakan kode berikut:

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
    }

}

Pastikan Anda memeriksa nilai URL dan Tipe navigasi.

Antoine
sumber
1

Inilah Xamarin iOS yang setara dengan jawaban 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;
    }
}
danfordham
sumber
1

Jawaban yang diterima tidak berfungsi.

Jika halaman Anda memuat URL melalui Javascript, itu navigationTypeakan menjadi UIWebViewNavigationTypeOther. Yang, sayangnya, juga mencakup pemuatan laman latar belakang seperti analitik.

Untuk mendeteksi navigasi halaman, Anda perlu membandingkannya [request URL]dengan [request mainDocumentURL].

Solusi ini akan berfungsi dalam semua kasus:

- (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;
    }
}
Ian
sumber
1
Bisakah Anda memposting versi Swift 4 ini?
Amjad
1

Catatan penolakan aplikasi:

Akhirnya UIWbViewmati dan Apple tidak akan lagi menerimanya.

Apple mulai mengirim email ke semua pemilik Aplikasi yang masih menggunakan UIWebView:

Penggunaan API yang Tidak Digunakan - Apple akan berhenti menerima pengiriman aplikasi yang menggunakan UIWebViewAPI.

Apple memperlakukan Privasi Pengguna dengan sangat serius dan jelas bahwa mereka tidak akan mengizinkan tampilan web yang tidak aman .

Jadi jangan hapus UIWebView dari aplikasi Anda sesegera mungkin. jangan gunakan coba gunakan UIWebViewdi aplikasi baru yang dibuat dan saya lebih suka menggunakan WKWebViewjika mungkin

ITMS-90809: Penggunaan API yang Tidak Digunakan - Apple akan berhenti menerima pengajuan aplikasi yang menggunakan API UIWebView. Lihat https://developer.apple.com/documentation/uikit/uiwebview untuk informasi lebih lanjut.

Contoh:

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")
    }
}
Nazmul Hasan
sumber
0

Dalam kasus saya, saya ingin memastikan bahwa semua yang ada di tampilan web membuka Safari kecuali beban awal dan jadi saya menggunakan ...

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